Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/opcache/jit/zend_jit_ir.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend JIT                                                             |
4
   +----------------------------------------------------------------------+
5
   | Copyright © The PHP Group and Contributors.                          |
6
   +----------------------------------------------------------------------+
7
   | This source file is subject to the Modified BSD License that is      |
8
   | bundled with this package in the file LICENSE, and is available      |
9
   | through the World Wide Web at <https://www.php.net/license/>.        |
10
   |                                                                      |
11
   | SPDX-License-Identifier: BSD-3-Clause                                |
12
   +----------------------------------------------------------------------+
13
   | Authors: Dmitry Stogov <dmitry@php.net>                              |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#include "Zend/zend_cpuinfo.h"
18
#include "Zend/zend_types.h"
19
#include "Zend/zend_type_info.h"
20
#include "jit/ir/ir.h"
21
#include "jit/ir/ir_builder.h"
22
#include "jit/tls/zend_jit_tls.h"
23
24
#if defined(IR_TARGET_X86)
25
# define IR_REG_SP            4 /* IR_REG_RSP */
26
# define IR_REG_FP            5 /* IR_REG_RBP */
27
# define ZREG_FP              6 /* IR_REG_RSI */
28
# define ZREG_IP              7 /* IR_REG_RDI */
29
# define ZREG_FIRST_FPR       8
30
# define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7)) /* all preserved registers */
31
# if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
32
#  error
33
# endif
34
#elif defined(IR_TARGET_X64)
35
0
# define IR_REG_SP            4 /* IR_REG_RSP */
36
0
# define IR_REG_FP            5 /* IR_REG_RBP */
37
# if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
38
/* Use the first two arg registers of the preserve_none calling convention for FP/IP
39
 * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/X86/X86CallingConv.td#L1029 */
40
0
#  define ZREG_FP             12 /* IR_REG_R12 */
41
0
#  define ZREG_IP             13 /* IR_REG_R13 */
42
# else
43
#  define ZREG_FP             14 /* IR_REG_R14 */
44
#  define ZREG_IP             15 /* IR_REG_R15 */
45
# endif
46
0
# define ZREG_FIRST_FPR      16
47
# if defined(_WIN64)
48
#  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15))
49
/*
50
#  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<6) | (1<<7) | (1<<12) | (1<<13) | (1<<14) | (1<<15) | \
51
                               (1<<(16+6)) | (1<<(16+7)) | (1<<(16+8)) | (1<<(16+9)) | (1<<(16+10)) | \
52
                               (1<<(16+11)) | (1<<(16+12)) | (1<<(16+13)) | (1<<(16+14)) | (1<<(16+15)))
53
*/
54
#  define IR_SHADOW_ARGS     32
55
# else
56
0
#  define IR_REGSET_PRESERVED ((1<<3) | (1<<5) | (1<<12) | (1<<13) | (1<<14) | (1<<15)) /* all preserved registers */
57
# endif
58
#elif defined(IR_TARGET_AARCH64)
59
# define IR_REG_SP           31 /* IR_REG_RSP */
60
# define IR_REG_LR           30 /* IR_REG_X30 */
61
# define IR_REG_FP           29 /* IR_REG_X29 */
62
# if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
63
/* Use the first two arg registers of the preserve_none calling convention for FP/IP
64
 * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/AArch64/AArch64CallingConvention.td#L541 */
65
#  define ZREG_FP             20 /* IR_REG_X20 */
66
#  define ZREG_IP             21 /* IR_REG_X21 */
67
# else
68
#  define ZREG_FP             27 /* IR_REG_X27 */
69
#  define ZREG_IP             28 /* IR_REG_X28 */
70
# endif
71
# define ZREG_FIRST_FPR      32
72
# define IR_REGSET_PRESERVED ((1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23) | \
73
                              (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28)) /* all preserved registers */
74
#else
75
# error "Unknown IR target"
76
#endif
77
78
0
#define ZREG_RX ZREG_IP
79
80
#define OPTIMIZE_FOR_SIZE 0
81
82
/* IR builder defines */
83
#undef  _ir_CTX
84
0
#define _ir_CTX                 (&jit->ctx)
85
86
#if GCC_GLOBAL_REGS
87
# define IR_OPCODE_HANDLER_RET IR_VOID
88
#else
89
# define IR_OPCODE_HANDLER_RET IR_ADDR
90
#endif
91
92
#undef  ir_CONST_ADDR
93
0
#define ir_CONST_ADDR(_addr)    jit_CONST_ADDR(jit, (uintptr_t)(_addr))
94
#define ir_CONST_FUNC(_addr)    jit_CONST_FUNC(jit, (uintptr_t)(_addr), 0)
95
0
#define ir_CONST_FC_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), IR_FASTCALL_FUNC)
96
#define ir_CAST_FC_FUNC(_addr)  ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
97
  ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_I32))
98
# define ir_CONST_OPCODE_HANDLER_FUNC(_addr) \
99
0
  jit_CONST_OPCODE_HANDLER_FUNC(jit, _addr)
100
# define ir_CAST_OPCODE_HANDLER_FUNC(_addr)  ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
101
  ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_OPCODE_HANDLER_RET))
102
103
#define ir_CONST_FUNC_PROTO(_addr, _proto) \
104
  jit_CONST_FUNC_PROTO(jit, (uintptr_t)(_addr), (_proto))
105
106
#undef  ir_ADD_OFFSET
107
#define ir_ADD_OFFSET(_addr, _offset) \
108
0
  jit_ADD_OFFSET(jit, _addr, _offset)
109
110
#ifdef ZEND_ENABLE_ZVAL_LONG64
111
0
# define IR_LONG           IR_I64
112
0
# define ir_CONST_LONG     ir_CONST_I64
113
# define ir_UNARY_OP_L     ir_UNARY_OP_I64
114
0
# define ir_BINARY_OP_L    ir_BINARY_OP_I64
115
# define ir_ADD_L          ir_ADD_I64
116
0
# define ir_SUB_L          ir_SUB_I64
117
0
# define ir_MUL_L          ir_MUL_I64
118
0
# define ir_DIV_L          ir_DIV_I64
119
0
# define ir_MOD_L          ir_MOD_I64
120
# define ir_NEG_L          ir_NEG_I64
121
# define ir_ABS_L          ir_ABS_I64
122
# define ir_SEXT_L         ir_SEXT_I64
123
0
# define ir_ZEXT_L         ir_ZEXT_I64
124
# define ir_TRUNC_L        ir_TRUNC_I64
125
0
# define ir_BITCAST_L      ir_BITCAST_I64
126
# define ir_FP2L           ir_FP2I64
127
0
# define ir_ADD_OV_L       ir_ADD_OV_I64
128
0
# define ir_SUB_OV_L       ir_SUB_OV_I64
129
# define ir_MUL_OV_L       ir_MUL_OV_I64
130
# define ir_NOT_L          ir_NOT_I64
131
# define ir_OR_L           ir_OR_I64
132
0
# define ir_AND_L          ir_AND_I64
133
# define ir_XOR_L          ir_XOR_I64
134
0
# define ir_SHL_L          ir_SHL_I64
135
0
# define ir_SHR_L          ir_SHR_I64
136
0
# define ir_SAR_L          ir_SAR_I64
137
# define ir_ROL_L          ir_ROL_I64
138
# define ir_ROR_L          ir_ROR_I64
139
# define ir_MIN_L          ir_MIN_I64
140
# define ir_MAX_L          ir_MAX_I64
141
0
# define ir_LOAD_L         ir_LOAD_I64
142
#else
143
# define IR_LONG           IR_I32
144
# define ir_CONST_LONG     ir_CONST_I32
145
# define ir_UNARY_OP_L     ir_UNARY_OP_I32
146
# define ir_BINARY_OP_L    ir_BINARY_OP_I32
147
# define ir_ADD_L          ir_ADD_I32
148
# define ir_SUB_L          ir_SUB_I32
149
# define ir_MUL_L          ir_MUL_I32
150
# define ir_DIV_L          ir_DIV_I32
151
# define ir_MOD_L          ir_MOD_I32
152
# define ir_NEG_L          ir_NEG_I32
153
# define ir_ABS_L          ir_ABS_I32
154
# define ir_SEXT_L         ir_SEXT_I32
155
# define ir_ZEXT_L         ir_ZEXT_I32
156
# define ir_TRUNC_L        ir_TRUNC_I32
157
# define ir_BITCAST_L      ir_BITCAST_I32
158
# define ir_FP2L           ir_FP2I32
159
# define ir_ADD_OV_L       ir_ADD_OV_I32
160
# define ir_SUB_OV_L       ir_SUB_OV_I32
161
# define ir_MUL_OV_L       ir_MUL_OV_I32
162
# define ir_NOT_L          ir_NOT_I32
163
# define ir_OR_L           ir_OR_I32
164
# define ir_AND_L          ir_AND_I32
165
# define ir_XOR_L          ir_XOR_I32
166
# define ir_SHL_L          ir_SHL_I32
167
# define ir_SHR_L          ir_SHR_I32
168
# define ir_SAR_L          ir_SAR_I32
169
# define ir_ROL_L          ir_ROL_I32
170
# define ir_ROR_L          ir_ROR_I32
171
# define ir_MIN_L          ir_MIN_I32
172
# define ir_MAX_L          ir_MAX_I32
173
# define ir_LOAD_L         ir_LOAD_I32
174
#endif
175
176
/* A helper structure to collect IT rers for the following use in (MERGE/PHI)_N */
177
typedef struct _ir_refs {
178
  uint32_t count;
179
  uint32_t limit;
180
  ir_ref   refs[] ZEND_ELEMENT_COUNT(count);
181
} ir_refs;
182
183
#define ir_refs_size(_n)          (offsetof(ir_refs, refs) + sizeof(ir_ref) * (_n))
184
0
#define ir_refs_init(_name, _n)   _name = alloca(ir_refs_size(_n)); \
185
0
                                  do {_name->count = 0; _name->limit = (_n);} while (0)
186
187
static void ir_refs_add(ir_refs *refs, ir_ref ref)
188
0
{
189
0
  ir_ref *ptr;
190
191
0
  ZEND_ASSERT(refs->count < refs->limit);
192
0
  ptr = refs->refs;
193
0
  ptr[refs->count++] = ref;
194
0
}
195
196
static size_t zend_jit_trace_prologue_size = (size_t)-1;
197
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
198
static uint32_t allowed_opt_flags = 0;
199
static uint32_t default_mflags = 0;
200
#endif
201
static bool delayed_call_chain = false; // TODO: remove this var (use jit->delayed_call_level) ???
202
203
#ifdef ZTS
204
static size_t tsrm_ls_cache_tcb_offset = 0;
205
static size_t tsrm_tls_index = -1;
206
static size_t tsrm_tls_offset = -1;
207
208
# define EG_TLS_OFFSET(field) \
209
  (executor_globals_offset + offsetof(zend_executor_globals, field))
210
211
# define CG_TLS_OFFSET(field) \
212
  (compiler_globals_offset + offsetof(zend_compiler_globals, field))
213
214
# define jit_EG(_field) \
215
  ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
216
217
# define jit_CG(_field) \
218
  ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
219
220
#else
221
222
# define jit_EG(_field) \
223
0
  ir_CONST_ADDR(&EG(_field))
224
225
# define jit_CG(_field) \
226
  ir_CONST_ADDR(&CG(_field))
227
228
#endif
229
230
#define jit_CALL(_call, _field) \
231
0
  ir_ADD_OFFSET(_call, offsetof(zend_execute_data, _field))
232
233
#define jit_EX(_field) \
234
  jit_CALL(jit_FP(jit), _field)
235
236
#define jit_RX(_field) \
237
  jit_CALL(jit_IP(jit), _field)
238
239
#define JIT_STUBS(_) \
240
  _(exception_handler,              IR_SKIP_PROLOGUE) \
241
  _(exception_handler_undef,        IR_SKIP_PROLOGUE) \
242
  _(exception_handler_free_op2,     IR_SKIP_PROLOGUE) \
243
  _(exception_handler_free_op1_op2, IR_SKIP_PROLOGUE) \
244
  _(interrupt_handler,              IR_SKIP_PROLOGUE) \
245
  _(leave_function_handler,         IR_SKIP_PROLOGUE) \
246
  _(negative_shift,                 IR_SKIP_PROLOGUE) \
247
  _(mod_by_zero,                    IR_SKIP_PROLOGUE) \
248
  _(invalid_this,                   IR_SKIP_PROLOGUE) \
249
  _(undefined_function,             IR_SKIP_PROLOGUE) \
250
  _(throw_cannot_pass_by_ref,       IR_SKIP_PROLOGUE) \
251
  _(icall_throw,                    IR_SKIP_PROLOGUE) \
252
  _(leave_throw,                    IR_SKIP_PROLOGUE) \
253
  _(hybrid_runtime_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
254
  _(hybrid_profile_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
255
  _(hybrid_func_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
256
  _(hybrid_loop_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
257
  _(hybrid_func_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
258
  _(hybrid_ret_trace_counter,       IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
259
  _(hybrid_loop_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
260
  _(trace_halt,                     IR_SKIP_PROLOGUE) \
261
  _(trace_escape,                   IR_SKIP_PROLOGUE) \
262
  _(trace_exit,                     IR_SKIP_PROLOGUE) \
263
  _(undefined_offset,               IR_FUNCTION | IR_FASTCALL_FUNC) \
264
  _(undefined_key,                  IR_FUNCTION | IR_FASTCALL_FUNC) \
265
  _(cannot_add_element,             IR_FUNCTION | IR_FASTCALL_FUNC) \
266
  _(assign_const,                   IR_FUNCTION | IR_FASTCALL_FUNC) \
267
  _(assign_tmp,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
268
  _(assign_var,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
269
  _(assign_cv_noref,                IR_FUNCTION | IR_FASTCALL_FUNC) \
270
  _(assign_cv,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
271
  _(new_array,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
272
273
#define JIT_STUB_ID(name, flags) \
274
  jit_stub_ ## name,
275
276
#define JIT_STUB_FORWARD(name, flags) \
277
  static int zend_jit_ ## name ## _stub(zend_jit_ctx *jit);
278
279
#define JIT_STUB(name, flags) \
280
  {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, flags},
281
282
typedef enum _jit_stub_id {
283
  JIT_STUBS(JIT_STUB_ID)
284
  jit_last_stub
285
} jit_stub_id;
286
287
typedef struct _zend_jit_reg_var {
288
  ir_ref   ref;
289
  uint32_t flags;
290
} zend_jit_reg_var;
291
292
typedef struct _zend_jit_ctx {
293
  ir_ctx               ctx;
294
  const zend_op       *last_valid_opline;
295
  bool                 use_last_valid_opline;
296
  bool                 track_last_valid_opline;
297
  bool                 reuse_ip;
298
  uint32_t             delayed_call_level;
299
  int                  b;           /* current basic block number or -1 */
300
#ifdef ZTS
301
  ir_ref               tls;
302
#endif
303
  ir_ref               fp;
304
  ir_ref               poly_func_ref; /* restored from parent trace snapshot */
305
  ir_ref               poly_this_ref; /* restored from parent trace snapshot */
306
  ir_ref               trace_loop_ref;
307
  ir_ref               return_inputs;
308
  const zend_op_array *op_array;
309
  const zend_op_array *current_op_array;
310
  zend_ssa            *ssa;
311
  zend_string         *name;
312
  ir_ref              *bb_start_ref;      /* PHP BB -> IR ref mapping */
313
  ir_ref              *bb_predecessors;   /* PHP BB -> index in bb_edges -> IR refs of predessors */
314
  ir_ref              *bb_edges;
315
  zend_jit_trace_info *trace;
316
  zend_jit_reg_var    *ra;
317
  int                  delay_var;
318
  ir_refs             *delay_refs;
319
  ir_ref               eg_exception_addr;
320
  HashTable            addr_hash;
321
  ir_ref               stub_addr[jit_last_stub];
322
} zend_jit_ctx;
323
324
typedef int8_t zend_reg;
325
326
typedef struct _zend_jit_registers_buf {
327
#if defined(IR_TARGET_X64)
328
  uint64_t gpr[16]; /* general purpose integer register */
329
  double   fpr[16]; /* floating point registers */
330
#elif defined(IR_TARGET_X86)
331
  uint32_t gpr[8]; /* general purpose integer register */
332
  double   fpr[8]; /* floating point registers */
333
#elif defined (IR_TARGET_AARCH64)
334
  uint64_t gpr[32]; /* general purpose integer register */
335
  double   fpr[32]; /* floating point registers */
336
#else
337
# error "Unknown IR target"
338
#endif
339
} zend_jit_registers_buf;
340
341
/* Keep 32 exit points in a single code block */
342
0
#define ZEND_JIT_EXIT_POINTS_SPACING   4  // push byte + short jmp = bytes
343
0
#define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
344
345
static uint32_t zend_jit_exit_point_by_addr(const void *addr);
346
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
347
348
static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
349
                                       const zend_op  *opline,
350
                                       zend_jit_addr   var_use_addr,
351
                                       zend_jit_addr   var_addr,
352
                                       uint32_t        var_info,
353
                                       uint32_t        var_def_info,
354
                                       uint8_t         val_type,
355
                                       zend_jit_addr   val_addr,
356
                                       uint32_t        val_info,
357
                                       zend_jit_addr   res_addr,
358
                                       zend_jit_addr   ref_addr,
359
                                       bool       check_exception);
360
361
static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags);
362
363
static void zend_jit_preserve_parent_regs(zend_jit_ctx *jit,
364
                                          zend_ssa *ssa,
365
                                          zend_jit_trace_info *parent,
366
                                          uint32_t exit_num);
367
368
typedef struct _zend_jit_stub {
369
  const char *name;
370
  int (*stub)(zend_jit_ctx *jit);
371
  uint32_t flags;
372
} zend_jit_stub;
373
374
JIT_STUBS(JIT_STUB_FORWARD)
375
376
static const zend_jit_stub zend_jit_stubs[] = {
377
  JIT_STUBS(JIT_STUB)
378
};
379
380
#if defined(_WIN32) || defined(IR_TARGET_AARCH64)
381
/* We keep addresses in SHM to share them between sepaeate processes (on Windows) or to support veneers (on AArch64) */
382
static void** zend_jit_stub_handlers = NULL;
383
#else
384
static void* zend_jit_stub_handlers[sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])];
385
#endif
386
387
#if defined(IR_TARGET_AARCH64)
388
389
# ifdef __FreeBSD__
390
/* https://github.com/freebsd/freebsd-src/blob/c52ca7dd09066648b1cc40f758289404d68ab886/libexec/rtld-elf/aarch64/reloc.c#L180-L184 */
391
typedef struct TLSDescriptor {
392
  void*   thunk;
393
  int     index;
394
  size_t  offset;
395
} TLSDescriptor;
396
# endif
397
398
#define IR_HAS_VENEERS (1U<<31) /* IR_RESERVED_FLAG_1 */
399
400
static const void *zend_jit_get_veneer(ir_ctx *ctx, const void *addr)
401
{
402
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
403
404
  for (i = 0; i < count; i++) {
405
    if (zend_jit_stub_handlers[i] == addr) {
406
      return zend_jit_stub_handlers[count + i];
407
    }
408
  }
409
410
  if (((zend_jit_ctx*)ctx)->trace
411
   && (void*)addr >= dasm_buf && (void*)addr < dasm_end) {
412
    uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
413
414
    if (exit_point != (uint32_t)-1) {
415
      zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
416
417
      ZEND_ASSERT(exit_point < t->exit_count);
418
      return (const void*)((char*)ctx->deoptimization_exits_base + (exit_point * 4));
419
    }
420
  }
421
422
  return NULL;
423
}
424
425
static bool zend_jit_set_veneer(ir_ctx *ctx, const void *addr, const void *veneer)
426
{
427
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
428
  uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
429
430
  if (exit_point != (uint32_t)-1) {
431
    return true;
432
  }
433
  for (i = 0; i < count; i++) {
434
    if (zend_jit_stub_handlers[i] == addr) {
435
      const void **ptr = (const void**)&zend_jit_stub_handlers[count + i];
436
      *ptr = veneer;
437
      ctx->flags2 |= IR_HAS_VENEERS;
438
#ifdef HAVE_CAPSTONE
439
      int64_t offset;
440
        if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
441
        const char *name = ir_disasm_find_symbol((uint64_t)(uintptr_t)addr, &offset);
442
443
        if (name && !offset) {
444
          if (strstr(name, "@veneer") == NULL) {
445
            char *new_name;
446
447
            zend_spprintf(&new_name, 0, "%s@veneer", name);
448
            ir_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
449
            efree(new_name);
450
          } else {
451
            ir_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
452
          }
453
        }
454
      }
455
#endif
456
      return true;
457
    }
458
  }
459
460
  return false;
461
}
462
463
static void zend_jit_commit_veneers(void)
464
{
465
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
466
467
  for (i = 0; i < count; i++) {
468
    if (zend_jit_stub_handlers[count + i]) {
469
      zend_jit_stub_handlers[i] = zend_jit_stub_handlers[count + i];
470
      zend_jit_stub_handlers[count + i] = NULL;
471
    }
472
  }
473
}
474
#endif
475
476
static bool zend_jit_prefer_const_addr_load(zend_jit_ctx *jit, uintptr_t addr)
477
0
{
478
#if defined(IR_TARGET_X86)
479
  return false; /* always use immediate value */
480
#elif defined(IR_TARGET_X64)
481
  return addr > 0xffffffff; /* prefer loading long constant from memery */
482
#elif defined(IR_TARGET_AARCH64)
483
  return addr > 0xffff;
484
#else
485
# error "Unknown IR target"
486
#endif
487
0
}
488
489
static const char* zend_reg_name(int8_t reg)
490
0
{
491
0
  return ir_reg_name(reg, ir_reg_is_int(reg) ? IR_LONG : IR_DOUBLE);
492
0
}
493
494
/* IR helpers */
495
496
#ifdef ZTS
497
static void * ZEND_FASTCALL zend_jit_get_tsrm_ls_cache(void)
498
{
499
  return _tsrm_ls_cache;
500
}
501
502
static ir_ref jit_TLS(zend_jit_ctx *jit)
503
{
504
  ZEND_ASSERT(jit->ctx.control);
505
  if (jit->tls) {
506
    /* Emit "TLS" once for basic block */
507
    ir_insn *insn;
508
    ir_ref ref = jit->ctx.control;
509
510
    while (1) {
511
      if (ref == jit->tls) {
512
        return jit->tls;
513
      }
514
      insn = &jit->ctx.ir_base[ref];
515
      if (insn->op >= IR_START || insn->op == IR_CALL) {
516
        break;
517
      }
518
      ref = insn->op1;
519
    }
520
  }
521
522
  if (tsrm_ls_cache_tcb_offset == 0 && tsrm_tls_index == -1) {
523
    jit->tls = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_tsrm_ls_cache));
524
  } else {
525
    jit->tls = ir_TLS(
526
        tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
527
        tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
528
  }
529
530
  return jit->tls;
531
}
532
#endif
533
534
static ir_ref jit_CONST_ADDR(zend_jit_ctx *jit, uintptr_t addr)
535
0
{
536
0
  ir_ref ref;
537
0
  zval *zv;
538
539
0
  if (addr == 0) {
540
0
    return IR_NULL;
541
0
  }
542
0
  zv = zend_hash_index_lookup(&jit->addr_hash, addr);
543
0
  if (Z_TYPE_P(zv) == IS_LONG) {
544
0
    ref = Z_LVAL_P(zv);
545
0
    ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_ADDR, IR_ADDR));
546
0
  } else {
547
0
    ref = ir_unique_const_addr(&jit->ctx, addr);
548
0
    ZVAL_LONG(zv, ref);
549
0
  }
550
0
  return ref;
551
0
}
552
553
static ir_ref jit_CONST_FUNC_PROTO(zend_jit_ctx *jit, uintptr_t addr, ir_ref proto)
554
0
{
555
0
  ir_ref ref;
556
0
  ir_insn *insn;
557
0
  zval *zv;
558
559
0
  ZEND_ASSERT(addr != 0);
560
0
  zv = zend_hash_index_lookup(&jit->addr_hash, addr);
561
0
  if (Z_TYPE_P(zv) == IS_LONG) {
562
0
    ref = Z_LVAL_P(zv);
563
0
    ZEND_ASSERT(jit->ctx.ir_base[ref].opt == IR_OPT(IR_FUNC_ADDR, IR_ADDR) && jit->ctx.ir_base[ref].proto == proto);
564
0
  } else {
565
0
    ref = ir_unique_const_addr(&jit->ctx, addr);
566
0
    insn = &jit->ctx.ir_base[ref];
567
0
    insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
568
0
    insn->proto = proto;
569
0
    ZVAL_LONG(zv, ref);
570
0
  }
571
0
  return ref;
572
0
}
573
574
static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags)
575
0
{
576
#if defined(IR_TARGET_X86)
577
  /* TODO: dummy prototype (only flags matter) ??? */
578
  ir_ref proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
579
#else
580
0
  ir_ref proto = 0;
581
0
#endif
582
583
0
  return jit_CONST_FUNC_PROTO(jit, addr, proto);
584
0
}
585
586
static ir_ref jit_CONST_OPCODE_HANDLER_FUNC(zend_jit_ctx *jit, zend_vm_opcode_handler_t handler)
587
0
{
588
0
  return jit_CONST_FUNC(jit, (uintptr_t)handler, IR_FASTCALL_FUNC);
589
0
}
590
591
static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset)
592
0
{
593
0
  if (offset) {
594
0
    addr = ir_ADD_A(addr, ir_CONST_ADDR(offset));
595
0
  }
596
0
  return addr;
597
0
}
598
599
static ir_ref jit_EG_exception(zend_jit_ctx *jit)
600
0
{
601
#ifdef ZTS
602
  return jit_EG(exception);
603
#else
604
0
  ir_ref ref = jit->eg_exception_addr;
605
606
0
  if (UNEXPECTED(!ref)) {
607
0
    ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)&EG(exception));
608
0
    jit->eg_exception_addr = ref;
609
0
  }
610
0
  return ref;
611
0
#endif
612
0
}
613
614
static ir_ref jit_STUB_ADDR(zend_jit_ctx *jit, jit_stub_id id)
615
0
{
616
0
  ir_ref ref = jit->stub_addr[id];
617
618
0
  if (UNEXPECTED(!ref)) {
619
0
    ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
620
0
    jit->stub_addr[id] = ref;
621
0
  }
622
0
  return ref;
623
0
}
624
625
static ir_ref jit_STUB_FUNC_ADDR(zend_jit_ctx *jit, jit_stub_id id, uint16_t flags)
626
0
{
627
0
  ir_ref ref = jit->stub_addr[id];
628
0
  ir_insn *insn;
629
630
0
  if (UNEXPECTED(!ref)) {
631
0
    ref = ir_unique_const_addr(&jit->ctx, (uintptr_t)zend_jit_stub_handlers[id]);
632
0
    insn = &jit->ctx.ir_base[ref];
633
0
    insn->optx = IR_OPT(IR_FUNC_ADDR, IR_ADDR);
634
#if defined(IR_TARGET_X86)
635
    /* TODO: dummy prototype (only flags matter) ??? */
636
    insn->proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
637
#else
638
0
    insn->proto = 0;
639
0
#endif
640
0
    jit->stub_addr[id] = ref;
641
0
  }
642
0
  return ref;
643
0
}
644
645
static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
646
0
{
647
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
648
0
    const void *ptr = (const void*)jit->ctx.ir_base[addr].val.addr;
649
0
    const zend_op_array *op_array = &JIT_G(current_frame)->func->op_array;
650
0
    uint32_t stack_size = op_array->last_var + op_array->T;
651
652
0
    if (ptr == zend_jit_stub_handlers[jit_stub_exception_handler]
653
0
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_undef]
654
0
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op1_op2]
655
0
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op2]
656
0
       || ptr == zend_jit_stub_handlers[jit_stub_interrupt_handler]
657
0
       || ptr == zend_jit_stub_handlers[jit_stub_leave_function_handler]
658
0
       || ptr == zend_jit_stub_handlers[jit_stub_negative_shift]
659
0
       || ptr == zend_jit_stub_handlers[jit_stub_mod_by_zero]
660
0
       || ptr == zend_jit_stub_handlers[jit_stub_invalid_this]
661
0
       || ptr == zend_jit_stub_handlers[jit_stub_undefined_function]
662
0
       || ptr == zend_jit_stub_handlers[jit_stub_throw_cannot_pass_by_ref]
663
0
       || ptr == zend_jit_stub_handlers[jit_stub_icall_throw]
664
0
       || ptr == zend_jit_stub_handlers[jit_stub_leave_throw]
665
0
       || ptr == zend_jit_stub_handlers[jit_stub_trace_halt]
666
0
       || ptr == zend_jit_stub_handlers[jit_stub_trace_escape]) {
667
      /* This is a GUARD that trigger exit through a stub code (without deoptimization) */
668
0
      return;
669
0
    }
670
671
    /* Check if we need snapshot entries for polymorphic method call */
672
0
    zend_jit_trace_info *t = jit->trace;
673
0
    uint32_t exit_point = 0, n = 0;
674
675
0
    if (addr < 0) {
676
      /* addr is not always the address of the *last* exit point,
677
       * so we can not optimize this to 'exit_point = t->exit_count-1' */
678
0
      exit_point = zend_jit_exit_point_by_addr(ptr);
679
0
      ZEND_ASSERT(exit_point != -1);
680
0
      if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
681
0
        n = 2;
682
0
      }
683
0
    }
684
685
0
    if (stack_size || n) {
686
0
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
687
0
      uint32_t snapshot_size, i;
688
689
0
      snapshot_size = stack_size;
690
0
      while (snapshot_size > 0) {
691
0
        ir_ref ref = STACK_REF(stack, snapshot_size - 1);
692
693
0
        if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, snapshot_size - 1) & (/*ZREG_LOAD|*/ZREG_STORE))) {
694
0
          snapshot_size--;
695
0
        } else {
696
0
          break;
697
0
        }
698
0
      }
699
0
      if (snapshot_size || n) {
700
0
        ir_ref snapshot;
701
702
0
        snapshot = ir_SNAPSHOT(snapshot_size + n);
703
0
        for (i = 0; i < snapshot_size; i++) {
704
0
          ir_ref ref = STACK_REF(stack, i);
705
706
0
          if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, i) & (/*ZREG_LOAD|*/ZREG_STORE))) {
707
0
            ref = IR_UNUSED;
708
0
          }
709
0
          ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
710
0
        }
711
0
        if (n) {
712
0
          ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func.ref);
713
0
          ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this.ref);
714
0
        }
715
0
      }
716
0
    }
717
0
  }
718
0
}
719
720
static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
721
0
{
722
0
  int32_t i;
723
724
0
  for (i = 0; i < t->consts_count; i++) {
725
0
    if (t->constants[i].i == val) {
726
0
      return i;
727
0
    }
728
0
  }
729
0
  ZEND_ASSERT(i < 0x7fffffff);
730
0
  t->consts_count = i + 1;
731
0
  t->constants = erealloc(t->constants, (i + 1) * sizeof(zend_jit_exit_const));
732
0
  t->constants[i].i = val;
733
0
  return i;
734
0
}
735
736
uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
737
0
{
738
0
  uint32_t stack_size, stack_offset;
739
0
  uint32_t new_exit_point = t->exit_count;
740
741
0
  if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
742
0
    ctx->status = -ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
743
0
    return exit_point;
744
0
  }
745
746
0
  t->exit_count++;
747
0
  memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
748
0
  stack_size = t->exit_info[new_exit_point].stack_size;
749
0
  if (stack_size != 0) {
750
0
    stack_offset = t->stack_map_size;
751
0
    t->stack_map_size += stack_size;
752
    // TODO: reduce number of reallocations ???
753
0
    t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
754
0
    memcpy(t->stack_map + stack_offset, t->stack_map + t->exit_info[new_exit_point].stack_offset, stack_size * sizeof(zend_jit_trace_stack));
755
0
    t->exit_info[new_exit_point].stack_offset = stack_offset;
756
0
  }
757
0
  t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
758
759
0
  return new_exit_point;
760
0
}
761
762
static void zend_jit_resolve_ref_snapshot(zend_jit_ref_snapshot *dest, ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, int op)
763
0
{
764
0
  int8_t *reg_ops = ctx->regs[snapshot_ref];
765
0
  ZEND_ASSERT(reg_ops[op] != ZREG_NONE);
766
767
0
  int8_t reg = reg_ops[op];
768
0
  int32_t offset;
769
770
0
  if (IR_REG_SPILLED(reg)) {
771
0
    reg = ((ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP) | IR_REG_SPILL_LOAD;
772
0
    offset = ir_get_spill_slot_offset(ctx, ir_insn_op(snapshot, op));
773
0
  } else {
774
0
    offset = 0;
775
0
  }
776
777
0
  dest->reg = reg;
778
0
  dest->offset = offset;
779
0
}
780
781
static bool zend_jit_ref_snapshot_equals(const zend_jit_ref_snapshot *a, const zend_jit_ref_snapshot *b)
782
0
{
783
0
  return a->reg == b->reg
784
0
    && (!IR_REG_SPILLED(a->reg) || (a->offset == b->offset));
785
0
}
786
787
void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
788
0
{
789
0
  zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
790
0
  uint32_t exit_point, exit_flags;
791
0
  ir_ref n = snapshot->inputs_count;
792
0
  ir_ref i;
793
794
0
  exit_point = zend_jit_exit_point_by_addr(addr);
795
0
  ZEND_ASSERT(exit_point < t->exit_count);
796
0
  exit_flags = t->exit_info[exit_point].flags;
797
798
0
  if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
799
0
    zend_jit_ref_snapshot func, this;
800
0
    zend_jit_resolve_ref_snapshot(&func, ctx, snapshot_ref, snapshot, n - 1);
801
0
    zend_jit_resolve_ref_snapshot(&this, ctx, snapshot_ref, snapshot, n);
802
803
0
    if ((exit_flags & ZEND_JIT_EXIT_FIXED)
804
0
     && (!zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_func, &func)
805
0
       || !zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_this, &this))) {
806
0
      exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
807
0
      addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
808
0
      exit_flags &= ~ZEND_JIT_EXIT_FIXED;
809
0
    }
810
0
    t->exit_info[exit_point].poly_func = func;
811
0
    t->exit_info[exit_point].poly_this = this;
812
0
    n -= 2;
813
0
  }
814
815
0
  for (i = 2; i <= n; i++) {
816
0
    ir_ref ref = ir_insn_op(snapshot, i);
817
818
0
    if (ref) {
819
0
      int8_t *reg_ops = ctx->regs[snapshot_ref];
820
0
      int8_t reg = reg_ops[i];
821
0
      ir_ref var = i - 2;
822
823
0
      ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
824
0
      if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
825
0
        ZEND_ASSERT(reg != ZREG_NONE);
826
0
        if ((exit_flags & ZEND_JIT_EXIT_FIXED)
827
0
         && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
828
0
          exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
829
0
          addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
830
0
          exit_flags &= ~ZEND_JIT_EXIT_FIXED;
831
0
        }
832
0
        t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
833
0
      } else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
834
0
        ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
835
0
          t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_DOUBLE);
836
837
0
        if (ref > 0) {
838
0
          if (reg != ZREG_NONE) {
839
0
            if (reg & IR_REG_SPILL_LOAD) {
840
0
              ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
841
              /* spill slot on a CPU stack */
842
0
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
843
0
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
844
0
                || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
845
0
                || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
846
0
                exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
847
0
                addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
848
0
                exit_flags &= ~ZEND_JIT_EXIT_FIXED;
849
0
              }
850
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
851
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
852
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
853
0
            } else if (reg & IR_REG_SPILL_SPECIAL) {
854
              /* spill slot on a VM stack */
855
0
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
856
0
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
857
0
               || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
858
0
                exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
859
0
                addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
860
0
                exit_flags &= ~ZEND_JIT_EXIT_FIXED;
861
0
              }
862
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
863
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
864
0
            } else {
865
0
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
866
0
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)
867
0
               || (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ~(ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE)))) {
868
0
                exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
869
0
                addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
870
0
                exit_flags &= ~ZEND_JIT_EXIT_FIXED;
871
0
              }
872
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
873
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags &= (ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE);
874
0
            }
875
0
          } else {
876
0
            if ((exit_flags & ZEND_JIT_EXIT_FIXED)
877
0
             && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
878
0
             || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
879
0
              exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
880
0
              addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
881
0
              exit_flags &= ~ZEND_JIT_EXIT_FIXED;
882
0
            }
883
0
            t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
884
0
            t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
885
0
          }
886
0
        } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
887
0
          int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
888
0
          t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
889
0
          t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
890
0
        }
891
0
      }
892
0
    }
893
0
  }
894
0
  t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
895
0
  return addr;
896
0
}
897
898
static void jit_SIDE_EXIT(zend_jit_ctx *jit, ir_ref addr)
899
0
{
900
0
  jit_SNAPSHOT(jit, addr);
901
0
  ir_IJMP(addr);
902
0
}
903
904
/* PHP JIT helpers */
905
906
static ir_ref jit_EMALLOC(zend_jit_ctx *jit, size_t size, const zend_op_array *op_array, const zend_op *opline)
907
0
{
908
0
#if ZEND_DEBUG
909
0
  return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_emalloc),
910
0
    ir_CONST_ADDR(size),
911
0
    op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
912
0
    ir_CONST_U32(opline ? opline->lineno : 0),
913
0
    IR_NULL,
914
0
    ir_CONST_U32(0));
915
#elif defined(HAVE_BUILTIN_CONSTANT_P)
916
  if (size > 24 && size <= 32) {
917
    return ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_emalloc_32));
918
  } else {
919
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
920
  }
921
#else
922
  return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
923
#endif
924
0
}
925
926
static ir_ref jit_EFREE(zend_jit_ctx *jit, ir_ref ptr, size_t size, const zend_op_array *op_array, const zend_op *opline)
927
0
{
928
0
#if ZEND_DEBUG
929
0
  return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_efree),
930
0
    ptr,
931
0
    op_array && op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
932
0
    ir_CONST_U32(opline ? opline->lineno : 0),
933
0
    IR_NULL,
934
0
    ir_CONST_U32(0));
935
#elif defined(HAVE_BUILTIN_CONSTANT_P)
936
  if (size > 24 && size <= 32) {
937
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree_32), ptr);
938
  } else {
939
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
940
  }
941
#else
942
  return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
943
#endif
944
0
}
945
946
static ir_ref jit_FP(zend_jit_ctx *jit)
947
0
{
948
0
  ZEND_ASSERT(jit->ctx.control);
949
0
  if (jit->fp == IR_UNUSED) {
950
    /* Emit "RLOAD FP" once for basic block */
951
0
    jit->fp = ir_RLOAD_A(ZREG_FP);
952
0
  } else {
953
0
    ir_insn *insn;
954
0
    ir_ref ref = jit->ctx.control;
955
956
0
    while (1) {
957
0
      if (ref == jit->fp) {
958
0
        break;
959
0
      }
960
0
      insn = &jit->ctx.ir_base[ref];
961
0
      if (insn->op >= IR_START || insn->op == IR_CALL) {
962
0
        jit->fp = ir_RLOAD_A(ZREG_FP);
963
0
        break;
964
0
      }
965
0
      ref = insn->op1;
966
0
    }
967
0
  }
968
0
  return jit->fp;
969
0
}
970
971
static void jit_STORE_FP(zend_jit_ctx *jit, ir_ref ref)
972
0
{
973
0
  ir_RSTORE(ZREG_FP, ref);
974
0
  jit->fp = IR_UNUSED;
975
0
}
976
977
static ir_ref jit_IP(zend_jit_ctx *jit)
978
0
{
979
0
  return ir_RLOAD_A(ZREG_IP);
980
0
}
981
982
static void jit_STORE_IP(zend_jit_ctx *jit, ir_ref ref)
983
0
{
984
0
  ir_RSTORE(ZREG_IP, ref);
985
0
}
986
987
static ir_ref jit_IP32(zend_jit_ctx *jit)
988
0
{
989
0
  return ir_RLOAD_U32(ZREG_IP);
990
0
}
991
992
static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target)
993
0
{
994
0
  jit_STORE_IP(jit, ir_CONST_ADDR(target));
995
0
}
996
997
static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit)
998
0
{
999
0
  jit->use_last_valid_opline = false;
1000
0
  jit->track_last_valid_opline = true;
1001
0
}
1002
1003
static void zend_jit_use_last_valid_opline(zend_jit_ctx *jit)
1004
0
{
1005
0
  if (jit->track_last_valid_opline) {
1006
0
    jit->use_last_valid_opline = true;
1007
0
    jit->track_last_valid_opline = false;
1008
0
  }
1009
0
}
1010
1011
static bool zend_jit_trace_uses_initial_ip(zend_jit_ctx *jit)
1012
0
{
1013
0
  return jit->use_last_valid_opline;
1014
0
}
1015
1016
static void zend_jit_set_last_valid_opline(zend_jit_ctx *jit, const zend_op *opline)
1017
0
{
1018
0
  if (!jit->reuse_ip) {
1019
0
    jit->track_last_valid_opline = true;
1020
0
    jit->last_valid_opline = opline;
1021
0
  }
1022
0
}
1023
1024
static void zend_jit_reset_last_valid_opline(zend_jit_ctx *jit)
1025
0
{
1026
0
  jit->track_last_valid_opline = false;
1027
0
  jit->last_valid_opline = NULL;
1028
0
}
1029
1030
static void zend_jit_start_reuse_ip(zend_jit_ctx *jit)
1031
0
{
1032
0
  zend_jit_reset_last_valid_opline(jit);
1033
0
  jit->reuse_ip = true;
1034
0
}
1035
1036
static int zend_jit_reuse_ip(zend_jit_ctx *jit)
1037
0
{
1038
0
  if (!jit->reuse_ip) {
1039
0
    zend_jit_start_reuse_ip(jit);
1040
    // RX = EX(call);
1041
0
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
1042
0
  }
1043
0
  return 1;
1044
0
}
1045
1046
static void zend_jit_stop_reuse_ip(zend_jit_ctx *jit)
1047
0
{
1048
0
  jit->reuse_ip = false;
1049
0
}
1050
1051
static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level)
1052
0
{
1053
0
  ir_ref rx, call;
1054
1055
0
  if (call_level == 1) {
1056
    // JIT: call = NULL;
1057
0
    call = IR_NULL;
1058
0
  } else {
1059
    // JIT: call = EX(call);
1060
0
    call = ir_LOAD_A(jit_EX(call));
1061
0
  }
1062
1063
0
  rx = jit_IP(jit);
1064
1065
  // JIT: call->prev_execute_data = call;
1066
0
  ir_STORE(jit_CALL(rx, prev_execute_data), call);
1067
1068
  // JIT: EX(call) = call;
1069
0
  ir_STORE(jit_EX(call), rx);
1070
1071
0
  jit->delayed_call_level = 0;
1072
0
  delayed_call_chain = false;
1073
1074
0
  return 1;
1075
0
}
1076
1077
static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target)
1078
0
{
1079
0
  ir_ref ref;
1080
1081
0
  if (jit->delayed_call_level) {
1082
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
1083
0
      return 0;
1084
0
    }
1085
0
  }
1086
1087
0
  if (jit->last_valid_opline) {
1088
0
    zend_jit_use_last_valid_opline(jit);
1089
0
    if (jit->last_valid_opline != target) {
1090
0
      ref = jit_IP(jit);
1091
0
      if (target > jit->last_valid_opline) {
1092
0
        ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline);
1093
0
      } else {
1094
0
        ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target));
1095
0
      }
1096
0
      jit_STORE_IP(jit, ref);
1097
0
    }
1098
0
  } else {
1099
0
    jit_STORE_IP(jit, ir_CONST_ADDR(target));
1100
0
  }
1101
0
  jit->reuse_ip = false;
1102
0
  zend_jit_set_last_valid_opline(jit, target);
1103
0
  return 1;
1104
0
}
1105
1106
static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target)
1107
0
{
1108
0
  if (jit->last_valid_opline == target) {
1109
0
    zend_jit_use_last_valid_opline(jit);
1110
    // EX(opline) = opline
1111
0
    ir_STORE(jit_EX(opline), jit_IP(jit));
1112
0
  } else {
1113
0
    ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1114
0
  }
1115
0
}
1116
1117
static ir_ref jit_ZVAL_ADDR(zend_jit_ctx *jit, zend_jit_addr addr)
1118
0
{
1119
0
  if (Z_MODE(addr) == IS_MEM_ZVAL) {
1120
0
    ir_ref reg;
1121
1122
0
    if (Z_REG(addr) == ZREG_FP) {
1123
0
      reg = jit_FP(jit);
1124
0
    } else if (Z_REG(addr) == ZREG_RX) {
1125
0
      reg = jit_IP(jit);
1126
0
    } else {
1127
0
      ZEND_UNREACHABLE();
1128
0
    }
1129
0
    return ir_ADD_OFFSET(reg, Z_OFFSET(addr));
1130
0
  } else if (Z_MODE(addr) == IS_REF_ZVAL) {
1131
0
    return Z_IR_REF(addr);
1132
0
  } else {
1133
0
    ZEND_ASSERT(Z_MODE(addr) == IS_CONST_ZVAL);
1134
0
    return ir_CONST_ADDR(Z_ZV(addr));
1135
0
  }
1136
0
}
1137
1138
static ir_ref jit_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref)
1139
0
{
1140
0
  return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type)));
1141
0
}
1142
1143
static ir_ref jit_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr)
1144
0
{
1145
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1146
0
    return ir_CONST_U8(Z_TYPE_P(Z_ZV(addr)));
1147
0
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1148
0
    ir_ref reg;
1149
1150
0
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1151
0
    if (Z_REG(addr) == ZREG_FP) {
1152
0
      reg = jit_FP(jit);
1153
0
    } else if (Z_REG(addr) == ZREG_RX) {
1154
0
      reg = jit_IP(jit);
1155
0
    } else {
1156
0
      ZEND_UNREACHABLE();
1157
0
    }
1158
0
    return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type)));
1159
0
  } else {
1160
0
    return jit_Z_TYPE_ref(jit, jit_ZVAL_ADDR(jit, addr));
1161
0
  }
1162
0
}
1163
1164
static ir_ref jit_Z_TYPE_FLAGS_ref(zend_jit_ctx *jit, ir_ref ref)
1165
0
{
1166
0
  return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type_flags)));
1167
0
}
1168
1169
static ir_ref jit_Z_TYPE_FLAGS(zend_jit_ctx *jit, zend_jit_addr addr)
1170
0
{
1171
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1172
0
    return ir_CONST_U8(Z_TYPE_FLAGS_P(Z_ZV(addr)));
1173
0
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1174
0
    ir_ref reg;
1175
1176
0
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1177
0
    if (Z_REG(addr) == ZREG_FP) {
1178
0
      reg = jit_FP(jit);
1179
0
    } else if (Z_REG(addr) == ZREG_RX) {
1180
0
      reg = jit_IP(jit);
1181
0
    } else {
1182
0
      ZEND_UNREACHABLE();
1183
0
    }
1184
0
    return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type_flags)));
1185
0
  } else {
1186
0
    return jit_Z_TYPE_FLAGS_ref(jit, jit_ZVAL_ADDR(jit, addr));
1187
0
  }
1188
0
}
1189
1190
static ir_ref jit_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref)
1191
0
{
1192
0
  return ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)));
1193
0
}
1194
1195
static ir_ref jit_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr)
1196
0
{
1197
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1198
0
    return ir_CONST_U32(Z_TYPE_INFO_P(Z_ZV(addr)));
1199
0
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1200
0
    ir_ref reg;
1201
1202
0
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1203
0
    if (Z_REG(addr) == ZREG_FP) {
1204
0
      reg = jit_FP(jit);
1205
0
    } else if (Z_REG(addr) == ZREG_RX) {
1206
0
      reg = jit_IP(jit);
1207
0
    } else {
1208
0
      ZEND_UNREACHABLE();
1209
0
    }
1210
0
    return ir_LOAD_U32(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)));
1211
0
  } else {
1212
0
    return jit_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr));
1213
0
  }
1214
0
}
1215
1216
static void jit_set_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type_info)
1217
0
{
1218
0
  ir_STORE(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)), type_info);
1219
0
}
1220
1221
static void jit_set_Z_TYPE_INFO_ex(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref type_info)
1222
0
{
1223
0
  if (Z_MODE(addr) == IS_MEM_ZVAL) {
1224
0
    ir_ref reg;
1225
1226
0
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1227
0
    if (Z_REG(addr) == ZREG_FP) {
1228
0
      reg = jit_FP(jit);
1229
0
    } else if (Z_REG(addr) == ZREG_RX) {
1230
0
      reg = jit_IP(jit);
1231
0
    } else {
1232
0
      ZEND_UNREACHABLE();
1233
0
    }
1234
0
    ir_STORE(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)), type_info);
1235
0
  } else {
1236
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr), type_info);
1237
0
  }
1238
0
}
1239
1240
static void jit_set_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr, uint32_t type_info)
1241
0
{
1242
0
  if (type_info < IS_STRING
1243
0
   && Z_MODE(addr) == IS_MEM_ZVAL
1244
0
   && Z_REG(addr) == ZREG_FP
1245
0
   && JIT_G(current_frame)
1246
0
   && STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(addr))) == type_info) {
1247
    /* type is already set */
1248
0
    return;
1249
0
  }
1250
0
  jit_set_Z_TYPE_INFO_ex(jit, addr, ir_CONST_U32(type_info));
1251
0
}
1252
1253
static ir_ref jit_if_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type)
1254
0
{
1255
0
  return ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), type));
1256
0
}
1257
1258
static ir_ref jit_if_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1259
0
{
1260
0
  ZEND_ASSERT(type != IS_UNDEF);
1261
0
  return ir_IF(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)));
1262
0
}
1263
1264
static ir_ref jit_if_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1265
0
{
1266
0
  ir_ref ref = jit_Z_TYPE(jit, addr);
1267
1268
0
  if (type != IS_UNDEF) {
1269
0
    ref = ir_NE(ref, ir_CONST_U8(type));
1270
0
  }
1271
0
  return ir_IF(ref);
1272
0
}
1273
1274
static void jit_guard_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1275
0
{
1276
0
  ir_ref ref = jit_Z_TYPE(jit, addr);
1277
1278
0
  if (type != IS_UNDEF) {
1279
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
1280
0
  } else {
1281
0
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1282
0
  }
1283
0
}
1284
1285
static void jit_guard_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1286
0
{
1287
0
  ir_ref ref = jit_Z_TYPE(jit, addr);
1288
1289
0
  if (type != IS_UNDEF) {
1290
0
    ref = ir_NE(ref, ir_CONST_U8(type));
1291
0
  }
1292
0
  ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
1293
0
}
1294
1295
static ir_ref jit_if_REFCOUNTED(zend_jit_ctx *jit, zend_jit_addr addr)
1296
0
{
1297
0
  return ir_IF(jit_Z_TYPE_FLAGS(jit, addr));
1298
0
}
1299
1300
static ir_ref jit_if_COLLECTABLE_ref(zend_jit_ctx *jit, ir_ref addr_ref)
1301
0
{
1302
0
  return ir_IF(ir_AND_U8(jit_Z_TYPE_FLAGS_ref(jit, addr_ref), ir_CONST_U8(IS_TYPE_COLLECTABLE)));
1303
0
}
1304
1305
static ir_ref jit_Z_LVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1306
0
{
1307
0
  return ir_LOAD_L(ref);
1308
0
}
1309
1310
static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1311
0
{
1312
0
  return ir_LOAD_D(ref);
1313
0
}
1314
1315
static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1316
0
{
1317
0
  if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1318
    /* Deoptimization */
1319
0
    return false;
1320
0
  }
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
//    /* LOAD from the same location (the LOAD is pinned) */
1328
//    // TODO: should be anti-dependent with the following stores ???
1329
//    return 0;
1330
//  }
1331
0
  if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1332
    /* IS_CV */
1333
0
    if (jit->ctx.ir_base[val].op == IR_LOAD
1334
0
     && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1335
0
     && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1336
0
     && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1337
0
     && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1338
0
     && 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)
1339
0
     && 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) {
1340
      /* binding between different CVs may cause spill conflict */
1341
0
      return true;
1342
0
    } else if (jit->ssa->vars[var].definition >= 0
1343
0
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1344
0
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1345
0
     && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].no_val
1346
0
     && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi
1347
0
     && (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)) {
1348
      /* Avoid moving spill store out of loop */
1349
0
      return true;
1350
0
    } else if (jit->ssa->vars[var].definition >= 0
1351
0
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1352
0
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1353
0
     && jit->ssa->ops[jit->ssa->vars[var].definition].op2_use >= 0
1354
0
     && jit->ra[jit->ssa->ops[jit->ssa->vars[var].definition].op2_use].ref == val) {
1355
      /* Avoid spill conflict between of ASSIGN.op1_def and ASSIGN.op1_use */
1356
0
      return true;
1357
0
    }
1358
0
    return false;
1359
0
  }
1360
0
  return true;
1361
0
}
1362
1363
static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1364
0
{
1365
0
  int var;
1366
1367
0
  ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1368
0
  var = Z_SSA_VAR(addr);
1369
0
  if (var == jit->delay_var) {
1370
0
    ir_refs_add(jit->delay_refs, val);
1371
0
    return;
1372
0
  }
1373
0
  ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1374
1375
  /* Negative "var" has special meaning for IR */
1376
0
  if (val > 0) {
1377
0
    if (jit->ctx.binding) {
1378
0
      ir_ref old = ir_binding_find(&jit->ctx, val);
1379
0
      if (old && old != -EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1380
0
        val = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[val].type), val, 1);
1381
0
      }
1382
0
    }
1383
0
    if (!zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1384
0
      val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1385
0
    }
1386
0
  }
1387
0
  jit->ra[var].ref = val;
1388
1389
0
  if (jit->ra[var].flags & ZREG_FORWARD) {
1390
0
    zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1391
0
    zend_basic_block *bb;
1392
0
    int n, j, *p;
1393
0
    ir_ref *q;
1394
1395
0
    jit->ra[var].flags &= ~ZREG_FORWARD;
1396
0
    while (phi != NULL) {
1397
0
      zend_ssa_phi *dst_phi = phi;
1398
0
      int src_var = var;
1399
1400
0
      if (dst_phi->pi >= 0) {
1401
0
        jit->ra[src_var].ref = val;
1402
0
        src_var = dst_phi->ssa_var;
1403
0
        if (!(jit->ra[src_var].flags & ZREG_FORWARD)) {
1404
0
          phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1405
0
          continue;
1406
0
        }
1407
0
        dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1408
0
        ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1409
0
        ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1410
0
        jit->ra[src_var].flags &= ~ZREG_FORWARD;
1411
0
      }
1412
1413
0
      if (jit->ra[dst_phi->ssa_var].ref > 0) {
1414
0
        ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1415
0
        if (phi_insn->op == IR_PHI) {
1416
//          ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1417
0
          bb = &jit->ssa->cfg.blocks[dst_phi->block];
1418
0
          n = bb->predecessors_count;
1419
0
          for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1420
0
            if (*p == src_var) {
1421
0
              *q = val;
1422
0
            }
1423
0
          }
1424
0
        }
1425
0
      }
1426
1427
0
      phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1428
0
    }
1429
0
  }
1430
0
}
1431
1432
static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1433
0
{
1434
0
  int var = Z_SSA_VAR(addr);
1435
1436
0
  ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1437
0
  ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1438
0
  if (jit->ra[var].ref == IR_NULL) {
1439
0
    zend_jit_addr mem_addr;
1440
0
    ir_ref ref;
1441
1442
0
    ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1443
0
    mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1444
0
    if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1445
0
      ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1446
0
    } else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1447
0
      ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1448
0
    } else {
1449
0
      ZEND_UNREACHABLE();
1450
0
    }
1451
0
    zend_jit_def_reg(jit, addr, ref);
1452
0
    return ref;
1453
0
  }
1454
0
  return jit->ra[Z_SSA_VAR(addr)].ref;
1455
0
}
1456
1457
static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1458
0
{
1459
0
  int src_var = phi->sources[0];
1460
0
  int dst_var = phi->ssa_var;
1461
1462
0
  ZEND_ASSERT(phi->pi >= 0);
1463
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1464
0
  ZEND_ASSERT(jit->ra[src_var].ref);
1465
1466
0
  if (jit->ra[src_var].ref == IR_NULL) {
1467
    /* Not defined yet */
1468
0
    if (jit->ssa->vars[dst_var].use_chain < 0
1469
0
     && jit->ssa->vars[dst_var].phi_use_chain) {
1470
0
      zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1471
0
      if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1472
        /* This is a Pi forwarded to Phi */
1473
0
        jit->ra[src_var].flags |= ZREG_FORWARD;
1474
0
        return;
1475
0
      }
1476
0
    }
1477
0
    ZEND_ASSERT(0 && "Not defined Pi source");
1478
0
  }
1479
  /* Reuse register */
1480
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1481
0
    zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1482
0
}
1483
1484
static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1485
0
{
1486
0
  int dst_var = phi->ssa_var;
1487
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1488
0
  uint32_t n = bb->predecessors_count;
1489
0
  ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1490
0
  ir_ref merge = jit->bb_start_ref[phi->block];
1491
0
  ir_ref ref;
1492
0
  ir_ref old_insns_count = jit->ctx.insns_count;
1493
0
  ir_ref same_src_ref = IR_UNUSED;
1494
0
  bool phi_inputs_are_the_same = true;
1495
1496
0
  ZEND_ASSERT(phi->pi < 0);
1497
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1498
0
  ZEND_ASSERT(merge);
1499
0
  ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1500
0
  ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1501
1502
0
  ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1503
0
  ir_set_op(&jit->ctx, ref, 1, merge);
1504
1505
0
  for (uint32_t i = 0; i < n; i++) {
1506
0
    int src_var = phi->sources[i];
1507
1508
0
    ZEND_ASSERT(jit->ra[src_var].ref);
1509
0
    if (jit->ra[src_var].ref == IR_NULL) {
1510
0
      jit->ra[src_var].flags |= ZREG_FORWARD;
1511
0
      phi_inputs_are_the_same = false;
1512
0
    } else {
1513
0
      ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1514
0
      if (i == 0) {
1515
0
        same_src_ref = src_ref;
1516
0
      } else if (same_src_ref != src_ref) {
1517
0
        phi_inputs_are_the_same = false;
1518
0
      }
1519
0
      ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1520
0
    }
1521
0
  }
1522
0
  if (phi_inputs_are_the_same) {
1523
0
    ref = same_src_ref;
1524
0
    jit->ctx.insns_count = old_insns_count;
1525
0
  }
1526
1527
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1528
0
}
1529
1530
static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1531
0
{
1532
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1533
0
    return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1534
0
  } else if (Z_MODE(addr) == IS_REG) {
1535
0
    return zend_jit_use_reg(jit, addr);
1536
0
  } else {
1537
0
    return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1538
0
  }
1539
0
}
1540
1541
static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1542
0
{
1543
0
  if (Z_MODE(addr) == IS_REG) {
1544
0
    zend_jit_def_reg(jit, addr, lval);
1545
0
  } else {
1546
0
    ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1547
0
  }
1548
0
}
1549
1550
#if SIZEOF_ZEND_LONG == 4
1551
static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1552
{
1553
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1554
    return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1555
  } else {
1556
    return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1557
  }
1558
}
1559
1560
static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1561
{
1562
  ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1563
}
1564
#endif
1565
1566
static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1567
0
{
1568
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1569
0
    return ir_CONST_DOUBLE(Z_DVAL_P(Z_ZV(addr)));
1570
0
  } else if (Z_MODE(addr) == IS_REG) {
1571
0
    return zend_jit_use_reg(jit, addr);
1572
0
  } else {
1573
0
    return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1574
0
  }
1575
0
}
1576
1577
static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1578
0
{
1579
0
  if (Z_MODE(addr) == IS_REG) {
1580
0
    zend_jit_def_reg(jit, addr, dval);
1581
0
  } else {
1582
0
    ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1583
0
  }
1584
0
}
1585
1586
static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1587
0
{
1588
0
  return ir_LOAD_A(ref);
1589
0
}
1590
1591
static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1592
0
{
1593
0
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1594
0
    return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1595
0
  } else {
1596
0
    return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1597
0
  }
1598
0
}
1599
1600
static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1601
0
{
1602
0
  ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1603
0
}
1604
1605
static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1606
0
{
1607
0
  return ir_LOAD_U32(ref);
1608
0
}
1609
1610
static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1611
0
{
1612
0
  ir_STORE(ref, ir_CONST_U32(refcount));
1613
0
}
1614
1615
static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1616
0
{
1617
0
  ir_STORE(ref, ir_ADD_U32(ir_LOAD_U32(ref), ir_CONST_U32(1)));
1618
0
}
1619
1620
static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1621
0
{
1622
0
  ir_ref counter = ir_LOAD_U32(ref);
1623
0
  ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1624
0
}
1625
1626
static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1627
0
{
1628
0
  ir_ref counter = ir_LOAD_U32(ref);
1629
0
  counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1630
0
  ir_STORE(ref, counter);
1631
0
  return counter;
1632
0
}
1633
1634
static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1635
0
{
1636
0
  return ir_IF(
1637
0
    ir_AND_U32(
1638
0
      ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1639
0
      ir_CONST_U32(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))));
1640
0
}
1641
1642
static void jit_ZVAL_COPY_CONST(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, uint32_t dst_def_info, zval *zv, bool addref)
1643
0
{
1644
0
  ir_ref ref = IR_UNUSED;
1645
1646
0
  if (Z_TYPE_P(zv) > IS_TRUE) {
1647
0
    if (Z_TYPE_P(zv) == IS_DOUBLE) {
1648
0
      jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1649
0
    } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1650
0
      jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1651
0
    } else if (Z_TYPE_P(zv) == IS_LONG) {
1652
0
      jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1653
0
    } else {
1654
0
      ref = ir_CONST_ADDR(Z_PTR_P(zv));
1655
0
      jit_set_Z_PTR(jit, dst, ref);
1656
0
      if (addref && Z_REFCOUNTED_P(zv)) {
1657
0
        jit_GC_ADDREF(jit, ref);
1658
0
      }
1659
0
    }
1660
0
  }
1661
0
  if (Z_MODE(dst) != IS_REG) {
1662
0
    if (dst_def_info == MAY_BE_DOUBLE) {
1663
0
      if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1664
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1665
0
      }
1666
0
    } 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) {
1667
0
      jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1668
0
    }
1669
0
  }
1670
0
}
1671
1672
static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1673
0
{
1674
0
  return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1675
0
}
1676
1677
static void jit_ZVAL_COPY(zend_jit_ctx *jit, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, bool addref)
1678
0
{
1679
0
  ir_ref ref = IR_UNUSED;
1680
1681
0
  if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1682
0
    if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1683
0
      jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1684
0
    } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1685
0
      jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1686
0
    } else {
1687
#if SIZEOF_ZEND_LONG == 4
1688
      if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1689
        jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1690
      }
1691
#endif
1692
0
      ref = jit_Z_PTR(jit, src);
1693
0
      jit_set_Z_PTR(jit, dst, ref);
1694
0
    }
1695
0
  }
1696
0
  if (has_concrete_type(src_info & MAY_BE_ANY)
1697
0
   && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1698
0
     && !(src_info & MAY_BE_GUARD)) {
1699
0
    if (Z_MODE(dst) != IS_REG
1700
0
     && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1701
0
      uint8_t type = concrete_type(src_info);
1702
0
      jit_set_Z_TYPE_INFO(jit, dst, type);
1703
0
    }
1704
0
  } else {
1705
0
    ir_ref type = jit_Z_TYPE_INFO(jit, src);
1706
0
    jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1707
0
    if (addref) {
1708
0
      if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1709
0
        ir_ref if_refcounted = IR_UNUSED;
1710
1711
0
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1712
0
          if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1713
0
          ir_IF_TRUE(if_refcounted);
1714
0
        }
1715
1716
0
        jit_GC_ADDREF(jit, ref);
1717
1718
0
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1719
0
          ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1720
0
        }
1721
0
      }
1722
0
    }
1723
0
  }
1724
0
}
1725
1726
static void jit_ZVAL_COPY_2(zend_jit_ctx *jit, zend_jit_addr dst2, zend_jit_addr dst, uint32_t dst_info, zend_jit_addr src, uint32_t src_info, int addref)
1727
0
{
1728
0
  ir_ref ref = IR_UNUSED;
1729
1730
0
  if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1731
0
    if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1732
0
      ref = jit_Z_LVAL(jit, src);
1733
0
      jit_set_Z_LVAL(jit, dst, ref);
1734
0
      jit_set_Z_LVAL(jit, dst2, ref);
1735
0
    } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1736
0
      ref = jit_Z_DVAL(jit, src);
1737
0
      jit_set_Z_DVAL(jit, dst, ref);
1738
0
      jit_set_Z_DVAL(jit, dst2, ref);
1739
0
    } else {
1740
#if SIZEOF_ZEND_LONG == 4
1741
      if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1742
        ref = jit_Z_W2(jit, src);
1743
        jit_set_Z_W2(jit, dst, ref);
1744
        jit_set_Z_W2(jit, dst2, ref);
1745
      }
1746
#endif
1747
0
      ref = jit_Z_PTR(jit, src);
1748
0
      jit_set_Z_PTR(jit, dst, ref);
1749
0
      jit_set_Z_PTR(jit, dst2, ref);
1750
0
    }
1751
0
  }
1752
0
  if (has_concrete_type(src_info & MAY_BE_ANY)
1753
0
   && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1754
0
     && !(src_info & MAY_BE_GUARD)) {
1755
0
    uint8_t type = concrete_type(src_info);
1756
0
    ir_ref type_ref = ir_CONST_U32(type);
1757
1758
0
    if (Z_MODE(dst) != IS_REG
1759
0
     && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1760
0
      jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1761
0
    }
1762
0
    if (Z_MODE(dst2) != IS_REG) {
1763
0
      jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1764
0
    }
1765
0
  } else {
1766
0
    ir_ref type = jit_Z_TYPE_INFO(jit, src);
1767
0
    jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1768
0
    jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1769
0
    if (addref) {
1770
0
      if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1771
0
        ir_ref if_refcounted = IR_UNUSED;
1772
1773
0
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1774
0
          if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1775
0
          ir_IF_TRUE(if_refcounted);
1776
0
        }
1777
1778
0
        if (addref == 2) {
1779
0
          jit_GC_ADDREF2(jit, ref);
1780
0
        } else {
1781
0
          jit_GC_ADDREF(jit, ref);
1782
0
        }
1783
1784
0
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1785
0
          ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1786
0
        }
1787
0
      }
1788
0
    }
1789
0
  }
1790
0
}
1791
1792
static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1793
0
{
1794
0
  if (!((op_info) & MAY_BE_GUARD)
1795
0
   && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1796
0
    uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1797
0
    if (type == IS_STRING && !ZEND_DEBUG) {
1798
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(_efree), ref);
1799
0
        return;
1800
0
    } else if (type == IS_ARRAY) {
1801
0
      if ((op_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) {
1802
0
        if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1803
0
          jit_SET_EX_OPLINE(jit, opline);
1804
0
        }
1805
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref);
1806
0
      } else {
1807
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1808
0
      }
1809
0
      return;
1810
0
    } else if (type == IS_OBJECT) {
1811
0
      if (opline) {
1812
0
        jit_SET_EX_OPLINE(jit, opline);
1813
0
      }
1814
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1815
0
      return;
1816
0
    }
1817
0
  }
1818
0
  if (opline) {
1819
0
    jit_SET_EX_OPLINE(jit, opline);
1820
0
  }
1821
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(rc_dtor_func), ref);
1822
0
}
1823
1824
static void jit_ZVAL_PTR_DTOR(zend_jit_ctx  *jit,
1825
                              zend_jit_addr  addr,
1826
                              uint32_t       op_info,
1827
                              bool           gc,
1828
                              const zend_op *opline)
1829
0
{
1830
0
    ir_ref ref, ref2;
1831
0
  ir_ref if_refcounted = IR_UNUSED;
1832
0
  ir_ref if_not_zero = IR_UNUSED;
1833
0
  ir_ref end_inputs = IR_UNUSED;
1834
1835
0
  if (op_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1836
0
    if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1837
0
      if_refcounted = jit_if_REFCOUNTED(jit, addr);
1838
0
      ir_IF_FALSE(if_refcounted);
1839
0
      ir_END_list(end_inputs);
1840
0
      ir_IF_TRUE(if_refcounted);
1841
0
    }
1842
0
    ref = jit_Z_PTR(jit, addr);
1843
0
    ref2 = jit_GC_DELREF(jit, ref);
1844
1845
0
    if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1846
0
      if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1847
0
        if_not_zero = ir_IF(ref2);
1848
0
        ir_IF_FALSE(if_not_zero);
1849
0
      }
1850
      // zval_dtor_func(r);
1851
0
      jit_ZVAL_DTOR(jit, ref, op_info, opline);
1852
0
      if (if_not_zero) {
1853
0
        ir_END_list(end_inputs);
1854
0
        ir_IF_TRUE(if_not_zero);
1855
0
      }
1856
0
    }
1857
0
    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))) {
1858
0
      ir_ref if_may_not_leak;
1859
1860
0
      if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1861
0
        ir_ref if_ref, if_collectable;
1862
1863
0
        if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1864
0
        ir_IF_TRUE(if_ref);
1865
1866
0
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
1867
1868
0
        if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1869
0
        ir_IF_FALSE(if_collectable);
1870
0
        ir_END_list(end_inputs);
1871
0
        ir_IF_TRUE(if_collectable);
1872
1873
0
        ref2 = jit_Z_PTR_ref(jit, ref2);
1874
1875
0
        ir_MERGE_WITH_EMPTY_FALSE(if_ref);
1876
0
        ref = ir_PHI_2(IR_ADDR, ref2, ref);
1877
0
      }
1878
1879
0
      if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1880
0
      ir_IF_TRUE(if_may_not_leak);
1881
0
      ir_END_list(end_inputs);
1882
0
      ir_IF_FALSE(if_may_not_leak);
1883
1884
0
      if (opline) {
1885
0
        jit_SET_EX_OPLINE(jit, opline);
1886
0
      }
1887
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1888
0
    }
1889
1890
0
    if (end_inputs) {
1891
0
      ir_END_list(end_inputs);
1892
0
      ir_MERGE_list(end_inputs);
1893
0
    }
1894
0
  }
1895
0
}
1896
1897
static void jit_FREE_OP(zend_jit_ctx  *jit,
1898
                        uint8_t        op_type,
1899
                        znode_op       op,
1900
                        uint32_t       op_info,
1901
                        const zend_op *opline)
1902
0
{
1903
0
  if (op_type & (IS_VAR|IS_TMP_VAR)) {
1904
0
    jit_ZVAL_PTR_DTOR(jit,
1905
0
      ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1906
0
      op_info, false, opline);
1907
0
  }
1908
0
}
1909
1910
static void jit_OBJ_RELEASE(zend_jit_ctx  *jit, ir_ref ref)
1911
0
{
1912
0
  ir_ref end_inputs = IR_UNUSED;
1913
0
    ir_ref if_not_zero, if_may_not_leak;
1914
1915
  // JIT: if (GC_DELREF(obj) == 0) {
1916
0
  if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1917
0
  ir_IF_FALSE(if_not_zero);
1918
1919
  // JIT: zend_objects_store_del(obj)
1920
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1921
0
  ir_END_list(end_inputs);
1922
1923
0
  ir_IF_TRUE(if_not_zero);
1924
0
  if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1925
1926
0
  ir_IF_TRUE(if_may_not_leak);
1927
0
  ir_END_list(end_inputs);
1928
1929
0
  ir_IF_FALSE(if_may_not_leak);
1930
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1931
0
  ir_END_list(end_inputs);
1932
1933
0
  ir_MERGE_list(end_inputs);
1934
0
}
1935
1936
static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1937
0
{
1938
0
  ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1939
1940
0
  if (exit_addr) {
1941
0
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1942
0
  } else if (!opline || jit->last_valid_opline == opline) {
1943
0
    ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1944
0
  } else {
1945
0
    ir_ref if_timeout = ir_IF(ref);
1946
1947
0
    ir_IF_TRUE_cold(if_timeout);
1948
0
    jit_LOAD_IP_ADDR(jit, opline);
1949
0
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1950
0
    ir_IF_FALSE(if_timeout);
1951
0
  }
1952
0
}
1953
1954
static void zend_jit_vm_enter(zend_jit_ctx *jit, ir_ref to_opline)
1955
0
{
1956
  // ZEND_VM_ENTER()
1957
0
  ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)));
1958
0
}
1959
1960
static void zend_jit_vm_leave(zend_jit_ctx *jit, ir_ref to_opline)
1961
0
{
1962
0
  // ZEND_VM_LEAVE()
1963
0
  ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)));
1964
0
}
1965
1966
static void zend_jit_tailcall_handler(zend_jit_ctx *jit, ir_ref handler)
1967
0
{
1968
#if defined(IR_TARGET_X86)
1969
  if (!IR_IS_CONST_REF(handler)) {
1970
    handler = ir_CAST_OPCODE_HANDLER_FUNC(handler);
1971
  }
1972
#endif
1973
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
1974
0
    ir_TAILCALL(IR_OPCODE_HANDLER_RET, handler);
1975
0
  } else {
1976
0
    ir_TAILCALL_2(IR_ADDR, handler, jit_FP(jit), jit_IP(jit));
1977
0
  }
1978
0
}
1979
1980
/* stubs */
1981
1982
static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1983
0
{
1984
0
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
1985
0
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(EG(exception_op));
1986
1987
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
1988
0
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1989
0
  } else {
1990
0
    zend_vm_opcode_handler_t handler = EG(exception_op)->handler;
1991
1992
0
    if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
1993
0
      zend_jit_tailcall_handler(jit, ir_CONST_OPCODE_HANDLER_FUNC(handler));
1994
0
    } else {
1995
0
      ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
1996
0
      zend_jit_vm_enter(jit, ref);
1997
0
    }
1998
0
  }
1999
0
  return 1;
2000
0
}
2001
2002
static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
2003
0
{
2004
0
  ir_ref ref, result_type, if_result_used;
2005
2006
0
  ref = jit_EG(opline_before_exception);
2007
0
  result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
2008
2009
0
  if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2010
0
  ir_IF_TRUE(if_result_used);
2011
2012
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result.var)));
2013
0
  if (sizeof(void*) == 8) {
2014
0
    ref = ir_ZEXT_A(ref);
2015
0
  }
2016
0
  ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
2017
0
  ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2018
2019
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2020
2021
0
  return 1;
2022
0
}
2023
2024
static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
2025
0
{
2026
0
  ir_ref ref, if_dtor;
2027
0
  zend_jit_addr var_addr;
2028
2029
0
  ref = ir_LOAD_A(jit_EG(opline_before_exception));
2030
0
  if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
2031
0
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2032
0
  ir_IF_TRUE(if_dtor);
2033
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
2034
0
  if (sizeof(void*) == 8) {
2035
0
    ref = ir_ZEXT_A(ref);
2036
0
  }
2037
0
  ref = ir_ADD_A(jit_FP(jit), ref);
2038
0
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
2039
0
  jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2040
0
  ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
2041
2042
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
2043
2044
0
  return 1;
2045
0
}
2046
2047
static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
2048
0
{
2049
0
  ir_ref ref, if_dtor;
2050
0
  zend_jit_addr var_addr;
2051
2052
0
  ref = ir_LOAD_A(jit_EG(opline_before_exception));
2053
0
  if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
2054
0
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2055
0
  ir_IF_TRUE(if_dtor);
2056
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
2057
0
  if (sizeof(void*) == 8) {
2058
0
    ref = ir_ZEXT_A(ref);
2059
0
  }
2060
0
  ref = ir_ADD_A(jit_FP(jit), ref);
2061
0
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
2062
0
  jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2063
0
  ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
2064
2065
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2066
2067
0
  return 1;
2068
0
}
2069
2070
static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
2071
0
{
2072
0
  ir_ref if_timeout, if_exception;
2073
2074
  // EX(opline) = opline
2075
0
  ir_STORE(jit_EX(opline), jit_IP(jit));
2076
2077
0
  ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
2078
0
  if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
2079
0
  ir_IF_FALSE(if_timeout);
2080
0
  ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout));
2081
0
  ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
2082
2083
0
  if (zend_interrupt_function) {
2084
0
    ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit));
2085
0
    if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
2086
0
    ir_IF_TRUE(if_exception);
2087
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
2088
0
    ir_MERGE_WITH_EMPTY_FALSE(if_exception);
2089
2090
0
    jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2091
0
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2092
0
  }
2093
2094
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2095
0
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2096
0
  } else {
2097
0
    zend_jit_vm_enter(jit, jit_IP(jit));
2098
0
  }
2099
0
  return 1;
2100
0
}
2101
2102
static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2103
0
{
2104
0
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
2105
0
  ir_TAILCALL(IR_OPCODE_HANDLER_RET, ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_leave_func_helper_tailcall));
2106
0
  return 1;
2107
#else
2108
  ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2109
  ir_ref if_top = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_TOP)));
2110
2111
  ir_IF_FALSE(if_top);
2112
2113
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2114
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2115
    jit_STORE_IP(jit,
2116
      ir_LOAD_A(jit_EX(opline)));
2117
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2118
  } else if (GCC_GLOBAL_REGS) {
2119
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2120
  } else {
2121
    ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), jit_FP(jit), jit_IP(jit), call_info);
2122
  }
2123
2124
  ir_IF_TRUE(if_top);
2125
2126
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2127
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2128
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2129
  } else if (GCC_GLOBAL_REGS) {
2130
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2131
  } else {
2132
    ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), jit_FP(jit), jit_IP(jit), call_info);
2133
  }
2134
2135
  return 1;
2136
#endif /* ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL */
2137
0
}
2138
2139
static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2140
0
{
2141
0
  ir_CALL_2(IR_VOID,
2142
0
    ir_CONST_FUNC_PROTO(zend_throw_error,
2143
0
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2144
0
    ir_CONST_ADDR(zend_ce_arithmetic_error),
2145
0
    ir_CONST_ADDR("Bit shift by negative number"));
2146
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2147
0
  return 1;
2148
0
}
2149
2150
static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2151
0
{
2152
0
  ir_CALL_2(IR_VOID,
2153
0
    ir_CONST_FUNC_PROTO(zend_throw_error,
2154
0
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2155
0
    ir_CONST_ADDR(zend_ce_division_by_zero_error),
2156
0
    ir_CONST_ADDR("Modulo by zero"));
2157
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2158
0
  return 1;
2159
0
}
2160
2161
static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2162
0
{
2163
0
  ir_CALL_2(IR_VOID,
2164
0
    ir_CONST_FUNC_PROTO(zend_throw_error,
2165
0
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2166
0
    IR_NULL,
2167
0
    ir_CONST_ADDR("Using $this when not in object context"));
2168
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2169
0
  return 1;
2170
0
}
2171
2172
static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2173
0
{
2174
  // JIT: load EX(opline)
2175
0
  ir_ref ref = ir_LOAD_A(jit_FP(jit));
2176
0
  ir_ref arg3 = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.constant)));
2177
2178
0
  if (sizeof(void*) == 8) {
2179
0
    arg3 = ir_LOAD_A(ir_ADD_A(ref, ir_SEXT_A(arg3)));
2180
0
  } else {
2181
0
    arg3 = ir_LOAD_A(arg3);
2182
0
  }
2183
0
  arg3 = ir_ADD_OFFSET(arg3, offsetof(zend_string, val));
2184
2185
0
  ir_CALL_3(IR_VOID,
2186
0
    ir_CONST_FUNC_PROTO(zend_throw_error,
2187
0
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2188
0
    IR_NULL,
2189
0
    ir_CONST_ADDR("Call to undefined function %s()"),
2190
0
    arg3);
2191
2192
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2193
2194
0
  return 1;
2195
0
}
2196
2197
static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2198
0
{
2199
0
  ir_ref opline, ref, rx, if_eq, if_tmp;
2200
2201
  // JIT: opline = EX(opline)
2202
0
  opline = ir_LOAD_A(jit_FP(jit));
2203
2204
  // JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2205
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2206
0
  if (sizeof(void*) == 8) {
2207
0
    ref = ir_ZEXT_A(ref);
2208
0
  }
2209
0
  rx = jit_IP(jit);
2210
0
  jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2211
2212
  // last EX(call) frame may be delayed
2213
  // JIT: if (EX(call) == RX)
2214
0
  ref = ir_LOAD_A(jit_EX(call));
2215
0
  if_eq = ir_IF(ir_EQ(rx, ref));
2216
0
  ir_IF_FALSE(if_eq);
2217
2218
  // JIT: RX->prev_execute_data == EX(call)
2219
0
  ir_STORE(jit_CALL(rx, prev_execute_data), ref);
2220
2221
  // JIT: EX(call) = RX
2222
0
  ir_STORE(jit_EX(call), rx);
2223
0
  ir_MERGE_WITH_EMPTY_TRUE(if_eq);
2224
2225
  // JIT: IP = opline
2226
0
  jit_STORE_IP(jit, opline);
2227
2228
  // JIT: zend_cannot_pass_by_reference(opline->op2.num)
2229
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_cannot_pass_by_reference),
2230
0
    ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2231
2232
  // JIT: if (IP->op1_type == IS_TMP_VAR)
2233
0
  ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2234
0
  if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2235
0
  ir_IF_TRUE(if_tmp);
2236
2237
  // JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2238
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2239
0
  if (sizeof(void*) == 8) {
2240
0
    ref = ir_ZEXT_A(ref);
2241
0
  }
2242
0
  ref = ir_ADD_A(jit_FP(jit), ref);
2243
0
  jit_ZVAL_PTR_DTOR(jit,
2244
0
    ZEND_ADDR_REF_ZVAL(ref),
2245
0
    MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2246
0
  ir_MERGE_WITH_EMPTY_FALSE(if_tmp);
2247
2248
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2249
2250
0
  return 1;
2251
0
}
2252
2253
static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2254
0
{
2255
0
  ir_ref ip, if_set;
2256
2257
  // JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2258
  // JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2259
0
  jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2260
0
  ip = jit_IP(jit);
2261
0
  if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2262
0
    ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2263
0
  ir_IF_FALSE(if_set);
2264
2265
  // JIT: EG(opline_before_exception) = opline;
2266
0
  ir_STORE(jit_EG(opline_before_exception), ip);
2267
0
  ir_MERGE_WITH_EMPTY_TRUE(if_set);
2268
2269
  // JIT: opline = EG(exception_op);
2270
0
  jit_STORE_IP(jit, jit_EG(exception_op));
2271
2272
0
  ir_STORE(jit_EX(opline), jit_IP(jit));
2273
2274
0
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2275
2276
0
  return 1;
2277
0
}
2278
2279
static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2280
0
{
2281
0
  ir_ref ip, if_set;
2282
2283
  // JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2284
0
  jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2285
0
  ip = jit_IP(jit);
2286
0
  if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2287
0
    ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2288
0
  ir_IF_FALSE(if_set);
2289
2290
  // JIT: EG(opline_before_exception) = opline;
2291
0
  ir_STORE(jit_EG(opline_before_exception), ip);
2292
0
  ir_MERGE_WITH_EMPTY_TRUE(if_set);
2293
2294
  // JIT: opline = EG(exception_op);
2295
0
  jit_STORE_IP(jit, jit_EG(exception_op));
2296
2297
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2298
0
    ir_STORE(jit_EX(opline), jit_IP(jit));
2299
2300
    // JIT: HANDLE_EXCEPTION()
2301
0
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2302
0
  } else {
2303
0
    zend_jit_vm_leave(jit, jit_IP(jit));
2304
0
  }
2305
2306
0
  return 1;
2307
0
}
2308
2309
static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2310
0
{
2311
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) {
2312
0
    return 0;
2313
0
  }
2314
2315
0
  ir_CALL(IR_VOID, ir_CONST_OPCODE_HANDLER_FUNC(zend_runtime_jit));
2316
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2317
0
  return 1;
2318
0
}
2319
2320
static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2321
0
{
2322
0
  ir_ref addr, func, run_time_cache, jit_extension;
2323
2324
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) {
2325
0
    return 0;
2326
0
  }
2327
2328
0
  addr = ir_CONST_ADDR(&zend_jit_profile_counter),
2329
0
  ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2330
2331
0
  func = ir_LOAD_A(jit_EX(func));
2332
0
  run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2333
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2334
2335
0
  if (zend_jit_profile_counter_rid) {
2336
0
    addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2337
0
  } else {
2338
0
    addr = run_time_cache;
2339
0
  }
2340
0
  ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2341
2342
0
  addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2343
0
  ir_IJMP(ir_LOAD_A(addr));
2344
2345
0
  return 1;
2346
0
}
2347
2348
static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2349
0
{
2350
0
  ir_ref func, jit_extension, addr, ref, if_overflow;
2351
0
2352
0
  func = ir_LOAD_A(jit_EX(func));
2353
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2354
0
  addr = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, counter)));
2355
0
  ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2356
0
  ir_STORE(addr, ref);
2357
0
  if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2358
0
2359
0
  ir_IF_TRUE_cold(if_overflow);
2360
0
  ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2361
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_hot_func),
2362
0
    jit_FP(jit),
2363
0
    jit_IP(jit));
2364
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2365
0
2366
0
  ir_IF_FALSE(if_overflow);
2367
0
  ref = ir_SUB_A(jit_IP(jit),
2368
0
    ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, opcodes))));
2369
0
  ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2370
0
2371
0
  addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2372
0
    ref);
2373
0
  ir_IJMP(ir_LOAD_A(addr));
2374
0
2375
0
  return 1;
2376
0
}
2377
2378
static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2379
0
{
2380
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2381
0
    return 0;
2382
0
  }
2383
2384
0
  return _zend_jit_hybrid_hot_counter_stub(jit,
2385
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2386
0
}
2387
2388
static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2389
0
{
2390
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2391
0
    return 0;
2392
0
  }
2393
2394
0
  return _zend_jit_hybrid_hot_counter_stub(jit,
2395
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2396
0
}
2397
2398
static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2399
0
{
2400
0
  ir_ref addr = ir_ADD_A(offset, jit_IP(jit));
2401
2402
0
  return ir_LOAD_A(addr);
2403
0
}
2404
2405
static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2406
0
{
2407
0
  ir_ref func, jit_extension, offset;
2408
2409
0
  func = ir_LOAD_A(jit_EX(func));
2410
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2411
0
  offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2412
0
  return _zend_jit_orig_opline_handler(jit, offset);
2413
0
}
2414
2415
static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2416
0
{
2417
0
  ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2418
0
2419
0
  func = ir_LOAD_A(jit_EX(func));
2420
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2421
0
  offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2422
0
  addr = ir_LOAD_A(ir_ADD_OFFSET(ir_ADD_A(offset, jit_IP(jit)), offsetof(zend_op_trace_info, counter)));
2423
0
  ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2424
0
  ir_STORE(addr, ref);
2425
0
  if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2426
0
2427
0
  ir_IF_TRUE_cold(if_overflow);
2428
0
  ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2429
0
  ret = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_trace_hot_root),
2430
0
    jit_FP(jit),
2431
0
    jit_IP(jit));
2432
0
  if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2433
0
  ir_IF_FALSE(if_halt);
2434
0
2435
0
  ref = jit_EG(current_execute_data);
2436
0
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2437
0
  ref = ir_LOAD_A(jit_EX(opline));
2438
0
  jit_STORE_IP(jit, ref);
2439
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2440
0
2441
0
  ir_IF_FALSE(if_overflow);
2442
0
  ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2443
0
2444
0
  ir_IF_TRUE(if_halt);
2445
0
  ir_IJMP(ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_halt_op->handler));
2446
0
2447
0
  return 1;
2448
0
}
2449
2450
static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2451
0
{
2452
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2453
0
    return 0;
2454
0
  }
2455
2456
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2457
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2458
0
}
2459
2460
static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2461
0
{
2462
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2463
0
    return 0;
2464
0
  }
2465
2466
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2467
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2468
0
}
2469
2470
static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2471
0
{
2472
0
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2473
0
    return 0;
2474
0
  }
2475
2476
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2477
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2478
0
}
2479
2480
static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2481
0
{
2482
0
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2483
0
    ir_TAILCALL(IR_VOID, ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_halt_op->handler));
2484
0
  } else if (GCC_GLOBAL_REGS) {
2485
0
    jit_STORE_IP(jit, IR_NULL);
2486
0
    ir_RETURN(IR_VOID);
2487
0
  } else {
2488
0
    ir_RETURN(ir_CONST_ADDR(ZEND_VM_ENTER_BIT)); // ZEND_VM_RETURN
2489
0
  }
2490
0
  return 1;
2491
0
}
2492
2493
static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2494
0
{
2495
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2496
0
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2497
0
  } else {
2498
0
    zend_jit_vm_enter(jit, jit_IP(jit));
2499
0
  }
2500
2501
0
  return 1;
2502
0
}
2503
2504
static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2505
0
{
2506
0
  ir_ref ref, ret, if_zero, addr;
2507
2508
  // EX(opline) = opline
2509
0
  ir_STORE(jit_EX(opline), jit_IP(jit));
2510
2511
0
  ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit));
2512
2513
0
  if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2514
2515
0
  ir_IF_TRUE(if_zero);
2516
2517
0
  ref = jit_EG(current_execute_data);
2518
0
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2519
0
  ref = ir_LOAD_A(jit_EX(opline));
2520
0
  jit_STORE_IP(jit, ref);
2521
2522
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2523
0
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2524
0
  } else {
2525
0
    zend_jit_vm_enter(jit, ref);
2526
0
  }
2527
2528
0
  ir_IF_FALSE(if_zero);
2529
2530
0
  ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2531
2532
0
  ref = jit_EG(current_execute_data);
2533
0
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2534
2535
0
  ref = ir_LOAD_A(jit_EX(opline));
2536
0
  jit_STORE_IP(jit, ref);
2537
2538
  // check for interrupt (try to avoid this ???)
2539
0
  zend_jit_check_timeout(jit, NULL, NULL);
2540
2541
0
  addr = zend_jit_orig_opline_handler(jit);
2542
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2543
0
    zend_jit_tailcall_handler(jit, addr);
2544
0
  } else {
2545
#if defined(IR_TARGET_X86)
2546
    addr = ir_CAST_OPCODE_HANDLER_FUNC(addr);
2547
#endif
2548
0
    ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit));
2549
0
    zend_jit_vm_enter(jit, ref);
2550
0
  }
2551
2552
0
  return 1;
2553
0
}
2554
2555
static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2556
0
{
2557
0
  if (GCC_GLOBAL_REGS) {
2558
0
    ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key));
2559
0
  } else {
2560
0
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit));
2561
0
  }
2562
2563
0
  return 1;
2564
0
}
2565
2566
static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2567
0
{
2568
0
  if (GCC_GLOBAL_REGS) {
2569
0
    ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key));
2570
0
  } else {
2571
0
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit));
2572
0
  }
2573
2574
0
  return 1;
2575
0
}
2576
2577
static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2578
0
{
2579
0
  ir_ref opline = ir_LOAD_A(jit_EX(opline));
2580
0
  ir_ref ref, if_result_used;
2581
2582
0
  if_result_used = ir_IF(ir_AND_U8(
2583
0
    ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2584
0
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2585
0
  ir_IF_TRUE(if_result_used);
2586
2587
0
  ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2588
0
  if (sizeof(void*) == 8) {
2589
0
    ref = ir_ZEXT_A(ref);
2590
0
  }
2591
0
  jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2592
0
  ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2593
2594
0
  ir_CALL_2(IR_VOID,
2595
0
    ir_CONST_FUNC_PROTO(zend_throw_error,
2596
0
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2597
0
    IR_NULL,
2598
0
    ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2599
0
  ir_RETURN(IR_VOID);
2600
2601
0
  return 1;
2602
0
}
2603
2604
static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2605
0
{
2606
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2607
0
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2608
2609
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2610
0
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2611
0
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2612
2613
0
  if (!zend_jit_assign_to_variable(
2614
0
      jit, NULL,
2615
0
      var_addr, var_addr, -1, -1,
2616
0
      IS_CONST, val_addr, val_info,
2617
0
      0, 0, false)) {
2618
0
    return 0;
2619
0
  }
2620
0
  ir_RETURN(IR_VOID);
2621
0
  return 1;
2622
0
}
2623
2624
static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2625
0
{
2626
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2627
0
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2628
2629
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2630
0
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2631
0
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2632
2633
0
  if (!zend_jit_assign_to_variable(
2634
0
      jit, NULL,
2635
0
      var_addr, var_addr, -1, -1,
2636
0
      IS_TMP_VAR, val_addr, val_info,
2637
0
      0, 0, false)) {
2638
0
    return 0;
2639
0
  }
2640
0
  ir_RETURN(IR_VOID);
2641
0
  return 1;
2642
0
}
2643
2644
static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2645
0
{
2646
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2647
0
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2648
2649
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2650
0
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2651
0
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2652
2653
0
  if (!zend_jit_assign_to_variable(
2654
0
      jit, NULL,
2655
0
      var_addr, var_addr, -1, -1,
2656
0
      IS_VAR, val_addr, val_info,
2657
0
      0, 0, false)) {
2658
0
    return 0;
2659
0
  }
2660
0
  ir_RETURN(IR_VOID);
2661
0
  return 1;
2662
0
}
2663
2664
static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2665
0
{
2666
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2667
0
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2668
2669
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2670
0
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2671
0
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2672
2673
0
  if (!zend_jit_assign_to_variable(
2674
0
      jit, NULL,
2675
0
      var_addr, var_addr, -1, -1,
2676
0
      IS_CV, val_addr, val_info,
2677
0
      0, 0, false)) {
2678
0
    return 0;
2679
0
  }
2680
0
  ir_RETURN(IR_VOID);
2681
0
  return 1;
2682
0
}
2683
2684
static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2685
0
{
2686
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2687
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2688
0
  ir_ref ref = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_zend_new_array_0));
2689
2690
0
  jit_set_Z_PTR(jit, var_addr, ref);
2691
0
  jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2692
0
  ir_RETURN(ref);
2693
0
  return 1;
2694
0
}
2695
2696
static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2697
0
{
2698
0
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2699
0
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2700
2701
0
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2702
0
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2703
0
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2704
2705
0
  if (!zend_jit_assign_to_variable(
2706
0
      jit, NULL,
2707
0
      var_addr, var_addr, -1, -1,
2708
0
      IS_CV, val_addr, val_info,
2709
0
      0, 0, false)) {
2710
0
    return 0;
2711
0
  }
2712
0
  ir_RETURN(IR_VOID);
2713
0
  return 1;
2714
0
}
2715
2716
static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2717
0
{
2718
#if defined (__CET__) && (__CET__ & 1) != 0
2719
  flags |= IR_GEN_ENDBR;
2720
#endif
2721
0
  flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
2722
2723
0
  ir_init(&jit->ctx, flags, 256, 1024);
2724
0
  jit->ctx.ret_type = -1;
2725
2726
0
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2727
0
  jit->ctx.mflags |= default_mflags;
2728
0
  if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2729
0
    jit->ctx.mflags |= IR_X86_AVX;
2730
0
  }
2731
#elif defined(IR_TARGET_AARCH64)
2732
  jit->ctx.get_veneer = zend_jit_get_veneer;
2733
  jit->ctx.set_veneer = zend_jit_set_veneer;
2734
#endif
2735
2736
0
  jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2737
0
  if (!(flags & IR_FUNCTION)) {
2738
0
    jit->ctx.flags |= IR_NO_STACK_COMBINE;
2739
0
    if (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2740
0
      jit->ctx.flags |= IR_FUNCTION;
2741
      /* Stack must be 16 byte aligned */
2742
      /* TODO: select stack size ??? */
2743
0
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
2744
# if defined(IR_TARGET_AARCH64)
2745
      /* Must save LR */
2746
      jit->ctx.flags |= IR_USE_FRAME_POINTER;
2747
      /* Same as HYBRID VM */
2748
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 4; /* 4 spill slots */
2749
# else
2750
      /* Same as HYBRID VM, plus 1 slot for re-alignment (caller pushes return address, frame is not aligned on entry) */
2751
0
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 5; /* 5 spill slots (8 bytes) or 10 spill slots (4 bytes) */
2752
0
# endif
2753
#elif defined(IR_TARGET_AARCH64)
2754
      jit->ctx.flags |= IR_USE_FRAME_POINTER;
2755
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2756
#elif defined(_WIN64)
2757
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2758
#elif defined(IR_TARGET_X86_64)
2759
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9;  /* 6 saved registers and 3 spill slots (8 bytes) */
2760
#else /* IR_TARGET_x86 */
2761
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2762
#endif
2763
      /* JIT-ed code is called only from execute_ex, which takes care
2764
       * of saving ZREG_FP, ZREG_IP when GCC_GLOBAL_REGS is 1, so we don't
2765
       * have to save them.
2766
       */
2767
0
      if (GCC_GLOBAL_REGS) {
2768
0
        jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2769
0
      } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2770
        /* The only preserved register on x86 is RBP:
2771
         * https://github.com/llvm/llvm-project/blob/a414877a7a5f000d01370acb1162eb1dea87f48c/llvm/lib/Target/X86/X86RegisterInfo.cpp#L319
2772
         * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/X86/X86CallingConv.td#L1183
2773
         * On AArch64 it's LR, FP:
2774
         * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/AArch64/AArch64CallingConvention.td#L681
2775
         *
2776
         * Add them to the fixed_regset to prevent usage or these regs.
2777
         * It's cheaper to not use them than to save them.
2778
         */
2779
0
#if defined(IR_TARGET_X64)
2780
0
        jit->ctx.fixed_regset |= (1<<IR_REG_FP);
2781
#elif defined(IR_TARGET_AARCH64)
2782
        jit->ctx.fixed_regset |= (1<<IR_REG_FP) | (1<<IR_REG_LR);
2783
#else
2784
        ZEND_UNREACHABLE();
2785
#endif
2786
0
      } else {
2787
0
        jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED;
2788
//#ifdef _WIN64
2789
//        jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2790
//#endif
2791
0
      }
2792
#ifdef _WIN64
2793
      jit->ctx.fixed_call_stack_size = 16 + IR_SHADOW_ARGS;
2794
#else
2795
0
      jit->ctx.fixed_call_stack_size = 16;
2796
0
#endif
2797
0
    } else {
2798
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2799
      jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2800
      if (jit->ctx.fixed_stack_red_zone > 16) {
2801
        jit->ctx.fixed_stack_frame_size = jit->ctx.fixed_stack_red_zone - 16;
2802
        jit->ctx.fixed_call_stack_size = 16;
2803
      }
2804
      jit->ctx.flags |= IR_MERGE_EMPTY_ENTRIES;
2805
#else
2806
0
      jit->ctx.fixed_stack_red_zone = 0;
2807
0
      jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2808
0
      jit->ctx.fixed_call_stack_size = 16;
2809
0
#endif
2810
0
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2811
0
      jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2812
0
#endif
2813
0
    }
2814
0
  }
2815
2816
0
  jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2817
2818
0
  jit->op_array = NULL;
2819
0
  jit->current_op_array = NULL;
2820
0
  jit->ssa = NULL;
2821
0
  jit->name = NULL;
2822
0
  jit->last_valid_opline = NULL;
2823
0
  jit->use_last_valid_opline = false;
2824
0
  jit->track_last_valid_opline = false;
2825
0
  jit->reuse_ip = false;
2826
0
  jit->delayed_call_level = 0;
2827
0
  delayed_call_chain = false;
2828
0
  jit->b = -1;
2829
#ifdef ZTS
2830
  jit->tls = IR_UNUSED;
2831
#endif
2832
0
  jit->fp = IR_UNUSED;
2833
0
  jit->poly_func_ref = IR_UNUSED;
2834
0
  jit->poly_this_ref = IR_UNUSED;
2835
0
  jit->trace_loop_ref = IR_UNUSED;
2836
0
  jit->return_inputs = IR_UNUSED;
2837
0
  jit->bb_start_ref = NULL;
2838
0
  jit->bb_predecessors = NULL;
2839
0
  jit->bb_edges = NULL;
2840
0
  jit->trace = NULL;
2841
0
  jit->ra = NULL;
2842
0
  jit->delay_var = -1;
2843
0
  jit->delay_refs = NULL;
2844
0
  jit->eg_exception_addr = 0;
2845
0
  zend_hash_init(&jit->addr_hash, 64, NULL, NULL, 0);
2846
0
  memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2847
2848
0
  ir_START();
2849
0
}
2850
2851
static int zend_jit_free_ctx(zend_jit_ctx *jit)
2852
0
{
2853
0
  if (jit->name) {
2854
0
    zend_string_release(jit->name);
2855
0
  }
2856
0
  zend_hash_destroy(&jit->addr_hash);
2857
0
  ir_free(&jit->ctx);
2858
0
  return 1;
2859
0
}
2860
2861
static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2862
0
{
2863
0
  void *entry;
2864
0
  ir_code_buffer code_buffer;
2865
2866
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_SRC) {
2867
0
    if (name) fprintf(stderr, "%s: ; after folding\n", name);
2868
0
    ir_save(ctx, 0, stderr);
2869
0
  }
2870
2871
0
#if ZEND_DEBUG
2872
0
  ir_check(ctx);
2873
0
#endif
2874
2875
0
  ir_build_def_use_lists(ctx);
2876
2877
0
#if ZEND_DEBUG
2878
0
  ir_check(ctx);
2879
0
#endif
2880
2881
0
#if 1
2882
0
  ir_sccp(ctx);
2883
0
#endif
2884
2885
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCCP) {
2886
0
    if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2887
0
    ir_save(ctx, 0, stderr);
2888
0
  }
2889
2890
0
  ir_build_cfg(ctx);
2891
0
  ir_build_dominators_tree(ctx);
2892
0
  ir_find_loops(ctx);
2893
2894
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_CFG) {
2895
0
    if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2896
0
    ir_save(ctx, IR_SAVE_CFG, stderr);
2897
0
  }
2898
2899
0
  ir_gcm(ctx);
2900
2901
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_GCM) {
2902
0
    if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2903
0
    ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2904
0
  }
2905
2906
0
  ir_schedule(ctx);
2907
2908
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE) {
2909
0
    if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2910
0
    ir_save(ctx, IR_SAVE_CFG, stderr);
2911
0
  }
2912
2913
0
  ir_match(ctx);
2914
0
#if !defined(IR_TARGET_AARCH64)
2915
0
  ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2916
0
#endif
2917
0
  ir_assign_virtual_registers(ctx);
2918
0
  ir_compute_live_ranges(ctx);
2919
0
  ir_coalesce(ctx);
2920
0
  ir_reg_alloc(ctx);
2921
2922
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_REGS) {
2923
0
    if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2924
0
    ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2925
0
    ir_dump_live_ranges(ctx, stderr);
2926
0
  }
2927
2928
0
  ir_schedule_blocks(ctx);
2929
2930
0
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
2931
0
    if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_CODEGEN) {
2932
0
      if (name) fprintf(stderr, "%s: ; codegen\n", name);
2933
0
      ir_dump_codegen(ctx, stderr);
2934
0
    } else {
2935
0
      if (name) fprintf(stderr, "%s: ; final\n", name);
2936
0
      ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2937
0
    }
2938
0
  }
2939
2940
0
#if ZEND_DEBUG
2941
0
  ir_check(ctx);
2942
0
#endif
2943
2944
0
  code_buffer.start = dasm_buf;
2945
0
  code_buffer.end = dasm_end;
2946
0
  code_buffer.pos = *dasm_ptr;
2947
0
  ctx->code_buffer = &code_buffer;
2948
2949
0
  entry = ir_emit_code(ctx, size);
2950
2951
0
  *dasm_ptr = code_buffer.pos;
2952
2953
#if defined(IR_TARGET_AARCH64)
2954
  if (ctx->flags2 & IR_HAS_VENEERS) {
2955
    zend_jit_commit_veneers();
2956
  }
2957
#endif
2958
2959
0
  return entry;
2960
0
}
2961
2962
static void zend_jit_setup_stubs(void)
2963
0
{
2964
0
  zend_jit_ctx jit;
2965
0
  void *entry;
2966
0
  size_t size;
2967
0
  uint32_t i;
2968
2969
0
  for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2970
0
    zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2971
2972
0
    if (!zend_jit_stubs[i].stub(&jit)) {
2973
0
      zend_jit_free_ctx(&jit);
2974
0
      zend_jit_stub_handlers[i] = NULL;
2975
0
      continue;
2976
0
    }
2977
2978
0
    entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2979
0
    if (!entry) {
2980
0
      zend_jit_free_ctx(&jit);
2981
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2982
0
    }
2983
2984
0
    zend_jit_stub_handlers[i] = entry;
2985
2986
0
    if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2987
#ifdef HAVE_CAPSTONE
2988
      if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
2989
        ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2990
      }
2991
      if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_STUBS) {
2992
        ir_disasm(zend_jit_stubs[i].name,
2993
          entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2994
      }
2995
#endif
2996
0
#ifndef _WIN32
2997
0
      if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
2998
//        ir_mem_unprotect(entry, size);
2999
0
        ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
3000
//        ir_mem_protect(entry, size);
3001
0
      }
3002
3003
0
      if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
3004
0
        ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
3005
0
        if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3006
0
          ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
3007
0
        }
3008
0
      }
3009
0
#endif
3010
0
    }
3011
0
    zend_jit_free_ctx(&jit);
3012
0
  }
3013
0
}
3014
3015
#define REGISTER_HELPER(n)  \
3016
  ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
3017
#define REGISTER_DATA(n)  \
3018
  ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
3019
3020
static void zend_jit_setup_disasm(void)
3021
0
{
3022
#ifdef HAVE_CAPSTONE
3023
  ir_disasm_init();
3024
3025
  if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
3026
    zend_op opline;
3027
3028
    memset(&opline, 0, sizeof(opline));
3029
3030
    opline.opcode = ZEND_DO_UCALL;
3031
    opline.result_type = IS_UNUSED;
3032
    zend_vm_set_opcode_handler(&opline);
3033
    ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3034
3035
    opline.opcode = ZEND_DO_UCALL;
3036
    opline.result_type = IS_VAR;
3037
    zend_vm_set_opcode_handler(&opline);
3038
    ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3039
3040
    opline.opcode = ZEND_DO_FCALL_BY_NAME;
3041
    opline.result_type = IS_UNUSED;
3042
    zend_vm_set_opcode_handler(&opline);
3043
    ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3044
3045
    opline.opcode = ZEND_DO_FCALL_BY_NAME;
3046
    opline.result_type = IS_VAR;
3047
    zend_vm_set_opcode_handler(&opline);
3048
    ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3049
3050
    opline.opcode = ZEND_DO_FCALL;
3051
    opline.result_type = IS_UNUSED;
3052
    zend_vm_set_opcode_handler(&opline);
3053
    ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3054
3055
    opline.opcode = ZEND_DO_FCALL;
3056
    opline.result_type = IS_VAR;
3057
    zend_vm_set_opcode_handler(&opline);
3058
    ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3059
3060
    opline.opcode = ZEND_RETURN;
3061
    opline.op1_type = IS_CONST;
3062
    zend_vm_set_opcode_handler(&opline);
3063
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3064
3065
    opline.opcode = ZEND_RETURN;
3066
    opline.op1_type = IS_TMP_VAR;
3067
    zend_vm_set_opcode_handler(&opline);
3068
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3069
3070
    opline.opcode = ZEND_RETURN;
3071
    opline.op1_type = IS_VAR;
3072
    zend_vm_set_opcode_handler(&opline);
3073
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3074
3075
    opline.opcode = ZEND_RETURN;
3076
    opline.op1_type = IS_CV;
3077
    zend_vm_set_opcode_handler(&opline);
3078
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3079
3080
    ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
3081
  }
3082
3083
  REGISTER_DATA(zend_jit_profile_counter);
3084
3085
  REGISTER_HELPER(zend_runtime_jit);
3086
  REGISTER_HELPER(zend_jit_hot_func);
3087
  REGISTER_HELPER(zend_jit_trace_hot_root);
3088
  REGISTER_HELPER(zend_jit_trace_exit);
3089
3090
  REGISTER_HELPER(zend_jit_array_free);
3091
  REGISTER_HELPER(zend_jit_undefined_op_helper);
3092
  REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
3093
  REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
3094
  REGISTER_HELPER(zend_jit_post_inc_typed_ref);
3095
  REGISTER_HELPER(zend_jit_post_dec_typed_ref);
3096
  REGISTER_HELPER(zend_jit_pre_inc);
3097
  REGISTER_HELPER(zend_jit_pre_dec);
3098
  REGISTER_HELPER(zend_jit_add_arrays_helper);
3099
  REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
3100
  REGISTER_HELPER(zend_jit_fast_concat_helper);
3101
  REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
3102
  REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
3103
  REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
3104
  REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
3105
  REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
3106
  REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
3107
  REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
3108
  REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
3109
  REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
3110
  REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
3111
  REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
3112
  REGISTER_HELPER(zend_jit_check_constant);
3113
  REGISTER_HELPER(zend_jit_get_constant);
3114
  REGISTER_HELPER(zend_jit_int_extend_stack_helper);
3115
  REGISTER_HELPER(zend_jit_extend_stack_helper);
3116
  REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
3117
  REGISTER_HELPER(zend_jit_find_func_helper);
3118
  REGISTER_HELPER(zend_jit_find_ns_func_helper);
3119
  REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3120
  REGISTER_HELPER(zend_jit_unref_helper);
3121
  REGISTER_HELPER(zend_jit_invalid_method_call);
3122
  REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3123
  REGISTER_HELPER(zend_jit_find_method_helper);
3124
  REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3125
  REGISTER_HELPER(zend_jit_push_static_method_call_frame);
3126
  REGISTER_HELPER(zend_jit_push_static_method_call_frame_tmp);
3127
  REGISTER_HELPER(zend_jit_find_class_helper);
3128
  REGISTER_HELPER(zend_jit_find_static_method_helper);
3129
  REGISTER_HELPER(zend_jit_push_this_method_call_frame);
3130
  REGISTER_HELPER(zend_jit_free_trampoline_helper);
3131
  REGISTER_HELPER(zend_jit_verify_return_slow);
3132
  REGISTER_HELPER(zend_jit_deprecated_helper);
3133
  REGISTER_HELPER(zend_jit_undefined_long_key);
3134
  REGISTER_HELPER(zend_jit_undefined_long_key_ex);
3135
  REGISTER_HELPER(zend_jit_undefined_string_key);
3136
  REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3137
  REGISTER_HELPER(zend_jit_copy_extra_args_helper_no_skip_recv);
3138
  REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3139
  REGISTER_HELPER(zend_free_extra_named_params);
3140
  REGISTER_HELPER(zend_jit_free_call_frame);
3141
  REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3142
  REGISTER_HELPER(zend_jit_verify_arg_slow);
3143
  REGISTER_HELPER(zend_missing_arg_error);
3144
  REGISTER_HELPER(zend_jit_only_vars_by_reference);
3145
  REGISTER_HELPER(zend_jit_leave_func_helper);
3146
  REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3147
  REGISTER_HELPER(zend_jit_leave_top_func_helper);
3148
  REGISTER_HELPER(zend_jit_fetch_global_helper);
3149
  REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3150
  REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3151
  REGISTER_HELPER(zend_jit_hash_lookup_rw);
3152
  REGISTER_HELPER(zend_jit_symtable_find);
3153
  REGISTER_HELPER(zend_jit_symtable_lookup_w);
3154
  REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3155
  REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3156
  REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3157
  REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3158
  REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3159
  REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3160
  REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3161
  REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3162
  REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3163
  REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3164
  REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3165
  REGISTER_HELPER(zend_jit_invalid_array_access);
3166
  REGISTER_HELPER(zend_jit_zval_array_dup);
3167
  REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3168
  REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3169
  REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3170
  REGISTER_HELPER(zend_jit_isset_dim_helper);
3171
  REGISTER_HELPER(zend_jit_assign_dim_helper);
3172
  REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3173
  REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3174
  REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3175
  REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3176
  REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3177
  REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3178
  REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3179
  REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3180
  REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3181
  REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3182
  REGISTER_HELPER(zend_jit_check_array_promotion);
3183
  REGISTER_HELPER(zend_jit_create_typed_ref);
3184
  REGISTER_HELPER(zend_jit_invalid_property_write);
3185
  REGISTER_HELPER(zend_jit_invalid_property_read);
3186
  REGISTER_HELPER(zend_jit_extract_helper);
3187
  REGISTER_HELPER(zend_jit_invalid_property_assign);
3188
  REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3189
  REGISTER_HELPER(zend_jit_assign_obj_helper);
3190
  REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3191
  REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3192
  REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3193
  REGISTER_HELPER(zend_jit_invalid_property_incdec);
3194
  REGISTER_HELPER(zend_jit_inc_typed_prop);
3195
  REGISTER_HELPER(zend_jit_dec_typed_prop);
3196
  REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3197
  REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3198
  REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3199
  REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3200
  REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3201
  REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3202
  REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3203
  REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3204
  REGISTER_HELPER(zend_jit_uninit_static_prop);
3205
  REGISTER_HELPER(zend_jit_rope_end);
3206
  REGISTER_HELPER(zend_fcall_interrupt);
3207
3208
#ifndef ZTS
3209
  REGISTER_DATA(EG(current_execute_data));
3210
  REGISTER_DATA(EG(exception));
3211
  REGISTER_DATA(EG(opline_before_exception));
3212
  REGISTER_DATA(EG(vm_interrupt));
3213
  REGISTER_DATA(EG(timed_out));
3214
  REGISTER_DATA(EG(uninitialized_zval));
3215
  REGISTER_DATA(EG(zend_constants));
3216
  REGISTER_DATA(EG(jit_trace_num));
3217
  REGISTER_DATA(EG(vm_stack_top));
3218
  REGISTER_DATA(EG(vm_stack_end));
3219
  REGISTER_DATA(EG(exception_op));
3220
  REGISTER_DATA(EG(symbol_table));
3221
3222
  REGISTER_DATA(CG(map_ptr_base));
3223
#else /* ZTS */
3224
  REGISTER_HELPER(zend_jit_get_tsrm_ls_cache);
3225
#endif
3226
#endif
3227
0
}
3228
3229
static void zend_jit_calc_trace_prologue_size(void)
3230
0
{
3231
0
  zend_jit_ctx jit_ctx;
3232
0
  zend_jit_ctx *jit = &jit_ctx;
3233
0
  void *entry;
3234
0
  size_t size;
3235
3236
0
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : IR_START_BR_TARGET);
3237
3238
0
  if (!GCC_GLOBAL_REGS) {
3239
0
    if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
3240
0
      ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3241
0
      ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
3242
0
      jit_STORE_FP(jit, execute_data_ref);
3243
0
      jit_STORE_IP(jit, opline_ref);
3244
0
    }
3245
0
    jit->ctx.flags |= IR_FASTCALL_FUNC;
3246
0
  }
3247
3248
0
  ir_UNREACHABLE();
3249
3250
0
  entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3251
0
  zend_jit_free_ctx(jit);
3252
3253
0
  if (!entry) {
3254
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3255
0
  }
3256
3257
0
  zend_jit_trace_prologue_size = size;
3258
0
}
3259
3260
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3261
static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3262
3263
typedef struct _Unwind_Context _Unwind_Context;
3264
typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3265
extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3266
extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3267
3268
typedef struct _zend_jit_unwind_arg {
3269
  int cnt;
3270
  uintptr_t cfa[3];
3271
} zend_jit_unwind_arg;
3272
3273
static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3274
0
{
3275
0
  zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3276
0
  arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3277
0
  arg->cnt++;
3278
0
  if (arg->cnt == 3) {
3279
0
    return 5; // _URC_END_OF_STACK
3280
0
  }
3281
0
  return 0; // _URC_NO_REASON;
3282
0
}
3283
3284
static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3285
0
{
3286
0
  zend_jit_unwind_arg arg;
3287
0
3288
0
  memset(&arg, 0, sizeof(arg));
3289
0
  _Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3290
0
  if (arg.cnt == 3) {
3291
0
    zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3292
0
  }
3293
0
}
3294
3295
extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3296
3297
static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3298
0
{
3299
0
  void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3300
0
3301
0
  orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3302
0
  zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3303
0
  execute_ex(NULL);                                        // set sp_adj[SP_ADJ_VM]
3304
0
  zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3305
0
}
3306
#endif
3307
3308
#ifdef _WIN64
3309
/*
3310
 * We use a single unwind entry for the whole JIT buffer.
3311
 * This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3312
 */
3313
static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3314
3315
#ifdef ZEND_JIT_RT_UNWINDER
3316
static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3317
{
3318
  return zend_jit_uw_func;
3319
}
3320
#endif
3321
3322
static void zend_jit_setup_unwinder(void)
3323
{
3324
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
3325
  /* TAILCALL VM: fixed_save_regset=0, no registers pushed in prologue.
3326
   * fixed_stack_frame_size=40, fixed_call_stack_size=48 (16+IR_SHADOW_ARGS).
3327
   * Prologue is: sub rsp, 0x58 (88 bytes = 40+48). */
3328
  static const unsigned char uw_data[] = {
3329
    0x01, // Version=1, Flags=0
3330
    0x04, // Size of prolog (sub rsp,imm8 = 4 bytes: 48 83 ec 58)
3331
    0x01, // Count of unwind codes
3332
    0x00, // Frame Register=none
3333
    0x04, 0xa2, // offset 4: UWOP_ALLOC_SMALL info=10, alloc=(10+1)*8=88
3334
    0x00, 0x00, // padding
3335
  };
3336
  /* Exit call variant: base 88 + 304 (shadow+GP+FP+padding) = 392 (0x188) */
3337
  static const unsigned char uw_data_exitcall[] = {
3338
    0x01, // Version=1, Flags=0
3339
    0x07, // Size of prolog (sub rsp,imm32 = 7 bytes: 48 81 ec 88 01 00 00)
3340
    0x02, // Count of unwind codes
3341
    0x00, // Frame Register=none
3342
    0x07, 0x01, 0x31, 0x00, // offset 7: UWOP_ALLOC_LARGE info=0, size/8=49, alloc=392
3343
  };
3344
#else
3345
  /* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
3346
  static const unsigned char uw_data[] = {
3347
    0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3348
    0x10, // UBYTE Size of prolog
3349
    0x09, // UBYTE Count of unwind codes
3350
    0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3351
    // USHORT * n Unwind codes array
3352
    0x10, 0x82, // c: subq $0x48, %rsp
3353
    0x0c, 0xf0, // a: pushq %r15
3354
    0x0a, 0xe0, // 8: pushq %r14
3355
    0x08, 0xd0, // 6: pushq %r13
3356
    0x06, 0xc0, // 4: pushq %r12
3357
    0x04, 0x70, // 3: pushq %rdi
3358
    0x03, 0x60, // 2: pushq %rsi
3359
    0x02, 0x50, // 1: pushq %rbp
3360
    0x01, 0x30, // 0: pushq %rbx
3361
    0x00, 0x00,
3362
  };
3363
  static const unsigned char uw_data_exitcall[] = {
3364
    0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3365
    0x10, // UBYTE Size of prolog
3366
    0x0a, // UBYTE Count of unwind codes
3367
    0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3368
    // USHORT * n Unwind codes array
3369
    0x10, 0x01, 0x2f, 0x00, // c: subq 376, %rsp ; 0x48 + 32+16*8+16*8+8+8
3370
    0x0c, 0xf0, // a: pushq %r15
3371
    0x0a, 0xe0, // 8: pushq %r14
3372
    0x08, 0xd0, // 6: pushq %r13
3373
    0x06, 0xc0, // 4: pushq %r12
3374
    0x04, 0x70, // 3: pushq %rdi
3375
    0x03, 0x60, // 2: pushq %rsi
3376
    0x02, 0x50, // 1: pushq %rbp
3377
    0x01, 0x30, // 0: pushq %rbx
3378
  };
3379
#endif
3380
3381
  zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3382
  *dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +
3383
    sizeof(uw_data) + sizeof(uw_data_exitcall) + sizeof(uw_data), 16);
3384
3385
  zend_jit_uw_func[0].BeginAddress = 0;
3386
  zend_jit_uw_func[1].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_trace_exit] - (uintptr_t)dasm_buf;
3387
  zend_jit_uw_func[2].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_undefined_offset] - (uintptr_t)dasm_buf;
3388
3389
  zend_jit_uw_func[0].EndAddress = zend_jit_uw_func[1].BeginAddress;
3390
  zend_jit_uw_func[1].EndAddress = zend_jit_uw_func[2].BeginAddress;
3391
  zend_jit_uw_func[2].EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3392
3393
  zend_jit_uw_func[0].UnwindData = (uintptr_t)zend_jit_uw_func  - (uintptr_t)dasm_buf + sizeof(RUNTIME_FUNCTION) * 4;
3394
  zend_jit_uw_func[1].UnwindData = zend_jit_uw_func[0].UnwindData + sizeof(uw_data);
3395
  zend_jit_uw_func[2].UnwindData = zend_jit_uw_func[1].UnwindData + sizeof(uw_data_exitcall);
3396
3397
  memcpy((char*)dasm_buf + zend_jit_uw_func[0].UnwindData, uw_data, sizeof(uw_data));
3398
  memcpy((char*)dasm_buf + zend_jit_uw_func[1].UnwindData, uw_data_exitcall, sizeof(uw_data_exitcall));
3399
  memcpy((char*)dasm_buf + zend_jit_uw_func[2].UnwindData, uw_data, sizeof(uw_data));
3400
3401
#ifdef ZEND_JIT_RT_UNWINDER
3402
  RtlInstallFunctionTableCallback(
3403
    (uintptr_t)dasm_buf | 3,
3404
    (uintptr_t) dasm_buf,
3405
    (uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3406
    zend_jit_unwind_callback,
3407
    NULL,
3408
    NULL);
3409
#else
3410
  RtlAddFunctionTable(zend_jit_uw_func, 3, (uintptr_t)dasm_buf);
3411
#endif
3412
}
3413
#endif
3414
3415
static void zend_jit_setup(bool reattached)
3416
0
{
3417
#if defined(IR_TARGET_X86)
3418
  if (!zend_cpu_supports_sse2()) {
3419
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3420
  }
3421
#endif
3422
0
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3423
0
  allowed_opt_flags = 0;
3424
0
  if (zend_cpu_supports_avx()) {
3425
0
    allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3426
0
  }
3427
0
# ifdef HAVE_ZEND_CPU_SUPPORTS_CLDEMOTE
3428
0
  if (zend_cpu_supports_cldemote()) {
3429
0
    default_mflags |= IR_X86_CLDEMOTE;
3430
0
  }
3431
0
# endif
3432
0
#endif
3433
3434
#ifdef ZTS
3435
  zend_result result = zend_jit_resolve_tsrm_ls_cache_offsets(
3436
    &tsrm_ls_cache_tcb_offset,
3437
    &tsrm_tls_index,
3438
    &tsrm_tls_offset
3439
  );
3440
  if (result == FAILURE) {
3441
    zend_accel_error(ACCEL_LOG_INFO,
3442
        "Could not get _tsrm_ls_cache offsets, will fallback to runtime resolution");
3443
  }
3444
#endif
3445
3446
0
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3447
0
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
3448
0
    zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3449
0
  }
3450
0
#endif
3451
3452
0
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3453
0
    zend_jit_setup_disasm();
3454
0
  }
3455
3456
0
#ifndef _WIN32
3457
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3458
0
    ir_perf_jitdump_open();
3459
0
  }
3460
3461
0
#endif
3462
0
  zend_long debug = JIT_G(debug);
3463
0
  if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3464
0
    JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3465
0
      ZEND_JIT_DEBUG_IR_CODEGEN|
3466
0
      ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3467
0
      ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3468
0
  }
3469
3470
0
  zend_jit_calc_trace_prologue_size();
3471
0
  if (!reattached) {
3472
0
    zend_jit_setup_stubs();
3473
0
  }
3474
0
  JIT_G(debug) = debug;
3475
3476
#ifdef _WIN64
3477
  zend_jit_setup_unwinder();
3478
#endif
3479
0
}
3480
3481
static void zend_jit_shutdown_ir(void)
3482
0
{
3483
0
#ifndef _WIN32
3484
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3485
0
    ir_perf_jitdump_close();
3486
0
  }
3487
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3488
0
    ir_gdb_unregister_all();
3489
0
  }
3490
0
#endif
3491
#ifdef HAVE_CAPSTONE
3492
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3493
    ir_disasm_free();
3494
  }
3495
#endif
3496
0
}
3497
3498
/* PHP control flow reconstruction helpers */
3499
static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3500
0
{
3501
0
  ir_ref ref = ir_IF(condition);
3502
  /* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3503
   *
3504
   * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3505
   * to start target block
3506
   */
3507
0
  ir_set_op(&jit->ctx, ref, 3, true_block);
3508
0
  return ref;
3509
0
}
3510
3511
static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3512
0
{
3513
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3514
0
  ZEND_ASSERT(if_ref);
3515
0
  ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3516
0
  ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3517
0
  if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3518
0
    ir_IF_TRUE(if_ref);
3519
0
  } else {
3520
0
    ir_IF_FALSE(if_ref);
3521
0
  }
3522
0
}
3523
3524
static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref);
3525
3526
static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3527
0
{
3528
0
  int *p;
3529
0
  zend_basic_block *bb;
3530
0
  ir_ref *r, header;
3531
3532
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3533
0
  bb = &jit->ssa->cfg.blocks[b];
3534
0
  p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3535
0
  r = &jit->bb_edges[jit->bb_predecessors[b]];
3536
0
  for (uint32_t i = 0; i < bb->predecessors_count; i++, p++, r++) {
3537
0
    if (*p == pred) {
3538
0
      ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3539
0
      header = jit->bb_start_ref[b];
3540
0
      if (header) {
3541
        /* this is back edge */
3542
0
        ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3543
0
        if (jit->ctx.ir_base[ref].op == IR_END) {
3544
0
          jit->ctx.ir_base[ref].op = IR_LOOP_END;
3545
0
        } else if (jit->ctx.ir_base[ref].op == IR_IF) {
3546
0
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3547
0
          ref = ir_LOOP_END();
3548
0
        } else if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
3549
0
          zend_jit_case_start(jit, pred, b, ref);
3550
0
          ref = ir_LOOP_END();
3551
0
        } else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3552
0
          ir_BEGIN(ref);
3553
0
          ref = ir_LOOP_END();
3554
0
        } else {
3555
0
          ZEND_UNREACHABLE();
3556
0
        }
3557
0
        ir_MERGE_SET_OP(header, i + 1, ref);
3558
0
      }
3559
0
      *r = ref;
3560
0
      return;
3561
0
    }
3562
0
  }
3563
0
  ZEND_UNREACHABLE();
3564
0
}
3565
3566
static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3567
                                                uint32_t      true_label,
3568
                                                uint32_t      false_label,
3569
                                                ir_ref        true_inputs,
3570
                                                ir_ref        false_inputs)
3571
0
{
3572
0
  ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3573
3574
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3575
0
  if (true_inputs) {
3576
0
    ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3577
0
    if (!jit->ctx.ir_base[true_inputs].op2) {
3578
0
      true_path = true_inputs;
3579
0
    } else {
3580
0
      ir_MERGE_list(true_inputs);
3581
0
      true_path = ir_END();
3582
0
    }
3583
0
  }
3584
0
  if (false_inputs) {
3585
0
    ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3586
0
    if (!jit->ctx.ir_base[false_inputs].op2) {
3587
0
      false_path = false_inputs;
3588
0
    } else {
3589
0
      ir_MERGE_list(false_inputs);
3590
0
      false_path = ir_END();
3591
0
    }
3592
0
  }
3593
3594
0
  if (true_label == false_label && true_path && false_path) {
3595
0
    ir_MERGE_2(true_path, false_path);
3596
0
    _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3597
0
  } else if (!true_path && !false_path) {
3598
    /* dead code */
3599
0
    true_path = ir_END();
3600
0
    _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3601
0
  } else {
3602
0
    if (true_path) {
3603
0
      _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3604
0
    }
3605
0
    if (false_path) {
3606
0
      _zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3607
0
    }
3608
0
  }
3609
3610
0
  jit->b = -1;
3611
0
}
3612
3613
static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3614
0
{
3615
0
  int i, count;
3616
0
  ir_ref j, k, n, *p, *q, *r;
3617
0
  ir_ref ref;
3618
0
  ir_insn *insn, *phi;
3619
3620
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3621
0
  count = jit->ssa->cfg.blocks_count;
3622
0
  for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3623
0
    ref = *p;
3624
0
    if (ref) {
3625
0
      insn = &jit->ctx.ir_base[ref];
3626
0
      if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3627
0
        n = insn->inputs_count;
3628
        /* Remove IS_UNUSED inputs */
3629
0
        for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3630
0
          if (*q) {
3631
0
            if (q != r) {
3632
0
              *r = *q;
3633
0
              phi = insn + 1 + (n >> 2);
3634
0
              while (phi->op == IR_PI) {
3635
0
                phi++;
3636
0
              }
3637
0
              while (phi->op == IR_PHI) {
3638
0
                ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3639
0
                phi += 1 + ((n + 1) >> 2);
3640
0
              }
3641
0
            }
3642
0
            k++;
3643
0
            r++;
3644
0
          }
3645
0
        }
3646
0
        if (k != n) {
3647
0
          ir_ref n2, k2;
3648
3649
0
          if (k <= 1) {
3650
0
            insn->op = IR_BEGIN;
3651
0
            insn->inputs_count = 0;
3652
0
          } else {
3653
0
            insn->inputs_count = k;
3654
0
          }
3655
0
          n2 = 1 + (n >> 2);
3656
0
          k2 = 1 + (k >> 2);
3657
0
          while (k2 != n2) {
3658
0
            (insn+k2)->optx = IR_NOP;
3659
0
            k2++;
3660
0
          }
3661
0
          phi = insn + 1 + (n >> 2);
3662
0
          while (phi->op == IR_PI) {
3663
0
            phi++;
3664
0
          }
3665
0
          while (phi->op == IR_PHI) {
3666
0
            if (k <= 1) {
3667
0
              phi->op = IR_COPY;
3668
0
              phi->op1 = phi->op2;
3669
0
              phi->op2 = 1;
3670
0
              phi->inputs_count = 0;
3671
0
            } else {
3672
0
              phi->inputs_count = k + 1;
3673
0
            }
3674
0
            n2 = 1 + ((n + 1) >> 2);
3675
0
            k2 = 1 + ((k + 1) >> 2);
3676
0
            while (k2 != n2) {
3677
0
              (phi+k2)->optx = IR_NOP;
3678
0
              k2++;
3679
0
            }
3680
0
            phi += 1 + ((n + 1) >> 2);
3681
0
          }
3682
0
        }
3683
0
      }
3684
0
    }
3685
0
  }
3686
0
}
3687
3688
static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3689
0
{
3690
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3691
0
  const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3692
3693
0
  if (opline->opcode == ZEND_SWITCH_LONG
3694
0
   || opline->opcode == ZEND_SWITCH_STRING
3695
0
   || opline->opcode == ZEND_MATCH) {
3696
0
    HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3697
0
    const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3698
0
    int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3699
0
    zval *zv;
3700
0
    ir_ref list = IR_UNUSED, idx;
3701
0
    bool first = true;
3702
3703
0
    ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3704
0
      const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3705
0
      int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3706
3707
0
      if (b == case_b) {
3708
0
        if (!first) {
3709
0
          ir_END_list(list);
3710
0
        }
3711
0
        if (HT_IS_PACKED(jumptable)) {
3712
0
          idx = ir_CONST_LONG(zv - jumptable->arPacked);
3713
0
        } else {
3714
0
          idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3715
0
        }
3716
0
        ir_CASE_VAL(switch_ref, idx);
3717
0
        first = false;
3718
0
      }
3719
0
    } ZEND_HASH_FOREACH_END();
3720
0
    if (default_b == case_b) {
3721
0
      if (!first) {
3722
0
        ir_END_list(list);
3723
0
      }
3724
0
      if (jit->ctx.ir_base[switch_ref].op3) {
3725
        /* op3 may contain a list of additional "default" path inputs for MATCH */
3726
0
        ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3727
0
        jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3728
0
        ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3729
0
        ir_ref end = ref;
3730
0
        while (jit->ctx.ir_base[end].op2) {
3731
0
          ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3732
0
          end = jit->ctx.ir_base[end].op2;
3733
0
        }
3734
0
        jit->ctx.ir_base[end].op2 = list;
3735
0
        list = ref;
3736
0
      }
3737
0
      ir_CASE_DEFAULT(switch_ref);
3738
0
    }
3739
0
    if (list) {
3740
0
      ir_END_list(list);
3741
0
      ir_MERGE_list(list);
3742
0
    }
3743
0
  } else {
3744
0
    ZEND_UNREACHABLE();
3745
0
  }
3746
0
}
3747
3748
static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3749
0
{
3750
0
  zend_basic_block *bb;
3751
0
  int *p, pred;
3752
0
  ir_ref ref, bb_start;
3753
3754
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3755
0
  ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3756
0
  bb = &jit->ssa->cfg.blocks[b];
3757
0
  ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3758
0
  uint32_t n = bb->predecessors_count;
3759
3760
0
  if (n == 0) {
3761
    /* pass */
3762
0
    ZEND_ASSERT(jit->ctx.control);
3763
0
#if ZEND_DEBUG
3764
0
    ref = jit->ctx.control;
3765
0
    ir_insn *insn = &jit->ctx.ir_base[ref];
3766
0
    while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3767
0
      ref = insn->op1;
3768
0
      insn = &jit->ctx.ir_base[ref];
3769
0
    }
3770
0
    ZEND_ASSERT(insn->op == IR_START);
3771
0
    ZEND_ASSERT(ref == 1);
3772
0
#endif
3773
0
    bb_start = 1;
3774
0
    if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3775
      /* prvent END/BEGIN merging */
3776
0
      jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3777
0
      bb_start = jit->ctx.control;
3778
0
    }
3779
0
  } else if (n == 1) {
3780
0
    ZEND_ASSERT(!jit->ctx.control);
3781
0
    pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3782
0
    ref = jit->bb_edges[jit->bb_predecessors[b]];
3783
0
    if (ref == IR_UNUSED) {
3784
0
      if (!jit->ctx.control) {
3785
0
        ir_BEGIN(IR_UNUSED); /* unreachable block */
3786
0
      }
3787
0
    } else {
3788
0
      ir_op op = jit->ctx.ir_base[ref].op;
3789
3790
0
      if (op == IR_IF) {
3791
0
        if (!jit->ctx.control) {
3792
0
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3793
0
        } else {
3794
0
          ir_ref entry_path = ir_END();
3795
0
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3796
0
          ir_MERGE_WITH(entry_path);
3797
0
        }
3798
0
      } else if (op == IR_SWITCH) {
3799
0
        zend_jit_case_start(jit, pred, b, ref);
3800
0
      } else {
3801
0
        if (!jit->ctx.control) {
3802
0
          ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3803
0
          if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3804
0
           && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3805
            /* prvent END/BEGIN merging */
3806
0
            jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3807
0
          } else {
3808
0
            ir_BEGIN(ref);
3809
0
          }
3810
0
        } else {
3811
0
          ir_MERGE_WITH(ref);
3812
0
        }
3813
0
      }
3814
0
    }
3815
0
    bb_start = jit->ctx.control;
3816
0
  } else {
3817
0
    int forward_edges_count = 0;
3818
0
    int back_edges_count = 0;
3819
0
    ir_ref *pred_refs;
3820
0
    ir_ref entry_path = IR_UNUSED;
3821
0
    ALLOCA_FLAG(use_heap);
3822
3823
0
    ZEND_ASSERT(!jit->ctx.control);
3824
0
    if (jit->ctx.control) {
3825
0
      entry_path = ir_END();
3826
0
    }
3827
0
    pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3828
0
    uint32_t i;
3829
0
    for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3830
0
      pred = *p;
3831
0
      if (jit->bb_start_ref[pred]) {
3832
        /* forward edge */
3833
0
        forward_edges_count++;
3834
0
        ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3835
0
        if (ref == IR_UNUSED) {
3836
          /* dead edge */
3837
0
          pred_refs[i] = IR_UNUSED;
3838
0
        } else {
3839
0
          ir_op op = jit->ctx.ir_base[ref].op;
3840
3841
0
          if (op == IR_IF) {
3842
0
            jit_IF_TRUE_FALSE_ex(jit, ref, b);
3843
0
            pred_refs[i] = ir_END();
3844
0
          } else if (op == IR_SWITCH) {
3845
0
            zend_jit_case_start(jit, pred, b, ref);
3846
0
            pred_refs[i] = ir_END();
3847
0
          } else {
3848
0
            ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3849
0
            pred_refs[i] = ref;
3850
0
          }
3851
0
        }
3852
0
      } else {
3853
        /* backward edge */
3854
0
        back_edges_count++;
3855
0
        pred_refs[i] = IR_UNUSED;
3856
0
      }
3857
0
    }
3858
3859
0
    if (bb->flags & ZEND_BB_LOOP_HEADER) {
3860
0
      ZEND_ASSERT(back_edges_count != 0);
3861
0
      ZEND_ASSERT(forward_edges_count != 0);
3862
0
      ir_MERGE_N(n, pred_refs);
3863
0
      jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3864
0
      bb_start = jit->ctx.control;
3865
0
      if (entry_path) {
3866
0
        ir_MERGE_WITH(entry_path);
3867
0
      }
3868
0
    } else {
3869
//      ZEND_ASSERT(back_edges_count != 0);
3870
      /* edges from exceptional blocks may be counted as back edges */
3871
0
      ir_MERGE_N(n, pred_refs);
3872
0
      bb_start = jit->ctx.control;
3873
0
      if (entry_path) {
3874
0
        ir_MERGE_WITH(entry_path);
3875
0
      }
3876
0
    }
3877
0
    free_alloca(pred_refs, use_heap);
3878
0
  }
3879
0
  jit->b = b;
3880
0
  jit->bb_start_ref[b] = bb_start;
3881
3882
0
  if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3883
0
    jit->ctx.fold_cse_limit = bb_start;
3884
0
  }
3885
3886
0
  return 1;
3887
0
}
3888
3889
static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3890
0
{
3891
0
  int succ;
3892
0
  zend_basic_block *bb;
3893
3894
0
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3895
0
  if (jit->b != b) {
3896
0
    return 1;
3897
0
  }
3898
3899
0
  bb = &jit->ssa->cfg.blocks[b];
3900
0
  ZEND_ASSERT(bb->successors_count != 0);
3901
0
  if (bb->successors_count == 1) {
3902
0
    succ = bb->successors[0];
3903
0
  } else {
3904
0
    const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3905
3906
    /* Use only the following successor of SWITCH and FE_RESET_R */
3907
0
    ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3908
0
     || opline->opcode == ZEND_SWITCH_STRING
3909
0
     || opline->opcode == ZEND_MATCH
3910
0
     || opline->opcode == ZEND_FE_RESET_R);
3911
0
    succ = b + 1;
3912
0
  }
3913
0
  _zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3914
0
  jit->b = -1;
3915
0
  return 1;
3916
0
}
3917
3918
static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3919
0
{
3920
0
  ir_ref ref;
3921
3922
0
#if 1
3923
0
  ref = jit_IP32(jit);
3924
0
  ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3925
#else
3926
  ref = jit_IP(jit);
3927
  ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3928
#endif
3929
0
  return ref;
3930
0
}
3931
3932
static int zend_jit_jmp_frameless(
3933
  zend_jit_ctx *jit,
3934
  const zend_op *opline,
3935
  const void *exit_addr,
3936
  zend_jmp_fl_result guard
3937
0
) {
3938
0
  ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3939
0
  zend_basic_block *bb;
3940
3941
  // JIT: CACHED_PTR(opline->extended_value)
3942
0
  cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3943
0
  cache_result = ir_LOAD_L(cache_slot_ref);
3944
3945
  // JIT: if (UNEXPECTED(!result))
3946
0
  if_ref = ir_IF(cache_result);
3947
0
  ir_IF_FALSE_cold(if_ref);
3948
0
  zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3949
0
  function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3950
0
    ir_CONST_ADDR(func_name_zv),
3951
0
    cache_slot_ref);
3952
0
  ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3953
3954
0
  phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3955
3956
0
  if (exit_addr) {
3957
0
    ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3958
0
  } else {
3959
0
    ZEND_ASSERT(jit->b >= 0);
3960
0
    bb = &jit->ssa->cfg.blocks[jit->b];
3961
    // JIT: if (result == ZEND_JMP_FL_HIT)
3962
0
    ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3963
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3964
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3965
0
    jit->b = -1;
3966
0
  }
3967
3968
0
  return 1;
3969
0
}
3970
3971
static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3972
0
{
3973
0
  ir_ref ref;
3974
0
  zend_basic_block *bb;
3975
3976
0
  ZEND_ASSERT(jit->b >= 0);
3977
0
  bb = &jit->ssa->cfg.blocks[jit->b];
3978
3979
0
  ZEND_ASSERT(bb->successors_count == 2);
3980
0
  if (bb->successors[0] == bb->successors[1]) {
3981
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3982
0
    jit->b = -1;
3983
0
    zend_jit_set_last_valid_opline(jit, next_opline);
3984
0
    return 1;
3985
0
  }
3986
3987
0
  ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3988
3989
0
  _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3990
0
  _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3991
3992
0
  jit->b = -1;
3993
0
  zend_jit_set_last_valid_opline(jit, next_opline);
3994
3995
0
  return 1;
3996
0
}
3997
3998
static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *opline, const zend_op *next_opline, uint32_t var)
3999
0
{
4000
0
  ir_ref ref;
4001
4002
0
  ir_op op = (opline->result_type & IS_SMART_BRANCH_JMPZ) ? IR_EQ : IR_NE;
4003
0
  ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, op, next_opline)), ir_CONST_U32(IS_FALSE));
4004
4005
  // EX_VAR(var) = ...
4006
0
  ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
4007
4008
0
  zend_jit_reset_last_valid_opline(jit);
4009
0
  return zend_jit_set_ip(jit, next_opline - 1);
4010
0
}
4011
4012
/* PHP JIT handlers */
4013
static void zend_jit_check_exception(zend_jit_ctx *jit)
4014
0
{
4015
0
  ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4016
0
    jit_STUB_ADDR(jit, jit_stub_exception_handler));
4017
0
}
4018
4019
static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
4020
0
{
4021
0
  ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4022
0
    jit_STUB_ADDR(jit,
4023
0
      (opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
4024
0
}
4025
4026
static void zend_jit_type_check_undef(zend_jit_ctx  *jit,
4027
                                      ir_ref         type,
4028
                                      uint32_t       var,
4029
                                      const zend_op *opline,
4030
                                      bool           check_exception,
4031
                                      bool           in_cold_path,
4032
                                      bool           undef_result)
4033
0
{
4034
0
  ir_ref if_def = ir_IF(type);
4035
4036
0
  if (!in_cold_path) {
4037
0
    ir_IF_FALSE_cold(if_def);
4038
0
  } else {
4039
0
    ir_IF_FALSE(if_def);
4040
0
  }
4041
0
  if (opline) {
4042
0
    jit_SET_EX_OPLINE(jit, opline);
4043
0
  }
4044
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4045
0
  if (check_exception) {
4046
0
    if (undef_result) {
4047
0
      zend_jit_check_exception_undef_result(jit, opline);
4048
0
    } else {
4049
0
      zend_jit_check_exception(jit);
4050
0
    }
4051
0
  }
4052
0
  ir_MERGE_WITH_EMPTY_TRUE(if_def);
4053
0
}
4054
4055
static ir_ref zend_jit_zval_check_undef(zend_jit_ctx  *jit,
4056
                                        ir_ref         ref,
4057
                                        uint32_t       var,
4058
                                        const zend_op *opline,
4059
                                        bool           check_exception)
4060
0
{
4061
0
  ir_ref if_def, ref2;
4062
4063
0
  if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
4064
0
  ir_IF_FALSE_cold(if_def);
4065
4066
0
  if (opline) {
4067
0
    jit_SET_EX_OPLINE(jit, opline);
4068
0
  }
4069
4070
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4071
4072
0
  if (check_exception) {
4073
0
    zend_jit_check_exception(jit);
4074
0
  }
4075
4076
0
  ref2 = jit_EG(uninitialized_zval);
4077
4078
0
  ir_MERGE_WITH_EMPTY_TRUE(if_def);
4079
4080
0
  return ir_PHI_2(IR_ADDR, ref2, ref);
4081
0
}
4082
4083
static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
4084
0
{
4085
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4086
0
  int pred;
4087
0
  ir_ref ref;
4088
4089
0
  ZEND_ASSERT(bb->predecessors_count > 0);
4090
4091
0
  pred = jit->bb_predecessors[b];
4092
0
  ref = jit->bb_edges[pred];
4093
4094
0
  ZEND_ASSERT(ref);
4095
0
  ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4096
4097
  /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4098
0
  ir_ENTRY(ref, bb->start);
4099
0
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4100
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4101
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4102
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4103
0
    jit_STORE_FP(jit, 2);
4104
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4105
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4106
0
    jit_STORE_IP(jit, 3);
4107
0
  }
4108
4109
0
  ir_MERGE_WITH(ref);
4110
0
  jit->bb_edges[pred] = ir_END();
4111
0
}
4112
4113
static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4114
0
{
4115
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4116
0
  ir_ref ref = ir_END();
4117
4118
  /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4119
0
  ir_ENTRY(ref, bb->start);
4120
0
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4121
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4122
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4123
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4124
0
    jit_STORE_FP(jit, 2);
4125
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4126
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4127
0
    jit_STORE_IP(jit, 3);
4128
0
  }
4129
4130
0
  ir_MERGE_WITH(ref);
4131
0
}
4132
4133
static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4134
0
{
4135
0
  ir_ENTRY(src, label);
4136
0
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4137
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4138
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4139
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4140
0
    jit_STORE_FP(jit, 2);
4141
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4142
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4143
0
    jit_STORE_IP(jit, 3);
4144
0
  }
4145
0
  return ir_END();
4146
0
}
4147
4148
static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4149
0
{
4150
0
  zend_jit_set_ip(jit, opline);
4151
0
  if (GCC_GLOBAL_REGS) {
4152
0
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4153
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4154
0
  } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
4155
0
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4156
0
    ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
4157
0
    jit_STORE_IP(jit, ip);
4158
0
  } else {
4159
0
    zend_vm_opcode_handler_t handler = opline->handler;
4160
0
    ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
4161
0
    jit_STORE_IP(jit, ip);
4162
0
  }
4163
0
  if (may_throw) {
4164
0
    zend_jit_check_exception(jit);
4165
0
  }
4166
  /* Skip the following OP_DATA */
4167
0
  switch (opline->opcode) {
4168
0
    case ZEND_ASSIGN_DIM:
4169
0
    case ZEND_ASSIGN_OBJ:
4170
0
    case ZEND_ASSIGN_STATIC_PROP:
4171
0
    case ZEND_ASSIGN_DIM_OP:
4172
0
    case ZEND_ASSIGN_OBJ_OP:
4173
0
    case ZEND_ASSIGN_STATIC_PROP_OP:
4174
0
    case ZEND_ASSIGN_STATIC_PROP_REF:
4175
0
    case ZEND_ASSIGN_OBJ_REF:
4176
0
    case ZEND_FRAMELESS_ICALL_3:
4177
0
    case ZEND_DECLARE_ATTRIBUTED_CONST:
4178
0
      zend_jit_set_last_valid_opline(jit, opline + 2);
4179
0
      break;
4180
0
    default:
4181
0
      zend_jit_set_last_valid_opline(jit, opline + 1);
4182
0
      break;
4183
0
  }
4184
0
  return 1;
4185
0
}
4186
4187
static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4188
0
{
4189
0
  ir_ref ref;
4190
0
  zend_basic_block *bb;
4191
4192
0
  zend_jit_set_ip(jit, opline);
4193
0
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
4194
0
    if (opline->opcode == ZEND_DO_UCALL ||
4195
0
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4196
0
        opline->opcode == ZEND_DO_FCALL ||
4197
0
        opline->opcode == ZEND_RETURN) {
4198
4199
      /* Use inlined HYBRID VM handler */
4200
0
      zend_vm_opcode_handler_t handler = opline->handler;
4201
0
      ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4202
0
    } else {
4203
0
      zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4204
0
      ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4205
0
      ref = ir_LOAD_A(jit_IP(jit));
4206
0
      ir_TAILCALL(IR_VOID, ref);
4207
0
    }
4208
0
  } else {
4209
0
    zend_vm_opcode_handler_t handler = opline->handler;
4210
0
    if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
4211
0
      zend_jit_tailcall_handler(jit, ir_CONST_OPCODE_HANDLER_FUNC(handler));
4212
0
    } else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4213
0
     && (opline->opcode == ZEND_CATCH
4214
0
      || opline->opcode == ZEND_FAST_CALL
4215
0
      || opline->opcode == ZEND_FAST_RET
4216
0
      || opline->opcode == ZEND_MATCH_ERROR
4217
0
      || opline->opcode == ZEND_THROW
4218
0
      || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4219
0
      ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
4220
0
      zend_jit_vm_enter(jit, ip);
4221
0
    } else {
4222
0
      ir_TAILCALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
4223
0
    }
4224
0
  }
4225
0
  if (jit->b >= 0) {
4226
0
    bb = &jit->ssa->cfg.blocks[jit->b];
4227
0
    if (bb->successors_count > 0
4228
0
     && (opline->opcode == ZEND_DO_FCALL
4229
0
      || opline->opcode == ZEND_DO_UCALL
4230
0
      || opline->opcode == ZEND_DO_FCALL_BY_NAME
4231
0
      || opline->opcode == ZEND_INCLUDE_OR_EVAL
4232
0
      || opline->opcode == ZEND_GENERATOR_CREATE
4233
0
      || opline->opcode == ZEND_YIELD
4234
0
      || opline->opcode == ZEND_YIELD_FROM
4235
0
      || opline->opcode == ZEND_FAST_CALL)) {
4236
      /* Add a fake control edge from UNREACHABLE to the following ENTRY */
4237
0
      int succ;
4238
4239
0
      if (bb->successors_count == 1) {
4240
0
        succ = bb->successors[0];
4241
0
        ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4242
0
      } else {
4243
        /* Use only the following successor of FAST_CALL */
4244
0
        ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4245
0
        succ = jit->b + 1;
4246
        /* we need an entry */
4247
0
        jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4248
0
      }
4249
0
      ref = jit->ctx.insns_count - 1;
4250
0
      ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4251
0
      ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4252
0
      _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4253
0
    }
4254
0
    jit->b = -1;
4255
0
    zend_jit_reset_last_valid_opline(jit);
4256
0
  }
4257
0
  return 1;
4258
0
}
4259
4260
static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4261
0
{
4262
0
  return zend_jit_tail_handler(jit, opline);
4263
0
}
4264
4265
static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4266
0
{
4267
0
  ZEND_ASSERT(Z_MODE(src) == IS_REG);
4268
0
  ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4269
4270
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4271
0
    jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4272
0
    if (set_type &&
4273
0
        (Z_REG(dst) != ZREG_FP ||
4274
0
         !JIT_G(current_frame) ||
4275
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4276
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4277
0
    }
4278
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4279
0
    jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4280
0
    if (set_type &&
4281
0
        (Z_REG(dst) != ZREG_FP ||
4282
0
         !JIT_G(current_frame) ||
4283
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4284
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4285
0
    }
4286
0
  } else {
4287
0
    ZEND_UNREACHABLE();
4288
0
  }
4289
0
  return 1;
4290
0
}
4291
4292
static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4293
0
{
4294
0
  ZEND_ASSERT(Z_MODE(src) == IS_REG);
4295
0
  ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4296
4297
0
  if (Z_LOAD(src) || Z_STORE(src)) {
4298
    /* it's not necessary to store register if it was previously loaded or already stored */
4299
0
    return 1;
4300
0
  }
4301
4302
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4303
0
    jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4304
0
    if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4305
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4306
0
    } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4307
      /* invalidate memory type */
4308
0
      STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4309
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4310
0
    }
4311
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4312
0
    jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4313
0
    if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4314
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4315
0
    } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4316
      /* invalidate memory type */
4317
0
      STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4318
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4319
0
    }
4320
0
  } else {
4321
0
    ZEND_UNREACHABLE();
4322
0
  }
4323
0
  return 1;
4324
0
}
4325
4326
static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4327
0
{
4328
0
  ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4329
0
  ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4330
4331
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4332
0
    zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4333
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4334
0
    zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4335
0
  } else {
4336
0
    ZEND_UNREACHABLE();
4337
0
  }
4338
0
  return 1;
4339
0
}
4340
4341
static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4342
0
{
4343
0
  zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4344
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4345
4346
0
  return zend_jit_spill_store(jit, src, dst, info, set_type);
4347
0
}
4348
4349
static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4350
0
{
4351
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4352
4353
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4354
0
    jit_set_Z_LVAL(jit, dst, src);
4355
0
    if (set_type &&
4356
0
        (Z_REG(dst) != ZREG_FP ||
4357
0
         !JIT_G(current_frame) ||
4358
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4359
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4360
0
    }
4361
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4362
0
    jit_set_Z_DVAL(jit, dst, src);
4363
0
    if (set_type &&
4364
0
        (Z_REG(dst) != ZREG_FP ||
4365
0
         !JIT_G(current_frame) ||
4366
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4367
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4368
0
    }
4369
0
  } else {
4370
0
    ZEND_UNREACHABLE();
4371
0
  }
4372
0
  return 1;
4373
0
}
4374
4375
static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4376
0
{
4377
0
  ir_ref ref = jit->ctx.control;
4378
0
  ir_insn *insn;
4379
4380
0
  while (1) {
4381
0
    insn = &jit->ctx.ir_base[ref];
4382
0
    if (insn->op == IR_RLOAD && insn->op2 == reg) {
4383
0
      ZEND_ASSERT(insn->type == type);
4384
0
      return ref;
4385
0
    } else if (insn->op == IR_START) {
4386
0
      break;
4387
0
    }
4388
0
    ref = insn->op1;
4389
0
  }
4390
0
  return ir_RLOAD(type, reg);
4391
0
}
4392
4393
/* Same as zend_jit_deopt_rload(), but 'reg' may be spilled on C stack */
4394
static ir_ref zend_jit_deopt_rload_spilled(zend_jit_ctx *jit, ir_type type, int8_t reg, int32_t offset)
4395
0
{
4396
0
  ZEND_ASSERT(reg >= 0);
4397
4398
0
  if (IR_REG_SPILLED(reg)) {
4399
0
    return ir_LOAD(type, ir_ADD_OFFSET(zend_jit_deopt_rload(jit, type, IR_REG_NUM(reg)), offset));
4400
0
  } else {
4401
0
    return zend_jit_deopt_rload(jit, type, reg);
4402
0
  }
4403
0
}
4404
4405
static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4406
0
{
4407
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4408
0
  ir_ref src = ir_CONST_LONG(val);
4409
4410
0
  if (jit->ra && jit->ra[var].ref == IR_NULL) {
4411
0
    zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4412
0
  }
4413
0
  jit_set_Z_LVAL(jit, dst, src);
4414
0
  jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4415
0
  return 1;
4416
0
}
4417
4418
static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4419
0
{
4420
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4421
0
  ir_ref src = ir_CONST_DOUBLE(val);
4422
4423
0
  if (jit->ra && jit->ra[var].ref == IR_NULL) {
4424
0
    zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4425
0
  }
4426
0
  jit_set_Z_DVAL(jit, dst, src);
4427
0
  jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4428
0
  return 1;
4429
0
}
4430
4431
static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4432
0
{
4433
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4434
4435
0
  ZEND_ASSERT(type <= IS_DOUBLE);
4436
0
  jit_set_Z_TYPE_INFO(jit, dst, type);
4437
0
  return 1;
4438
0
}
4439
4440
static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4441
0
{
4442
0
  zend_jit_addr src;
4443
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4444
0
  ir_type type;
4445
4446
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4447
0
    type = IR_LONG;
4448
0
    src = zend_jit_deopt_rload(jit, type, reg);
4449
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4450
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4451
0
    } else if (!in_mem) {
4452
0
      jit_set_Z_LVAL(jit, dst, src);
4453
0
      if (set_type &&
4454
0
          (Z_REG(dst) != ZREG_FP ||
4455
0
           !JIT_G(current_frame) ||
4456
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4457
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4458
0
      }
4459
0
    }
4460
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4461
0
    type = IR_DOUBLE;
4462
0
    src = zend_jit_deopt_rload(jit, type, reg);
4463
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4464
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4465
0
    } else if (!in_mem) {
4466
0
      jit_set_Z_DVAL(jit, dst, src);
4467
0
      if (set_type &&
4468
0
          (Z_REG(dst) != ZREG_FP ||
4469
0
           !JIT_G(current_frame) ||
4470
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4471
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4472
0
      }
4473
0
    }
4474
0
  } else {
4475
0
    ZEND_UNREACHABLE();
4476
0
  }
4477
0
  return 1;
4478
0
}
4479
4480
static int zend_jit_store_spill_slot(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, int32_t offset, bool set_type)
4481
0
{
4482
0
  zend_jit_addr src;
4483
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4484
4485
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4486
0
    src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4487
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4488
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4489
0
    } else {
4490
0
      jit_set_Z_LVAL(jit, dst, src);
4491
0
      if (set_type &&
4492
0
          (Z_REG(dst) != ZREG_FP ||
4493
0
           !JIT_G(current_frame) ||
4494
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4495
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4496
0
      }
4497
0
    }
4498
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4499
0
    src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4500
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4501
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4502
0
    } else {
4503
0
      jit_set_Z_DVAL(jit, dst, src);
4504
0
      if (set_type &&
4505
0
          (Z_REG(dst) != ZREG_FP ||
4506
0
           !JIT_G(current_frame) ||
4507
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4508
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4509
0
      }
4510
0
    }
4511
0
  } else {
4512
0
    ZEND_UNREACHABLE();
4513
0
  }
4514
0
  return 1;
4515
0
}
4516
4517
static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4518
0
{
4519
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4520
4521
0
  jit_set_Z_TYPE_INFO(jit, dst, type);
4522
0
  return 1;
4523
0
}
4524
4525
static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4526
0
{
4527
0
  ir_ref if_refcounted, end1;
4528
4529
0
  if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4530
0
  ir_IF_FALSE(if_refcounted);
4531
0
  end1 = ir_END();
4532
0
  ir_IF_TRUE(if_refcounted);
4533
0
  jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4534
0
  ir_MERGE_WITH(end1);
4535
0
  return 1;
4536
0
}
4537
4538
static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4539
0
{
4540
0
  if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4541
0
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4542
0
    return zend_jit_spill_store(jit, src, dst, info, true);
4543
0
  }
4544
0
  return 1;
4545
0
}
4546
4547
static int zend_jit_store_var_if_necessary_ex(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info)
4548
0
{
4549
0
  if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4550
0
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4551
0
    bool set_type = true;
4552
4553
0
    if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4554
0
        (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4555
0
      if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4556
0
        if (JIT_G(current_frame)) {
4557
0
          uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4558
4559
0
          if (mem_type != IS_UNKNOWN
4560
0
           && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4561
0
            set_type = false;
4562
0
          }
4563
0
        } else {
4564
0
          set_type = false;
4565
0
        }
4566
0
      }
4567
0
    }
4568
0
    return zend_jit_spill_store(jit, src, dst, info, set_type);
4569
0
  }
4570
0
  return 1;
4571
0
}
4572
4573
static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4574
0
{
4575
0
  zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4576
0
  zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4577
4578
0
  return zend_jit_load_reg(jit, src, dst, info);
4579
0
}
4580
4581
static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4582
0
{
4583
0
  if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4584
    /* Invalidate operand type to prevent incorrect destuction by exception_handler_free_op1_op2() */
4585
0
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4586
0
    jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4587
0
  }
4588
0
  return 1;
4589
0
}
4590
4591
static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4592
0
{
4593
0
  if (!zend_jit_same_addr(src, dst)) {
4594
0
    if (Z_MODE(src) == IS_REG) {
4595
0
      if (Z_MODE(dst) == IS_REG) {
4596
0
        zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4597
0
        if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4598
0
          zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4599
4600
0
          if (!zend_jit_spill_store(jit, dst, var_addr, info,
4601
0
              JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4602
0
              JIT_G(current_frame) == NULL ||
4603
0
              STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4604
0
              (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4605
0
          )) {
4606
0
            return 0;
4607
0
          }
4608
0
        }
4609
0
      } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4610
0
        if (!Z_LOAD(src) && !Z_STORE(src)) {
4611
0
          if (!zend_jit_spill_store(jit, src, dst, info,
4612
0
              JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4613
0
              JIT_G(current_frame) == NULL ||
4614
0
              STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4615
0
              (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4616
0
          )) {
4617
0
            return 0;
4618
0
          }
4619
0
        }
4620
0
      } else {
4621
0
        ZEND_UNREACHABLE();
4622
0
      }
4623
0
    } else if (Z_MODE(src) == IS_MEM_ZVAL) {
4624
0
      if (Z_MODE(dst) == IS_REG) {
4625
0
        if (!zend_jit_load_reg(jit, src, dst, info)) {
4626
0
          return 0;
4627
0
        }
4628
0
      } else {
4629
0
        ZEND_UNREACHABLE();
4630
0
      }
4631
0
    } else {
4632
0
      ZEND_UNREACHABLE();
4633
0
    }
4634
0
  } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4635
0
    dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4636
0
    if (!zend_jit_spill_store(jit, src, dst, info,
4637
0
        JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4638
0
        JIT_G(current_frame) == NULL ||
4639
0
        STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4640
0
        (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4641
0
    )) {
4642
0
      return 0;
4643
0
    }
4644
0
  }
4645
0
  return 1;
4646
0
}
4647
4648
struct jit_observer_fcall_is_unobserved_data {
4649
  ir_ref if_unobserved;
4650
  ir_ref ir_end_inputs;
4651
};
4652
4653
0
static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobserved_start(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4654
0
  ir_ref run_time_cache;
4655
0
  struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4656
0
  if (func) {
4657
0
    ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4658
0
  } else {
4659
    // JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4660
0
    ZEND_ASSERT(rx != IR_UNUSED);
4661
0
    ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4662
0
      ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4663
0
      ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4664
0
    ir_IF_TRUE(if_trampoline_or_generator);
4665
0
    ir_END_list(data.ir_end_inputs);
4666
0
    ir_IF_FALSE(if_trampoline_or_generator);
4667
0
  }
4668
0
  if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4669
    // JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4670
0
    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)));
4671
0
#ifndef ZTS
4672
0
  } else if (func && rx == IS_UNUSED) { // happens for internal functions only
4673
0
    ZEND_ASSERT(!ZEND_USER_CODE(func->type));
4674
0
    run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4675
0
#endif
4676
0
  } else {
4677
    // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4678
0
    if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4679
0
      run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4680
0
    } else {
4681
      // JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4682
0
      run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4683
0
      ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4684
0
      ir_IF_TRUE(if_odd);
4685
4686
0
      ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4687
4688
0
      ir_ref if_odd_end = ir_END();
4689
0
      ir_IF_FALSE(if_odd);
4690
4691
      // JIT: if (func->common.runtime_cache != NULL) {
4692
0
      ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4693
0
      ir_IF_TRUE(if_rt_cache);
4694
0
      ir_END_list(data.ir_end_inputs);
4695
0
      ir_IF_FALSE(if_rt_cache);
4696
4697
0
      ir_MERGE_WITH(if_odd_end);
4698
0
      run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4699
0
    }
4700
0
  }
4701
  // JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4702
0
  if (func) {
4703
0
    *observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4704
0
  } else {
4705
    // JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4706
0
    ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4707
0
    ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4708
0
    ir_IF_TRUE(if_internal_func);
4709
4710
0
    ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4711
4712
0
    ir_ref if_internal_func_end = ir_END();
4713
0
    ir_IF_FALSE(if_internal_func);
4714
4715
0
    ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4716
4717
0
    ir_MERGE_WITH(if_internal_func_end);
4718
0
    *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_user, observer_handler_internal);
4719
0
  }
4720
4721
  // JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4722
0
  data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4723
0
  ir_IF_FALSE(data.if_unobserved);
4724
0
  return data;
4725
0
}
4726
4727
/* For frameless the true branch of if_unobserved is used and this function not called. */
4728
0
static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4729
0
  ir_END_list(data->ir_end_inputs);
4730
0
  ir_IF_TRUE(data->if_unobserved);
4731
0
  ir_END_list(data->ir_end_inputs);
4732
0
  ir_MERGE_list(data->ir_end_inputs);
4733
0
}
4734
4735
0
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4736
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4737
0
}
4738
4739
0
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4740
  // JIT: if (execute_data == EG(current_observed_frame)) {
4741
0
  ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4742
0
  ir_IF_TRUE(has_end_observer);
4743
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4744
0
    rx, res_ref);
4745
0
  ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4746
0
}
4747
4748
static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
4749
0
{
4750
0
  ir_ref if_long = IR_UNUSED;
4751
0
  ir_ref op1_lval_ref = IR_UNUSED;
4752
0
  ir_ref ref;
4753
0
  ir_op op;
4754
4755
0
  if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4756
0
    if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4757
0
    ir_IF_TRUE(if_long);
4758
0
  }
4759
0
  if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4760
0
    op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4761
0
    jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4762
0
    if (Z_MODE(res_addr) != IS_REG) {
4763
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4764
0
    }
4765
0
  }
4766
0
  if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4767
0
   && Z_MODE(op1_addr) == IS_REG
4768
0
   && !Z_LOAD(op1_addr)
4769
0
   && !Z_STORE(op1_addr)) {
4770
0
    jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4771
0
  }
4772
0
  if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4773
0
    op = may_overflow ? IR_ADD_OV : IR_ADD;
4774
0
  } else {
4775
0
    op = may_overflow ? IR_SUB_OV : IR_SUB;
4776
0
  }
4777
0
  if (!op1_lval_ref) {
4778
0
    op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4779
0
  }
4780
0
  ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4781
0
  if (op1_def_info & MAY_BE_LONG) {
4782
0
    jit_set_Z_LVAL(jit, op1_def_addr, ref);
4783
0
  }
4784
0
  if (may_overflow &&
4785
0
      (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4786
0
       ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4787
0
    int32_t exit_point;
4788
0
    const void *exit_addr;
4789
0
    zend_jit_trace_stack *stack;
4790
0
    uint32_t old_op1_info, old_res_info = 0;
4791
4792
0
    stack = JIT_G(current_frame)->stack;
4793
0
    old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4794
0
    SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4795
0
    if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4796
0
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4797
0
    } else {
4798
0
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4799
0
    }
4800
0
    if (opline->result_type != IS_UNUSED) {
4801
0
      old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4802
0
      if (opline->opcode == ZEND_PRE_INC) {
4803
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4804
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4805
0
      } else if (opline->opcode == ZEND_PRE_DEC) {
4806
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4807
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4808
0
      } else if (opline->opcode == ZEND_POST_INC) {
4809
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4810
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4811
0
      } else if (opline->opcode == ZEND_POST_DEC) {
4812
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4813
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4814
0
      }
4815
0
    }
4816
4817
0
    exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4818
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4819
0
    ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4820
4821
0
    if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4822
0
        opline->result_type != IS_UNUSED) {
4823
0
      jit_set_Z_LVAL(jit, res_addr, ref);
4824
0
      if (Z_MODE(res_addr) != IS_REG) {
4825
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4826
0
      }
4827
0
    }
4828
4829
0
    SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4830
0
    if (opline->result_type != IS_UNUSED) {
4831
0
      SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4832
0
    }
4833
0
  } else if (may_overflow) {
4834
0
    ir_ref if_overflow;
4835
0
    ir_ref merge_inputs = IR_UNUSED;
4836
4837
0
    if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4838
0
     || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) ==  (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4839
0
      int32_t exit_point;
4840
0
      const void *exit_addr;
4841
0
      zend_jit_trace_stack *stack;
4842
0
      uint32_t old_res_info = 0, old_op1_info = 0;
4843
4844
0
      stack = JIT_G(current_frame)->stack;
4845
0
      if (opline->result_type != IS_UNUSED) {
4846
0
        old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4847
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4848
0
        if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4849
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ref);
4850
0
        } else {
4851
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), op1_lval_ref);
4852
0
        }
4853
0
      }
4854
0
      old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4855
0
      SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_LONG, 0);
4856
0
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ref);
4857
4858
0
      exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4859
0
      exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4860
0
      ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4861
4862
0
      if (opline->result_type != IS_UNUSED) {
4863
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4864
0
      }
4865
0
      SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4866
0
    } else {
4867
0
      if_overflow = ir_IF(ir_OVERFLOW(ref));
4868
0
      ir_IF_FALSE(if_overflow);
4869
0
      if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4870
0
          opline->result_type != IS_UNUSED) {
4871
0
        jit_set_Z_LVAL(jit, res_addr, ref);
4872
0
        if (Z_MODE(res_addr) != IS_REG) {
4873
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4874
0
        }
4875
0
      }
4876
0
      ir_END_list(merge_inputs);
4877
4878
      /* overflow => cold path */
4879
0
      ir_IF_TRUE_cold(if_overflow);
4880
0
    }
4881
4882
0
    if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4883
0
      if (Z_MODE(op1_def_addr) == IS_REG) {
4884
0
        jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4885
0
      } else {
4886
#if SIZEOF_ZEND_LONG == 4
4887
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0));
4888
        jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0x41e00000));
4889
#else
4890
0
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4891
0
#endif
4892
0
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4893
0
      }
4894
0
    } else {
4895
0
      if (Z_MODE(op1_def_addr) == IS_REG) {
4896
0
        jit_set_Z_DVAL(jit, op1_def_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4897
0
      } else {
4898
#if SIZEOF_ZEND_LONG == 4
4899
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x00200000));
4900
        jit_set_Z_W2(jit, op1_def_addr, ir_CONST_U32(0xc1e00000));
4901
#else
4902
0
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4903
0
#endif
4904
0
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4905
0
      }
4906
0
    }
4907
0
    if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4908
0
        opline->result_type != IS_UNUSED) {
4909
0
      if (opline->opcode == ZEND_PRE_INC) {
4910
0
        if (Z_MODE(res_addr) == IS_REG) {
4911
0
          jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4912
0
        } else {
4913
#if SIZEOF_ZEND_LONG == 4
4914
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
4915
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
4916
#else
4917
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4918
0
#endif
4919
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4920
0
        }
4921
0
      } else {
4922
0
        if (Z_MODE(res_addr) == IS_REG) {
4923
0
          jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4924
0
        } else {
4925
#if SIZEOF_ZEND_LONG == 4
4926
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
4927
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
4928
#else
4929
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
4930
0
#endif
4931
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4932
0
        }
4933
0
      }
4934
0
    }
4935
4936
0
    if (merge_inputs) {
4937
0
      ir_END_list(merge_inputs);
4938
0
      ir_MERGE_list(merge_inputs);
4939
0
    }
4940
0
  } else {
4941
0
    if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4942
0
        opline->result_type != IS_UNUSED) {
4943
0
      jit_set_Z_LVAL(jit, res_addr, ref);
4944
0
      if (Z_MODE(res_addr) != IS_REG) {
4945
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4946
0
      }
4947
0
    }
4948
0
  }
4949
0
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4950
0
    ir_ref merge_inputs = ir_END();
4951
4952
    /* !is_long => cold path */
4953
0
    ir_IF_FALSE_cold(if_long);
4954
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4955
0
      jit_SET_EX_OPLINE(jit, opline);
4956
0
      if (op1_info & MAY_BE_UNDEF) {
4957
0
        ir_ref if_def;
4958
4959
0
        if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4960
0
        ir_IF_FALSE_cold(if_def);
4961
4962
        // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
4963
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4964
4965
0
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4966
0
        ir_MERGE_WITH_EMPTY_TRUE(if_def);
4967
4968
0
        op1_info |= MAY_BE_NULL;
4969
0
      }
4970
4971
0
      ref = jit_ZVAL_ADDR(jit, op1_addr);
4972
4973
0
      if (op1_info & MAY_BE_REF) {
4974
0
        ir_ref if_ref, if_typed, func, ref2, arg2;
4975
4976
0
        if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4977
0
        ir_IF_TRUE(if_ref);
4978
0
        ref2 = jit_Z_PTR_ref(jit, ref);
4979
4980
0
        if_typed = jit_if_TYPED_REF(jit, ref2);
4981
0
        ir_IF_TRUE(if_typed);
4982
4983
0
        if (RETURN_VALUE_USED(opline)) {
4984
0
          ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4985
0
          arg2 = jit_ZVAL_ADDR(jit, res_addr);
4986
0
        } else {
4987
0
          arg2 = IR_NULL;
4988
0
        }
4989
0
        if (opline->opcode == ZEND_PRE_INC) {
4990
0
          func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4991
0
        } else if (opline->opcode == ZEND_PRE_DEC) {
4992
0
          func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4993
0
        } else if (opline->opcode == ZEND_POST_INC) {
4994
0
          func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4995
0
        } else if (opline->opcode == ZEND_POST_DEC) {
4996
0
          func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4997
0
        } else {
4998
0
          ZEND_UNREACHABLE();
4999
0
        }
5000
5001
0
        ir_CALL_2(IR_VOID, func, ref2, arg2);
5002
0
        zend_jit_check_exception(jit);
5003
0
        ir_END_list(merge_inputs);
5004
5005
0
        ir_IF_FALSE(if_typed);
5006
0
        ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
5007
0
        ir_MERGE_WITH_EMPTY_FALSE(if_ref);
5008
0
        ref = ir_PHI_2(IR_ADDR, ref2, ref);
5009
0
      }
5010
5011
0
      if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
5012
0
        jit_ZVAL_COPY(jit,
5013
0
          res_addr,
5014
0
          res_use_info,
5015
0
          ZEND_ADDR_REF_ZVAL(ref), op1_info, true);
5016
0
      }
5017
0
      if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
5018
0
        if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
5019
0
          ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
5020
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
5021
0
        } else {
5022
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
5023
0
        }
5024
0
      } else {
5025
0
        if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) {
5026
0
          ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
5027
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec), ref, arg2);
5028
0
        } else {
5029
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
5030
0
        }
5031
0
      }
5032
0
      if (may_throw) {
5033
0
        zend_jit_check_exception(jit);
5034
0
      }
5035
0
    } else {
5036
0
      ref = jit_Z_DVAL(jit, op1_addr);
5037
0
      if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
5038
0
        jit_set_Z_DVAL(jit, res_addr, ref);
5039
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5040
0
      }
5041
0
      if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
5042
0
        op = IR_ADD;
5043
0
      } else {
5044
0
        op = IR_SUB;
5045
0
      }
5046
0
      ref = ir_BINARY_OP_D(op, ref, ir_CONST_DOUBLE(1.0));
5047
0
      jit_set_Z_DVAL(jit, op1_def_addr, ref);
5048
0
      if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
5049
0
          opline->result_type != IS_UNUSED) {
5050
0
        jit_set_Z_DVAL(jit, res_addr, ref);
5051
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5052
0
      }
5053
0
    }
5054
0
    ir_END_list(merge_inputs);
5055
0
    ir_MERGE_list(merge_inputs);
5056
0
  }
5057
0
  if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
5058
0
    return 0;
5059
0
  }
5060
0
  if (opline->result_type != IS_UNUSED) {
5061
0
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5062
0
      return 0;
5063
0
    }
5064
0
  }
5065
0
  return 1;
5066
0
}
5067
5068
static int zend_jit_math_long_long(zend_jit_ctx   *jit,
5069
                                   const zend_op  *opline,
5070
                                   uint8_t         opcode,
5071
                                   zend_jit_addr   op1_addr,
5072
                                   zend_jit_addr   op2_addr,
5073
                                   zend_jit_addr   res_addr,
5074
                                   uint32_t        res_info,
5075
                                   uint32_t        res_use_info,
5076
                                   int             may_overflow)
5077
0
{
5078
0
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5079
0
  ir_op op;
5080
0
  ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
5081
5082
0
  if (opcode == ZEND_ADD) {
5083
0
    op = may_overflow ? IR_ADD_OV : IR_ADD;
5084
0
  } else if (opcode == ZEND_SUB) {
5085
0
    op = may_overflow ? IR_SUB_OV : IR_SUB;
5086
0
  } else if (opcode == ZEND_MUL) {
5087
0
    op = may_overflow ? IR_MUL_OV : IR_MUL;
5088
0
  } else {
5089
0
    ZEND_UNREACHABLE();
5090
0
  }
5091
0
  op1 = jit_Z_LVAL(jit, op1_addr);
5092
0
  op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5093
0
  ref = ir_BINARY_OP_L(op, op1, op2);
5094
5095
0
  if (may_overflow) {
5096
0
    if (res_info & MAY_BE_GUARD) {
5097
0
      if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
5098
0
        zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5099
0
        uint32_t old_res_info;
5100
0
        int32_t exit_point;
5101
0
        const void *exit_addr;
5102
5103
0
        if (opline->opcode == ZEND_ADD
5104
0
         && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5105
0
          old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5106
0
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5107
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5108
0
          exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5109
0
          SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5110
0
        } else if (opline->opcode == ZEND_SUB
5111
0
         && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5112
0
          old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5113
0
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5114
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5115
0
          exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5116
0
          SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5117
0
        } else {
5118
0
          exit_point = zend_jit_trace_get_exit_point(opline, 0);
5119
0
        }
5120
5121
0
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5122
0
        if (!exit_addr) {
5123
0
          return 0;
5124
0
        }
5125
0
        ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5126
0
        may_overflow = 0;
5127
0
      } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5128
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5129
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5130
5131
0
        if (!exit_addr) {
5132
0
          return 0;
5133
0
        }
5134
0
        ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5135
0
      } else {
5136
0
        ZEND_UNREACHABLE();
5137
0
      }
5138
0
    } else {
5139
0
      if_overflow = ir_IF(ir_OVERFLOW(ref));
5140
0
      ir_IF_FALSE(if_overflow);
5141
0
    }
5142
0
  }
5143
5144
0
  if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5145
0
    jit_set_Z_LVAL(jit, res_addr, ref);
5146
5147
0
    if (Z_MODE(res_addr) != IS_REG) {
5148
0
      if (!zend_jit_same_addr(op1_addr, res_addr)) {
5149
0
        if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5150
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5151
0
        }
5152
0
      }
5153
0
    }
5154
0
  }
5155
5156
0
  if (may_overflow) {
5157
0
    ir_ref fast_path = IR_UNUSED;
5158
5159
0
    if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5160
0
      fast_path = ir_END();
5161
0
      ir_IF_TRUE_cold(if_overflow);
5162
0
    }
5163
0
    if (opcode == ZEND_ADD) {
5164
0
      if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5165
0
        if (Z_MODE(res_addr) == IS_REG) {
5166
0
          jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
5167
0
        } else {
5168
#if SIZEOF_ZEND_LONG == 4
5169
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
5170
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
5171
#else
5172
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5173
0
#endif
5174
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5175
0
        }
5176
0
        if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5177
0
          ir_MERGE_WITH(fast_path);
5178
0
        }
5179
0
        return 1;
5180
0
      }
5181
0
      op = IR_ADD;
5182
0
    } else if (opcode == ZEND_SUB) {
5183
0
      if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5184
0
        if (Z_MODE(res_addr) == IS_REG) {
5185
0
          jit_set_Z_DVAL(jit, res_addr, ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5186
0
        } else {
5187
#if SIZEOF_ZEND_LONG == 4
5188
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
5189
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
5190
#else
5191
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
5192
0
#endif
5193
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5194
0
        }
5195
0
        if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5196
0
          ir_MERGE_WITH(fast_path);
5197
0
        }
5198
0
        return 1;
5199
0
      }
5200
0
      op = IR_SUB;
5201
0
    } else if (opcode == ZEND_MUL) {
5202
0
      op = IR_MUL;
5203
0
    } else {
5204
0
      ZEND_UNREACHABLE();
5205
0
    }
5206
0
#if 1
5207
    /* reload */
5208
0
    op1 = jit_Z_LVAL(jit, op1_addr);
5209
0
    op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5210
0
#endif
5211
0
#if 1
5212
    /* disable CSE */
5213
0
    ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5214
0
    jit->ctx.fold_cse_limit = 0x7fffffff;
5215
0
#endif
5216
0
    op1 = ir_INT2D(op1);
5217
0
    op2 = ir_INT2D(op2);
5218
0
#if 1
5219
0
    jit->ctx.fold_cse_limit = old_cse_limit;
5220
0
#endif
5221
0
    ref = ir_BINARY_OP_D(op, op1, op2);
5222
0
    jit_set_Z_DVAL(jit, res_addr, ref);
5223
0
    if (Z_MODE(res_addr) != IS_REG) {
5224
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5225
0
    }
5226
0
    if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5227
0
      ir_MERGE_WITH(fast_path);
5228
0
    }
5229
0
  }
5230
5231
0
  return 1;
5232
0
}
5233
5234
static int zend_jit_math_long_double(zend_jit_ctx   *jit,
5235
                                     uint8_t         opcode,
5236
                                     zend_jit_addr   op1_addr,
5237
                                     zend_jit_addr   op2_addr,
5238
                                     zend_jit_addr   res_addr,
5239
                                     uint32_t        res_use_info)
5240
0
{
5241
0
  ir_op op;
5242
0
  ir_ref op1, op2, ref;
5243
5244
0
  if (opcode == ZEND_ADD) {
5245
0
    op = IR_ADD;
5246
0
  } else if (opcode == ZEND_SUB) {
5247
0
    op = IR_SUB;
5248
0
  } else if (opcode == ZEND_MUL) {
5249
0
    op = IR_MUL;
5250
0
  } else if (opcode == ZEND_DIV) {
5251
0
    op = IR_DIV;
5252
0
  } else {
5253
0
    ZEND_UNREACHABLE();
5254
0
  }
5255
0
  op1 = jit_Z_LVAL(jit, op1_addr);
5256
0
  op2 = jit_Z_DVAL(jit, op2_addr);
5257
0
  ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5258
0
  jit_set_Z_DVAL(jit, res_addr, ref);
5259
5260
0
  if (Z_MODE(res_addr) != IS_REG) {
5261
0
    if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5262
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5263
0
    }
5264
0
  }
5265
0
  return 1;
5266
0
}
5267
5268
static int zend_jit_math_double_long(zend_jit_ctx   *jit,
5269
                                     uint8_t         opcode,
5270
                                     zend_jit_addr   op1_addr,
5271
                                     zend_jit_addr   op2_addr,
5272
                                     zend_jit_addr   res_addr,
5273
                                     uint32_t        res_use_info)
5274
0
{
5275
0
  ir_op op;
5276
0
  ir_ref op1, op2, ref;
5277
5278
0
  if (opcode == ZEND_ADD) {
5279
0
    op = IR_ADD;
5280
0
  } else if (opcode == ZEND_SUB) {
5281
0
    op = IR_SUB;
5282
0
  } else if (opcode == ZEND_MUL) {
5283
0
    op = IR_MUL;
5284
0
  } else if (opcode == ZEND_DIV) {
5285
0
    op = IR_DIV;
5286
0
  } else {
5287
0
    ZEND_UNREACHABLE();
5288
0
  }
5289
0
  op1 = jit_Z_DVAL(jit, op1_addr);
5290
0
  op2 = jit_Z_LVAL(jit, op2_addr);
5291
0
  ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5292
0
  jit_set_Z_DVAL(jit, res_addr, ref);
5293
5294
0
  if (Z_MODE(res_addr) != IS_REG) {
5295
0
    if (!zend_jit_same_addr(op1_addr, res_addr)) {
5296
0
      if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5297
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5298
0
      }
5299
0
    }
5300
0
  }
5301
0
  return 1;
5302
0
}
5303
5304
static int zend_jit_math_double_double(zend_jit_ctx   *jit,
5305
                                       uint8_t         opcode,
5306
                                       zend_jit_addr   op1_addr,
5307
                                       zend_jit_addr   op2_addr,
5308
                                       zend_jit_addr   res_addr,
5309
                                       uint32_t        res_use_info)
5310
0
{
5311
0
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5312
0
  ir_op op;
5313
0
  ir_ref op1, op2, ref;
5314
5315
0
  if (opcode == ZEND_ADD) {
5316
0
    op = IR_ADD;
5317
0
  } else if (opcode == ZEND_SUB) {
5318
0
    op = IR_SUB;
5319
0
  } else if (opcode == ZEND_MUL) {
5320
0
    op = IR_MUL;
5321
0
  } else if (opcode == ZEND_DIV) {
5322
0
    op = IR_DIV;
5323
0
  } else {
5324
0
    ZEND_UNREACHABLE();
5325
0
  }
5326
0
  op1 = jit_Z_DVAL(jit, op1_addr);
5327
0
  op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5328
0
  ref = ir_BINARY_OP_D(op, op1, op2);
5329
0
  jit_set_Z_DVAL(jit, res_addr, ref);
5330
5331
0
  if (Z_MODE(res_addr) != IS_REG) {
5332
0
    if (!zend_jit_same_addr(op1_addr, res_addr)) {
5333
0
      if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5334
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5335
0
      }
5336
0
    }
5337
0
  }
5338
0
  return 1;
5339
0
}
5340
5341
static int zend_jit_math_helper(zend_jit_ctx   *jit,
5342
                                const zend_op  *opline,
5343
                                uint8_t         opcode,
5344
                                uint8_t         op1_type,
5345
                                znode_op        op1,
5346
                                zend_jit_addr   op1_addr,
5347
                                uint32_t        op1_info,
5348
                                uint8_t         op2_type,
5349
                                znode_op        op2,
5350
                                zend_jit_addr   op2_addr,
5351
                                uint32_t        op2_info,
5352
                                uint32_t        res_var,
5353
                                zend_jit_addr   res_addr,
5354
                                uint32_t        res_info,
5355
                                uint32_t        res_use_info,
5356
                                int             may_overflow,
5357
                                int             may_throw)
5358
0
{
5359
0
  ir_ref if_op1_long = IR_UNUSED;
5360
0
  ir_ref if_op1_double = IR_UNUSED;
5361
0
  ir_ref if_op2_double = IR_UNUSED;
5362
0
  ir_ref if_op1_long_op2_long = IR_UNUSED;
5363
0
  ir_ref if_op1_long_op2_double = IR_UNUSED;
5364
0
  ir_ref if_op1_double_op2_double = IR_UNUSED;
5365
0
  ir_ref if_op1_double_op2_long = IR_UNUSED;
5366
0
  ir_ref slow_inputs = IR_UNUSED;
5367
0
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5368
0
  ir_refs *end_inputs;
5369
0
  ir_refs *res_inputs;
5370
5371
0
  ir_refs_init(end_inputs, 6);
5372
0
  ir_refs_init(res_inputs, 6);
5373
5374
0
  if (Z_MODE(op1_addr) == IS_REG) {
5375
0
    if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5376
      /* Force load */
5377
0
      zend_jit_use_reg(jit, op1_addr);
5378
0
    }
5379
0
  } else if (Z_MODE(op2_addr) == IS_REG) {
5380
0
    if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5381
      /* Force load */
5382
0
      zend_jit_use_reg(jit, op2_addr);
5383
0
    }
5384
0
  }
5385
5386
0
  if (Z_MODE(res_addr) == IS_REG) {
5387
0
    jit->delay_var = Z_SSA_VAR(res_addr);
5388
0
    jit->delay_refs = res_inputs;
5389
0
  }
5390
5391
0
  if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5392
0
    if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5393
0
      if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5394
0
      ir_IF_TRUE(if_op1_long);
5395
0
    }
5396
0
    if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5397
0
      if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5398
0
      ir_IF_TRUE(if_op1_long_op2_long);
5399
0
    }
5400
0
    if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5401
0
      return 0;
5402
0
    }
5403
0
    ir_refs_add(end_inputs, ir_END());
5404
0
    if (if_op1_long) {
5405
0
      ir_IF_FALSE_cold(if_op1_long);
5406
0
      ir_END_list(slow_inputs);
5407
0
    }
5408
0
    if (if_op1_long_op2_long) {
5409
0
      ir_IF_FALSE_cold(if_op1_long_op2_long);
5410
0
      ir_END_list(slow_inputs);
5411
0
    }
5412
0
  } else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5413
0
    if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5414
0
      if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5415
0
      ir_IF_TRUE(if_op1_long);
5416
0
    }
5417
0
    if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5418
0
      if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5419
0
      ir_IF_FALSE_cold(if_op1_long_op2_long);
5420
0
      if (op2_info & MAY_BE_DOUBLE) {
5421
0
        if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5422
0
          if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5423
0
          ir_IF_FALSE_cold(if_op1_long_op2_double);
5424
0
          ir_END_list(slow_inputs);
5425
0
          ir_IF_TRUE(if_op1_long_op2_double);
5426
0
        }
5427
0
        if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5428
0
          return 0;
5429
0
        }
5430
0
        ir_refs_add(end_inputs, ir_END());
5431
0
      } else {
5432
0
        ir_END_list(slow_inputs);
5433
0
      }
5434
0
      ir_IF_TRUE(if_op1_long_op2_long);
5435
0
    }
5436
0
    if (!zend_jit_math_long_long(jit, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) {
5437
0
      return 0;
5438
0
    }
5439
0
    ir_refs_add(end_inputs, ir_END());
5440
5441
0
    if (if_op1_long) {
5442
0
      ir_IF_FALSE_cold(if_op1_long);
5443
0
    }
5444
5445
0
    if (op1_info & MAY_BE_DOUBLE) {
5446
0
      if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5447
0
        if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5448
0
        ir_IF_FALSE_cold(if_op1_double);
5449
0
        ir_END_list(slow_inputs);
5450
0
        ir_IF_TRUE(if_op1_double);
5451
0
      }
5452
0
      if (op2_info & MAY_BE_DOUBLE) {
5453
0
        if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5454
0
          if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5455
0
          ir_IF_TRUE(if_op1_double_op2_double);
5456
0
        }
5457
0
        if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5458
0
          return 0;
5459
0
        }
5460
0
        ir_refs_add(end_inputs, ir_END());
5461
0
        if (if_op1_double_op2_double) {
5462
0
          ir_IF_FALSE_cold(if_op1_double_op2_double);
5463
0
        }
5464
0
      }
5465
0
      if (!same_ops) {
5466
0
        if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5467
0
          if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5468
0
          ir_IF_FALSE_cold(if_op1_double_op2_long);
5469
0
          ir_END_list(slow_inputs);
5470
0
          ir_IF_TRUE(if_op1_double_op2_long);
5471
0
        }
5472
0
        if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5473
0
          return 0;
5474
0
        }
5475
0
        ir_refs_add(end_inputs, ir_END());
5476
0
      } else if (if_op1_double_op2_double) {
5477
0
        ir_END_list(slow_inputs);
5478
0
      }
5479
0
    } else if (if_op1_long) {
5480
0
      ir_END_list(slow_inputs);
5481
0
    }
5482
0
  } else if ((op1_info & MAY_BE_DOUBLE) &&
5483
0
             !(op1_info & MAY_BE_LONG) &&
5484
0
             (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5485
0
             (res_info & MAY_BE_DOUBLE)) {
5486
0
    if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5487
0
      if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5488
0
      ir_IF_FALSE_cold(if_op1_double);
5489
0
      ir_END_list(slow_inputs);
5490
0
      ir_IF_TRUE(if_op1_double);
5491
0
    }
5492
0
    if (op2_info & MAY_BE_DOUBLE) {
5493
0
      if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5494
0
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5495
0
        ir_IF_TRUE(if_op1_double_op2_double);
5496
0
      }
5497
0
      if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5498
0
        return 0;
5499
0
      }
5500
0
      ir_refs_add(end_inputs, ir_END());
5501
0
      if (if_op1_double_op2_double) {
5502
0
        ir_IF_FALSE_cold(if_op1_double_op2_double);
5503
0
      }
5504
0
    }
5505
0
    if (!same_ops && (op2_info & MAY_BE_LONG)) {
5506
0
      if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5507
0
        if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5508
0
        ir_IF_FALSE_cold(if_op1_double_op2_long);
5509
0
        ir_END_list(slow_inputs);
5510
0
        ir_IF_TRUE(if_op1_double_op2_long);
5511
0
      }
5512
0
      if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5513
0
        return 0;
5514
0
      }
5515
0
      ir_refs_add(end_inputs, ir_END());
5516
0
    } else if (if_op1_double_op2_double) {
5517
0
      ir_END_list(slow_inputs);
5518
0
    }
5519
0
  } else if ((op2_info & MAY_BE_DOUBLE) &&
5520
0
             !(op2_info & MAY_BE_LONG) &&
5521
0
             (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5522
0
             (res_info & MAY_BE_DOUBLE)) {
5523
0
    if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) {
5524
0
      if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5525
0
      ir_IF_FALSE_cold(if_op2_double);
5526
0
      ir_END_list(slow_inputs);
5527
0
      ir_IF_TRUE(if_op2_double);
5528
0
    }
5529
0
    if (op1_info & MAY_BE_DOUBLE) {
5530
0
      if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5531
0
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5532
0
        ir_IF_TRUE(if_op1_double_op2_double);
5533
0
      }
5534
0
      if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5535
0
        return 0;
5536
0
      }
5537
0
      ir_refs_add(end_inputs, ir_END());
5538
0
      if (if_op1_double_op2_double) {
5539
0
        ir_IF_FALSE_cold(if_op1_double_op2_double);
5540
0
      }
5541
0
    }
5542
0
    if (!same_ops && (op1_info & MAY_BE_LONG)) {
5543
0
      if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5544
0
        if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5545
0
        ir_IF_FALSE_cold(if_op1_long_op2_double);
5546
0
        ir_END_list(slow_inputs);
5547
0
        ir_IF_TRUE(if_op1_long_op2_double);
5548
0
      }
5549
0
      if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5550
0
        return 0;
5551
0
      }
5552
0
      ir_refs_add(end_inputs, ir_END());
5553
0
    } else if (if_op1_double_op2_double) {
5554
0
      ir_END_list(slow_inputs);
5555
0
    }
5556
0
  }
5557
5558
0
  if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5559
0
    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5560
0
    ir_ref func, arg1, arg2, arg3;
5561
5562
0
    if (slow_inputs) {
5563
0
      ir_MERGE_list(slow_inputs);
5564
0
    }
5565
5566
0
    if (Z_MODE(op1_addr) == IS_REG) {
5567
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5568
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5569
0
        return 0;
5570
0
      }
5571
0
      op1_addr = real_addr;
5572
0
    }
5573
0
    if (Z_MODE(op2_addr) == IS_REG) {
5574
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5575
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5576
0
        return 0;
5577
0
      }
5578
0
      op2_addr = real_addr;
5579
0
    }
5580
0
    if (Z_MODE(res_addr) == IS_REG) {
5581
0
      arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5582
0
    } else {
5583
0
      arg1 = jit_ZVAL_ADDR(jit, res_addr);
5584
0
    }
5585
0
    arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5586
0
    arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5587
0
    jit_SET_EX_OPLINE(jit, opline);
5588
0
    if (opcode == ZEND_ADD) {
5589
0
      func = ir_CONST_FC_FUNC(add_function);
5590
0
    } else if (opcode == ZEND_SUB) {
5591
0
      func = ir_CONST_FC_FUNC(sub_function);
5592
0
    } else if (opcode == ZEND_MUL) {
5593
0
      func = ir_CONST_FC_FUNC(mul_function);
5594
0
    } else if (opcode == ZEND_DIV) {
5595
0
      func = ir_CONST_FC_FUNC(div_function);
5596
0
    } else {
5597
0
      ZEND_UNREACHABLE();
5598
0
    }
5599
0
    ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5600
5601
0
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5602
0
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5603
5604
0
    if (may_throw) {
5605
0
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5606
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5607
0
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5608
0
      } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5609
0
        zend_jit_check_exception_undef_result(jit, opline);
5610
0
      } else {
5611
0
        zend_jit_check_exception(jit);
5612
0
      }
5613
0
    }
5614
0
    if (Z_MODE(res_addr) == IS_REG) {
5615
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
5616
0
      if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
5617
0
        return 0;
5618
0
      }
5619
0
    }
5620
0
    ir_refs_add(end_inputs, ir_END());
5621
0
  }
5622
5623
0
  if (end_inputs->count) {
5624
0
    ir_MERGE_N(end_inputs->count, end_inputs->refs);
5625
0
  }
5626
5627
0
  if (Z_MODE(res_addr) == IS_REG) {
5628
0
    ZEND_ASSERT(jit->delay_refs == res_inputs);
5629
0
    ZEND_ASSERT(end_inputs->count == res_inputs->count);
5630
0
    jit->delay_var = -1;
5631
0
    jit->delay_refs = NULL;
5632
0
    if (res_inputs->count == 1) {
5633
0
      zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5634
0
    } else {
5635
0
      ir_ref phi = ir_PHI_N((res_info & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE, res_inputs->count, res_inputs->refs);
5636
0
      zend_jit_def_reg(jit, res_addr, phi);
5637
0
    }
5638
0
  }
5639
5640
0
  return 1;
5641
0
}
5642
5643
static int zend_jit_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
5644
0
{
5645
0
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5646
5647
0
  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)) {
5648
0
    return 0;
5649
0
  }
5650
0
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5651
0
    return 0;
5652
0
  }
5653
0
  return 1;
5654
0
}
5655
5656
static int zend_jit_add_arrays(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr)
5657
0
{
5658
0
  ir_ref ref;
5659
0
  ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5660
0
  ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5661
5662
0
  ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5663
0
  jit_set_Z_PTR(jit, res_addr, ref);
5664
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5665
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5666
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5667
0
  return 1;
5668
0
}
5669
5670
static int zend_jit_long_math_helper(zend_jit_ctx   *jit,
5671
                                     const zend_op  *opline,
5672
                                     uint8_t         opcode,
5673
                                     uint8_t         op1_type,
5674
                                     znode_op        op1,
5675
                                     zend_jit_addr   op1_addr,
5676
                                     uint32_t        op1_info,
5677
                                     zend_ssa_range *op1_range,
5678
                                     uint8_t         op2_type,
5679
                                     znode_op        op2,
5680
                                     zend_jit_addr   op2_addr,
5681
                                     uint32_t        op2_info,
5682
                                     zend_ssa_range *op2_range,
5683
                                     uint32_t        res_var,
5684
                                     zend_jit_addr   res_addr,
5685
                                     uint32_t        res_info,
5686
                                     uint32_t        res_use_info,
5687
                                     int             may_throw)
5688
0
{
5689
0
  ir_ref ref = IR_UNUSED;
5690
0
  ir_ref if_long1 = IR_UNUSED;
5691
0
  ir_ref if_long2 = IR_UNUSED;
5692
0
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5693
0
  ir_refs *res_inputs;
5694
5695
0
  ir_refs_init(res_inputs, 2);
5696
5697
0
  if (Z_MODE(op1_addr) == IS_REG
5698
0
   && Z_LOAD(op1_addr)
5699
0
   && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
5700
    /* Force load */
5701
0
    zend_jit_use_reg(jit, op1_addr);
5702
0
  }
5703
0
  if (Z_MODE(op2_addr) == IS_REG
5704
0
   && Z_LOAD(op2_addr)
5705
0
   && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
5706
    /* Force load */
5707
0
    zend_jit_use_reg(jit, op2_addr);
5708
0
  }
5709
5710
0
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5711
0
    if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5712
0
    ir_IF_TRUE(if_long1);
5713
0
  }
5714
0
  if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5715
0
    if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5716
0
    ir_IF_TRUE(if_long2);
5717
0
  }
5718
5719
0
  if (opcode == ZEND_SL) {
5720
0
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5721
0
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5722
5723
0
      if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5724
0
        if (EXPECTED(op2_lval > 0)) {
5725
0
          ref = ir_CONST_LONG(0);
5726
0
        } else {
5727
0
          zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5728
0
          zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5729
0
          jit_SET_EX_OPLINE(jit, opline);
5730
0
          ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5731
0
          if (Z_MODE(res_addr) == IS_REG) {
5732
0
            ref = ir_CONST_LONG(0); // dead code
5733
0
          }
5734
0
        }
5735
0
      } else {
5736
0
        ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5737
0
      }
5738
0
    } else {
5739
0
      ref = jit_Z_LVAL(jit, op2_addr);
5740
0
      if (!op2_range ||
5741
0
           op2_range->min < 0 ||
5742
0
           op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5743
5744
0
        ir_ref if_wrong, cold_path, ref2, if_ok;
5745
0
        ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5746
5747
0
        if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5748
0
        ir_IF_TRUE_cold(if_wrong);
5749
0
        if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5750
0
        ir_IF_FALSE(if_ok);
5751
0
        jit_SET_EX_OPLINE(jit, opline);
5752
0
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5753
0
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5754
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5755
0
        ir_IF_TRUE(if_ok);
5756
0
        ref2 = ir_CONST_LONG(0);
5757
0
        cold_path = ir_END();
5758
0
        ir_IF_FALSE(if_wrong);
5759
0
        ref = ir_SHL_L(op1_ref, ref);
5760
0
        ir_MERGE_WITH(cold_path);
5761
0
        ref = ir_PHI_2(IR_LONG, ref, ref2);
5762
0
      } else {
5763
0
        ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5764
0
      }
5765
0
    }
5766
0
  } else if (opcode == ZEND_SR) {
5767
0
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5768
0
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5769
5770
0
      if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5771
0
        if (EXPECTED(op2_lval > 0)) {
5772
0
          ref = ir_SAR_L(
5773
0
            jit_Z_LVAL(jit, op1_addr),
5774
0
            ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5775
0
        } else {
5776
0
          zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5777
0
          zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5778
0
          jit_SET_EX_OPLINE(jit, opline);
5779
0
          ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5780
0
          if (Z_MODE(res_addr) == IS_REG) {
5781
0
            ref = ir_CONST_LONG(0); // dead code
5782
0
          }
5783
0
        }
5784
0
      } else {
5785
0
        ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5786
0
      }
5787
0
    } else {
5788
0
      ref = jit_Z_LVAL(jit, op2_addr);
5789
0
      if (!op2_range ||
5790
0
           op2_range->min < 0 ||
5791
0
           op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5792
5793
0
        ir_ref if_wrong, cold_path, ref2, if_ok;
5794
5795
0
        if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5796
0
        ir_IF_TRUE_cold(if_wrong);
5797
0
        if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5798
0
        ir_IF_FALSE(if_ok);
5799
0
        jit_SET_EX_OPLINE(jit, opline);
5800
0
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5801
0
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5802
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5803
0
        ir_IF_TRUE(if_ok);
5804
0
        ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5805
0
        cold_path = ir_END();
5806
0
        ir_IF_FALSE(if_wrong);
5807
0
        ir_MERGE_WITH(cold_path);
5808
0
        ref = ir_PHI_2(IR_LONG, ref, ref2);
5809
0
      }
5810
0
      ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5811
0
    }
5812
0
  } else if (opcode == ZEND_MOD) {
5813
0
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5814
0
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5815
5816
0
      if (op2_lval == 0) {
5817
0
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5818
0
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5819
0
        jit_SET_EX_OPLINE(jit, opline);
5820
0
        ir_GUARD(IR_FALSE,  jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5821
0
        if (Z_MODE(res_addr) == IS_REG) {
5822
0
          ref = ir_CONST_LONG(0); // dead code
5823
0
        }
5824
0
      } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5825
0
        ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5826
0
      } else {
5827
0
        ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5828
0
      }
5829
0
    } else {
5830
0
      ir_ref zero_path = 0;
5831
0
      ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5832
5833
0
      ref = jit_Z_LVAL(jit, op2_addr);
5834
0
      if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5835
0
        ir_ref if_ok = ir_IF(ref);
5836
0
        ir_IF_FALSE(if_ok);
5837
0
        jit_SET_EX_OPLINE(jit, opline);
5838
0
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5839
0
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5840
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5841
0
        ir_IF_TRUE(if_ok);
5842
0
      }
5843
5844
      /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5845
0
      if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5846
0
        ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5847
0
        ir_IF_TRUE_cold(if_minus_one);
5848
0
        zero_path = ir_END();
5849
0
        ir_IF_FALSE(if_minus_one);
5850
0
      }
5851
0
      ref = ir_MOD_L(op1_ref, ref);
5852
5853
0
      if (zero_path) {
5854
0
        ir_MERGE_WITH(zero_path);
5855
0
        ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5856
0
      }
5857
0
    }
5858
0
  } else {
5859
0
    ir_op op;
5860
0
    ir_ref op1, op2;
5861
5862
0
    if (opcode == ZEND_BW_OR) {
5863
0
      op = IR_OR;
5864
0
    } else if (opcode == ZEND_BW_AND) {
5865
0
      op = IR_AND;
5866
0
    } else if (opcode == ZEND_BW_XOR) {
5867
0
      op = IR_XOR;
5868
0
    } else {
5869
0
      ZEND_UNREACHABLE();
5870
0
    }
5871
0
    op1 = jit_Z_LVAL(jit, op1_addr);
5872
0
    op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5873
0
    ref = ir_BINARY_OP_L(op, op1, op2);
5874
0
  }
5875
5876
0
  if (ref) {
5877
0
    if (Z_MODE(res_addr) == IS_REG
5878
0
     && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5879
0
      || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5880
0
      jit->delay_var = Z_SSA_VAR(res_addr);
5881
0
      jit->delay_refs = res_inputs;
5882
0
    }
5883
0
    jit_set_Z_LVAL(jit, res_addr, ref);
5884
0
    if (Z_MODE(res_addr) != IS_REG) {
5885
0
      if (!zend_jit_same_addr(op1_addr, res_addr)) {
5886
0
        if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5887
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5888
0
        }
5889
0
      }
5890
0
    }
5891
0
  }
5892
5893
0
  if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5894
0
    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5895
0
    ir_ref fast_path = ir_END();
5896
0
    ir_ref func, arg1, arg2, arg3;
5897
5898
0
    if (if_long2 && if_long1) {
5899
0
      ir_ref ref;
5900
0
      ir_IF_FALSE_cold(if_long2);
5901
0
      ref = ir_END();
5902
0
      ir_IF_FALSE_cold(if_long1);
5903
0
      ir_MERGE_2(ref, ir_END());
5904
0
    } else if (if_long1) {
5905
0
      ir_IF_FALSE_cold(if_long1);
5906
0
    } else if (if_long2) {
5907
0
      ir_IF_FALSE_cold(if_long2);
5908
0
    }
5909
5910
0
    if (op1_info & MAY_BE_UNDEF) {
5911
0
      ir_ref if_def, ref, ref2;
5912
5913
0
      ref = jit_ZVAL_ADDR(jit, op1_addr);
5914
0
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5915
0
      ir_IF_FALSE_cold(if_def);
5916
5917
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5918
0
      jit_SET_EX_OPLINE(jit, opline);
5919
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5920
5921
0
      ref2 = jit_EG(uninitialized_zval);
5922
0
      ir_MERGE_WITH_EMPTY_TRUE(if_def);
5923
0
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
5924
0
      op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5925
0
    }
5926
5927
0
    if (op2_info & MAY_BE_UNDEF) {
5928
0
      ir_ref if_def, ref, ref2;
5929
5930
0
      ref = jit_ZVAL_ADDR(jit, op2_addr);
5931
0
      if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5932
0
      ir_IF_FALSE_cold(if_def);
5933
5934
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5935
0
      jit_SET_EX_OPLINE(jit, opline);
5936
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5937
5938
0
      ref2 = jit_EG(uninitialized_zval);
5939
0
      ir_MERGE_WITH_EMPTY_TRUE(if_def);
5940
0
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
5941
0
      op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5942
0
    }
5943
5944
0
    if (Z_MODE(op1_addr) == IS_REG) {
5945
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5946
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5947
0
        return 0;
5948
0
      }
5949
0
      op1_addr = real_addr;
5950
0
    }
5951
0
    if (Z_MODE(op2_addr) == IS_REG) {
5952
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5953
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5954
0
        return 0;
5955
0
      }
5956
0
      op2_addr = real_addr;
5957
0
    }
5958
0
    if (Z_MODE(res_addr) == IS_REG) {
5959
0
      arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5960
0
    } else {
5961
0
      arg1 = jit_ZVAL_ADDR(jit, res_addr);
5962
0
    }
5963
0
    arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5964
0
    arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5965
0
    jit_SET_EX_OPLINE(jit, opline);
5966
0
    if (opcode == ZEND_BW_OR) {
5967
0
      func = ir_CONST_FC_FUNC(bitwise_or_function);
5968
0
    } else if (opcode == ZEND_BW_AND) {
5969
0
      func = ir_CONST_FC_FUNC(bitwise_and_function);
5970
0
    } else if (opcode == ZEND_BW_XOR) {
5971
0
      func = ir_CONST_FC_FUNC(bitwise_xor_function);
5972
0
    } else if (opcode == ZEND_SL) {
5973
0
      func = ir_CONST_FC_FUNC(shift_left_function);
5974
0
    } else if (opcode == ZEND_SR) {
5975
0
      func = ir_CONST_FC_FUNC(shift_right_function);
5976
0
    } else if (opcode == ZEND_MOD) {
5977
0
      func = ir_CONST_FC_FUNC(mod_function);
5978
0
    } else {
5979
0
      ZEND_UNREACHABLE();
5980
0
    }
5981
0
    ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5982
5983
0
    if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5984
      /* compound assignment may decrement "op2" refcount */
5985
0
      op2_info |= MAY_BE_RC1;
5986
0
    }
5987
5988
0
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5989
0
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5990
5991
0
    if (may_throw) {
5992
0
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5993
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5994
0
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5995
0
      } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5996
0
        zend_jit_check_exception_undef_result(jit, opline);
5997
0
      } else {
5998
0
        zend_jit_check_exception(jit);
5999
0
      }
6000
0
    }
6001
6002
0
    if (Z_MODE(res_addr) == IS_REG) {
6003
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
6004
0
      if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
6005
0
        return 0;
6006
0
      }
6007
0
    }
6008
6009
0
    ir_MERGE_2(fast_path, ir_END());
6010
6011
0
    if (Z_MODE(res_addr) == IS_REG) {
6012
0
      ZEND_ASSERT(jit->delay_refs == res_inputs);
6013
0
      ZEND_ASSERT(res_inputs->count == 2);
6014
0
      jit->delay_var = -1;
6015
0
      jit->delay_refs = NULL;
6016
0
      if (res_inputs->count == 1) {
6017
0
        zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
6018
0
      } else {
6019
0
        ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
6020
0
        zend_jit_def_reg(jit, res_addr, phi);
6021
0
      }
6022
0
    }
6023
0
  }
6024
6025
0
  return 1;
6026
0
}
6027
6028
static int zend_jit_long_math(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw)
6029
0
{
6030
0
  ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
6031
6032
0
  if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
6033
0
      opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6034
0
      opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6035
0
      opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
6036
0
    return 0;
6037
0
  }
6038
0
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6039
0
    return 0;
6040
0
  }
6041
0
  return 1;
6042
0
}
6043
6044
static int zend_jit_concat_helper(zend_jit_ctx   *jit,
6045
                                  const zend_op  *opline,
6046
                                  uint8_t         op1_type,
6047
                                  znode_op        op1,
6048
                                  zend_jit_addr   op1_addr,
6049
                                  uint32_t        op1_info,
6050
                                  uint8_t         op2_type,
6051
                                  znode_op        op2,
6052
                                  zend_jit_addr   op2_addr,
6053
                                  uint32_t        op2_info,
6054
                                  zend_jit_addr   res_addr,
6055
                                  int             may_throw)
6056
0
{
6057
0
  ir_ref if_op1_string = IR_UNUSED;
6058
0
  ir_ref if_op2_string = IR_UNUSED;
6059
0
  ir_ref fast_path = IR_UNUSED;
6060
6061
0
  if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6062
0
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6063
0
      if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
6064
0
      ir_IF_TRUE(if_op1_string);
6065
0
    }
6066
0
    if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6067
0
      if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
6068
0
      ir_IF_TRUE(if_op2_string);
6069
0
    }
6070
0
    if (zend_jit_same_addr(op1_addr, res_addr)) {
6071
0
      ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6072
0
      ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6073
6074
0
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
6075
      /* concatenation with itself may reduce refcount */
6076
0
      op2_info |= MAY_BE_RC1;
6077
0
    } else {
6078
0
      ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6079
0
      ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6080
0
      ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6081
6082
0
      if (op1_type == IS_CV || op1_type == IS_CONST) {
6083
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
6084
0
      } else {
6085
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
6086
0
      }
6087
0
    }
6088
    /* concatenation with empty string may increase refcount */
6089
0
    op2_info |= MAY_BE_RCN;
6090
0
    jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
6091
0
    if (if_op1_string || if_op2_string) {
6092
0
      fast_path = ir_END();
6093
0
    }
6094
0
  }
6095
0
  if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
6096
0
      (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
6097
0
    if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6098
0
      if (if_op1_string && if_op2_string) {
6099
0
        ir_IF_FALSE(if_op1_string);
6100
0
        ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
6101
0
      } else if (if_op1_string) {
6102
0
        ir_IF_FALSE_cold(if_op1_string);
6103
0
      } else if (if_op2_string) {
6104
0
        ir_IF_FALSE_cold(if_op2_string);
6105
0
      }
6106
0
    }
6107
0
    ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6108
0
    ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6109
0
    ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6110
6111
0
    jit_SET_EX_OPLINE(jit, opline);
6112
0
    ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
6113
    /* concatenation with empty string may increase refcount */
6114
0
    op1_info |= MAY_BE_RCN;
6115
0
    op2_info |= MAY_BE_RCN;
6116
0
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6117
0
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6118
0
    if (may_throw) {
6119
0
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6120
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6121
0
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6122
0
      } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6123
0
        zend_jit_check_exception_undef_result(jit, opline);
6124
0
      } else {
6125
0
        zend_jit_check_exception(jit);
6126
0
      }
6127
0
    }
6128
0
    if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6129
0
      ir_MERGE_WITH(fast_path);
6130
0
    }
6131
0
  }
6132
0
  return 1;
6133
0
}
6134
6135
static int zend_jit_concat(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw)
6136
0
{
6137
0
  zend_jit_addr op1_addr, op2_addr;
6138
6139
0
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6140
0
  ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6141
6142
0
  op1_addr = OP1_ADDR();
6143
0
  op2_addr = OP2_ADDR();
6144
6145
0
  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);
6146
0
}
6147
6148
static int zend_jit_assign_op(zend_jit_ctx   *jit,
6149
                              const zend_op  *opline,
6150
                              uint32_t        op1_info,
6151
                              zend_jit_addr   op1_addr,
6152
                              zend_ssa_range *op1_range,
6153
                              uint32_t        op1_def_info,
6154
                              zend_jit_addr   op1_def_addr,
6155
                              uint32_t        op1_mem_info,
6156
                              uint32_t        op2_info,
6157
                              zend_jit_addr   op2_addr,
6158
                              zend_ssa_range *op2_range,
6159
                              int             may_overflow,
6160
                              int             may_throw)
6161
0
{
6162
0
  int result = 1;
6163
0
  ir_ref slow_path = IR_UNUSED;
6164
6165
0
  ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6166
0
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6167
6168
0
  if (op1_info & MAY_BE_REF) {
6169
0
    ir_ref ref, ref2, arg2, op1_noref_path;
6170
0
    ir_ref if_op1_ref = IR_UNUSED;
6171
0
    ir_ref if_op1_typed = IR_UNUSED;
6172
0
    binary_op_type binary_op = get_binary_op(opline->extended_value);
6173
6174
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
6175
0
    if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6176
0
    ir_IF_FALSE(if_op1_ref);
6177
0
    op1_noref_path = ir_END();
6178
0
    ir_IF_TRUE(if_op1_ref);
6179
0
    ref2 = jit_Z_PTR_ref(jit, ref);
6180
6181
0
    if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6182
0
    ir_IF_TRUE_cold(if_op1_typed);
6183
6184
0
    if (Z_MODE(op2_addr) == IS_REG) {
6185
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6186
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6187
0
        return 0;
6188
0
      }
6189
0
      arg2 = jit_ZVAL_ADDR(jit, real_addr);
6190
0
    } else {
6191
0
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6192
0
    }
6193
0
    jit_SET_EX_OPLINE(jit, opline);
6194
0
    if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6195
0
     && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6196
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6197
0
        ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6198
0
    } else {
6199
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6200
0
        ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6201
0
    }
6202
0
    zend_jit_check_exception(jit);
6203
0
    slow_path = ir_END();
6204
6205
0
    ir_IF_FALSE(if_op1_typed);
6206
0
    ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6207
6208
0
    ir_MERGE_WITH(op1_noref_path);
6209
0
    ref = ir_PHI_2(IR_ADDR, ref2, ref);
6210
0
    ZEND_ASSERT(op1_addr == op1_def_addr);
6211
0
    op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6212
0
  }
6213
6214
0
  switch (opline->extended_value) {
6215
0
    case ZEND_ADD:
6216
0
    case ZEND_SUB:
6217
0
    case ZEND_MUL:
6218
0
    case ZEND_DIV:
6219
0
      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);
6220
0
      break;
6221
0
    case ZEND_BW_OR:
6222
0
    case ZEND_BW_AND:
6223
0
    case ZEND_BW_XOR:
6224
0
    case ZEND_SL:
6225
0
    case ZEND_SR:
6226
0
    case ZEND_MOD:
6227
0
      result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6228
0
        opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6229
0
        opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6230
0
        opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6231
0
      break;
6232
0
    case ZEND_CONCAT:
6233
0
      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);
6234
0
      break;
6235
0
    default:
6236
0
      ZEND_UNREACHABLE();
6237
0
  }
6238
6239
0
  if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6240
0
    return 0;
6241
0
  }
6242
6243
0
  if (op1_info & MAY_BE_REF) {
6244
0
    ir_MERGE_WITH(slow_path);
6245
0
  }
6246
6247
0
  return result;
6248
0
}
6249
6250
static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6251
0
{
6252
0
  ir_ref if_ref, ref2;
6253
6254
0
  if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6255
0
  ir_IF_TRUE(if_ref);
6256
0
  ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6257
0
  ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6258
0
  return ir_PHI_2(IR_ADDR, ref2, ref);
6259
0
}
6260
6261
static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6262
0
{
6263
0
  ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6264
0
  ref = jit_ZVAL_DEREF_ref(jit, ref);
6265
0
  return ZEND_ADDR_REF_ZVAL(ref);
6266
0
}
6267
6268
static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6269
0
{
6270
0
  ir_ref if_ref, ref2;
6271
6272
0
  if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6273
0
  ir_IF_TRUE(if_ref);
6274
0
  ref2 = jit_Z_PTR_ref(jit, ref);
6275
0
  ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6276
0
  return ir_PHI_2(IR_ADDR, ref2, ref);
6277
0
}
6278
6279
static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6280
0
{
6281
0
  ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6282
0
  ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6283
0
  return ZEND_ADDR_REF_ZVAL(ref);
6284
0
}
6285
6286
static int zend_jit_simple_assign(zend_jit_ctx   *jit,
6287
                                  const zend_op  *opline,
6288
                                  zend_jit_addr   var_addr,
6289
                                  uint32_t        var_info,
6290
                                  uint32_t        var_def_info,
6291
                                  uint8_t         val_type,
6292
                                  zend_jit_addr   val_addr,
6293
                                  uint32_t        val_info,
6294
                                  zend_jit_addr   res_addr,
6295
                                  bool            check_exception)
6296
0
{
6297
0
  ir_ref end_inputs = IR_UNUSED;
6298
6299
0
  if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6300
0
    zval *zv = Z_ZV(val_addr);
6301
6302
0
    if (!res_addr) {
6303
0
      jit_ZVAL_COPY_CONST(jit,
6304
0
        var_addr,
6305
0
        var_info, var_def_info,
6306
0
        zv, true);
6307
0
    } else {
6308
0
      jit_ZVAL_COPY_CONST(jit,
6309
0
        var_addr,
6310
0
        var_info, var_def_info,
6311
0
        zv, true);
6312
0
      jit_ZVAL_COPY_CONST(jit,
6313
0
        res_addr,
6314
0
        -1, var_def_info,
6315
0
        zv, true);
6316
0
    }
6317
0
  } else {
6318
0
    if (val_info & MAY_BE_UNDEF) {
6319
0
      ir_ref if_def, ret;
6320
6321
0
      if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6322
0
      ir_IF_FALSE_cold(if_def);
6323
6324
0
      jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6325
0
      if (res_addr) {
6326
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6327
0
      }
6328
0
      jit_SET_EX_OPLINE(jit, opline);
6329
6330
0
      ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6331
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6332
0
      ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6333
6334
0
      if (check_exception) {
6335
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6336
0
      }
6337
6338
0
      ir_END_list(end_inputs);
6339
0
      ir_IF_TRUE(if_def);
6340
0
    }
6341
0
    if (val_info & MAY_BE_REF) {
6342
0
      if (val_type == IS_CV) {
6343
0
        ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6344
0
        ref = jit_ZVAL_DEREF_ref(jit, ref);
6345
0
        val_addr = ZEND_ADDR_REF_ZVAL(ref);
6346
0
      } else {
6347
0
        ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6348
6349
0
        ref = jit_ZVAL_ADDR(jit, val_addr);
6350
0
        type = jit_Z_TYPE_ref(jit, ref);
6351
0
        if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6352
6353
0
        ir_IF_TRUE_cold(if_ref);
6354
0
        ref = jit_Z_PTR_ref(jit, ref);
6355
0
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6356
0
        if (!res_addr) {
6357
0
          jit_ZVAL_COPY(jit,
6358
0
            var_addr,
6359
0
            var_info,
6360
0
            ZEND_ADDR_REF_ZVAL(ref2), val_info, true);
6361
0
        } else {
6362
0
          jit_ZVAL_COPY_2(jit,
6363
0
            res_addr,
6364
0
            var_addr,
6365
0
            var_info,
6366
0
            ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6367
0
        }
6368
6369
0
        refcount = jit_GC_DELREF(jit, ref);
6370
0
        if_not_zero = ir_IF(refcount);
6371
0
        ir_IF_FALSE(if_not_zero);
6372
        // TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6373
        // This is related to GH-10168 (keep this before GH-10168 is completely closed)
6374
        // jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6375
0
        jit_ZVAL_DTOR(jit, ref, val_info, opline);
6376
0
        ir_END_list(end_inputs);
6377
0
        ir_IF_TRUE(if_not_zero);
6378
0
        ir_END_list(end_inputs);
6379
6380
0
        ir_IF_FALSE(if_ref);
6381
0
      }
6382
0
    }
6383
6384
0
    if (!res_addr) {
6385
0
      jit_ZVAL_COPY(jit,
6386
0
        var_addr,
6387
0
        var_info,
6388
0
        val_addr, val_info, val_type == IS_CV);
6389
0
    } else {
6390
0
      jit_ZVAL_COPY_2(jit,
6391
0
        res_addr,
6392
0
        var_addr,
6393
0
        var_info,
6394
0
        val_addr, val_info, val_type == IS_CV ? 2 : 1);
6395
0
    }
6396
0
  }
6397
6398
0
  if (end_inputs) {
6399
0
    ir_END_list(end_inputs);
6400
0
    ir_MERGE_list(end_inputs);
6401
0
  }
6402
6403
0
  return 1;
6404
0
}
6405
6406
static int zend_jit_assign_to_variable_call(zend_jit_ctx   *jit,
6407
                                            const zend_op  *opline,
6408
                                            zend_jit_addr   __var_use_addr,
6409
                                            zend_jit_addr   var_addr,
6410
                                            uint32_t        __var_info,
6411
                                            uint32_t        __var_def_info,
6412
                                            uint8_t         val_type,
6413
                                            zend_jit_addr   val_addr,
6414
                                            uint32_t        val_info,
6415
                                            zend_jit_addr   __res_addr,
6416
                                            bool       __check_exception)
6417
0
{
6418
0
  jit_stub_id func;
6419
0
  ir_ref undef_path = IR_UNUSED;
6420
6421
0
  if (val_info & MAY_BE_UNDEF) {
6422
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6423
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6424
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6425
6426
0
      if (!exit_addr) {
6427
0
        return 0;
6428
0
      }
6429
6430
0
      jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6431
0
    } else {
6432
0
      ir_ref if_def;
6433
6434
0
      ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6435
0
      if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6436
0
      ir_IF_FALSE_cold(if_def);
6437
0
      jit_SET_EX_OPLINE(jit, opline);
6438
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6439
6440
0
      ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6441
0
        jit_ZVAL_ADDR(jit, var_addr),
6442
0
        jit_EG(uninitialized_zval));
6443
6444
0
      undef_path = ir_END();
6445
0
      ir_IF_TRUE(if_def);
6446
0
    }
6447
0
  }
6448
6449
0
  if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6450
0
    func = jit_stub_assign_tmp;
6451
0
  } else if (val_type == IS_CONST) {
6452
0
    func = jit_stub_assign_const;
6453
0
  } else if (val_type == IS_TMP_VAR) {
6454
0
    func = jit_stub_assign_tmp;
6455
0
  } else if (val_type == IS_VAR) {
6456
0
    if (!(val_info & MAY_BE_REF)) {
6457
0
      func = jit_stub_assign_tmp;
6458
0
    } else {
6459
0
      func = jit_stub_assign_var;
6460
0
    }
6461
0
  } else if (val_type == IS_CV) {
6462
0
    if (!(val_info & MAY_BE_REF)) {
6463
0
      func = jit_stub_assign_cv_noref;
6464
0
    } else {
6465
0
      func = jit_stub_assign_cv;
6466
0
    }
6467
0
  } else {
6468
0
    ZEND_UNREACHABLE();
6469
0
  }
6470
6471
0
  if (opline) {
6472
0
    jit_SET_EX_OPLINE(jit, opline);
6473
0
  }
6474
6475
0
  ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6476
0
    jit_ZVAL_ADDR(jit, var_addr),
6477
0
    jit_ZVAL_ADDR(jit, val_addr));
6478
6479
0
  if (undef_path) {
6480
0
    ir_MERGE_WITH(undef_path);
6481
0
  }
6482
6483
0
  return 1;
6484
0
}
6485
6486
static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
6487
                                       const zend_op  *opline,
6488
                                       zend_jit_addr   var_use_addr,
6489
                                       zend_jit_addr   var_addr,
6490
                                       uint32_t        var_info,
6491
                                       uint32_t        var_def_info,
6492
                                       uint8_t         val_type,
6493
                                       zend_jit_addr   val_addr,
6494
                                       uint32_t        val_info,
6495
                                       zend_jit_addr   res_addr,
6496
                                       zend_jit_addr   ref_addr,
6497
                                       bool       check_exception)
6498
0
{
6499
0
  ir_ref if_refcounted = IR_UNUSED;
6500
0
  ir_ref simple_inputs = IR_UNUSED;
6501
0
  bool done = false;
6502
0
  zend_jit_addr real_res_addr = 0;
6503
0
  ir_refs *end_inputs;
6504
0
  ir_refs *res_inputs;
6505
6506
0
  ir_refs_init(end_inputs, 6);
6507
0
  ir_refs_init(res_inputs, 6);
6508
6509
0
  if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6510
    /* Force load */
6511
0
    zend_jit_use_reg(jit, val_addr);
6512
0
  }
6513
6514
0
  if (Z_MODE(var_addr) == IS_REG) {
6515
0
    jit->delay_var = Z_SSA_VAR(var_addr);
6516
0
    jit->delay_refs = res_inputs;
6517
0
    if (Z_MODE(res_addr) == IS_REG) {
6518
0
      real_res_addr = res_addr;
6519
0
      res_addr = 0;
6520
0
    }
6521
0
  } else if (Z_MODE(res_addr) == IS_REG) {
6522
0
    jit->delay_var = Z_SSA_VAR(res_addr);
6523
0
    jit->delay_refs = res_inputs;
6524
0
  }
6525
6526
0
  if ((var_info & MAY_BE_REF) || ref_addr) {
6527
0
    ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6528
0
    uintptr_t func;
6529
6530
0
    if (!ref_addr) {
6531
0
      ref = jit_ZVAL_ADDR(jit, var_use_addr);
6532
0
      if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6533
0
      ir_IF_TRUE(if_ref);
6534
0
      ref2 = jit_Z_PTR_ref(jit, ref);
6535
0
    } else {
6536
0
      ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6537
0
    }
6538
0
    if_typed = jit_if_TYPED_REF(jit, ref2);
6539
0
    ir_IF_TRUE_cold(if_typed);
6540
0
    jit_SET_EX_OPLINE(jit, opline);
6541
0
    if (Z_MODE(val_addr) == IS_REG) {
6542
0
      zend_jit_addr real_addr;
6543
6544
0
      if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6545
0
        real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6546
0
      } else {
6547
0
        ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6548
0
        real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6549
0
      }
6550
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6551
0
        return 0;
6552
0
      }
6553
0
      arg2 = jit_ZVAL_ADDR(jit, real_addr);
6554
0
    } else {
6555
0
      arg2 = jit_ZVAL_ADDR(jit, val_addr);
6556
0
    }
6557
0
    if (!res_addr) {
6558
0
      if (val_type == IS_CONST) {
6559
0
        func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6560
0
      } else if (val_type == IS_TMP_VAR) {
6561
0
        func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6562
0
      } else if (val_type == IS_VAR) {
6563
0
        func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6564
0
      } else if (val_type == IS_CV) {
6565
0
        func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6566
0
      } else {
6567
0
        ZEND_UNREACHABLE();
6568
0
      }
6569
0
      ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6570
0
    } else {
6571
0
      if (val_type == IS_CONST) {
6572
0
        func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6573
0
      } else if (val_type == IS_TMP_VAR) {
6574
0
        func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6575
0
      } else if (val_type == IS_VAR) {
6576
0
        func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6577
0
      } else if (val_type == IS_CV) {
6578
0
        func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6579
0
      } else {
6580
0
        ZEND_UNREACHABLE();
6581
0
      }
6582
0
      ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6583
0
    }
6584
0
    if (check_exception) {
6585
0
      zend_jit_check_exception(jit);
6586
0
    }
6587
0
    ir_refs_add(end_inputs, ir_END());
6588
6589
0
    if (!ref_addr) {
6590
0
      ir_IF_FALSE(if_ref);
6591
0
      non_ref_path = ir_END();
6592
0
      ir_IF_FALSE(if_typed);
6593
0
      ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6594
0
      ir_MERGE_WITH(non_ref_path);
6595
0
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
6596
0
      var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6597
0
    } else {
6598
0
      ir_IF_FALSE(if_typed);
6599
0
    }
6600
0
  }
6601
6602
0
  if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6603
0
    ir_ref ref, counter, if_not_zero;
6604
6605
0
    if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6606
0
      if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6607
0
      ir_IF_FALSE(if_refcounted);
6608
0
      ir_END_list(simple_inputs);
6609
0
      ir_IF_TRUE_cold(if_refcounted);
6610
0
    } else if (RC_MAY_BE_1(var_info)) {
6611
0
      done = true;
6612
0
    }
6613
0
    ref = jit_Z_PTR(jit, var_use_addr);
6614
0
    if (RC_MAY_BE_1(var_info)) {
6615
0
      if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, false)) {
6616
0
        return 0;
6617
0
      }
6618
0
      counter = jit_GC_DELREF(jit, ref);
6619
6620
0
      if_not_zero = ir_IF(counter);
6621
0
      ir_IF_FALSE(if_not_zero);
6622
0
      jit_ZVAL_DTOR(jit, ref, var_info, opline);
6623
0
      if (check_exception) {
6624
0
        zend_jit_check_exception(jit);
6625
0
      }
6626
0
      ir_refs_add(end_inputs, ir_END());
6627
0
      ir_IF_TRUE(if_not_zero);
6628
0
      if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6629
0
        ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6630
0
        ir_IF_FALSE(if_may_leak);
6631
0
        if (opline) {
6632
0
          jit_SET_EX_OPLINE(jit, opline);
6633
0
        }
6634
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6635
6636
0
        if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6637
0
          ZEND_ASSERT(jit->delay_refs == res_inputs);
6638
0
          ZEND_ASSERT(res_inputs->count > 0);
6639
0
          ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6640
0
        }
6641
0
        if (check_exception && (val_info & MAY_BE_UNDEF)) {
6642
0
          zend_jit_check_exception(jit);
6643
0
        }
6644
0
        ir_refs_add(end_inputs, ir_END());
6645
0
        ir_IF_TRUE(if_may_leak);
6646
0
      }
6647
0
      if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6648
0
        ZEND_ASSERT(jit->delay_refs == res_inputs);
6649
0
        ZEND_ASSERT(res_inputs->count > 0);
6650
0
        ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6651
0
      }
6652
0
      if (check_exception && (val_info & MAY_BE_UNDEF)) {
6653
0
        zend_jit_check_exception(jit);
6654
0
      }
6655
0
      ir_refs_add(end_inputs, ir_END());
6656
0
    } else /* if (RC_MAY_BE_N(var_info)) */ {
6657
0
      jit_GC_DELREF(jit, ref);
6658
0
      if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6659
0
        ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6660
0
        ir_IF_FALSE(if_may_leak);
6661
0
        if (opline) {
6662
0
          jit_SET_EX_OPLINE(jit, opline);
6663
0
        }
6664
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6665
0
        ir_END_list(simple_inputs);
6666
0
        ir_IF_TRUE(if_may_leak);
6667
0
      }
6668
0
      ir_END_list(simple_inputs);
6669
0
    }
6670
0
  }
6671
6672
0
  if (simple_inputs) {
6673
0
    ir_MERGE_list(simple_inputs);
6674
0
  }
6675
6676
0
  if (!done) {
6677
0
    if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6678
0
      return 0;
6679
0
    }
6680
0
    if (end_inputs->count) {
6681
0
      ir_refs_add(end_inputs, ir_END());
6682
0
    }
6683
0
  }
6684
6685
0
  if (end_inputs->count) {
6686
0
    ir_MERGE_N(end_inputs->count, end_inputs->refs);
6687
0
  }
6688
6689
0
  if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6690
0
    ir_ref phi;
6691
6692
0
    ZEND_ASSERT(jit->delay_refs == res_inputs);
6693
0
    ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6694
0
    jit->delay_var = -1;
6695
0
    jit->delay_refs = NULL;
6696
0
    if (res_inputs->count == 1) {
6697
0
      phi = res_inputs->refs[0];
6698
0
    } else {
6699
0
      phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6700
0
        res_inputs->count, res_inputs->refs);
6701
0
    }
6702
0
    if (Z_MODE(var_addr) == IS_REG) {
6703
0
      if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6704
0
        phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6705
0
      }
6706
0
      zend_jit_def_reg(jit, var_addr, phi);
6707
0
      if (real_res_addr) {
6708
0
        if (var_def_info & MAY_BE_LONG) {
6709
0
          jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6710
0
        } else {
6711
0
          jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6712
0
        }
6713
0
      }
6714
0
    } else {
6715
0
      zend_jit_def_reg(jit, res_addr, phi);
6716
0
    }
6717
0
  }
6718
6719
0
  return 1;
6720
0
}
6721
6722
static int zend_jit_qm_assign(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr)
6723
0
{
6724
0
  if (op1_addr != op1_def_addr) {
6725
0
    if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6726
0
      return 0;
6727
0
    }
6728
0
    if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6729
0
      op1_addr = op1_def_addr;
6730
0
    }
6731
0
  }
6732
6733
0
  if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, true)) {
6734
0
    return 0;
6735
0
  }
6736
0
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6737
0
    return 0;
6738
0
  }
6739
0
  return 1;
6740
0
}
6741
6742
static int zend_jit_assign(zend_jit_ctx  *jit,
6743
                           const zend_op *opline,
6744
                           uint32_t       op1_info,
6745
                           zend_jit_addr  op1_use_addr,
6746
                           uint32_t       op1_def_info,
6747
                           zend_jit_addr  op1_addr,
6748
                           uint32_t       op2_info,
6749
                           zend_jit_addr  op2_addr,
6750
                           zend_jit_addr  op2_def_addr,
6751
                           uint32_t       res_info,
6752
                           zend_jit_addr  res_addr,
6753
                           zend_jit_addr  ref_addr,
6754
                           int            may_throw)
6755
0
{
6756
0
  ZEND_ASSERT(opline->op1_type == IS_CV);
6757
6758
0
  if (op2_addr != op2_def_addr) {
6759
0
    if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6760
0
      return 0;
6761
0
    }
6762
0
    if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6763
0
      op2_addr = op2_def_addr;
6764
0
    }
6765
0
  }
6766
6767
0
  if (Z_MODE(op1_addr) != IS_REG
6768
0
   && Z_MODE(op1_use_addr) == IS_REG
6769
0
   && !Z_LOAD(op1_use_addr)
6770
0
   && !Z_STORE(op1_use_addr)) {
6771
    /* Force type update */
6772
0
    op1_info |= MAY_BE_UNDEF;
6773
0
  }
6774
0
  if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6775
0
      opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6776
0
    return 0;
6777
0
  }
6778
0
  if (Z_MODE(op1_addr) == IS_REG) {
6779
0
    if (Z_STORE(op1_addr)) {
6780
0
      if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6781
0
        return 0;
6782
0
      }
6783
0
    } else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6784
0
      && Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6785
0
      && Z_REG(op1_use_addr) == ZREG_FP
6786
0
      && EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6787
      /* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6788
0
      if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6789
0
        jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6790
0
        if (JIT_G(current_frame)) {
6791
0
          SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6792
0
        }
6793
0
      } else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6794
0
        jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6795
0
        if (JIT_G(current_frame)) {
6796
0
          SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6797
0
        }
6798
0
      } else {
6799
0
        ZEND_UNREACHABLE();
6800
0
      }
6801
0
    }
6802
0
  }
6803
0
  if (opline->result_type != IS_UNUSED) {
6804
0
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6805
0
      return 0;
6806
0
    }
6807
0
  }
6808
6809
0
  return 1;
6810
0
}
6811
6812
static ir_op zend_jit_cmp_op(const zend_op *opline)
6813
0
{
6814
0
  ir_op op;
6815
6816
0
  switch (opline->opcode) {
6817
0
    case ZEND_IS_EQUAL:
6818
0
    case ZEND_IS_IDENTICAL:
6819
0
    case ZEND_CASE:
6820
0
    case ZEND_CASE_STRICT:
6821
0
      op = IR_EQ;
6822
0
      break;
6823
0
    case ZEND_IS_NOT_EQUAL:
6824
0
    case ZEND_IS_NOT_IDENTICAL:
6825
0
      op = IR_NE;
6826
0
      break;
6827
0
    case ZEND_IS_SMALLER:
6828
0
      op = IR_LT;
6829
0
      break;
6830
0
    case ZEND_IS_SMALLER_OR_EQUAL:
6831
0
      op = IR_LE;
6832
0
      break;
6833
0
    default:
6834
0
      ZEND_UNREACHABLE();
6835
0
  }
6836
0
  return op;
6837
0
}
6838
6839
static ir_ref zend_jit_cmp_long_long(zend_jit_ctx   *jit,
6840
                                     const zend_op  *opline,
6841
                                     zend_ssa_range *op1_range,
6842
                                     zend_jit_addr   op1_addr,
6843
                                     zend_ssa_range *op2_range,
6844
                                     zend_jit_addr   op2_addr,
6845
                                     zend_jit_addr   res_addr,
6846
                                     uint8_t         smart_branch_opcode,
6847
                                     uint32_t        target_label,
6848
                                     uint32_t        target_label2,
6849
                                     const void     *exit_addr,
6850
                                     bool       skip_comparison)
6851
0
{
6852
0
  ir_ref ref;
6853
0
  bool result;
6854
6855
0
  if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6856
0
    if (!smart_branch_opcode ||
6857
0
        smart_branch_opcode == ZEND_JMPZ_EX ||
6858
0
        smart_branch_opcode == ZEND_JMPNZ_EX) {
6859
0
      jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6860
0
    }
6861
0
    if (smart_branch_opcode && !exit_addr) {
6862
0
      if (smart_branch_opcode == ZEND_JMPZ ||
6863
0
          smart_branch_opcode == ZEND_JMPZ_EX) {
6864
0
        return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6865
0
      } else if (smart_branch_opcode == ZEND_JMPNZ ||
6866
0
                 smart_branch_opcode == ZEND_JMPNZ_EX) {
6867
0
        return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6868
0
      } else {
6869
0
        ZEND_UNREACHABLE();
6870
0
      }
6871
0
    }
6872
0
    if (opline->opcode != ZEND_IS_IDENTICAL
6873
0
     && opline->opcode != ZEND_IS_NOT_IDENTICAL
6874
0
     && opline->opcode != ZEND_CASE_STRICT) {
6875
0
      return ir_END();
6876
0
    } else {
6877
0
      return IR_NULL; /* success */
6878
0
    }
6879
0
  }
6880
6881
0
  ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6882
6883
0
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6884
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6885
0
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6886
0
  }
6887
0
  if (exit_addr) {
6888
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6889
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6890
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6891
0
      } else {
6892
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6893
0
      }
6894
0
    } else {
6895
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6896
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6897
0
      } else {
6898
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6899
0
      }
6900
0
    }
6901
0
  } else if (smart_branch_opcode) {
6902
0
    return jit_IF_ex(jit, ref,
6903
0
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6904
0
  }
6905
6906
0
  if (opline->opcode != ZEND_IS_IDENTICAL
6907
0
   && opline->opcode != ZEND_IS_NOT_IDENTICAL
6908
0
   && opline->opcode != ZEND_CASE_STRICT) {
6909
0
    return ir_END();
6910
0
  } else {
6911
0
    return IR_NULL; /* success */
6912
0
  }
6913
0
}
6914
6915
static ir_ref zend_jit_cmp_long_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6916
0
{
6917
0
  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));
6918
6919
0
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6920
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6921
0
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6922
0
  }
6923
0
  if (exit_addr) {
6924
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6925
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6926
0
    } else {
6927
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6928
0
    }
6929
0
  } else if (smart_branch_opcode) {
6930
0
    return jit_IF_ex(jit, ref,
6931
0
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6932
0
  }
6933
0
  return ir_END();
6934
0
}
6935
6936
static ir_ref zend_jit_cmp_double_long(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6937
0
{
6938
0
  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)));
6939
6940
0
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6941
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6942
0
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6943
0
  }
6944
0
  if (exit_addr) {
6945
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6946
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6947
0
    } else {
6948
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6949
0
    }
6950
0
  } else if (smart_branch_opcode) {
6951
0
    return jit_IF_ex(jit, ref,
6952
0
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6953
0
  }
6954
0
  return ir_END();
6955
0
}
6956
6957
static ir_ref zend_jit_cmp_double_double(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6958
0
{
6959
0
  ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6960
6961
0
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6962
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6963
0
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6964
0
  }
6965
0
  if (exit_addr) {
6966
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6967
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6968
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6969
0
      } else {
6970
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6971
0
      }
6972
0
    } else {
6973
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6974
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6975
0
      } else {
6976
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6977
0
      }
6978
0
    }
6979
0
  } else if (smart_branch_opcode) {
6980
0
    return jit_IF_ex(jit, ref,
6981
0
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6982
0
  }
6983
0
  if (opline->opcode != ZEND_IS_IDENTICAL
6984
0
   && opline->opcode != ZEND_IS_NOT_IDENTICAL
6985
0
   && opline->opcode != ZEND_CASE_STRICT) {
6986
0
    return ir_END();
6987
0
  } else {
6988
0
    return IR_NULL; /* success */
6989
0
  }
6990
0
}
6991
6992
static ir_ref zend_jit_cmp_slow(zend_jit_ctx *jit, ir_ref ref, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
6993
0
{
6994
0
  ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
6995
6996
0
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6997
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6998
0
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6999
0
  }
7000
0
  if (exit_addr) {
7001
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7002
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7003
0
    } else {
7004
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7005
0
    }
7006
0
  } else if (smart_branch_opcode) {
7007
0
    return jit_IF_ex(jit, ref,
7008
0
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7009
0
  }
7010
7011
0
  return ir_END();
7012
0
}
7013
7014
static int zend_jit_cmp(zend_jit_ctx   *jit,
7015
                        const zend_op  *opline,
7016
                        uint32_t        op1_info,
7017
                        zend_ssa_range *op1_range,
7018
                        zend_jit_addr   op1_addr,
7019
                        uint32_t        op2_info,
7020
                        zend_ssa_range *op2_range,
7021
                        zend_jit_addr   op2_addr,
7022
                        zend_jit_addr   res_addr,
7023
                        int             may_throw,
7024
                        uint8_t         smart_branch_opcode,
7025
                        uint32_t        target_label,
7026
                        uint32_t        target_label2,
7027
                        const void     *exit_addr,
7028
                        bool       skip_comparison)
7029
0
{
7030
0
  ir_ref ref = IR_UNUSED;
7031
0
  ir_ref if_op1_long = IR_UNUSED;
7032
0
  ir_ref if_op1_double = IR_UNUSED;
7033
0
  ir_ref if_op2_double = IR_UNUSED;
7034
0
  ir_ref if_op1_long_op2_long = IR_UNUSED;
7035
0
  ir_ref if_op1_long_op2_double = IR_UNUSED;
7036
0
  ir_ref if_op1_double_op2_double = IR_UNUSED;
7037
0
  ir_ref if_op1_double_op2_long = IR_UNUSED;
7038
0
  ir_ref slow_inputs = IR_UNUSED;
7039
0
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
7040
0
  bool has_slow =
7041
0
    (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7042
0
    (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7043
0
    ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7044
0
     (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
7045
0
  ir_refs *end_inputs;
7046
7047
0
  ir_refs_init(end_inputs, 8);
7048
7049
0
  if (Z_MODE(op1_addr) == IS_REG) {
7050
0
    if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
7051
      /* Force load */
7052
0
      zend_jit_use_reg(jit, op1_addr);
7053
0
    }
7054
0
  } else if (Z_MODE(op2_addr) == IS_REG) {
7055
0
    if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
7056
      /* Force load */
7057
0
      zend_jit_use_reg(jit, op2_addr);
7058
0
    }
7059
0
  }
7060
7061
0
  if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
7062
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
7063
0
      if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7064
0
      ir_IF_TRUE(if_op1_long);
7065
0
    }
7066
0
    if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
7067
0
      if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7068
0
      ir_IF_FALSE_cold(if_op1_long_op2_long);
7069
0
      if (op2_info & MAY_BE_DOUBLE) {
7070
0
        if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7071
0
          if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7072
0
          ir_IF_FALSE_cold(if_op1_long_op2_double);
7073
0
          ir_END_list(slow_inputs);
7074
0
          ir_IF_TRUE(if_op1_long_op2_double);
7075
0
        }
7076
0
        ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7077
0
        if (!ref) {
7078
0
          return 0;
7079
0
        }
7080
0
        ir_refs_add(end_inputs, ref);
7081
0
      } else {
7082
0
        ir_END_list(slow_inputs);
7083
0
      }
7084
0
      ir_IF_TRUE(if_op1_long_op2_long);
7085
0
    }
7086
0
    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);
7087
0
    if (!ref) {
7088
0
      return 0;
7089
0
    }
7090
0
    ir_refs_add(end_inputs, ref);
7091
7092
0
    if (if_op1_long) {
7093
0
      ir_IF_FALSE_cold(if_op1_long);
7094
0
    }
7095
0
    if (op1_info & MAY_BE_DOUBLE) {
7096
0
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7097
0
        if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7098
0
        ir_IF_FALSE_cold(if_op1_double);
7099
0
        ir_END_list(slow_inputs);
7100
0
        ir_IF_TRUE(if_op1_double);
7101
0
      }
7102
0
      if (op2_info & MAY_BE_DOUBLE) {
7103
0
        if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7104
0
          if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7105
0
          ir_IF_TRUE(if_op1_double_op2_double);
7106
0
        }
7107
0
        ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7108
0
        if (!ref) {
7109
0
          return 0;
7110
0
        }
7111
0
        ir_refs_add(end_inputs, ref);
7112
0
        if (if_op1_double_op2_double) {
7113
0
          ir_IF_FALSE_cold(if_op1_double_op2_double);
7114
0
        }
7115
0
      }
7116
0
      if (!same_ops) {
7117
0
        if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7118
0
          if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7119
0
          ir_IF_FALSE_cold(if_op1_double_op2_long);
7120
0
          ir_END_list(slow_inputs);
7121
0
          ir_IF_TRUE(if_op1_double_op2_long);
7122
0
        }
7123
0
        ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7124
0
        if (!ref) {
7125
0
          return 0;
7126
0
        }
7127
0
        ir_refs_add(end_inputs, ref);
7128
0
      } else if (if_op1_double_op2_double) {
7129
0
        ir_END_list(slow_inputs);
7130
0
      }
7131
0
    } else if (if_op1_long) {
7132
0
      ir_END_list(slow_inputs);
7133
0
    }
7134
0
  } else if ((op1_info & MAY_BE_DOUBLE) &&
7135
0
             !(op1_info & MAY_BE_LONG) &&
7136
0
             (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7137
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7138
0
      if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7139
0
      ir_IF_FALSE_cold(if_op1_double);
7140
0
      ir_END_list(slow_inputs);
7141
0
      ir_IF_TRUE(if_op1_double);
7142
0
    }
7143
0
    if (op2_info & MAY_BE_DOUBLE) {
7144
0
      if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7145
0
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7146
0
        ir_IF_TRUE(if_op1_double_op2_double);
7147
0
      }
7148
0
      ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7149
0
      if (!ref) {
7150
0
        return 0;
7151
0
      }
7152
0
      ir_refs_add(end_inputs, ref);
7153
0
      if (if_op1_double_op2_double) {
7154
0
        ir_IF_FALSE_cold(if_op1_double_op2_double);
7155
0
      }
7156
0
    }
7157
0
    if (!same_ops && (op2_info & MAY_BE_LONG)) {
7158
0
      if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7159
0
        if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7160
0
        ir_IF_FALSE_cold(if_op1_double_op2_long);
7161
0
        ir_END_list(slow_inputs);
7162
0
        ir_IF_TRUE(if_op1_double_op2_long);
7163
0
      }
7164
0
      ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7165
0
      if (!ref) {
7166
0
        return 0;
7167
0
      }
7168
0
      ir_refs_add(end_inputs, ref);
7169
0
    } else if (if_op1_double_op2_double) {
7170
0
      ir_END_list(slow_inputs);
7171
0
    }
7172
0
  } else if ((op2_info & MAY_BE_DOUBLE) &&
7173
0
             !(op2_info & MAY_BE_LONG) &&
7174
0
             (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7175
0
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7176
0
      if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7177
0
      ir_IF_FALSE_cold(if_op2_double);
7178
0
      ir_END_list(slow_inputs);
7179
0
      ir_IF_TRUE(if_op2_double);
7180
0
    }
7181
0
    if (op1_info & MAY_BE_DOUBLE) {
7182
0
      if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7183
0
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7184
0
        ir_IF_TRUE(if_op1_double_op2_double);
7185
0
      }
7186
0
      ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7187
0
      if (!ref) {
7188
0
        return 0;
7189
0
      }
7190
0
      ir_refs_add(end_inputs, ref);
7191
0
      if (if_op1_double_op2_double) {
7192
0
        ir_IF_FALSE_cold(if_op1_double_op2_double);
7193
0
      }
7194
0
    }
7195
0
    if (!same_ops && (op1_info & MAY_BE_LONG)) {
7196
0
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7197
0
        if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7198
0
        ir_IF_FALSE_cold(if_op1_long_op2_double);
7199
0
        ir_END_list(slow_inputs);
7200
0
        ir_IF_TRUE(if_op1_long_op2_double);
7201
0
      }
7202
0
      ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7203
0
      if (!ref) {
7204
0
        return 0;
7205
0
      }
7206
0
      ir_refs_add(end_inputs, ref);
7207
0
    } else if (if_op1_double_op2_double) {
7208
0
      ir_END_list(slow_inputs);
7209
0
    }
7210
0
  }
7211
7212
0
  if (has_slow ||
7213
0
      (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7214
0
      (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7215
0
      ir_ref op1, op2, ref;
7216
7217
0
    if (slow_inputs) {
7218
0
      ir_MERGE_list(slow_inputs);
7219
0
    }
7220
0
    jit_SET_EX_OPLINE(jit, opline);
7221
7222
0
    if (Z_MODE(op1_addr) == IS_REG) {
7223
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7224
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7225
0
        return 0;
7226
0
      }
7227
0
      op1_addr = real_addr;
7228
0
    }
7229
0
    if (Z_MODE(op2_addr) == IS_REG) {
7230
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7231
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7232
0
        return 0;
7233
0
      }
7234
0
      op2_addr = real_addr;
7235
0
    }
7236
7237
0
    op1 = jit_ZVAL_ADDR(jit, op1_addr);
7238
0
    if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7239
0
      op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, false);
7240
0
    }
7241
0
    op2 = jit_ZVAL_ADDR(jit, op2_addr);
7242
0
    if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7243
0
      op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, false);
7244
0
    }
7245
0
    ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7246
0
    if (opline->opcode != ZEND_CASE) {
7247
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7248
0
    }
7249
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7250
0
    if (may_throw) {
7251
0
      zend_jit_check_exception_undef_result(jit, opline);
7252
0
    }
7253
7254
0
    ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7255
0
    if (!ref) {
7256
0
      return 0;
7257
0
    }
7258
0
    ir_refs_add(end_inputs, ref);
7259
0
  }
7260
7261
0
  if (end_inputs->count) {
7262
0
    uint32_t n = end_inputs->count;
7263
7264
0
    if (smart_branch_opcode && !exit_addr) {
7265
0
      zend_basic_block *bb;
7266
0
      ir_ref ref;
7267
0
      uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7268
0
        target_label2 : target_label;
7269
0
      uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7270
0
        target_label : target_label2;
7271
7272
0
      ZEND_ASSERT(jit->b >= 0);
7273
0
      bb = &jit->ssa->cfg.blocks[jit->b];
7274
0
      ZEND_ASSERT(bb->successors_count == 2);
7275
7276
0
      if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7277
0
        ir_ref merge_inputs = IR_UNUSED;
7278
7279
0
        while (n) {
7280
0
          n--;
7281
0
          ir_IF_TRUE(end_inputs->refs[n]);
7282
0
          ir_END_list(merge_inputs);
7283
0
          ir_IF_FALSE(end_inputs->refs[n]);
7284
0
          ir_END_list(merge_inputs);
7285
0
        }
7286
0
        ir_MERGE_list(merge_inputs);
7287
0
        _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7288
0
      } else if (n == 1) {
7289
0
        ref = end_inputs->refs[0];
7290
0
        _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7291
0
        _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7292
0
      } else {
7293
0
        ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7294
7295
0
        while (n) {
7296
0
          n--;
7297
0
          jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label);
7298
0
          ir_END_list(true_inputs);
7299
0
          jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label2);
7300
0
          ir_END_list(false_inputs);
7301
0
        }
7302
0
        ir_MERGE_list(true_inputs);
7303
0
        _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7304
0
        ir_MERGE_list(false_inputs);
7305
0
        _zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7306
0
      }
7307
0
      jit->b = -1;
7308
0
    } else {
7309
0
      ir_MERGE_N(n, end_inputs->refs);
7310
0
    }
7311
0
  } else if (smart_branch_opcode && !exit_addr) {
7312
    /* dead code */
7313
0
    _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7314
0
    jit->b = -1;
7315
0
  }
7316
7317
0
  return 1;
7318
0
}
7319
7320
static int zend_jit_identical(zend_jit_ctx   *jit,
7321
                              const zend_op  *opline,
7322
                              uint32_t        op1_info,
7323
                              zend_ssa_range *op1_range,
7324
                              zend_jit_addr   op1_addr,
7325
                              uint32_t        op2_info,
7326
                              zend_ssa_range *op2_range,
7327
                              zend_jit_addr   op2_addr,
7328
                              zend_jit_addr   res_addr,
7329
                              int             may_throw,
7330
                              uint8_t         smart_branch_opcode,
7331
                              uint32_t        target_label,
7332
                              uint32_t        target_label2,
7333
                              const void     *exit_addr,
7334
                              bool       skip_comparison)
7335
0
{
7336
0
  bool always_false = false, always_true = false;
7337
0
  ir_ref ref = IR_UNUSED;
7338
7339
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7340
0
    ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7341
0
    op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, false);
7342
0
    op1_info |= MAY_BE_NULL;
7343
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7344
0
  }
7345
0
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7346
0
    ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7347
0
    op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, false);
7348
0
    op2_info |= MAY_BE_NULL;
7349
0
    op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7350
0
  }
7351
7352
0
  if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7353
0
    always_false = true;
7354
0
  } else if (has_concrete_type(op1_info)
7355
0
   && has_concrete_type(op2_info)
7356
0
   && concrete_type(op1_info) == concrete_type(op2_info)
7357
0
   && concrete_type(op1_info) <= IS_TRUE) {
7358
0
    always_true = true;
7359
0
  } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7360
0
    if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7361
0
      always_true = true;
7362
0
    } else {
7363
0
      always_false = true;
7364
0
    }
7365
0
  }
7366
7367
0
  if (always_true) {
7368
0
    if (opline->opcode != ZEND_CASE_STRICT) {
7369
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7370
0
    }
7371
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7372
0
    if (!smart_branch_opcode
7373
0
     || smart_branch_opcode == ZEND_JMPZ_EX
7374
0
     || smart_branch_opcode == ZEND_JMPNZ_EX) {
7375
0
      jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7376
0
    }
7377
0
    if (may_throw) {
7378
0
      zend_jit_check_exception(jit);
7379
0
    }
7380
0
    if (exit_addr) {
7381
0
      if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7382
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7383
0
      }
7384
0
    } else if (smart_branch_opcode) {
7385
0
      uint32_t label;
7386
7387
0
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7388
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7389
0
          target_label : target_label2;
7390
0
      } else {
7391
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7392
0
          target_label2 : target_label;
7393
0
      }
7394
0
      _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7395
0
      jit->b = -1;
7396
0
    }
7397
0
    return 1;
7398
0
  } else if (always_false) {
7399
0
    if (opline->opcode != ZEND_CASE_STRICT) {
7400
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7401
0
    }
7402
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7403
0
    if (!smart_branch_opcode
7404
0
     || smart_branch_opcode == ZEND_JMPZ_EX
7405
0
     || smart_branch_opcode == ZEND_JMPNZ_EX) {
7406
0
      jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7407
0
    }
7408
0
    if (may_throw) {
7409
0
      zend_jit_check_exception(jit);
7410
0
    }
7411
0
    if (exit_addr) {
7412
0
      if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7413
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7414
0
      }
7415
0
    } else if (smart_branch_opcode) {
7416
0
      uint32_t label;
7417
7418
0
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7419
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7420
0
          target_label2 : target_label;
7421
0
      } else {
7422
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7423
0
          target_label : target_label2;
7424
0
      }
7425
0
      _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7426
0
      jit->b = -1;
7427
0
    }
7428
0
    return 1;
7429
0
  }
7430
7431
0
  if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7432
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
7433
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7434
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7435
0
  }
7436
0
  if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7437
0
    ref = jit_ZVAL_ADDR(jit, op2_addr);
7438
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7439
0
    op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7440
0
  }
7441
7442
0
  if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7443
0
      (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7444
0
    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);
7445
0
    if (!ref) {
7446
0
      return 0;
7447
0
    }
7448
0
  } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7449
0
             (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7450
0
    ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7451
0
    if (!ref) {
7452
0
      return 0;
7453
0
    }
7454
0
  } else {
7455
0
    if (opline->op1_type != IS_CONST) {
7456
0
      if (Z_MODE(op1_addr) == IS_REG) {
7457
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7458
0
        if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7459
0
          return 0;
7460
0
        }
7461
0
        op1_addr = real_addr;
7462
0
      }
7463
0
    }
7464
0
    if (opline->op2_type != IS_CONST) {
7465
0
      if (Z_MODE(op2_addr) == IS_REG) {
7466
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7467
0
        if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7468
0
          return 0;
7469
0
        }
7470
0
      }
7471
0
    }
7472
7473
0
    if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7474
0
      zval *val = Z_ZV(op1_addr);
7475
7476
0
      ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7477
0
    } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7478
0
      zval *val = Z_ZV(op2_addr);
7479
7480
0
      ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7481
0
    } else {
7482
0
      if (Z_MODE(op1_addr) == IS_REG) {
7483
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7484
0
        if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7485
0
          return 0;
7486
0
        }
7487
0
        op1_addr = real_addr;
7488
0
      }
7489
0
      if (Z_MODE(op2_addr) == IS_REG) {
7490
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7491
0
        if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7492
0
          return 0;
7493
0
        }
7494
0
        op2_addr = real_addr;
7495
0
      }
7496
0
      if (may_throw) {
7497
0
        jit_SET_EX_OPLINE(jit, opline);
7498
0
      }
7499
7500
0
      ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7501
0
        jit_ZVAL_ADDR(jit, op1_addr),
7502
0
        jit_ZVAL_ADDR(jit, op2_addr));
7503
0
    }
7504
7505
0
    if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7506
0
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7507
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7508
0
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7509
0
      } else {
7510
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7511
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7512
0
      }
7513
0
    }
7514
0
    if (opline->opcode != ZEND_CASE_STRICT) {
7515
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7516
0
    }
7517
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7518
0
    if (may_throw) {
7519
0
      zend_jit_check_exception_undef_result(jit, opline);
7520
0
    }
7521
0
    if (exit_addr) {
7522
0
      if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7523
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7524
0
      } else {
7525
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7526
0
      }
7527
0
    } else if (smart_branch_opcode) {
7528
0
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7529
        /* swap labels */
7530
0
        uint32_t tmp = target_label;
7531
0
        target_label = target_label2;
7532
0
        target_label2 = tmp;
7533
0
      }
7534
0
      ref = jit_IF_ex(jit, ref,
7535
0
        (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7536
0
    }
7537
0
  }
7538
7539
0
  if (smart_branch_opcode && !exit_addr) {
7540
0
    zend_basic_block *bb;
7541
7542
0
    ZEND_ASSERT(jit->b >= 0);
7543
0
    bb = &jit->ssa->cfg.blocks[jit->b];
7544
0
    ZEND_ASSERT(bb->successors_count == 2);
7545
7546
0
    if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7547
0
      ir_IF_TRUE(ref);
7548
0
      ir_MERGE_WITH_EMPTY_FALSE(ref);
7549
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7550
0
    } else {
7551
0
      ZEND_ASSERT(bb->successors_count == 2);
7552
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7553
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7554
0
    }
7555
0
    jit->b = -1;
7556
0
  }
7557
7558
0
  return 1;
7559
0
}
7560
7561
static int zend_jit_bool_jmpznz(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr)
7562
0
{
7563
0
  uint32_t true_label = -1;
7564
0
  uint32_t false_label = -1;
7565
0
  bool set_bool = false;
7566
0
  bool set_bool_not = false;
7567
0
  bool always_true = false, always_false = false;
7568
0
  ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7569
0
  ir_type type = IR_UNUSED;
7570
7571
0
  if (branch_opcode == ZEND_BOOL) {
7572
0
    set_bool = true;
7573
0
  } else if (branch_opcode == ZEND_BOOL_NOT) {
7574
0
    set_bool = true;
7575
0
    set_bool_not = true;
7576
0
  } else if (branch_opcode == ZEND_JMPZ) {
7577
0
    true_label = target_label2;
7578
0
    false_label = target_label;
7579
0
  } else if (branch_opcode == ZEND_JMPNZ) {
7580
0
    true_label = target_label;
7581
0
    false_label = target_label2;
7582
0
  } else if (branch_opcode == ZEND_JMPZ_EX) {
7583
0
    set_bool = true;
7584
0
    true_label = target_label2;
7585
0
    false_label = target_label;
7586
0
  } else if (branch_opcode == ZEND_JMPNZ_EX) {
7587
0
    set_bool = true;
7588
0
    true_label = target_label;
7589
0
    false_label = target_label2;
7590
0
  } else {
7591
0
    ZEND_UNREACHABLE();
7592
0
  }
7593
7594
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7595
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
7596
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7597
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7598
0
  }
7599
7600
0
  if (Z_MODE(op1_addr) == IS_CONST_ZVAL
7601
    /* NAN Value must cause a warning to be emitted */
7602
0
    && (Z_TYPE_P(Z_ZV(op1_addr)) != IS_DOUBLE || !zend_isnan(Z_DVAL_P(Z_ZV(op1_addr))))) {
7603
0
    if (zend_is_true(Z_ZV(op1_addr))) {
7604
0
      always_true = true;
7605
0
    } else {
7606
0
      always_false = true;
7607
0
    }
7608
0
  } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7609
0
    if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7610
0
      always_true = true;
7611
0
    } else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7612
0
      if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7613
0
        ref = jit_ZVAL_ADDR(jit, op1_addr);
7614
0
        zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, false);
7615
0
      }
7616
0
      always_false = true;
7617
0
    }
7618
0
  }
7619
7620
0
  if (always_true) {
7621
0
    if (set_bool) {
7622
0
      jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7623
0
    }
7624
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7625
0
    if (may_throw) {
7626
0
      zend_jit_check_exception(jit);
7627
0
    }
7628
0
    if (true_label != (uint32_t)-1) {
7629
0
      ZEND_ASSERT(exit_addr == NULL);
7630
0
      _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7631
0
      jit->b = -1;
7632
0
    }
7633
0
    return 1;
7634
0
  } else if (always_false) {
7635
0
    if (set_bool) {
7636
0
      jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7637
0
    }
7638
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7639
0
    if (may_throw) {
7640
0
      zend_jit_check_exception(jit);
7641
0
    }
7642
0
    if (false_label != (uint32_t)-1) {
7643
0
      ZEND_ASSERT(exit_addr == NULL);
7644
0
      _zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7645
0
      jit->b = -1;
7646
0
    }
7647
0
    return 1;
7648
0
  }
7649
7650
0
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7651
0
    type = jit_Z_TYPE(jit, op1_addr);
7652
0
    if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7653
0
      ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7654
7655
0
      ir_IF_TRUE_cold(if_type);
7656
7657
0
      if (op1_info & MAY_BE_UNDEF) {
7658
0
        zend_jit_type_check_undef(jit,
7659
0
          type,
7660
0
          opline->op1.var,
7661
0
          opline, true, false, true);
7662
0
      }
7663
0
      if (set_bool) {
7664
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7665
0
      }
7666
0
      if (exit_addr) {
7667
0
        if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) {
7668
0
          ir_END_list(end_inputs);
7669
0
        } else {
7670
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7671
0
        }
7672
0
      } else if (false_label != (uint32_t)-1) {
7673
0
        ir_END_list(false_inputs);
7674
0
      } else {
7675
0
        ir_END_list(end_inputs);
7676
0
      }
7677
0
      ir_IF_FALSE(if_type);
7678
0
    }
7679
7680
0
    if (op1_info & MAY_BE_TRUE) {
7681
0
      ir_ref if_type = IR_UNUSED;
7682
7683
0
      if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7684
0
        if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7685
7686
0
        ir_IF_TRUE(if_type);
7687
0
      }
7688
0
      if (set_bool) {
7689
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7690
0
      }
7691
0
      if (exit_addr) {
7692
0
        if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7693
0
          ir_END_list(end_inputs);
7694
0
        } else {
7695
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7696
0
        }
7697
0
      } else if (true_label != (uint32_t)-1) {
7698
0
        ir_END_list(true_inputs);
7699
0
      } else {
7700
0
        ir_END_list(end_inputs);
7701
0
      }
7702
0
      if (if_type) {
7703
0
        ir_IF_FALSE(if_type);
7704
0
      }
7705
0
    }
7706
0
  }
7707
7708
0
  if (op1_info & MAY_BE_LONG) {
7709
0
    ir_ref if_long = IR_UNUSED;
7710
0
    ir_ref ref;
7711
7712
0
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7713
0
      if (!type) {
7714
0
        type = jit_Z_TYPE(jit, op1_addr);
7715
0
      }
7716
0
      if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7717
0
      ir_IF_TRUE(if_long);
7718
0
    }
7719
0
    ref = jit_Z_LVAL(jit, op1_addr);
7720
0
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7721
0
      ref = ir_NE(ref, ir_CONST_LONG(0));
7722
0
      if (set_bool_not) {
7723
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7724
0
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7725
0
      } else {
7726
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7727
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7728
0
      }
7729
0
      ir_END_list(end_inputs);
7730
0
    } else if (exit_addr) {
7731
0
      if (set_bool) {
7732
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7733
0
          ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7734
0
      }
7735
0
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7736
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7737
0
      } else {
7738
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7739
0
      }
7740
0
      ir_END_list(end_inputs);
7741
0
    } else {
7742
0
      ir_ref if_val = ir_IF(ref);
7743
0
      ir_IF_TRUE(if_val);
7744
0
      if (set_bool) {
7745
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7746
0
      }
7747
0
      ir_END_list(true_inputs);
7748
0
      ir_IF_FALSE(if_val);
7749
0
      if (set_bool) {
7750
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7751
0
      }
7752
0
      ir_END_list(false_inputs);
7753
0
    }
7754
0
    if (if_long) {
7755
0
      ir_IF_FALSE(if_long);
7756
0
    }
7757
0
  }
7758
7759
0
  if (op1_info & MAY_BE_DOUBLE) {
7760
0
    ir_ref if_double = IR_UNUSED;
7761
0
    ir_ref ref;
7762
7763
0
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7764
0
      if (!type) {
7765
0
        type = jit_Z_TYPE(jit, op1_addr);
7766
0
      }
7767
0
      if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7768
0
      ir_IF_TRUE(if_double);
7769
0
    }
7770
7771
0
    ir_ref dval = jit_Z_DVAL(jit, op1_addr);
7772
0
    ir_ref is_nan = ir_NE(dval, dval);
7773
0
    ir_ref if_val = ir_IF(is_nan);
7774
0
    ir_IF_TRUE_cold(if_val);
7775
0
    jit_SET_EX_OPLINE(jit, opline);
7776
0
    ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_nan_coerced_to_type_warning));
7777
0
    ir_MERGE_WITH_EMPTY_FALSE(if_val);
7778
7779
0
    ref = ir_NE(dval, ir_CONST_DOUBLE(0.0));
7780
0
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7781
0
      if (set_bool_not) {
7782
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7783
0
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7784
0
      } else {
7785
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7786
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7787
0
      }
7788
0
      ir_END_list(end_inputs);
7789
0
    } else if (exit_addr) {
7790
0
        if (set_bool) {
7791
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7792
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7793
0
        }
7794
0
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7795
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7796
0
      } else {
7797
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7798
0
      }
7799
0
      ir_END_list(end_inputs);
7800
0
    } else {
7801
0
      ir_ref if_val = ir_IF(ref);
7802
0
      ir_IF_TRUE(if_val);
7803
0
      if (set_bool) {
7804
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7805
0
      }
7806
0
      ir_END_list(true_inputs);
7807
0
      ir_IF_FALSE(if_val);
7808
0
      if (set_bool) {
7809
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7810
0
      }
7811
0
      ir_END_list(false_inputs);
7812
0
    }
7813
0
    if (if_double) {
7814
0
      ir_IF_FALSE(if_double);
7815
0
    }
7816
0
  }
7817
7818
0
  if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7819
0
    jit_SET_EX_OPLINE(jit, opline);
7820
0
    ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7821
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7822
0
    if (may_throw) {
7823
0
      zend_jit_check_exception_undef_result(jit, opline);
7824
0
    }
7825
0
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7826
0
      if (set_bool_not) {
7827
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7828
0
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7829
0
      } else {
7830
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7831
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7832
0
      }
7833
0
      if (end_inputs) {
7834
0
        ir_END_list(end_inputs);
7835
0
      }
7836
0
    } else if (exit_addr) {
7837
0
      if (set_bool) {
7838
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7839
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7840
0
      }
7841
0
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7842
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7843
0
      } else {
7844
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7845
0
      }
7846
0
      if (end_inputs) {
7847
0
        ir_END_list(end_inputs);
7848
0
      }
7849
0
    } else {
7850
0
      ir_ref if_val = ir_IF(ref);
7851
0
      ir_IF_TRUE(if_val);
7852
0
      if (set_bool) {
7853
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7854
0
      }
7855
0
      ir_END_list(true_inputs);
7856
0
      ir_IF_FALSE(if_val);
7857
0
      if (set_bool) {
7858
0
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7859
0
      }
7860
0
      ir_END_list(false_inputs);
7861
0
    }
7862
0
  }
7863
7864
0
  if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7865
0
    if (end_inputs) {
7866
0
      ir_MERGE_list(end_inputs);
7867
0
    }
7868
0
  } else {
7869
0
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7870
0
  }
7871
7872
0
  return 1;
7873
0
}
7874
7875
static int zend_jit_defined(zend_jit_ctx *jit, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
7876
0
{
7877
0
  uint32_t defined_label = (uint32_t)-1;
7878
0
  uint32_t undefined_label = (uint32_t)-1;
7879
0
  zval *zv = RT_CONSTANT(opline, opline->op1);
7880
0
  zend_jit_addr res_addr = 0;
7881
0
  ir_ref ref, ref2, if_set, if_zero, if_set2;
7882
0
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7883
7884
0
  if (smart_branch_opcode && !exit_addr) {
7885
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7886
0
      defined_label = target_label2;
7887
0
      undefined_label = target_label;
7888
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
7889
0
      defined_label = target_label;
7890
0
      undefined_label = target_label2;
7891
0
    } else {
7892
0
      ZEND_UNREACHABLE();
7893
0
    }
7894
0
  } else {
7895
0
    res_addr = RES_ADDR();
7896
0
  }
7897
7898
  // if (CACHED_PTR(opline->extended_value)) {
7899
0
  ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7900
7901
0
  if_set = ir_IF(ref);
7902
7903
0
  ir_IF_FALSE_cold(if_set);
7904
0
  if_zero = ir_END();
7905
7906
0
  ir_IF_TRUE(if_set);
7907
0
  if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7908
0
  ir_IF_FALSE(if_set2);
7909
7910
0
  if (exit_addr) {
7911
0
    if (smart_branch_opcode == ZEND_JMPNZ) {
7912
0
      jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7913
0
    } else {
7914
0
      ir_END_list(end_inputs);
7915
0
    }
7916
0
  } else if (smart_branch_opcode) {
7917
0
    ir_END_list(true_inputs);
7918
0
  } else {
7919
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7920
0
    ir_END_list(end_inputs);
7921
0
  }
7922
7923
0
  ir_IF_TRUE_cold(if_set2);
7924
7925
0
  ref2 = jit_EG(zend_constants);
7926
0
  ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7927
0
  if (sizeof(void*) == 8) {
7928
0
    ref = ir_TRUNC_U32(ref);
7929
0
  }
7930
0
  ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7931
0
  ref2 = ir_IF(ref2);
7932
0
  ir_IF_TRUE(ref2);
7933
7934
0
  if (exit_addr) {
7935
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7936
0
      jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7937
0
    } else {
7938
0
      ir_END_list(end_inputs);
7939
0
    }
7940
0
  } else if (smart_branch_opcode) {
7941
0
    ir_END_list(false_inputs);
7942
0
  } else {
7943
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7944
0
    ir_END_list(end_inputs);
7945
0
  }
7946
7947
0
  ir_IF_FALSE(ref2);
7948
0
  ir_MERGE_2(if_zero, ir_END());
7949
7950
0
  jit_SET_EX_OPLINE(jit, opline);
7951
0
  ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7952
0
  if (exit_addr) {
7953
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7954
0
      ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7955
0
    } else {
7956
0
      ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7957
0
    }
7958
0
    ir_END_list(end_inputs);
7959
0
  } else if (smart_branch_opcode) {
7960
0
    ref2 = ir_IF(ref2);
7961
0
    ir_IF_TRUE(ref2);
7962
0
    ir_END_list(true_inputs);
7963
0
    ir_IF_FALSE(ref2);
7964
0
    ir_END_list(false_inputs);
7965
0
  } else {
7966
0
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7967
0
      ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
7968
0
    ir_END_list(end_inputs);
7969
0
  }
7970
7971
0
  if (!smart_branch_opcode || exit_addr) {
7972
0
    if (end_inputs) {
7973
0
      ir_MERGE_list(end_inputs);
7974
0
    }
7975
0
  } else {
7976
0
    _zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
7977
0
  }
7978
7979
0
  return 1;
7980
0
}
7981
7982
static int zend_jit_escape_if_undef(zend_jit_ctx *jit, int var, uint32_t flags, const zend_op *opline, const zend_op_array *op_array, int8_t reg)
7983
0
{
7984
0
  zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
7985
0
  ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
7986
7987
0
  ir_IF_FALSE_cold(if_def);
7988
7989
0
  if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
7990
0
    if (!zend_jit_save_call_chain(jit, -1)) {
7991
0
      return 0;
7992
0
    }
7993
0
  }
7994
7995
0
  if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
7996
0
   && (opline-1)->opcode != ZEND_FETCH_LIST_R
7997
0
   && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
7998
0
   && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
7999
0
    zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
8000
8001
0
    zend_jit_zval_try_addref(jit, val_addr);
8002
0
  }
8003
8004
0
  jit_LOAD_IP_ADDR(jit, opline - 1);
8005
8006
  /* We can't use trace_escape() because opcode handler may be overridden by JIT */
8007
0
  zend_jit_op_array_trace_extension *jit_extension =
8008
0
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8009
0
  size_t offset = jit_extension->offset;
8010
0
  ir_ref ref = ir_CONST_FC_FUNC(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler);
8011
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
8012
0
    ir_TAILCALL(IR_OPCODE_HANDLER_RET, ref);
8013
0
  } else {
8014
0
    ir_ref opline_ref = ir_CALL_2(IR_OPCODE_HANDLER_RET, ref, jit_FP(jit), jit_IP(jit));
8015
0
    zend_jit_vm_enter(jit, opline_ref);
8016
0
  }
8017
8018
0
  ir_IF_TRUE(if_def);
8019
8020
0
  return 1;
8021
0
}
8022
8023
static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
8024
0
{
8025
0
  zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
8026
0
  zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
8027
8028
  // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8029
0
  jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, true);
8030
0
  return 1;
8031
0
}
8032
8033
static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx         *jit,
8034
                                                      const zend_op        *opline,
8035
                                                      zend_jit_addr         val_addr,
8036
                                                      uint8_t               type,
8037
                                                      bool                  deref,
8038
                                                      uint32_t              flags,
8039
                                                      bool                  op1_avoid_refcounting)
8040
0
{
8041
0
  zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
8042
0
  int32_t exit_point;
8043
0
  const void *res_exit_addr = NULL;
8044
0
  ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
8045
0
  ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
8046
0
  uint32_t old_op1_info = 0;
8047
0
  uint32_t old_info;
8048
0
  ir_ref old_ref;
8049
8050
8051
0
  if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8052
0
    old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
8053
0
    if (op1_avoid_refcounting
8054
0
     || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
8055
0
      && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
8056
0
      SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
8057
0
    }
8058
0
  }
8059
0
  old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
8060
0
  old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8061
0
  CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8062
0
  SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
8063
8064
0
  if (deref) {
8065
0
    ir_ref if_type;
8066
8067
0
    if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8068
0
      if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
8069
0
    } else {
8070
0
      if_type = jit_if_Z_TYPE(jit, val_addr, type);
8071
0
    }
8072
0
    ir_IF_TRUE(if_type);
8073
0
    end1 = ir_END();
8074
0
    ref1 = ref;
8075
0
    ir_IF_FALSE_cold(if_type);
8076
8077
0
    SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
8078
0
    exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8079
0
    res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8080
0
    if (!res_exit_addr) {
8081
0
      return 0;
8082
0
    }
8083
8084
0
    jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
8085
0
    ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
8086
0
    val_addr = ZEND_ADDR_REF_ZVAL(ref);
8087
0
  }
8088
8089
0
  SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
8090
0
  exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8091
0
  res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8092
0
  if (!res_exit_addr) {
8093
0
    return 0;
8094
0
  }
8095
8096
0
  if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8097
0
    ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
8098
0
  } else {
8099
0
    jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
8100
0
  }
8101
8102
0
  if (deref) {
8103
0
    ir_MERGE_WITH(end1);
8104
0
    ref = ir_PHI_2(IR_ADDR, ref, ref1);
8105
0
  }
8106
8107
0
  val_addr = ZEND_ADDR_REF_ZVAL(ref);
8108
8109
0
  SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
8110
0
  SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
8111
0
  if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8112
0
    SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
8113
0
  }
8114
8115
0
  return val_addr;
8116
0
}
8117
8118
static int zend_jit_fetch_constant(zend_jit_ctx         *jit,
8119
                                   const zend_op        *opline,
8120
                                   const zend_op_array  *op_array,
8121
                                   zend_ssa             *ssa,
8122
                                   const zend_ssa_op    *ssa_op,
8123
                                   zend_jit_addr         res_addr)
8124
0
{
8125
0
  zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
8126
0
  uint32_t res_info = RES_INFO();
8127
0
  ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
8128
8129
  // JIT: c = CACHED_PTR(opline->extended_value);
8130
0
  ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
8131
8132
  // JIT: if (c != NULL)
8133
0
  if_set = ir_IF(ref);
8134
8135
0
  if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
8136
    // JIT: if (!IS_SPECIAL_CACHE_VAL(c))
8137
0
    ir_IF_FALSE_cold(if_set);
8138
0
    not_set_path = ir_END();
8139
0
    ir_IF_TRUE(if_set);
8140
0
    if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
8141
0
    ir_IF_TRUE_cold(if_special);
8142
0
    special_path = ir_END();
8143
0
    ir_IF_FALSE(if_special);
8144
0
    fast_path = ir_END();
8145
0
    ir_MERGE_2(not_set_path, special_path);
8146
0
  } else {
8147
0
    ir_IF_TRUE(if_set);
8148
0
    fast_path = ir_END();
8149
0
    ir_IF_FALSE_cold(if_set);
8150
0
  }
8151
8152
  // JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8153
0
  jit_SET_EX_OPLINE(jit, opline);
8154
0
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
8155
0
    ir_CONST_ADDR(zv),
8156
0
    ir_CONST_U32(opline->op1.num));
8157
0
  ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8158
8159
0
  ir_MERGE_WITH(fast_path);
8160
0
  ref = ir_PHI_2(IR_ADDR, ref2, ref);
8161
8162
0
  if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8163
0
    uint8_t type = concrete_type(res_info);
8164
0
    zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8165
8166
0
    const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, false, 0, false);
8167
0
    if (!const_addr) {
8168
0
      return 0;
8169
0
    }
8170
8171
0
    res_info &= ~MAY_BE_GUARD;
8172
0
    ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8173
8174
    // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8175
0
    jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, true);
8176
0
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8177
0
      return 0;
8178
0
    }
8179
0
  } else {
8180
0
    ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8181
8182
    // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8183
0
    jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, true);
8184
0
  }
8185
8186
8187
0
  return 1;
8188
0
}
8189
8190
static int zend_jit_type_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8191
0
{
8192
0
  uint32_t  mask;
8193
0
  zend_jit_addr op1_addr = OP1_ADDR();
8194
0
  zend_jit_addr res_addr = 0;
8195
0
  uint32_t true_label = -1, false_label = -1;
8196
0
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8197
8198
  // TODO: support for is_resource() ???
8199
0
  ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8200
8201
0
  if (smart_branch_opcode && !exit_addr) {
8202
0
    if (smart_branch_opcode == ZEND_JMPZ) {
8203
0
      true_label = target_label2;
8204
0
      false_label = target_label;
8205
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
8206
0
      true_label = target_label;
8207
0
      false_label = target_label2;
8208
0
    } else {
8209
0
      ZEND_UNREACHABLE();
8210
0
    }
8211
0
  } else {
8212
0
    res_addr = RES_ADDR();
8213
0
  }
8214
8215
0
  if (op1_info & MAY_BE_UNDEF) {
8216
0
    ir_ref if_def = IR_UNUSED;
8217
8218
0
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8219
0
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8220
0
      ir_IF_FALSE_cold(if_def);
8221
0
    }
8222
8223
0
    jit_SET_EX_OPLINE(jit, opline);
8224
0
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8225
0
    zend_jit_check_exception_undef_result(jit, opline);
8226
0
    if (opline->extended_value & MAY_BE_NULL) {
8227
0
      if (exit_addr) {
8228
0
        if (smart_branch_opcode == ZEND_JMPNZ) {
8229
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8230
0
        } else {
8231
0
          ir_END_list(end_inputs);
8232
0
        }
8233
0
      } else if (smart_branch_opcode) {
8234
0
        ir_END_list(true_inputs);
8235
0
      } else {
8236
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8237
0
        ir_END_list(end_inputs);
8238
0
      }
8239
0
    } else {
8240
0
      if (exit_addr) {
8241
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8242
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8243
0
        } else {
8244
0
          ir_END_list(end_inputs);
8245
0
        }
8246
0
      } else if (smart_branch_opcode) {
8247
0
        ir_END_list(false_inputs);
8248
0
      } else {
8249
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8250
0
        if (if_def) {
8251
0
          ir_END_list(end_inputs);
8252
0
        }
8253
0
      }
8254
0
    }
8255
8256
0
    if (if_def) {
8257
0
      ir_IF_TRUE(if_def);
8258
0
      op1_info |= MAY_BE_NULL;
8259
0
    }
8260
0
  }
8261
8262
0
  if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8263
0
    mask = opline->extended_value;
8264
0
    if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8265
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8266
0
      if (exit_addr) {
8267
0
        if (smart_branch_opcode == ZEND_JMPNZ) {
8268
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8269
0
        } else if (end_inputs) {
8270
0
          ir_END_list(end_inputs);
8271
0
        }
8272
0
      } else if (smart_branch_opcode) {
8273
0
        ir_END_list(true_inputs);
8274
0
      } else {
8275
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8276
0
        ir_END_list(end_inputs);
8277
0
      }
8278
0
      } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8279
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8280
0
      if (exit_addr) {
8281
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8282
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8283
0
        } else if (end_inputs) {
8284
0
          ir_END_list(end_inputs);
8285
0
        }
8286
0
      } else if (smart_branch_opcode) {
8287
0
        ir_END_list(false_inputs);
8288
0
      } else {
8289
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8290
0
        ir_END_list(end_inputs);
8291
0
      }
8292
0
    } else {
8293
0
      ir_ref ref;
8294
0
      bool invert = false;
8295
0
      uint8_t type;
8296
8297
0
      switch (mask) {
8298
0
        case MAY_BE_NULL:   type = IS_NULL;   break;
8299
0
        case MAY_BE_FALSE:  type = IS_FALSE;  break;
8300
0
        case MAY_BE_TRUE:   type = IS_TRUE;   break;
8301
0
        case MAY_BE_LONG:   type = IS_LONG;   break;
8302
0
        case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8303
0
        case MAY_BE_STRING: type = IS_STRING; break;
8304
0
        case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
8305
0
        case MAY_BE_OBJECT: type = IS_OBJECT; break;
8306
0
        case MAY_BE_ANY - MAY_BE_NULL:     type = IS_NULL;   invert = true; break;
8307
0
        case MAY_BE_ANY - MAY_BE_FALSE:    type = IS_FALSE;  invert = true; break;
8308
0
        case MAY_BE_ANY - MAY_BE_TRUE:     type = IS_TRUE;   invert = true; break;
8309
0
        case MAY_BE_ANY - MAY_BE_LONG:     type = IS_LONG;   invert = true; break;
8310
0
        case MAY_BE_ANY - MAY_BE_DOUBLE:   type = IS_DOUBLE; invert = true; break;
8311
0
        case MAY_BE_ANY - MAY_BE_STRING:   type = IS_STRING; invert = true; break;
8312
0
        case MAY_BE_ANY - MAY_BE_ARRAY:    type = IS_ARRAY;  invert = true; break;
8313
0
        case MAY_BE_ANY - MAY_BE_OBJECT:   type = IS_OBJECT; invert = true; break;
8314
0
        case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = true; break;
8315
0
        default:
8316
0
          type = 0;
8317
0
      }
8318
8319
0
      if (op1_info & MAY_BE_REF) {
8320
0
        ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8321
0
        ref = jit_ZVAL_DEREF_ref(jit, ref);
8322
0
        op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8323
0
      }
8324
0
      if (type == 0) {
8325
0
        ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8326
0
        if (!smart_branch_opcode) {
8327
0
          ref = ir_NE(ref, ir_CONST_U32(0));
8328
0
        }
8329
0
      } else if (invert) {
8330
0
        ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8331
0
      } else {
8332
0
        ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8333
0
      }
8334
8335
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8336
8337
0
      if (exit_addr) {
8338
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8339
0
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8340
0
        } else {
8341
0
          ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8342
0
        }
8343
0
        if (end_inputs) {
8344
0
          ir_END_list(end_inputs);
8345
0
        }
8346
0
      } else if (smart_branch_opcode) {
8347
0
        ir_ref if_val = ir_IF(ref);
8348
0
        ir_IF_TRUE(if_val);
8349
0
        ir_END_list(true_inputs);
8350
0
        ir_IF_FALSE(if_val);
8351
0
        ir_END_list(false_inputs);
8352
0
      } else {
8353
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8354
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8355
0
        ir_END_list(end_inputs);
8356
0
      }
8357
0
      }
8358
0
  }
8359
8360
0
  if (!smart_branch_opcode || exit_addr) {
8361
0
    if (end_inputs) {
8362
0
      ir_MERGE_list(end_inputs);
8363
0
    } else if (exit_addr && !jit->ctx.control) {
8364
0
      ir_BEGIN(IR_UNUSED); /* unreachable block */
8365
0
    }
8366
0
  } else {
8367
0
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8368
0
  }
8369
8370
0
  return 1;
8371
0
}
8372
8373
static int zend_jit_isset_isempty_cv(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
8374
0
{
8375
0
  zend_jit_addr res_addr = RES_ADDR();
8376
0
  uint32_t true_label = -1, false_label = -1;
8377
0
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8378
8379
  // TODO: support for empty() ???
8380
0
  ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8381
8382
0
  if (smart_branch_opcode && !exit_addr) {
8383
0
    if (smart_branch_opcode == ZEND_JMPZ) {
8384
0
      true_label = target_label2;
8385
0
      false_label = target_label;
8386
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
8387
0
      true_label = target_label;
8388
0
      false_label = target_label2;
8389
0
    } else {
8390
0
      ZEND_UNREACHABLE();
8391
0
    }
8392
0
  } else {
8393
0
    res_addr = RES_ADDR();
8394
0
  }
8395
8396
0
  if (op1_info & MAY_BE_REF) {
8397
0
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8398
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
8399
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8400
0
  }
8401
8402
0
  if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8403
0
    if (exit_addr) {
8404
0
      ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8405
0
    } else if (smart_branch_opcode) {
8406
0
      ir_END_list(true_inputs);
8407
0
    } else {
8408
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8409
0
      ir_END_list(end_inputs);
8410
0
    }
8411
0
  } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8412
0
    if (exit_addr) {
8413
0
      ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8414
0
    } else if (smart_branch_opcode) {
8415
0
      ir_END_list(false_inputs);
8416
0
    } else {
8417
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8418
0
      ir_END_list(end_inputs);
8419
0
    }
8420
0
  } else {
8421
0
    ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8422
0
    if (exit_addr) {
8423
0
      if (smart_branch_opcode == ZEND_JMPNZ) {
8424
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8425
0
      } else {
8426
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8427
0
      }
8428
0
    } else if (smart_branch_opcode) {
8429
0
      ir_ref if_val = ir_IF(ref);
8430
0
      ir_IF_TRUE(if_val);
8431
0
      ir_END_list(true_inputs);
8432
0
      ir_IF_FALSE(if_val);
8433
0
      ir_END_list(false_inputs);
8434
0
    } else {
8435
0
      jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8436
0
        ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8437
0
      ir_END_list(end_inputs);
8438
0
    }
8439
0
  }
8440
8441
0
  if (!smart_branch_opcode || exit_addr) {
8442
0
    if (end_inputs) {
8443
0
      ir_MERGE_list(end_inputs);
8444
0
    }
8445
0
  } else {
8446
0
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8447
0
  }
8448
8449
0
  return 1;
8450
0
}
8451
8452
/* copy of hidden zend_closure */
8453
typedef struct _zend_closure {
8454
  zend_object       std;
8455
  zend_function     func;
8456
  zend_object      *this_ptr;
8457
  zend_class_entry *called_scope;
8458
  zif_handler       orig_internal_handler;
8459
} zend_closure;
8460
8461
static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8462
0
{
8463
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8464
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8465
8466
0
  if (!exit_addr) {
8467
0
    return 0;
8468
0
  }
8469
8470
  // JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8471
0
  ir_GUARD(
8472
0
    ir_UGE(
8473
0
      ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8474
0
      ir_CONST_ADDR(used_stack)),
8475
0
    ir_CONST_ADDR(exit_addr));
8476
8477
0
  return 1;
8478
0
}
8479
8480
static int zend_jit_free_trampoline(zend_jit_ctx *jit, ir_ref func)
8481
0
{
8482
  // JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8483
0
  ir_ref if_trampoline = ir_IF(ir_AND_U32(
8484
0
    ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8485
0
    ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8486
8487
0
  ir_IF_TRUE(if_trampoline);
8488
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8489
0
  ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8490
8491
0
  return 1;
8492
0
}
8493
8494
static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool delayed_fetch_this, int checked_stack, ir_ref func_ref, ir_ref this_ref)
8495
0
{
8496
0
  uint32_t used_stack;
8497
0
  ir_ref used_stack_ref = IR_UNUSED;
8498
0
  bool stack_check = true;
8499
0
  ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8500
8501
0
  ZEND_ASSERT(func_ref != IR_NULL);
8502
0
  if (func) {
8503
0
    used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8504
0
    if ((int)used_stack <= checked_stack) {
8505
0
      stack_check = false;
8506
0
    }
8507
0
    used_stack_ref = ir_CONST_ADDR(used_stack);
8508
0
  } else {
8509
0
    ir_ref num_args_ref;
8510
0
    ir_ref if_internal_func = IR_UNUSED;
8511
0
    const size_t func_type_offset = is_closure ? offsetof(zend_closure, func.type) : offsetof(zend_function, type);
8512
8513
0
    used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8514
0
    used_stack_ref = ir_CONST_ADDR(used_stack);
8515
0
    used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8516
8517
    // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8518
0
    ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, func_type_offset));
8519
0
    if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8520
0
    ir_IF_FALSE(if_internal_func);
8521
8522
    // JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8523
0
    num_args_ref = ir_CONST_U32(opline->extended_value);
8524
0
    if (!is_closure) {
8525
0
      ref = ir_SUB_U32(
8526
0
        ir_SUB_U32(
8527
0
          ir_MIN_U32(
8528
0
            num_args_ref,
8529
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8530
0
          ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8531
0
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8532
0
    } else {
8533
0
      ref = ir_SUB_U32(
8534
0
        ir_SUB_U32(
8535
0
          ir_MIN_U32(
8536
0
            num_args_ref,
8537
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8538
0
          ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8539
0
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8540
0
    }
8541
0
    ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8542
0
    if (sizeof(void*) == 8) {
8543
0
      ref = ir_SEXT_A(ref);
8544
0
    }
8545
0
    ref = ir_SUB_A(used_stack_ref, ref);
8546
8547
0
    ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8548
0
    used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8549
0
  }
8550
8551
0
  zend_jit_start_reuse_ip(jit);
8552
8553
  // JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8554
0
  jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8555
8556
0
  if (stack_check) {
8557
    // JIT: Check Stack Overflow
8558
0
    ref = ir_UGE(
8559
0
      ir_SUB_A(
8560
0
        ir_LOAD_A(jit_EG(vm_stack_end)),
8561
0
        jit_IP(jit)),
8562
0
      used_stack_ref);
8563
8564
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8565
0
      bool may_be_trampoline = !func && (opline->opcode == ZEND_INIT_METHOD_CALL);
8566
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8567
0
        may_be_trampoline ?
8568
0
          (ZEND_JIT_EXIT_TO_VM | ZEND_JIT_EXIT_METHOD_CALL) : ZEND_JIT_EXIT_TO_VM);
8569
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8570
8571
0
      if (!exit_addr) {
8572
0
        return 0;
8573
0
      }
8574
8575
0
      if (may_be_trampoline) {
8576
0
        jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
8577
0
        jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
8578
0
      }
8579
8580
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8581
0
    } else {
8582
0
      if_enough_stack = ir_IF(ref);
8583
0
      ir_IF_FALSE_cold(if_enough_stack);
8584
8585
#ifdef _WIN32
8586
      if (0) {
8587
#else
8588
0
      if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8589
0
#endif
8590
0
        jit_SET_EX_OPLINE(jit, opline);
8591
0
        ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8592
0
      } else {
8593
0
        if (!is_closure) {
8594
0
          ref = func_ref;
8595
0
        } else {
8596
0
          ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8597
0
        }
8598
0
        jit_SET_EX_OPLINE(jit, opline);
8599
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8600
0
          used_stack_ref, ref);
8601
0
      }
8602
0
      jit_STORE_IP(jit, ref);
8603
8604
0
      cold_path = ir_END();
8605
0
      ir_IF_TRUE(if_enough_stack);
8606
0
    }
8607
0
  }
8608
8609
0
  ref = jit_EG(vm_stack_top);
8610
0
  rx = jit_IP(jit);
8611
0
#if !OPTIMIZE_FOR_SIZE
8612
  /* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8613
   * This vesions is longer but faster
8614
   *    mov EG(vm_stack_top), %CALL
8615
   *    lea size(%call), %tmp
8616
   *    mov %tmp, EG(vm_stack_top)
8617
   */
8618
0
  top = rx;
8619
#else
8620
  /* JIT: EG(vm_stack_top) += used_stack;
8621
   * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8622
   *    mov EG(vm_stack_top), %CALL
8623
   *    add $size, EG(vm_stack_top)
8624
   */
8625
  top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8626
#endif
8627
0
  ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8628
8629
  // JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8630
0
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8631
    // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8632
0
    ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8633
0
  }
8634
#ifdef _WIN32
8635
  if (0) {
8636
#else
8637
0
  if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8638
0
#endif
8639
0
    if (cold_path) {
8640
0
      ir_MERGE_WITH(cold_path);
8641
0
      rx = jit_IP(jit);
8642
0
    }
8643
8644
    // JIT: call->func = func;
8645
0
    ir_STORE(jit_CALL(rx, func), func_ref);
8646
0
  } else {
8647
0
    if (!is_closure) {
8648
      // JIT: call->func = func;
8649
0
      ir_STORE(jit_CALL(rx, func), func_ref);
8650
0
    } else {
8651
      // JIT: call->func = &closure->func;
8652
0
      ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8653
0
    }
8654
0
    if (cold_path) {
8655
0
      ir_MERGE_WITH(cold_path);
8656
0
      rx = jit_IP(jit);
8657
0
    }
8658
0
  }
8659
0
  if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8660
    // JIT: Z_PTR(call->This) = obj;
8661
0
    ZEND_ASSERT(this_ref != IR_NULL);
8662
0
    ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8663
0
      if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8664
      // JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8665
0
      ref = jit_CALL(rx, This.u1.type_info);
8666
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8667
0
        ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8668
0
      } else {
8669
0
        ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8670
0
      }
8671
0
      } else {
8672
0
      if (opline->op1_type == IS_CV) {
8673
        // JIT: GC_ADDREF(obj);
8674
0
        jit_GC_ADDREF(jit, this_ref);
8675
0
      }
8676
8677
      // JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8678
0
      ref = jit_CALL(rx, This.u1.type_info);
8679
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8680
0
        ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8681
0
      } else {
8682
0
        ir_STORE(ref,
8683
0
          ir_OR_U32(ir_LOAD_U32(ref),
8684
0
            ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8685
0
      }
8686
0
      }
8687
0
  } else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
8688
    // JIT: Z_CE(call->This) = called_scope;
8689
0
    ir_STORE(jit_CALL(rx, This), this_ref);
8690
0
  } else if (!is_closure) {
8691
    // JIT: Z_CE(call->This) = called_scope;
8692
0
    ir_STORE(jit_CALL(rx, This), IR_NULL);
8693
0
  } else {
8694
0
    ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8695
0
    ir_ref if_cond_user = IR_UNUSED;
8696
8697
0
    if (opline->op2_type == IS_CV) {
8698
      // JIT: GC_ADDREF(closure);
8699
0
      jit_GC_ADDREF(jit, func_ref);
8700
0
    }
8701
8702
    // JIT: RX(object_or_called_scope) = closure->called_scope;
8703
0
    object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8704
8705
    // JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8706
    //      (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8707
0
    call_info = ir_OR_U32(
8708
0
      ir_AND_U32(
8709
0
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8710
0
        ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8711
0
        ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8712
8713
    // JIT: object_or_called_scope = closure->this_ptr;
8714
0
    object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr)));
8715
    // JIT: if (closure->this_ptr != NULL) {
8716
0
    if_cond = ir_IF(object);
8717
0
    ir_IF_TRUE(if_cond);
8718
8719
    // JIT: call_info |= ZEND_CALL_HAS_THIS;
8720
0
    call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8721
8722
0
    ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8723
0
    call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8724
0
    object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8725
8726
    // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8727
0
    ref = jit_CALL(rx, This.u1.type_info);
8728
0
    ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8729
8730
    // JIT: Z_PTR(call->This) = object_or_called_scope;
8731
0
    ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8732
8733
0
    if (!func) {
8734
      // JIT: if (closure->func.common.type & ZEND_USER_FUNCTION)
8735
0
      ir_ref type = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.type)));
8736
0
      if_cond_user = ir_IF(ir_AND_U8(type, ir_CONST_U8(ZEND_USER_FUNCTION)));
8737
0
      ir_IF_TRUE(if_cond_user);
8738
0
    }
8739
8740
0
    if (!func || func->common.type == ZEND_USER_FUNCTION) {
8741
      // JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8742
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8743
0
        ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8744
0
    }
8745
8746
0
    if (!func) {
8747
0
      ir_MERGE_WITH_EMPTY_FALSE(if_cond_user);
8748
0
    }
8749
0
  }
8750
8751
  // JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8752
0
  ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8753
8754
0
  return 1;
8755
0
}
8756
8757
static int zend_jit_func_guard(zend_jit_ctx *jit, ir_ref func_ref, const zend_function *func, const void *exit_addr)
8758
0
{
8759
0
  if (func->type == ZEND_USER_FUNCTION &&
8760
0
      (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8761
0
       (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8762
0
       !func->common.function_name)) {
8763
0
    const zend_op *opcodes = func->op_array.opcodes;
8764
8765
    // JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8766
0
    ir_GUARD(
8767
0
      ir_EQ(
8768
0
        ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8769
0
        ir_CONST_ADDR(opcodes)),
8770
0
      ir_CONST_ADDR(exit_addr));
8771
#ifdef ZEND_WIN32
8772
  } else if (func->type == ZEND_INTERNAL_FUNCTION) {
8773
    // ASLR may cause different addresses in different workers. Check for the internal function handler.
8774
    // JIT: if (call->func.internal_function.handler != handler) goto exit_addr;
8775
    ir_GUARD(
8776
      ir_EQ(
8777
        ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler))),
8778
        ir_CONST_FC_FUNC(func->internal_function.handler)),
8779
      ir_CONST_ADDR(exit_addr));
8780
#endif
8781
0
  } else {
8782
    // JIT: if (call->func != func) goto exit_addr;
8783
0
    ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8784
0
  }
8785
8786
0
  return 1;
8787
0
}
8788
8789
static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8790
0
{
8791
0
  int32_t exit_point;
8792
0
  const void *exit_addr;
8793
0
  ir_ref call;
8794
8795
0
  if (func->type == ZEND_USER_FUNCTION
8796
0
   && !zend_accel_in_shm(func->op_array.opcodes)) {
8797
    /* op_array and op_array->opcodes are not persistent. We can't link. */
8798
0
    return 0;
8799
0
  }
8800
8801
0
  exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8802
0
  exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8803
0
  if (!exit_addr) {
8804
0
    return 0;
8805
0
  }
8806
8807
  // call = EX(call);
8808
0
  call = ir_LOAD_A(jit_EX(call));
8809
0
  while (level > 0) {
8810
    // call = call->prev_execute_data
8811
0
    call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8812
0
    level--;
8813
0
  }
8814
8815
0
  return zend_jit_func_guard(jit, ir_LOAD_A(jit_CALL(call, func)), func, exit_addr);
8816
0
}
8817
8818
static int zend_jit_init_fcall(zend_jit_ctx *jit, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack)
8819
0
{
8820
0
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
8821
0
  zend_call_info *call_info = NULL;
8822
0
  zend_function *func = NULL;
8823
0
  ir_ref func_ref = IR_UNUSED;
8824
8825
0
  if (jit->delayed_call_level) {
8826
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8827
0
      return 0;
8828
0
    }
8829
0
  }
8830
8831
0
  if (info) {
8832
0
    call_info = info->callee_info;
8833
0
    while (call_info && call_info->caller_init_opline != opline) {
8834
0
      call_info = call_info->next_callee;
8835
0
    }
8836
0
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
8837
0
      func = call_info->callee_func;
8838
0
    }
8839
0
  }
8840
8841
0
  if (!func
8842
0
   && trace
8843
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8844
#ifdef _WIN32
8845
    /* ASLR */
8846
    if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8847
      func = (zend_function*)trace->func;
8848
    }
8849
#else
8850
0
    func = (zend_function*)trace->func;
8851
0
#endif
8852
0
  }
8853
8854
#ifdef _WIN32
8855
  if (0) {
8856
#else
8857
0
  if (opline->opcode == ZEND_INIT_FCALL
8858
0
   && func
8859
0
   && func->type == ZEND_INTERNAL_FUNCTION) {
8860
0
#endif
8861
    /* load constant address later */
8862
0
    func_ref = ir_CONST_ADDR(func);
8863
0
  } else if (func && op_array == &func->op_array) {
8864
    /* recursive call */
8865
0
    if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8866
0
     || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8867
0
      func_ref = ir_LOAD_A(jit_EX(func));
8868
0
    } else {
8869
0
      func_ref = ir_CONST_ADDR(func);
8870
0
    }
8871
0
  } else {
8872
0
    ir_ref if_func, cache_slot_ref, ref;
8873
8874
    // JIT: if (CACHED_PTR(opline->result.num))
8875
0
    cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8876
0
    func_ref = ir_LOAD_A(cache_slot_ref);
8877
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8878
0
     && func
8879
0
     && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8880
0
     && opline->opcode != ZEND_INIT_FCALL) {
8881
      /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8882
0
      if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8883
0
    } else {
8884
0
      if_func = ir_IF(func_ref);
8885
0
    }
8886
0
    ir_IF_FALSE_cold(if_func);
8887
0
    if (opline->opcode == ZEND_INIT_FCALL
8888
0
     && func
8889
0
     && func->type == ZEND_USER_FUNCTION
8890
0
     && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8891
0
      ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8892
0
        ir_STORE(cache_slot_ref, ref);
8893
0
      ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8894
0
    } else {
8895
0
      zval *zv = RT_CONSTANT(opline, opline->op2);
8896
8897
0
      if (opline->opcode == ZEND_INIT_FCALL) {
8898
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8899
0
          ir_CONST_ADDR(Z_STR_P(zv)),
8900
0
          cache_slot_ref);
8901
0
      } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8902
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8903
0
          ir_CONST_ADDR(Z_STR_P(zv + 1)),
8904
0
          cache_slot_ref);
8905
0
      } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8906
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8907
0
          ir_CONST_ADDR(zv),
8908
0
          cache_slot_ref);
8909
0
      } else {
8910
0
        ZEND_UNREACHABLE();
8911
0
      }
8912
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8913
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8914
0
          func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8915
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8916
8917
0
        if (!exit_addr) {
8918
0
          return 0;
8919
0
        }
8920
0
        if (!func || opline->opcode == ZEND_INIT_FCALL) {
8921
0
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8922
0
        } else if (!zend_jit_func_guard(jit, ref, func, exit_addr)) {
8923
0
          return 0;
8924
0
        }
8925
0
      } else {
8926
0
jit_SET_EX_OPLINE(jit, opline);
8927
0
        ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8928
0
      }
8929
0
    }
8930
0
    ir_MERGE_WITH_EMPTY_TRUE(if_func);
8931
0
    func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8932
0
  }
8933
8934
0
  if (!zend_jit_push_call_frame(jit, opline, op_array, func, false, false, checked_stack, func_ref, IR_UNUSED)) {
8935
0
    return 0;
8936
0
  }
8937
8938
0
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8939
0
    if (!zend_jit_save_call_chain(jit, call_level)) {
8940
0
      return 0;
8941
0
    }
8942
0
  } else {
8943
0
    ZEND_ASSERT(call_level > 0);
8944
0
    jit->delayed_call_level = call_level;
8945
0
    delayed_call_chain = true;
8946
0
  }
8947
8948
0
  if (trace
8949
0
   && trace->op == ZEND_JIT_TRACE_END
8950
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
8951
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
8952
0
      return 0;
8953
0
    }
8954
0
  }
8955
8956
0
  return 1;
8957
0
}
8958
8959
static int zend_jit_init_method_call(zend_jit_ctx         *jit,
8960
                                     const zend_op        *opline,
8961
                                     uint32_t              b,
8962
                                     const zend_op_array  *op_array,
8963
                                     zend_ssa             *ssa,
8964
                                     const zend_ssa_op    *ssa_op,
8965
                                     int                   call_level,
8966
                                     uint32_t              op1_info,
8967
                                     zend_jit_addr         op1_addr,
8968
                                     zend_class_entry     *ce,
8969
                                     bool                  ce_is_instanceof,
8970
                                     bool                  on_this,
8971
                                     bool                  delayed_fetch_this,
8972
                                     zend_class_entry     *trace_ce,
8973
                                     zend_jit_trace_rec   *trace,
8974
                                     int                   checked_stack,
8975
                                     ir_ref                func_ref,
8976
                                     ir_ref                this_ref,
8977
                                     bool                  polymorphic_side_trace)
8978
0
{
8979
0
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
8980
0
  zend_call_info *call_info = NULL;
8981
0
  zend_function *func = NULL;
8982
0
  zval *function_name;
8983
0
  ir_ref if_static = IR_UNUSED, cold_path;
8984
8985
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
8986
0
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
8987
8988
0
  function_name = RT_CONSTANT(opline, opline->op2);
8989
8990
0
  if (info) {
8991
0
    call_info = info->callee_info;
8992
0
    while (call_info && call_info->caller_init_opline != opline) {
8993
0
      call_info = call_info->next_callee;
8994
0
    }
8995
0
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
8996
0
      func = call_info->callee_func;
8997
0
    }
8998
0
  }
8999
9000
0
  if (polymorphic_side_trace) {
9001
    /* function is passed from parent snapshot */
9002
0
    ZEND_ASSERT(func_ref != IR_UNUSED && this_ref != IR_UNUSED);
9003
0
  } else {
9004
0
    ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
9005
9006
0
    if (on_this) {
9007
0
      zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
9008
0
      this_ref = jit_Z_PTR(jit, this_addr);
9009
0
    } else {
9010
0
        if (op1_info & MAY_BE_REF) {
9011
0
        if (opline->op1_type == IS_CV) {
9012
          // JIT: ZVAL_DEREF(op1)
9013
0
          ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
9014
0
          ref = jit_ZVAL_DEREF_ref(jit, ref);
9015
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9016
0
        } else {
9017
0
          ir_ref if_ref;
9018
9019
          /* Hack: Convert reference to regular value to simplify JIT code */
9020
0
          ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
9021
9022
0
          if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9023
0
          ir_IF_TRUE(if_ref);
9024
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
9025
9026
0
          ir_MERGE_WITH_EMPTY_FALSE(if_ref);
9027
0
        }
9028
0
      }
9029
0
      if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
9030
0
        if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9031
0
          int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9032
0
          const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9033
9034
0
          if (!exit_addr) {
9035
0
            return 0;
9036
0
          }
9037
0
          ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
9038
0
            ir_CONST_ADDR(exit_addr));
9039
0
        } else {
9040
0
          ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
9041
9042
0
          ir_IF_FALSE_cold(if_object);
9043
9044
0
          jit_SET_EX_OPLINE(jit, opline);
9045
0
          if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9046
0
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
9047
0
              jit_ZVAL_ADDR(jit, op1_addr));
9048
0
          } else {
9049
0
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
9050
0
              jit_ZVAL_ADDR(jit, op1_addr));
9051
0
          }
9052
0
          ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
9053
0
          ir_IF_TRUE(if_object);
9054
0
        }
9055
0
      }
9056
9057
0
      this_ref = jit_Z_PTR(jit, op1_addr);
9058
0
    }
9059
9060
0
    if (jit->delayed_call_level) {
9061
0
      if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9062
0
        return 0;
9063
0
      }
9064
0
    }
9065
9066
0
    if (func) {
9067
      // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9068
0
      ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9069
9070
0
      if_found = ir_IF(ref);
9071
0
      ir_IF_TRUE(if_found);
9072
0
      fast_path = ir_END();
9073
0
    } else {
9074
      // JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
9075
0
      run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
9076
0
      ref = ir_EQ(
9077
0
        ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
9078
0
        ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
9079
0
      if_found = ir_IF(ref);
9080
0
      ir_IF_TRUE(if_found);
9081
9082
      // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9083
0
      ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
9084
0
      fast_path = ir_END();
9085
9086
0
    }
9087
9088
0
    ir_IF_FALSE_cold(if_found);
9089
0
    jit_SET_EX_OPLINE(jit, opline);
9090
9091
0
    if (!jit->ctx.fixed_call_stack_size) {
9092
      // JIT: alloca(sizeof(void*));
9093
0
      this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
9094
0
    } else {
9095
#ifdef _WIN64
9096
      this_ref2 = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9097
#else
9098
0
      this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
9099
0
#endif
9100
0
    }
9101
0
    ir_STORE(this_ref2, this_ref);
9102
9103
0
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9104
0
      ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
9105
0
          this_ref,
9106
0
          ir_CONST_ADDR(function_name),
9107
0
          this_ref2);
9108
0
    } else {
9109
0
      ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
9110
0
          this_ref,
9111
0
          ir_CONST_ADDR(function_name),
9112
0
          this_ref2);
9113
0
    }
9114
9115
9116
0
    if (!jit->ctx.fixed_call_stack_size) {
9117
0
      this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9118
      // JIT: revert alloca
9119
0
      ir_AFREE(ir_CONST_ADDR(0x10));
9120
0
    } else {
9121
#ifdef _WIN64
9122
      this_ref2 = ir_LOAD_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9123
#else
9124
0
      this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9125
0
#endif
9126
0
    }
9127
9128
0
    ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9129
9130
0
    ir_MERGE_WITH(fast_path);
9131
0
    func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
9132
0
    this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
9133
0
  }
9134
9135
0
  if ((!func || zend_jit_may_be_modified(func, op_array))
9136
0
   && trace
9137
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9138
0
   && trace->func) {
9139
0
    int32_t exit_point;
9140
0
    const void *exit_addr;
9141
9142
0
    exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
9143
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9144
0
    if (!exit_addr) {
9145
0
      return 0;
9146
0
    }
9147
9148
0
    jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
9149
0
    jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
9150
9151
0
    func = (zend_function*)trace->func;
9152
9153
0
    if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9154
0
      return 0;
9155
0
    }
9156
0
  }
9157
9158
0
  if (!func) {
9159
    // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9160
0
    if_static = ir_IF(ir_AND_U32(
9161
0
      ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9162
0
      ir_CONST_U32(ZEND_ACC_STATIC)));
9163
0
    ir_IF_TRUE_cold(if_static);
9164
0
  }
9165
9166
0
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9167
0
    ir_ref ret;
9168
9169
0
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9170
0
      ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame_tmp),
9171
0
          this_ref,
9172
0
          func_ref,
9173
0
          ir_CONST_U32(opline->extended_value));
9174
0
    } else {
9175
0
      ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame),
9176
0
          this_ref,
9177
0
          func_ref,
9178
0
          ir_CONST_U32(opline->extended_value));
9179
0
    }
9180
9181
0
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9182
0
      ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9183
0
    }
9184
0
    jit_STORE_IP(jit, ret);
9185
0
  }
9186
9187
0
  if (!func) {
9188
0
    cold_path = ir_END();
9189
0
    ir_IF_FALSE(if_static);
9190
0
  }
9191
9192
0
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9193
0
    if (!zend_jit_push_call_frame(jit, opline, NULL, func, false, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9194
0
      return 0;
9195
0
    }
9196
0
  }
9197
9198
0
  if (!func) {
9199
0
    ir_MERGE_WITH(cold_path);
9200
0
  }
9201
0
  zend_jit_start_reuse_ip(jit);
9202
9203
0
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9204
0
    if (!zend_jit_save_call_chain(jit, call_level)) {
9205
0
      return 0;
9206
0
    }
9207
0
  } else {
9208
0
    ZEND_ASSERT(call_level > 0);
9209
0
    delayed_call_chain = true;
9210
0
    jit->delayed_call_level = call_level;
9211
0
  }
9212
9213
0
  if (trace
9214
0
   && trace->op == ZEND_JIT_TRACE_END
9215
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9216
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9217
0
      return 0;
9218
0
    }
9219
0
  }
9220
9221
0
  return 1;
9222
0
}
9223
9224
static int zend_jit_init_static_method_call(zend_jit_ctx         *jit,
9225
                                            const zend_op        *opline,
9226
                                            uint32_t              b,
9227
                                            const zend_op_array  *op_array,
9228
                                            zend_ssa             *ssa,
9229
                                            const zend_ssa_op    *ssa_op,
9230
                                            int                   call_level,
9231
                                            zend_jit_trace_rec   *trace,
9232
                                            int                   checked_stack)
9233
0
{
9234
0
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
9235
0
  zend_call_info *call_info = NULL;
9236
0
  zend_class_entry *ce;
9237
0
  zend_function *func = NULL;
9238
0
  ir_ref func_ref, func_ref2, scope_ref, scope_ref2, if_cached, cold_path, ref;
9239
0
  ir_ref if_static = IR_UNUSED;
9240
9241
0
  if (info) {
9242
0
    call_info = info->callee_info;
9243
0
    while (call_info && call_info->caller_init_opline != opline) {
9244
0
      call_info = call_info->next_callee;
9245
0
    }
9246
0
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
9247
0
      func = call_info->callee_func;
9248
0
    }
9249
0
  }
9250
9251
0
  ce = zend_get_known_class(op_array, opline, opline->op1_type, opline->op1);
9252
0
  if (!func && ce && (opline->op1_type == IS_CONST || !(ce->ce_flags & ZEND_ACC_TRAIT))) {
9253
0
    zval *zv = RT_CONSTANT(opline, opline->op2);
9254
0
    zend_string *method_name;
9255
9256
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
9257
0
    method_name = Z_STR_P(zv);
9258
0
    zv = zend_hash_find(&ce->function_table, method_name);
9259
0
    if (zv) {
9260
0
      zend_function *fn = Z_PTR_P(zv);
9261
9262
0
      if (fn->common.scope == op_array->scope
9263
0
       || (fn->common.fn_flags & ZEND_ACC_PUBLIC)
9264
0
       || ((fn->common.fn_flags & ZEND_ACC_PROTECTED)
9265
0
        && op_array->scope
9266
0
        && instanceof_function_slow(op_array->scope, fn->common.scope))) {
9267
0
        func = fn;
9268
0
      }
9269
0
    }
9270
0
  }
9271
9272
0
  if (jit->delayed_call_level) {
9273
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9274
0
      return 0;
9275
0
    }
9276
0
  }
9277
9278
  // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9279
0
  func_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9280
9281
  // JIT: if (fbc)
9282
0
  if_cached = ir_IF(func_ref);
9283
0
  ir_IF_FALSE_cold(if_cached);
9284
9285
0
  jit_SET_EX_OPLINE(jit, opline);
9286
0
  scope_ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_class_helper), jit_FP(jit));
9287
0
  ir_GUARD(scope_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9288
9289
0
  func_ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_static_method_helper), jit_FP(jit), scope_ref2);
9290
0
  ir_GUARD(func_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9291
9292
0
  cold_path = ir_END();
9293
9294
0
  ir_IF_TRUE(if_cached);
9295
0
  if (ce && (ce->ce_flags & ZEND_ACC_IMMUTABLE) && (ce->ce_flags & ZEND_ACC_LINKED)) {
9296
0
    scope_ref = ir_CONST_ADDR(ce);
9297
0
  } else {
9298
0
    scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num));
9299
0
  }
9300
9301
0
  ir_MERGE_2(cold_path, ir_END());
9302
0
  func_ref = ir_PHI_2(IR_ADDR, func_ref2, func_ref);
9303
0
  scope_ref = ir_PHI_2(IR_ADDR, scope_ref2, scope_ref);
9304
9305
0
  if ((!func || zend_jit_may_be_modified(func, op_array))
9306
0
   && trace
9307
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9308
0
   && trace->func) {
9309
0
    int32_t exit_point;
9310
0
    const void *exit_addr;
9311
9312
0
    exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : 0);
9313
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9314
0
    if (!exit_addr) {
9315
0
      return 0;
9316
0
    }
9317
9318
//    jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9319
//    jit->trace->exit_info[exit_point].poly_this_ref = scope_ref;
9320
9321
0
    func = (zend_function*)trace->func;
9322
9323
0
    if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9324
0
      return 0;
9325
0
    }
9326
0
  }
9327
9328
0
  if (!func || !(func->common.fn_flags & ZEND_ACC_STATIC)) {
9329
0
    if (!func) {
9330
      // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9331
0
      if_static = ir_IF(ir_AND_U32(
9332
0
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9333
0
        ir_CONST_U32(ZEND_ACC_STATIC)));
9334
0
      ir_IF_FALSE_cold(if_static);
9335
0
    }
9336
9337
0
    jit_SET_EX_OPLINE(jit, opline);
9338
0
    ref = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_this_method_call_frame),
9339
0
        scope_ref,
9340
0
        func_ref,
9341
0
        ir_CONST_U32(opline->extended_value));
9342
0
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9343
0
    jit_STORE_IP(jit, ref);
9344
9345
0
    if (!func) {
9346
0
      cold_path = ir_END();
9347
0
      ir_IF_TRUE(if_static);
9348
0
    }
9349
0
  }
9350
9351
0
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC)) {
9352
0
    if (opline->op1_type == IS_UNUSED
9353
0
     && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
9354
0
         (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
9355
0
      if (op_array->fn_flags & ZEND_ACC_STATIC) {
9356
0
        scope_ref = ir_LOAD_A(jit_EX(This.value.ref));
9357
0
      } else if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
9358
0
        ir_ref if_object, values = IR_UNUSED;
9359
9360
0
        if_object = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, jit_EX(This)), ir_CONST_U8(IS_OBJECT)));
9361
0
        ir_IF_TRUE(if_object);
9362
0
        ir_END_PHI_list(values,
9363
0
          ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce))));
9364
0
        ir_IF_FALSE(if_object);
9365
0
        ir_END_PHI_list(values, ir_LOAD_A(jit_EX(This.value.ref)));
9366
0
        ir_PHI_list(values);
9367
0
      } else {
9368
0
        scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce)));
9369
0
      }
9370
0
    }
9371
0
    if (!zend_jit_push_call_frame(jit, opline, op_array, func, false, false, checked_stack, func_ref, scope_ref)) {
9372
0
      return 0;
9373
0
    }
9374
9375
0
    if (!func) {
9376
0
      ir_MERGE_2(cold_path, ir_END());
9377
0
    }
9378
0
  }
9379
9380
0
  zend_jit_start_reuse_ip(jit);
9381
0
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9382
0
    if (!zend_jit_save_call_chain(jit, call_level)) {
9383
0
      return 0;
9384
0
    }
9385
0
  } else {
9386
0
    ZEND_ASSERT(call_level > 0);
9387
0
    jit->delayed_call_level = call_level;
9388
0
    delayed_call_chain = true;
9389
0
  }
9390
9391
0
  if (trace
9392
0
   && trace->op == ZEND_JIT_TRACE_END
9393
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9394
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9395
0
      return 0;
9396
0
    }
9397
0
  }
9398
9399
0
  return 1;
9400
0
}
9401
9402
static int zend_jit_init_closure_call(zend_jit_ctx         *jit,
9403
                                      const zend_op        *opline,
9404
                                      uint32_t              b,
9405
                                      const zend_op_array  *op_array,
9406
                                      zend_ssa             *ssa,
9407
                                      const zend_ssa_op    *ssa_op,
9408
                                      int                   call_level,
9409
                                      zend_jit_trace_rec   *trace,
9410
                                      int                   checked_stack)
9411
0
{
9412
0
  zend_function *func = NULL;
9413
0
  zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9414
0
  ir_ref ref;
9415
9416
0
  ref = jit_Z_PTR(jit, op2_addr);
9417
9418
0
  if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9419
0
   && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9420
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9421
0
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9422
9423
0
    if (!exit_addr) {
9424
0
      return 0;
9425
0
    }
9426
9427
0
    ir_GUARD(
9428
0
      ir_EQ(
9429
0
        ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9430
0
        ir_CONST_ADDR(zend_ce_closure)),
9431
0
      ir_CONST_ADDR(exit_addr));
9432
9433
0
    if (ssa->var_info && ssa_op->op2_use >= 0) {
9434
0
      ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9435
0
      ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9436
0
      ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9437
0
    }
9438
0
  }
9439
9440
0
  if (trace
9441
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9442
0
   && trace->func
9443
0
   && trace->func->type == ZEND_USER_FUNCTION) {
9444
0
    const zend_op *opcodes;
9445
0
    int32_t exit_point;
9446
0
    const void *exit_addr;
9447
9448
0
    func = (zend_function*)trace->func;
9449
0
    opcodes = func->op_array.opcodes;
9450
0
    exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9451
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9452
0
    if (!exit_addr) {
9453
0
      return 0;
9454
0
    }
9455
9456
0
    ir_GUARD(
9457
0
      ir_EQ(
9458
0
        ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9459
0
        ir_CONST_ADDR(opcodes)),
9460
0
      ir_CONST_ADDR(exit_addr));
9461
0
  }
9462
9463
0
  if (jit->delayed_call_level) {
9464
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9465
0
      return 0;
9466
0
    }
9467
0
  }
9468
9469
0
  if (!zend_jit_push_call_frame(jit, opline, NULL, func, true, false, checked_stack, ref, IR_UNUSED)) {
9470
0
    return 0;
9471
0
  }
9472
9473
0
  if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9474
0
    if (!zend_jit_save_call_chain(jit, call_level)) {
9475
0
      return 0;
9476
0
    }
9477
0
  } else {
9478
0
    ZEND_ASSERT(call_level > 0);
9479
0
    delayed_call_chain = true;
9480
0
    jit->delayed_call_level = call_level;
9481
0
  }
9482
9483
0
  if (trace
9484
0
   && trace->op == ZEND_JIT_TRACE_END
9485
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9486
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9487
0
      return 0;
9488
0
    }
9489
0
  }
9490
9491
0
  return 1;
9492
0
}
9493
9494
static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9495
0
{
9496
0
  uint32_t arg_num = opline->op2.num;
9497
0
  zend_jit_addr arg_addr;
9498
9499
0
  ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9500
9501
0
  if (!zend_jit_reuse_ip(jit)) {
9502
0
    return 0;
9503
0
  }
9504
9505
0
  if (opline->opcode == ZEND_SEND_VAL_EX) {
9506
0
    uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9507
9508
0
    ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9509
9510
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9511
0
     && JIT_G(current_frame)
9512
0
     && JIT_G(current_frame)->call
9513
0
     && JIT_G(current_frame)->call->func) {
9514
0
      if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9515
        /* Don't generate code that always throws exception */
9516
0
        return 0;
9517
0
      }
9518
0
    } else {
9519
0
      ir_ref cond = ir_AND_U32(
9520
0
        ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9521
0
        ir_CONST_U32(mask));
9522
9523
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9524
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9525
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9526
0
        if (!exit_addr) {
9527
0
          return 0;
9528
0
        }
9529
0
        ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9530
0
      } else {
9531
0
        ir_ref if_pass_by_ref;
9532
9533
0
        if_pass_by_ref = ir_IF(cond);
9534
9535
0
        ir_IF_TRUE_cold(if_pass_by_ref);
9536
0
        if (Z_MODE(op1_addr) == IS_REG) {
9537
          /* set type to avoid zval_ptr_dtor() on uninitialized value */
9538
0
          zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9539
0
          jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9540
0
        }
9541
0
        jit_SET_EX_OPLINE(jit, opline);
9542
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9543
9544
0
        ir_IF_FALSE(if_pass_by_ref);
9545
0
      }
9546
0
    }
9547
0
  }
9548
9549
0
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9550
9551
0
  if (opline->op1_type == IS_CONST) {
9552
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
9553
9554
0
    jit_ZVAL_COPY_CONST(jit,
9555
0
      arg_addr,
9556
0
      MAY_BE_ANY, MAY_BE_ANY,
9557
0
      zv, true);
9558
0
  } else {
9559
0
    jit_ZVAL_COPY(jit,
9560
0
      arg_addr,
9561
0
      MAY_BE_ANY,
9562
0
      op1_addr, op1_info, false);
9563
0
  }
9564
9565
0
  return 1;
9566
0
}
9567
9568
static int zend_jit_send_ref(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold)
9569
0
{
9570
0
  zend_jit_addr op1_addr, arg_addr, ref_addr;
9571
0
  ir_ref ref_path = IR_UNUSED;
9572
9573
0
  op1_addr = OP1_ADDR();
9574
0
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9575
9576
0
  if (!zend_jit_reuse_ip(jit)) {
9577
0
    return 0;
9578
0
  }
9579
9580
0
  if (opline->op1_type == IS_VAR) {
9581
0
    if (op1_info & MAY_BE_INDIRECT) {
9582
0
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9583
0
    }
9584
0
  } else if (opline->op1_type == IS_CV) {
9585
0
    if (op1_info & MAY_BE_UNDEF) {
9586
0
      if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9587
        // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9588
0
        ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9589
0
        ir_IF_FALSE(if_def);
9590
        // JIT: ZVAL_NULL(op1)
9591
0
        jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9592
0
        ir_MERGE_WITH_EMPTY_TRUE(if_def);
9593
0
      }
9594
0
      op1_info &= ~MAY_BE_UNDEF;
9595
0
      op1_info |= MAY_BE_NULL;
9596
0
    }
9597
0
  } else {
9598
0
    ZEND_UNREACHABLE();
9599
0
  }
9600
9601
0
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9602
0
    ir_ref ref, ref2;
9603
9604
0
    if (op1_info & MAY_BE_REF) {
9605
0
      ir_ref if_ref;
9606
9607
      // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9608
0
      if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9609
0
      ir_IF_TRUE(if_ref);
9610
      // JIT: ref = Z_PTR_P(op1)
9611
0
      ref = jit_Z_PTR(jit, op1_addr);
9612
      // JIT: GC_ADDREF(ref)
9613
0
      jit_GC_ADDREF(jit, ref);
9614
      // JIT: ZVAL_REFERENCE(arg, ref)
9615
0
      jit_set_Z_PTR(jit, arg_addr, ref);
9616
0
      jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9617
0
      ref_path = ir_END();
9618
0
      ir_IF_FALSE(if_ref);
9619
0
    }
9620
9621
    // JIT: ZVAL_NEW_REF(arg, varptr);
9622
    // JIT: ref = emalloc(sizeof(zend_reference));
9623
0
    ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9624
    // JIT: GC_REFCOUNT(ref) = 2
9625
0
    jit_set_GC_REFCOUNT(jit, ref, 2);
9626
    // JIT: GC_TYPE(ref) = GC_REFERENCE
9627
0
    ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9628
0
    ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9629
0
    ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9630
0
    ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9631
9632
        // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9633
0
    jit_ZVAL_COPY(jit,
9634
0
      ref_addr,
9635
0
      MAY_BE_ANY,
9636
0
      op1_addr, op1_info, false);
9637
9638
    // JIT: ZVAL_REFERENCE(arg, ref)
9639
0
    jit_set_Z_PTR(jit, op1_addr, ref);
9640
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9641
9642
    // JIT: ZVAL_REFERENCE(arg, ref)
9643
0
    jit_set_Z_PTR(jit, arg_addr, ref);
9644
0
    jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9645
0
  }
9646
9647
0
  if (ref_path) {
9648
0
    ir_MERGE_WITH(ref_path);
9649
0
  }
9650
9651
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9652
9653
0
  return 1;
9654
0
}
9655
9656
static int zend_jit_send_var(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr)
9657
0
{
9658
0
  uint32_t arg_num = opline->op2.num;
9659
0
  zend_jit_addr arg_addr;
9660
0
  ir_ref end_inputs = IR_UNUSED;
9661
9662
0
  ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9663
0
       opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9664
0
      arg_num <= MAX_ARG_FLAG_NUM);
9665
9666
0
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9667
9668
0
  if (!zend_jit_reuse_ip(jit)) {
9669
0
    return 0;
9670
0
  }
9671
9672
0
  if (opline->opcode == ZEND_SEND_VAR_EX) {
9673
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9674
0
     && JIT_G(current_frame)
9675
0
     && JIT_G(current_frame)->call
9676
0
     && JIT_G(current_frame)->call->func) {
9677
0
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9678
0
        if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9679
0
          return 0;
9680
0
        }
9681
0
        return 1;
9682
0
      }
9683
0
    } else {
9684
0
      uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9685
9686
      // JIT: if (RX->func->quick_arg_flags & mask)
9687
0
      ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9688
0
        ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9689
0
        ir_CONST_U32(mask)));
9690
0
      ir_IF_TRUE_cold(if_send_by_ref);
9691
9692
0
      if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9693
0
        return 0;
9694
0
      }
9695
9696
0
      ir_END_list(end_inputs);
9697
0
      ir_IF_FALSE(if_send_by_ref);
9698
0
    }
9699
0
  } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9700
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9701
0
     && JIT_G(current_frame)
9702
0
     && JIT_G(current_frame)->call
9703
0
     && JIT_G(current_frame)->call->func) {
9704
0
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9705
9706
            // JIT: ZVAL_COPY_VALUE(arg, op1)
9707
0
        jit_ZVAL_COPY(jit,
9708
0
          arg_addr,
9709
0
          MAY_BE_ANY,
9710
0
          op1_addr, op1_info, false);
9711
9712
0
        if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9713
0
          if (!(op1_info & MAY_BE_REF)) {
9714
            /* Don't generate code that always throws exception */
9715
0
            return 0;
9716
0
          } else {
9717
0
            int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9718
0
            const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9719
0
            if (!exit_addr) {
9720
0
              return 0;
9721
0
            }
9722
9723
            // JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9724
0
            ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9725
0
              ir_CONST_ADDR(exit_addr));
9726
0
          }
9727
0
        }
9728
0
        return 1;
9729
0
      }
9730
0
    } else {
9731
0
      uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9732
0
      ir_ref func, if_send_by_ref, if_prefer_ref;
9733
9734
      // JIT: if (RX->func->quick_arg_flags & mask)
9735
0
      func = ir_LOAD_A(jit_RX(func));
9736
0
      if_send_by_ref = ir_IF(ir_AND_U32(
9737
0
        ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9738
0
        ir_CONST_U32(mask)));
9739
0
      ir_IF_TRUE_cold(if_send_by_ref);
9740
9741
0
      mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9742
9743
          // JIT: ZVAL_COPY_VALUE(arg, op1)
9744
0
      jit_ZVAL_COPY(jit,
9745
0
        arg_addr,
9746
0
        MAY_BE_ANY,
9747
0
        op1_addr, op1_info, false);
9748
9749
0
      if (op1_info & MAY_BE_REF) {
9750
0
        ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9751
0
        ir_IF_TRUE(if_ref);
9752
0
        ir_END_list(end_inputs);
9753
0
        ir_IF_FALSE(if_ref);
9754
0
      }
9755
9756
      // JIT: if (RX->func->quick_arg_flags & mask)
9757
0
      if_prefer_ref = ir_IF(ir_AND_U32(
9758
0
        ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9759
0
        ir_CONST_U32(mask)));
9760
0
      ir_IF_TRUE(if_prefer_ref);
9761
0
      ir_END_list(end_inputs);
9762
0
      ir_IF_FALSE(if_prefer_ref);
9763
9764
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9765
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9766
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9767
0
        if (!exit_addr) {
9768
0
          return 0;
9769
0
        }
9770
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9771
0
      } else {
9772
0
        jit_SET_EX_OPLINE(jit, opline);
9773
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9774
0
          jit_ZVAL_ADDR(jit, arg_addr));
9775
0
        zend_jit_check_exception(jit);
9776
0
        ir_END_list(end_inputs);
9777
0
      }
9778
9779
0
      ir_IF_FALSE(if_send_by_ref);
9780
0
    }
9781
0
  } else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9782
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9783
0
     && JIT_G(current_frame)
9784
0
     && JIT_G(current_frame)->call
9785
0
     && JIT_G(current_frame)->call->func) {
9786
0
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9787
0
        if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9788
0
          return 0;
9789
0
        }
9790
0
        return 1;
9791
0
      }
9792
0
    } else {
9793
      // JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9794
0
      ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9795
0
        ir_LOAD_U32(jit_RX(This.u1.type_info)),
9796
0
        ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9797
0
      ir_IF_TRUE_cold(if_send_by_ref);
9798
9799
0
      if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9800
0
        return 0;
9801
0
      }
9802
9803
0
      ir_END_list(end_inputs);
9804
0
      ir_IF_FALSE(if_send_by_ref);
9805
0
    }
9806
0
  }
9807
9808
0
  if (op1_info & MAY_BE_UNDEF) {
9809
0
    ir_ref ref, if_def = IR_UNUSED;
9810
9811
0
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9812
0
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9813
0
      ir_IF_FALSE_cold(if_def);
9814
0
    }
9815
9816
    // JIT: zend_jit_undefined_op_helper(opline->op1.var)
9817
0
    jit_SET_EX_OPLINE(jit, opline);
9818
0
    ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9819
0
      ir_CONST_U32(opline->op1.var));
9820
9821
    // JIT: ZVAL_NULL(arg)
9822
0
    jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9823
9824
    // JIT: check_exception
9825
0
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9826
9827
0
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9828
0
      ir_END_list(end_inputs);
9829
0
      ir_IF_TRUE(if_def);
9830
0
    } else {
9831
0
      if (end_inputs) {
9832
0
        ir_END_list(end_inputs);
9833
0
        ir_MERGE_list(end_inputs);
9834
0
      }
9835
0
      return 1;
9836
0
    }
9837
0
  }
9838
9839
0
  if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9840
        // JIT: ZVAL_COPY_VALUE(arg, op1)
9841
0
    jit_ZVAL_COPY(jit,
9842
0
      arg_addr,
9843
0
      MAY_BE_ANY,
9844
0
      op1_addr, op1_info, false);
9845
0
    if (op1_info & MAY_BE_REF) {
9846
        // JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9847
0
        ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9848
0
        ir_IF_TRUE(if_ref);
9849
0
        ir_END_list(end_inputs);
9850
0
        ir_IF_FALSE(if_ref);
9851
0
    }
9852
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9853
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9854
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9855
0
      if (!exit_addr) {
9856
0
        return 0;
9857
0
      }
9858
0
      ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9859
0
    } else {
9860
0
      jit_SET_EX_OPLINE(jit, opline);
9861
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9862
0
        jit_ZVAL_ADDR(jit, arg_addr));
9863
0
      zend_jit_check_exception(jit);
9864
0
    }
9865
0
  } else {
9866
0
    if (op1_info & MAY_BE_REF) {
9867
0
      if (opline->op1_type == IS_CV) {
9868
0
        ir_ref ref;
9869
9870
        // JIT: ZVAL_DEREF(op1)
9871
0
        ref = jit_ZVAL_ADDR(jit, op1_addr);
9872
0
        ref = jit_ZVAL_DEREF_ref(jit, ref);
9873
0
        op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9874
9875
            // JIT: ZVAL_COPY(arg, op1)
9876
0
        jit_ZVAL_COPY(jit,
9877
0
          arg_addr,
9878
0
          MAY_BE_ANY,
9879
0
          op1_addr, op1_info, true);
9880
0
      } else {
9881
0
        ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9882
0
        zend_jit_addr ref_addr;
9883
9884
        // JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9885
0
        if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9886
0
        ir_IF_TRUE_cold(if_ref);
9887
9888
        // JIT: ref = Z_COUNTED_P(op1);
9889
0
        ref = jit_Z_PTR(jit, op1_addr);
9890
0
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9891
0
        ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9892
9893
        // JIT: ZVAL_COPY_VALUE(arg, op1);
9894
0
        jit_ZVAL_COPY(jit,
9895
0
          arg_addr,
9896
0
          MAY_BE_ANY,
9897
0
          ref_addr, op1_info, false);
9898
9899
        // JIT: if (GC_DELREF(ref) != 0)
9900
0
        refcount = jit_GC_DELREF(jit, ref);
9901
0
        if_not_zero = ir_IF(refcount);
9902
0
        ir_IF_TRUE(if_not_zero);
9903
9904
                // JIT: if (Z_REFCOUNTED_P(arg)
9905
0
        if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9906
0
        ir_IF_TRUE(if_refcounted);
9907
        // JIT: Z_ADDREF_P(arg)
9908
0
        jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9909
0
        ir_END_list(end_inputs);
9910
0
        ir_IF_FALSE(if_refcounted);
9911
0
        ir_END_list(end_inputs);
9912
9913
0
        ir_IF_FALSE(if_not_zero);
9914
9915
        // JIT: efree(ref)
9916
0
        jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9917
0
        ir_END_list(end_inputs);
9918
9919
0
        ir_IF_FALSE(if_ref);
9920
9921
        // JIT: ZVAL_COPY_VALUE(arg, op1);
9922
0
        jit_ZVAL_COPY(jit,
9923
0
          arg_addr,
9924
0
          MAY_BE_ANY,
9925
0
          op1_addr, op1_info, false);
9926
0
      }
9927
0
    } else {
9928
0
      if (op1_addr != op1_def_addr) {
9929
0
        if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9930
0
          return 0;
9931
0
        }
9932
0
        if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9933
0
          op1_addr = op1_def_addr;
9934
0
        }
9935
0
      }
9936
9937
          // JIT: ZVAL_COPY_VALUE(arg, op1)
9938
0
      jit_ZVAL_COPY(jit,
9939
0
        arg_addr,
9940
0
        MAY_BE_ANY,
9941
0
        op1_addr, op1_info, opline->op1_type == IS_CV);
9942
0
    }
9943
0
  }
9944
9945
0
  if (end_inputs) {
9946
0
    ir_END_list(end_inputs);
9947
0
    ir_MERGE_list(end_inputs);
9948
0
  }
9949
9950
0
  return 1;
9951
0
}
9952
9953
static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
9954
0
{
9955
0
  uint32_t arg_num = opline->op2.num;
9956
0
  ir_ref ref;
9957
9958
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9959
0
   && JIT_G(current_frame)
9960
0
   && JIT_G(current_frame)->call
9961
0
   && JIT_G(current_frame)->call->func) {
9962
0
    if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9963
0
      if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
9964
0
        TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
9965
        // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9966
0
        if (jit->reuse_ip) {
9967
0
          ref = jit_IP(jit);
9968
0
        } else {
9969
0
          ref = ir_LOAD_A(jit_EX(call));
9970
0
        }
9971
0
        ref = jit_CALL(ref, This.u1.type_info);
9972
0
        ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9973
0
      }
9974
0
    } else {
9975
0
      if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
9976
0
        TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
9977
        // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
9978
0
        if (jit->reuse_ip) {
9979
0
          ref = jit_IP(jit);
9980
0
        } else {
9981
0
          ref = ir_LOAD_A(jit_EX(call));
9982
0
        }
9983
0
        ref = jit_CALL(ref, This.u1.type_info);
9984
0
        ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
9985
0
      }
9986
0
    }
9987
0
  } else {
9988
    // JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
9989
0
    uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9990
0
    ir_ref rx, if_ref, cold_path;
9991
9992
0
    if (!zend_jit_reuse_ip(jit)) {
9993
0
      return 0;
9994
0
    }
9995
9996
0
    rx = jit_IP(jit);
9997
9998
0
    ref = ir_AND_U32(
9999
0
      ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
10000
0
      ir_CONST_U32(mask));
10001
0
    if_ref = ir_IF(ref);
10002
0
    ir_IF_TRUE_cold(if_ref);
10003
10004
    // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10005
0
    ref = jit_CALL(rx, This.u1.type_info);
10006
0
    ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
10007
10008
0
    cold_path = ir_END();
10009
0
    ir_IF_FALSE(if_ref);
10010
10011
    // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10012
0
    ref = jit_CALL(rx, This.u1.type_info);
10013
0
    ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
10014
10015
0
    ir_MERGE_WITH(cold_path);
10016
0
  }
10017
10018
0
  return 1;
10019
0
}
10020
10021
static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
10022
0
{
10023
0
  ir_ref call, if_may_have_undef, ret;
10024
10025
0
  if (jit->reuse_ip) {
10026
0
    call = jit_IP(jit);
10027
0
  } else {
10028
0
    call = ir_LOAD_A(jit_EX(call));
10029
0
  }
10030
10031
0
  if_may_have_undef = ir_IF(ir_AND_U8(
10032
0
    ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10033
0
    ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
10034
10035
0
  ir_IF_TRUE_cold(if_may_have_undef);
10036
0
  jit_SET_EX_OPLINE(jit, opline);
10037
0
  ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
10038
0
  ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10039
0
  ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
10040
10041
0
  return 1;
10042
0
}
10043
10044
static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace)
10045
0
{
10046
0
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
10047
0
  zend_call_info *call_info = NULL;
10048
0
  const zend_function *func = NULL;
10049
0
  uint32_t i;
10050
0
  uint32_t call_num_args = 0;
10051
0
  bool unknown_num_args = false;
10052
0
  const void *exit_addr = NULL;
10053
0
  const zend_op *prev_opline;
10054
0
  ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
10055
10056
0
  prev_opline = opline - 1;
10057
0
  while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
10058
0
    prev_opline--;
10059
0
  }
10060
0
  if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
10061
0
      prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10062
0
    unknown_num_args = true;
10063
0
  }
10064
10065
0
  if (info) {
10066
0
    call_info = info->callee_info;
10067
0
    while (call_info && call_info->caller_call_opline != opline) {
10068
0
      call_info = call_info->next_callee;
10069
0
    }
10070
0
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
10071
0
      func = call_info->callee_func;
10072
0
    }
10073
0
    if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
10074
0
     && (!JIT_G(current_frame)
10075
0
      || !JIT_G(current_frame)->call
10076
0
      || !JIT_G(current_frame)->call->func)) {
10077
0
      call_info = NULL; func = NULL; /* megamorphic call from trait */
10078
0
    }
10079
0
  }
10080
0
  if (!func) {
10081
    /* resolve function at run time */
10082
0
  } else if (func->type == ZEND_USER_FUNCTION) {
10083
0
    ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
10084
0
    call_num_args = call_info->num_args;
10085
0
  } else if (func->type == ZEND_INTERNAL_FUNCTION) {
10086
0
    ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
10087
0
    call_num_args = call_info->num_args;
10088
0
  } else {
10089
0
    ZEND_UNREACHABLE();
10090
0
  }
10091
10092
0
  if (trace && !func) {
10093
0
    if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
10094
0
      ZEND_ASSERT(!trace->func || trace->func->type == ZEND_INTERNAL_FUNCTION);
10095
0
#ifndef ZEND_WIN32
10096
      // TODO: ASLR may cause different addresses in different workers ???
10097
0
      func = trace->func;
10098
0
      if (JIT_G(current_frame) &&
10099
0
          JIT_G(current_frame)->call &&
10100
0
          TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10101
0
        call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10102
0
      } else {
10103
0
        unknown_num_args = true;
10104
0
      }
10105
0
#endif
10106
0
    } else if (trace->op == ZEND_JIT_TRACE_ENTER) {
10107
0
      ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
10108
0
      if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
10109
0
        func = trace->func;
10110
0
        if (JIT_G(current_frame) &&
10111
0
            JIT_G(current_frame)->call &&
10112
0
            TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10113
0
          call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10114
0
        } else {
10115
0
          unknown_num_args = true;
10116
0
        }
10117
0
      }
10118
0
    }
10119
0
  }
10120
10121
0
  bool may_have_extra_named_params =
10122
0
    (opline->extended_value & ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS) &&
10123
0
    (!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
10124
10125
0
  if (!jit->reuse_ip) {
10126
0
    zend_jit_start_reuse_ip(jit);
10127
    // JIT: call = EX(call);
10128
0
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
10129
0
  }
10130
0
  rx = jit_IP(jit);
10131
0
  zend_jit_stop_reuse_ip(jit);
10132
10133
0
  jit_SET_EX_OPLINE(jit, opline);
10134
10135
0
  if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10136
0
    if (!func) {
10137
0
      if (trace) {
10138
0
        uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10139
10140
0
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10141
0
        if (!exit_addr) {
10142
0
          return 0;
10143
0
        }
10144
10145
0
        func_ref = ir_LOAD_A(jit_CALL(rx, func));
10146
0
        ir_GUARD_NOT(
10147
0
          ir_AND_U32(
10148
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10149
0
            ir_CONST_U32(ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)),
10150
0
          ir_CONST_ADDR(exit_addr));
10151
0
      }
10152
0
    }
10153
0
  }
10154
10155
0
  if (!jit->delayed_call_level) {
10156
    // JIT: EX(call) = call->prev_execute_data;
10157
0
    ir_STORE(jit_EX(call),
10158
0
      (call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
10159
0
  }
10160
0
  delayed_call_chain = false;
10161
0
  jit->delayed_call_level = 0;
10162
10163
  // JIT: call->prev_execute_data = execute_data;
10164
0
  ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
10165
10166
0
  if (!func) {
10167
0
    if (!func_ref) {
10168
0
      func_ref = ir_LOAD_A(jit_CALL(rx, func));
10169
0
    }
10170
0
  }
10171
10172
0
  if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10173
0
    if (!func) {
10174
0
      if (!trace) {
10175
0
        ir_ref if_deprecated_nodiscard, ret;
10176
10177
0
        uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
10178
10179
0
        if_deprecated_nodiscard = ir_IF(ir_AND_U32(
10180
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10181
0
            ir_CONST_U32(ZEND_ACC_DEPRECATED|no_discard)));
10182
0
        ir_IF_TRUE_cold(if_deprecated_nodiscard);
10183
10184
0
        ir_ref helper = ir_CONST_FC_FUNC(no_discard ? zend_jit_deprecated_nodiscard_helper : zend_jit_deprecated_helper);
10185
0
        if (GCC_GLOBAL_REGS) {
10186
0
          ret = ir_CALL(IR_BOOL, helper);
10187
0
        } else {
10188
0
          ret = ir_CALL_1(IR_BOOL, helper, rx);
10189
0
        }
10190
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10191
0
        ir_MERGE_WITH_EMPTY_FALSE(if_deprecated_nodiscard);
10192
0
      }
10193
0
    } else {
10194
0
      if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10195
0
        ir_ref ret;
10196
10197
0
        if (GCC_GLOBAL_REGS) {
10198
0
          ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10199
0
        } else {
10200
0
          ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10201
0
        }
10202
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10203
0
      }
10204
10205
0
      if ((func->common.fn_flags & ZEND_ACC_NODISCARD) && !RETURN_VALUE_USED(opline)) {
10206
0
        ir_ref ret;
10207
10208
0
        if (GCC_GLOBAL_REGS) {
10209
0
          ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper));
10210
0
        } else {
10211
0
          ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper), rx);
10212
0
        }
10213
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10214
0
      }
10215
0
    }
10216
0
  }
10217
10218
0
  if (!func
10219
0
   && opline->opcode != ZEND_DO_UCALL
10220
0
   && opline->opcode != ZEND_DO_ICALL) {
10221
0
    ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
10222
0
    if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
10223
0
    ir_IF_TRUE(if_user);
10224
0
  }
10225
10226
0
  if ((!func || func->type == ZEND_USER_FUNCTION)
10227
0
   && opline->opcode != ZEND_DO_ICALL) {
10228
0
    bool recursive_call_through_jmp = false;
10229
0
    uint32_t num_args = 0;
10230
10231
    // JIT: EX(call) = NULL;
10232
0
    ir_STORE(jit_CALL(rx, call), IR_NULL);
10233
10234
    // JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
10235
0
    ir_STORE(jit_CALL(rx, return_value),
10236
0
      RETURN_VALUE_USED(opline) ?
10237
0
        jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
10238
0
        IR_NULL);
10239
10240
    // JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
10241
0
    if (!func || func->op_array.cache_size) {
10242
0
      ir_ref run_time_cache;
10243
10244
0
      if (func && op_array == &func->op_array) {
10245
        /* recursive call */
10246
0
        run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
10247
0
      } else if (func
10248
0
       && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
10249
0
       && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10250
0
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
10251
0
          (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
10252
0
      } else if (func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
10253
        /* Closures always use direct pointers */
10254
0
        ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10255
10256
0
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10257
0
      } else {
10258
0
        ir_ref if_odd, run_time_cache2;
10259
0
        ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10260
10261
0
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10262
0
        if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
10263
0
        ir_IF_TRUE(if_odd);
10264
10265
0
        run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
10266
10267
0
        ir_MERGE_WITH_EMPTY_FALSE(if_odd);
10268
0
        run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
10269
0
      }
10270
10271
0
      ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
10272
0
    }
10273
10274
    // JIT: EG(current_execute_data) = execute_data = call;
10275
0
    ir_STORE(jit_EG(current_execute_data), rx);
10276
0
    jit_STORE_FP(jit, rx);
10277
10278
    // JIT: opline = op_array->opcodes;
10279
0
    if (func && !unknown_num_args) {
10280
10281
0
      for (i = call_num_args; i < func->op_array.last_var; i++) {
10282
0
        uint32_t n = EX_NUM_TO_VAR(i);
10283
0
        zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
10284
10285
0
        jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
10286
0
      }
10287
10288
0
      if (call_num_args <= func->op_array.num_args) {
10289
0
        if (!trace || (trace->op == ZEND_JIT_TRACE_END
10290
0
         && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10291
0
          if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10292
0
            if (trace) {
10293
0
              num_args = 0;
10294
0
            } else if (call_info) {
10295
0
              num_args = skip_valid_arguments(op_array, ssa, call_info);
10296
0
            } else {
10297
0
              num_args = call_num_args;
10298
0
            }
10299
0
          } else {
10300
0
            num_args = call_num_args;
10301
0
          }
10302
0
          if (zend_accel_in_shm(func->op_array.opcodes)) {
10303
0
            jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
10304
0
          } else {
10305
0
            if (!func_ref) {
10306
0
              func_ref = ir_LOAD_A(jit_CALL(rx, func));
10307
0
            }
10308
0
            ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10309
0
            if (num_args) {
10310
0
              ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
10311
0
            }
10312
0
            jit_STORE_IP(jit, ip);
10313
0
          }
10314
10315
0
          if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
10316
            /* recursive call */
10317
0
            recursive_call_through_jmp = true;
10318
0
          }
10319
0
        }
10320
0
      } else {
10321
0
        ir_ref helper;
10322
0
        if (!trace || (trace->op == ZEND_JIT_TRACE_END
10323
0
         && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10324
0
          ir_ref ip;
10325
10326
0
          if (zend_accel_in_shm(func->op_array.opcodes)) {
10327
0
            ip = ir_CONST_ADDR(func->op_array.opcodes);
10328
0
          } else {
10329
0
            if (!func_ref) {
10330
0
              func_ref = ir_LOAD_A(jit_CALL(rx, func));
10331
0
            }
10332
0
            ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10333
0
          }
10334
0
          jit_STORE_IP(jit, ip);
10335
0
          helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper);
10336
0
        } else {
10337
0
          helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper_no_skip_recv);
10338
0
        }
10339
0
        if (GCC_GLOBAL_REGS) {
10340
0
          ir_CALL(IR_VOID, helper);
10341
0
        } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
10342
0
          ir_CALL_2(IR_ADDR, helper, jit_FP(jit), jit_IP(jit));
10343
0
        } else {
10344
0
          ir_ref ref = ir_CALL_2(IR_ADDR, helper, jit_FP(jit), jit_IP(jit));
10345
0
          jit_STORE_IP(jit, ref);
10346
0
        }
10347
0
      }
10348
0
    } else {
10349
0
      ir_ref ip;
10350
0
      ir_ref merge_inputs = IR_UNUSED;
10351
10352
      // JIT: opline = op_array->opcodes
10353
0
      if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10354
0
        ip = ir_CONST_ADDR(func->op_array.opcodes);
10355
0
      } else {
10356
0
        if (!func_ref) {
10357
0
          func_ref = ir_LOAD_A(jit_CALL(rx, func));
10358
0
        }
10359
0
        ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10360
0
      }
10361
0
      jit_STORE_IP(jit, ip);
10362
10363
      // JIT: num_args = EX_NUM_ARGS();
10364
0
      ir_ref num_args, first_extra_arg;
10365
10366
0
      num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10367
0
      if (func) {
10368
0
        first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10369
0
      } else {
10370
        // JIT: first_extra_arg = op_array->num_args;
10371
0
        ZEND_ASSERT(func_ref);
10372
0
        first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10373
0
      }
10374
10375
      // JIT: if (UNEXPECTED(num_args > first_extra_arg))
10376
0
      ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10377
0
      ir_IF_TRUE_cold(if_extra_args);
10378
0
      if (GCC_GLOBAL_REGS) {
10379
0
        ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10380
0
      } else {
10381
0
        ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit), jit_IP(jit));
10382
0
        jit_STORE_IP(jit, ref);
10383
0
      }
10384
0
      ir_END_list(merge_inputs);
10385
0
      ir_IF_FALSE(if_extra_args);
10386
0
      if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10387
0
        if (!func) {
10388
          // JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10389
0
          ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10390
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10391
0
            ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
10392
0
          ir_IF_TRUE(if_has_type_hints);
10393
0
          ir_END_list(merge_inputs);
10394
0
          ir_IF_FALSE(if_has_type_hints);
10395
0
        }
10396
        // JIT: opline += num_args;
10397
10398
0
        ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
10399
10400
0
        if (sizeof(void*) == 8) {
10401
0
          ref = ir_ZEXT_A(ref);
10402
0
        }
10403
10404
0
        jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10405
0
      }
10406
10407
0
      ir_END_list(merge_inputs);
10408
0
      ir_MERGE_list(merge_inputs);
10409
10410
      // JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10411
0
      ir_ref last_var;
10412
10413
0
      if (func) {
10414
0
        last_var = ir_CONST_U32(func->op_array.last_var);
10415
0
      } else {
10416
0
        ZEND_ASSERT(func_ref);
10417
0
        last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10418
0
      }
10419
10420
0
      ir_ref idx = ir_SUB_U32(last_var, num_args);
10421
0
      ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10422
0
      ir_IF_TRUE(if_need);
10423
10424
      // JIT: zval *var = EX_VAR_NUM(num_args);
10425
0
      if (sizeof(void*) == 8) {
10426
0
        num_args = ir_ZEXT_A(num_args);
10427
0
      }
10428
0
      ir_ref var_ref = ir_ADD_OFFSET(
10429
0
        ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10430
0
        (ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10431
10432
0
      ir_ref loop = ir_LOOP_BEGIN(ir_END());
10433
0
      var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10434
0
      idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10435
0
      ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10436
0
      ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10437
0
      ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10438
0
      ir_PHI_SET_OP(idx, 2, idx2);
10439
0
      ir_ref if_not_zero = ir_IF(idx2);
10440
0
      ir_IF_TRUE(if_not_zero);
10441
0
      ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10442
0
      ir_IF_FALSE(if_not_zero);
10443
0
      ir_MERGE_WITH_EMPTY_FALSE(if_need);
10444
0
    }
10445
10446
0
    if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10447
0
      ir_ref observer_handler;
10448
0
      ir_ref rx = jit_FP(jit);
10449
0
      const zend_op *observer_opline = NULL;
10450
0
      struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10451
0
      if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10452
0
        ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10453
0
        observer_opline = trace[1].opline;
10454
0
        jit_SET_EX_OPLINE(jit, observer_opline);
10455
0
      } else {
10456
        // EX(opline) = opline
10457
0
        ir_STORE(jit_EX(opline), jit_IP(jit));
10458
0
      }
10459
0
      jit_observer_fcall_begin(jit, rx, observer_handler);
10460
10461
0
      zend_jit_check_timeout(jit, observer_opline, NULL);
10462
10463
0
      jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10464
0
    }
10465
10466
0
    if (trace) {
10467
0
      if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10468
0
        user_path = ir_END();
10469
0
      }
10470
0
    } else {
10471
0
      zend_basic_block *bb;
10472
10473
0
      do {
10474
0
        if (recursive_call_through_jmp) {
10475
0
          ir_ref begin, end;
10476
0
          ir_insn *insn;
10477
10478
          /* attempt to convert direct recursive call into loop */
10479
0
          begin = jit->bb_start_ref[num_args];
10480
0
          ZEND_ASSERT(begin != IR_UNUSED);
10481
0
          insn = &jit->ctx.ir_base[begin];
10482
0
          if (insn->op == IR_BEGIN) {
10483
0
            end = ir_LOOP_END();
10484
0
            insn = &jit->ctx.ir_base[begin];
10485
0
            insn->op = IR_LOOP_BEGIN;
10486
0
            insn->inputs_count = 2;
10487
0
            insn->op2 = end;
10488
0
            break;
10489
0
          } else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10490
0
              && insn->inputs_count == 2) {
10491
0
            end = ir_LOOP_END();
10492
0
            insn = &jit->ctx.ir_base[begin];
10493
0
            insn->op = IR_LOOP_BEGIN;
10494
0
            insn->inputs_count = 3;
10495
0
            insn->op3 = end;
10496
0
            break;
10497
0
          } else if (insn->op == IR_LOOP_BEGIN && insn->inputs_count == 3) {
10498
0
            ZEND_ASSERT(jit->ctx.ir_base[insn->op3].op == IR_LOOP_END);
10499
0
            jit->ctx.ir_base[insn->op3].op = IR_END;
10500
0
            ir_MERGE_2(insn->op3, ir_END());
10501
0
            end = ir_LOOP_END();
10502
0
            insn = &jit->ctx.ir_base[begin];
10503
0
            insn->op3 = end;
10504
0
            break;
10505
0
          }
10506
0
        }
10507
        /* fallback to indirect JMP or RETURN */
10508
0
        if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
10509
0
          zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
10510
0
        } else {
10511
0
          zend_jit_vm_enter(jit, jit_IP(jit));
10512
0
        }
10513
0
      } while (0);
10514
10515
0
      bb = &jit->ssa->cfg.blocks[jit->b];
10516
0
      if (bb->successors_count > 0) {
10517
0
        int succ;
10518
0
        ir_ref ref;
10519
10520
0
        ZEND_ASSERT(bb->successors_count == 1);
10521
0
        succ = bb->successors[0];
10522
        /* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10523
0
        ref = jit->ctx.insns_count - 1;
10524
0
        ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10525
0
          || jit->ctx.ir_base[ref].op == IR_RETURN
10526
0
          || jit->ctx.ir_base[ref].op == IR_LOOP_END);
10527
0
        ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10528
0
        ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10529
0
        if (func || (opline->opcode == ZEND_DO_UCALL)) {
10530
0
          _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10531
0
          jit->b = -1;
10532
0
        } else {
10533
0
          user_path = ref;
10534
0
        }
10535
0
      }
10536
0
    }
10537
0
  }
10538
10539
0
  if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10540
0
   && (opline->opcode != ZEND_DO_UCALL)) {
10541
0
    if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10542
0
      ir_IF_FALSE(if_user);
10543
0
    }
10544
10545
    // JIT: EG(current_execute_data) = execute_data;
10546
0
    ir_STORE(jit_EG(current_execute_data), rx);
10547
10548
0
    bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10549
0
    if (may_have_observer) {
10550
0
      ir_ref observer_handler;
10551
0
      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)));
10552
0
      jit_observer_fcall_begin(jit, rx, observer_handler);
10553
0
      jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10554
0
    }
10555
10556
    // JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10557
0
    ir_ref res_addr = IR_UNUSED, func_ptr;
10558
10559
0
    if (RETURN_VALUE_USED(opline)) {
10560
0
      res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10561
0
    } else {
10562
      /* CPU stack allocated temporary zval */
10563
0
      ir_ref ptr;
10564
10565
0
      if (!jit->ctx.fixed_call_stack_size) {
10566
        // JIT: alloca(sizeof(void*));
10567
0
        ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10568
0
      } else {
10569
#ifdef _WIN64
10570
        ptr = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
10571
#else
10572
0
        ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10573
0
#endif
10574
0
      }
10575
0
      res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10576
0
    }
10577
10578
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10579
10580
0
    zend_jit_reset_last_valid_opline(jit);
10581
10582
    // JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10583
0
    ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10584
0
    if (zend_execute_internal) {
10585
0
      ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10586
0
    } else {
10587
0
      if (func) {
10588
0
        func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10589
0
      } else {
10590
0
        func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10591
#if defined(IR_TARGET_X86)
10592
        func_ptr = ir_CAST_FC_FUNC(func_ptr);
10593
#endif
10594
0
      }
10595
0
      ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10596
0
    }
10597
10598
0
    if (may_have_observer) {
10599
0
      jit_observer_fcall_end(jit, rx, res_ref);
10600
0
    }
10601
10602
    /* When zend_interrupt_function is set, it gets called while
10603
     * the frame is still on top. This is less efficient than
10604
     * doing it later once it's popped off. There is code further
10605
     * down that handles when there isn't an interrupt function.
10606
     */
10607
0
    if (zend_interrupt_function) {
10608
      // JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10609
0
      ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10610
0
      ir_IF_TRUE_cold(if_interrupt);
10611
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
10612
0
      ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10613
0
    }
10614
10615
    // JIT: EG(current_execute_data) = execute_data;
10616
0
    ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10617
10618
    // JIT: zend_vm_stack_free_args(call);
10619
0
    if (func && !unknown_num_args) {
10620
0
      for (i = 0; i < call_num_args; i++ ) {
10621
0
        if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10622
0
          uint32_t offset = EX_NUM_TO_VAR(i);
10623
0
          zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10624
10625
0
          jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, false,
10626
0
                opline);
10627
0
        }
10628
0
      }
10629
0
    } else {
10630
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10631
0
    }
10632
10633
0
    if (may_have_extra_named_params) {
10634
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10635
0
      ir_ref if_has_named = ir_IF(ir_AND_U8(
10636
0
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10637
0
        ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10638
0
      ir_IF_TRUE_cold(if_has_named);
10639
10640
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10641
0
        ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10642
10643
0
      ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10644
0
    }
10645
10646
0
    if (opline->opcode == ZEND_DO_FCALL) {
10647
      // TODO: optimize ???
10648
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10649
0
      ir_ref if_release_this = ir_IF(ir_AND_U8(
10650
0
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10651
0
        ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10652
0
      ir_IF_TRUE_cold(if_release_this);
10653
10654
      // JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10655
0
      jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10656
10657
0
      ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10658
0
    }
10659
10660
10661
0
    ir_ref allocated_path = IR_UNUSED;
10662
10663
0
    if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10664
0
        !JIT_G(current_frame) ||
10665
0
        !JIT_G(current_frame)->call ||
10666
0
        !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10667
0
        prev_opline->opcode == ZEND_SEND_UNPACK ||
10668
0
        prev_opline->opcode == ZEND_SEND_ARRAY ||
10669
0
      prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10670
10671
      // JIT: zend_vm_stack_free_call_frame(call);
10672
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10673
0
      ir_ref if_allocated = ir_IF(ir_AND_U8(
10674
0
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10675
0
        ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10676
0
      ir_IF_TRUE_cold(if_allocated);
10677
10678
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10679
10680
0
      allocated_path = ir_END();
10681
0
      ir_IF_FALSE(if_allocated);
10682
0
    }
10683
10684
0
    ir_STORE(jit_EG(vm_stack_top), rx);
10685
10686
0
    if (allocated_path) {
10687
0
      ir_MERGE_WITH(allocated_path);
10688
0
    }
10689
10690
0
    if (!RETURN_VALUE_USED(opline)) {
10691
0
      zend_class_entry *ce;
10692
0
      bool ce_is_instanceof;
10693
0
      uint32_t func_info = call_info ?
10694
0
        zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10695
0
        (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10696
10697
      /* If an exception is thrown, the return_value may stay at the
10698
       * original value of null. */
10699
0
      func_info |= MAY_BE_NULL;
10700
10701
0
      if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10702
0
        ir_ref sp;
10703
0
        if (!jit->ctx.fixed_call_stack_size) {
10704
0
          sp = ir_RLOAD_A(IR_REG_SP);
10705
0
        } else {
10706
#ifdef _WIN64
10707
          sp = jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS);
10708
#else
10709
0
          sp = ir_RLOAD_A(IR_REG_SP);
10710
0
#endif
10711
0
        }
10712
0
        res_addr = ZEND_ADDR_REF_ZVAL(sp);
10713
0
        jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, true, opline);
10714
0
      }
10715
0
      if (!jit->ctx.fixed_call_stack_size) {
10716
        // JIT: revert alloca
10717
0
        ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10718
0
      }
10719
0
    }
10720
10721
    // JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10722
0
    ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10723
0
      jit_STUB_ADDR(jit, jit_stub_icall_throw));
10724
10725
    /* If there isn't a zend_interrupt_function, the timeout is
10726
     * handled here because it's more efficient.
10727
     */
10728
0
    if (!zend_interrupt_function) {
10729
      // TODO: Can we avoid checking for interrupts after each call ???
10730
0
      if (trace && jit->last_valid_opline != opline) {
10731
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10732
10733
0
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10734
0
        if (!exit_addr) {
10735
0
          return 0;
10736
0
        }
10737
0
      } else {
10738
0
        exit_addr = NULL;
10739
0
      }
10740
10741
0
      zend_jit_check_timeout(jit, opline + 1, exit_addr);
10742
0
    }
10743
10744
0
    if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10745
0
      jit_LOAD_IP_ADDR(jit, opline + 1);
10746
0
    } else if (trace
10747
0
     && trace->op == ZEND_JIT_TRACE_END
10748
0
     && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
10749
0
      jit_LOAD_IP_ADDR(jit, opline + 1);
10750
0
    }
10751
0
  }
10752
10753
0
  if (user_path) {
10754
0
    ir_MERGE_WITH(user_path);
10755
0
  }
10756
10757
0
  return 1;
10758
0
}
10759
10760
static int zend_jit_constructor(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, int next_block)
10761
0
{
10762
0
  ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10763
10764
0
  ir_IF_FALSE(if_skip_constructor);
10765
10766
0
  if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10767
0
    if (!zend_jit_tail_handler(jit, opline)) {
10768
0
      return 0;
10769
0
    }
10770
0
  } else {
10771
0
    if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10772
0
      return 0;
10773
0
    }
10774
0
  }
10775
10776
  /* override predecessors of the next block */
10777
0
  ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10778
0
  if (!jit->ctx.control) {
10779
0
    ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10780
0
    ir_IF_TRUE(if_skip_constructor);
10781
0
    ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10782
0
    jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10783
0
  } else {
10784
0
    ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10785
    /* merge current control path with the true branch of constructor skip condition */
10786
0
    ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10787
0
    jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10788
10789
0
    jit->b = -1;
10790
0
  }
10791
10792
0
  return 1;
10793
0
}
10794
10795
static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception)
10796
0
{
10797
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10798
0
  uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10799
0
  ir_ref ref, fast_path = IR_UNUSED;
10800
10801
0
  ref = jit_ZVAL_ADDR(jit, res_addr);
10802
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10803
0
   && JIT_G(current_frame)
10804
0
   && JIT_G(current_frame)->prev) {
10805
0
    zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10806
0
    uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10807
10808
0
    if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10809
0
      return 1;
10810
0
    }
10811
0
  }
10812
10813
0
  if (ZEND_ARG_SEND_MODE(arg_info)) {
10814
0
    if (opline->opcode == ZEND_RECV_INIT) {
10815
0
      ref = jit_ZVAL_DEREF_ref(jit, ref);
10816
0
    } else {
10817
0
      ref = jit_Z_PTR_ref(jit, ref);
10818
0
      ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10819
0
    }
10820
0
  }
10821
10822
0
  if (type_mask != 0) {
10823
0
    if (is_power_of_two(type_mask)) {
10824
0
      uint32_t type_code = concrete_type(type_mask);
10825
0
      ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10826
0
      ir_IF_TRUE(if_ok);
10827
0
      fast_path = ir_END();
10828
0
      ir_IF_FALSE_cold(if_ok);
10829
0
    } else {
10830
0
      ir_ref if_ok = ir_IF(ir_AND_U32(
10831
0
        ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10832
0
        ir_CONST_U32(type_mask)));
10833
0
      ir_IF_TRUE(if_ok);
10834
0
      fast_path = ir_END();
10835
0
      ir_IF_FALSE_cold(if_ok);
10836
0
    }
10837
0
  }
10838
10839
0
  jit_SET_EX_OPLINE(jit, opline);
10840
0
  ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10841
0
    ref, ir_CONST_ADDR(arg_info));
10842
10843
0
  if (check_exception) {
10844
0
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10845
0
  }
10846
10847
0
  if (fast_path) {
10848
0
    ir_MERGE_WITH(fast_path);
10849
0
  }
10850
10851
0
  return 1;
10852
0
}
10853
10854
static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
10855
0
{
10856
0
  uint32_t arg_num = opline->op1.num;
10857
0
  zend_arg_info *arg_info = NULL;
10858
10859
0
  if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10860
0
    if (EXPECTED(arg_num <= op_array->num_args)) {
10861
0
      arg_info = &op_array->arg_info[arg_num-1];
10862
0
    } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10863
0
      arg_info = &op_array->arg_info[op_array->num_args];
10864
0
    }
10865
0
    if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10866
0
      arg_info = NULL;
10867
0
    }
10868
0
  }
10869
10870
0
  if (arg_info || (opline+1)->opcode != ZEND_RECV) {
10871
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
10872
0
      if (!JIT_G(current_frame) ||
10873
0
          TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
10874
0
          arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10875
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10876
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10877
10878
0
        if (!exit_addr) {
10879
0
          return 0;
10880
0
        }
10881
0
        ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
10882
0
          ir_CONST_ADDR(exit_addr));
10883
0
      }
10884
0
    } else {
10885
0
      ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10886
0
      ir_IF_FALSE_cold(if_ok);
10887
10888
0
      jit_SET_EX_OPLINE(jit, opline);
10889
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
10890
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10891
0
      ir_IF_TRUE(if_ok);
10892
0
    }
10893
0
  }
10894
10895
0
  if (arg_info) {
10896
0
    if (!zend_jit_verify_arg_type(jit, opline, arg_info, true)) {
10897
0
      return 0;
10898
0
    }
10899
0
  }
10900
10901
0
  return 1;
10902
0
}
10903
10904
static int zend_jit_recv_init(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool is_last, int may_throw)
10905
0
{
10906
0
  uint32_t arg_num = opline->op1.num;
10907
0
  zval *zv = RT_CONSTANT(opline, opline->op2);
10908
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10909
0
  ir_ref ref, if_fail, skip_path = IR_UNUSED;
10910
10911
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10912
0
   && JIT_G(current_frame)
10913
0
   && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
10914
0
    if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
10915
0
      jit_ZVAL_COPY_CONST(jit,
10916
0
        res_addr,
10917
0
        -1, -1,
10918
0
        zv, true);
10919
0
    }
10920
0
  } else {
10921
0
    if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10922
0
        (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
10923
0
      ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
10924
0
      ir_IF_TRUE(if_skip);
10925
0
      skip_path = ir_END();
10926
0
      ir_IF_FALSE(if_skip);
10927
0
    }
10928
0
    jit_ZVAL_COPY_CONST(jit,
10929
0
      res_addr,
10930
0
      -1, -1,
10931
0
      zv, true);
10932
0
  }
10933
10934
0
  if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
10935
0
    jit_SET_EX_OPLINE(jit, opline);
10936
0
    ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
10937
0
      jit_ZVAL_ADDR(jit, res_addr),
10938
0
      ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
10939
10940
0
    if_fail = ir_IF(ref);
10941
0
    ir_IF_TRUE_cold(if_fail);
10942
0
    jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, true, opline);
10943
0
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
10944
0
    ir_IF_FALSE(if_fail);
10945
0
  }
10946
10947
0
  if (skip_path) {
10948
0
    ir_MERGE_WITH(skip_path);
10949
0
  }
10950
10951
0
  if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10952
0
    do {
10953
0
      zend_arg_info *arg_info;
10954
10955
0
      if (arg_num <= op_array->num_args) {
10956
0
        arg_info = &op_array->arg_info[arg_num-1];
10957
0
      } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
10958
0
        arg_info = &op_array->arg_info[op_array->num_args];
10959
0
      } else {
10960
0
        break;
10961
0
      }
10962
0
      if (!ZEND_TYPE_IS_SET(arg_info->type)) {
10963
0
        break;
10964
0
      }
10965
0
      if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw)) {
10966
0
        return 0;
10967
0
      }
10968
0
    } while (0);
10969
0
  }
10970
10971
0
  return 1;
10972
0
}
10973
10974
static bool zend_jit_verify_return_type(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info)
10975
0
{
10976
0
  zend_arg_info *arg_info = &op_array->arg_info[-1];
10977
0
  ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
10978
0
  zend_jit_addr op1_addr = OP1_ADDR();
10979
0
  bool needs_slow_check = true;
10980
0
  uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10981
0
  ir_ref fast_path = IR_UNUSED;
10982
10983
0
  if (type_mask != 0) {
10984
0
    if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
10985
      /* pass */
10986
0
    } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
10987
0
      needs_slow_check = false;
10988
0
    } else if (is_power_of_two(type_mask)) {
10989
0
      uint32_t type_code = concrete_type(type_mask);
10990
0
      ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
10991
10992
0
      ir_IF_TRUE(if_ok);
10993
0
      fast_path = ir_END();
10994
0
      ir_IF_FALSE_cold(if_ok);
10995
0
    } else {
10996
0
      ir_ref if_ok = ir_IF(ir_AND_U32(
10997
0
        ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
10998
0
        ir_CONST_U32(type_mask)));
10999
11000
0
      ir_IF_TRUE(if_ok);
11001
0
      fast_path = ir_END();
11002
0
      ir_IF_FALSE_cold(if_ok);
11003
0
    }
11004
0
  }
11005
0
  if (needs_slow_check) {
11006
0
    ir_ref ref;
11007
11008
0
    jit_SET_EX_OPLINE(jit, opline);
11009
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
11010
0
    if (op1_info & MAY_BE_UNDEF) {
11011
0
      ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, true);
11012
0
    }
11013
11014
0
    ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
11015
0
      ref,
11016
0
      ir_LOAD_A(jit_EX(func)),
11017
0
      ir_CONST_ADDR(arg_info));
11018
11019
0
    zend_jit_check_exception(jit);
11020
11021
0
    if (fast_path) {
11022
0
      ir_MERGE_WITH(fast_path);
11023
0
    }
11024
0
  }
11025
11026
0
  return true;
11027
0
}
11028
11029
static int zend_jit_leave_frame(zend_jit_ctx *jit)
11030
0
{
11031
  // JIT: EG(current_execute_data) = EX(prev_execute_data);
11032
0
  ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
11033
0
  return 1;
11034
0
}
11035
11036
static int zend_jit_free_cvs(zend_jit_ctx *jit)
11037
0
{
11038
  // JIT: EG(current_execute_data) = EX(prev_execute_data);
11039
0
  ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
11040
11041
  // JIT: zend_free_compiled_variables(execute_data);
11042
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
11043
0
  return 1;
11044
0
}
11045
11046
static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
11047
0
{
11048
0
  if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11049
0
    zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
11050
11051
0
    jit_ZVAL_PTR_DTOR(jit, var_addr, info, true, NULL);
11052
0
  }
11053
0
  return 1;
11054
0
}
11055
11056
static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
11057
0
{
11058
0
  if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11059
0
    jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, false, opline);
11060
0
  }
11061
0
  return 1;
11062
0
}
11063
11064
static int zend_jit_leave_func(zend_jit_ctx         *jit,
11065
                               const zend_op_array  *op_array,
11066
                               const zend_op        *opline,
11067
                               uint32_t              op1_info,
11068
                               bool             left_frame,
11069
                               zend_jit_trace_rec   *trace,
11070
                               zend_jit_trace_info  *trace_info,
11071
                               int                   indirect_var_access,
11072
                               int                   may_throw)
11073
0
{
11074
0
  bool may_be_top_frame =
11075
0
    JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11076
0
    !JIT_G(current_frame) ||
11077
0
    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
11078
0
  bool may_need_call_helper =
11079
0
    indirect_var_access || /* may have symbol table */
11080
0
    !op_array->function_name || /* may have symbol table */
11081
0
    may_be_top_frame ||
11082
0
    (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
11083
0
    JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11084
0
    !JIT_G(current_frame) ||
11085
0
    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
11086
0
    (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
11087
0
  bool may_need_release_this =
11088
0
    !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
11089
0
    op_array->scope &&
11090
0
    !(op_array->fn_flags & ZEND_ACC_STATIC) &&
11091
0
    (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11092
0
     !JIT_G(current_frame) ||
11093
0
     !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
11094
0
  ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
11095
11096
0
  if (may_need_call_helper) {
11097
0
    if (!left_frame) {
11098
0
      left_frame = true;
11099
0
        if (!zend_jit_leave_frame(jit)) {
11100
0
        return 0;
11101
0
        }
11102
0
    }
11103
    /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
11104
0
    call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11105
0
    ref = ir_AND_U32(call_info,
11106
0
      ir_CONST_U32(ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE));
11107
0
    if (trace && trace->op != ZEND_JIT_TRACE_END) {
11108
0
      ir_ref if_slow = ir_IF(ref);
11109
11110
0
      ir_IF_TRUE_cold(if_slow);
11111
0
      if (!GCC_GLOBAL_REGS) {
11112
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit), jit_IP(jit));
11113
0
      } else {
11114
0
        ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
11115
0
      }
11116
11117
0
      if (may_be_top_frame) {
11118
        // TODO: try to avoid this check ???
11119
0
        if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
11120
#if 0
11121
          /* this check should be handled by the following OPLINE guard */
11122
          | cmp IP, zend_jit_halt_op
11123
          | je ->trace_halt
11124
#endif
11125
0
        } else if (GCC_GLOBAL_REGS) {
11126
0
          ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
11127
0
        } else {
11128
0
          ir_GUARD(ir_NE(ref, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
11129
0
          jit_STORE_IP(jit, ref);
11130
0
        }
11131
0
      }
11132
11133
0
      if (!GCC_GLOBAL_REGS) {
11134
        // execute_data = EG(current_execute_data)
11135
0
        jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
11136
0
      }
11137
0
      cold_path = ir_END();
11138
0
      ir_IF_FALSE(if_slow);
11139
0
    } else {
11140
0
      ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
11141
0
    }
11142
0
  }
11143
11144
0
  if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
11145
0
    if (!left_frame) {
11146
0
      left_frame = true;
11147
0
        if (!zend_jit_leave_frame(jit)) {
11148
0
        return 0;
11149
0
        }
11150
0
    }
11151
    // JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11152
0
    jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
11153
0
  } else if (may_need_release_this) {
11154
0
    ir_ref if_release, fast_path = IR_UNUSED;
11155
11156
0
    if (!left_frame) {
11157
0
      left_frame = true;
11158
0
        if (!zend_jit_leave_frame(jit)) {
11159
0
        return 0;
11160
0
        }
11161
0
    }
11162
0
    if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
11163
      // JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
11164
0
      if (!call_info) {
11165
0
        call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11166
0
      }
11167
0
      if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
11168
0
      ir_IF_FALSE(if_release);
11169
0
      fast_path = ir_END();
11170
0
      ir_IF_TRUE(if_release);
11171
0
    }
11172
    // JIT: OBJ_RELEASE(execute_data->This))
11173
0
    jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
11174
0
    if (fast_path) {
11175
0
      ir_MERGE_WITH(fast_path);
11176
0
    }
11177
    // TODO: avoid EG(excption) check for $this->foo() calls
11178
0
    may_throw = 1;
11179
0
  }
11180
11181
  // JIT: EG(vm_stack_top) = (zval*)execute_data
11182
0
  ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
11183
11184
  // JITL execute_data = EX(prev_execute_data)
11185
0
  jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
11186
11187
0
  if (!left_frame) {
11188
    // JIT: EG(current_execute_data) = execute_data
11189
0
    ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
11190
0
  }
11191
11192
0
  if (trace) {
11193
0
    if (trace->op != ZEND_JIT_TRACE_END
11194
0
     && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11195
0
      zend_jit_reset_last_valid_opline(jit);
11196
0
    } else {
11197
      /* We add extra RLOAD and RSTORE to make fusion for persistent register
11198
       *     mov (%FP), %IP
11199
       *     add $0x1c, %IP
11200
       * The naive (commented) code leads to extra register allocation and move.
11201
       *     mov (%FP), %tmp
11202
       *     add $0x1c, %tmp
11203
       *     mov %tmp, %FP
11204
       */
11205
#if 0
11206
      jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
11207
#else
11208
0
      jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11209
0
      jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11210
0
#endif
11211
0
    }
11212
11213
0
    if (cold_path) {
11214
0
      ir_MERGE_WITH(cold_path);
11215
0
    }
11216
11217
0
    if (trace->op == ZEND_JIT_TRACE_BACK
11218
0
     && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11219
0
      const zend_op *next_opline = trace->opline;
11220
11221
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11222
0
       && (op1_info & MAY_BE_RC1)
11223
0
       && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
11224
        /* exception might be thrown during destruction of unused return value */
11225
        // JIT: if (EG(exception))
11226
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11227
0
      }
11228
0
      do {
11229
0
        trace++;
11230
0
      } while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11231
0
      ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11232
0
      next_opline = trace->opline;
11233
0
      ZEND_ASSERT(next_opline != NULL);
11234
11235
0
      if (trace->op == ZEND_JIT_TRACE_END
11236
0
       && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11237
0
        trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11238
11239
0
        ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
11240
11241
0
        ir_IF_TRUE(if_eq);
11242
0
        ZEND_ASSERT(jit->trace_loop_ref);
11243
0
        ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
11244
0
        ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
11245
0
        ir_IF_FALSE(if_eq);
11246
11247
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11248
        ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11249
#else
11250
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
11251
0
#endif
11252
0
      } else {
11253
0
        ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
11254
0
      }
11255
11256
0
      zend_jit_set_last_valid_opline(jit, trace->opline);
11257
11258
0
      return 1;
11259
0
    } else if (may_throw ||
11260
0
        (((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11261
0
          && (op1_info & MAY_BE_RC1)
11262
0
          && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
11263
0
         && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11264
      // JIT: if (EG(exception))
11265
0
      ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11266
0
    }
11267
11268
0
    return 1;
11269
0
  } else {
11270
    // JIT: if (EG(exception))
11271
0
    ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11272
    // JIT: opline = EX(opline) + 1
11273
0
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11274
0
    jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11275
0
  }
11276
11277
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
11278
0
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
11279
0
  } else {
11280
0
    zend_jit_vm_leave(jit, jit_IP(jit));
11281
0
  }
11282
11283
0
  jit->b = -1;
11284
11285
0
  return 1;
11286
0
}
11287
11288
static void zend_jit_common_return(zend_jit_ctx *jit)
11289
0
{
11290
0
  ZEND_ASSERT(jit->return_inputs);
11291
0
  ir_MERGE_list(jit->return_inputs);
11292
0
}
11293
11294
static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr)
11295
0
{
11296
0
  zend_jit_addr ret_addr;
11297
0
  int8_t return_value_used = -1;
11298
0
  ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
11299
11300
0
  ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11301
0
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11302
11303
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11304
0
    jit->return_inputs = IR_UNUSED;
11305
0
    if (JIT_G(current_frame)) {
11306
0
      if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11307
0
        return_value_used = 1;
11308
0
      } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11309
0
        return_value_used = 0;
11310
0
      } else {
11311
0
        return_value_used = -1;
11312
0
      }
11313
0
    }
11314
0
  }
11315
11316
0
  if (ZEND_OBSERVER_ENABLED) {
11317
0
    if (Z_MODE(op1_addr) == IS_REG) {
11318
0
      zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11319
11320
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
11321
0
        return 0;
11322
0
      }
11323
0
      op1_addr = dst;
11324
0
    }
11325
0
    jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
11326
0
  }
11327
11328
  // JIT: if (!EX(return_value))
11329
0
  return_value = ir_LOAD_A(jit_EX(return_value));
11330
0
  ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
11331
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11332
0
      (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11333
0
    if (return_value_used == -1) {
11334
0
      if_return_value_used = ir_IF(return_value);
11335
0
      ir_IF_FALSE_cold(if_return_value_used);
11336
0
    }
11337
0
    if (return_value_used != 1) {
11338
0
      if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11339
0
        ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11340
0
        ir_IF_FALSE(if_refcounted);
11341
0
        ir_END_list(jit->return_inputs);
11342
0
        ir_IF_TRUE(if_refcounted);
11343
0
      }
11344
0
      ref = jit_Z_PTR(jit, op1_addr);
11345
0
      refcount = jit_GC_DELREF(jit, ref);
11346
11347
0
      if (RC_MAY_BE_1(op1_info)) {
11348
0
        if (RC_MAY_BE_N(op1_info)) {
11349
0
          ir_ref if_non_zero = ir_IF(refcount);
11350
0
          ir_IF_TRUE(if_non_zero);
11351
0
          ir_END_list(jit->return_inputs);
11352
0
          ir_IF_FALSE(if_non_zero);
11353
0
        }
11354
0
        jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11355
0
      }
11356
0
      if (return_value_used == -1) {
11357
0
        ir_END_list(jit->return_inputs);
11358
0
      }
11359
0
    }
11360
0
  } else if (return_value_used == -1) {
11361
0
    if_return_value_used = ir_IF(return_value);
11362
0
    ir_IF_FALSE_cold(if_return_value_used);
11363
0
    ir_END_list(jit->return_inputs);
11364
0
  }
11365
11366
0
  if (if_return_value_used) {
11367
0
    ir_IF_TRUE(if_return_value_used);
11368
0
  }
11369
11370
0
  if (return_value_used == 0) {
11371
0
    if (jit->return_inputs) {
11372
0
      ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
11373
0
      ir_END_list(jit->return_inputs);
11374
0
      ir_MERGE_list(jit->return_inputs);
11375
0
      jit->return_inputs = IR_UNUSED;
11376
0
    }
11377
0
    return 1;
11378
0
  }
11379
11380
0
  if (opline->op1_type == IS_CONST) {
11381
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
11382
11383
0
    jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, true);
11384
0
  } else if (opline->op1_type == IS_TMP_VAR) {
11385
0
    jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11386
0
  } else if (opline->op1_type == IS_CV) {
11387
0
    if (op1_info & MAY_BE_REF) {
11388
0
      ref = jit_ZVAL_ADDR(jit, op1_addr);
11389
0
      ref = jit_ZVAL_DEREF_ref(jit, ref);
11390
0
      op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11391
0
    }
11392
11393
0
    if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11394
0
      if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11395
0
          (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11396
0
          !op_array->function_name) {
11397
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, true);
11398
0
      } else if (return_value_used != 1) {
11399
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11400
        // JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11401
0
        jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11402
0
      } else {
11403
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11404
0
      }
11405
0
    } else {
11406
0
      jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11407
0
    }
11408
0
  } else {
11409
0
    if (op1_info & MAY_BE_REF) {
11410
0
      ir_ref if_ref, ref2, if_non_zero;
11411
0
      zend_jit_addr ref_addr;
11412
11413
0
      if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11414
0
      ir_IF_TRUE_cold(if_ref);
11415
11416
      // JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11417
0
      ref = jit_Z_PTR(jit, op1_addr);
11418
11419
      // JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11420
0
      ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11421
0
      ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11422
0
      jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, false);
11423
0
      ref2 = jit_GC_DELREF(jit, ref);
11424
0
      if_non_zero = ir_IF(ref2);
11425
0
      ir_IF_TRUE(if_non_zero);
11426
11427
      // JIT: if (IS_REFCOUNTED())
11428
0
      ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11429
0
      ir_IF_FALSE(if_refcounted);
11430
0
      ir_END_list(jit->return_inputs);
11431
0
      ir_IF_TRUE(if_refcounted);
11432
11433
      // JIT: ADDREF
11434
0
      ref2 = jit_Z_PTR(jit, ret_addr);
11435
0
      jit_GC_ADDREF(jit, ref2);
11436
0
      ir_END_list(jit->return_inputs);
11437
11438
0
      ir_IF_FALSE(if_non_zero);
11439
11440
0
      jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11441
0
      ir_END_list(jit->return_inputs);
11442
11443
0
      ir_IF_FALSE(if_ref);
11444
0
    }
11445
0
    jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11446
0
  }
11447
11448
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11449
0
    if (jit->return_inputs) {
11450
0
      ir_END_list(jit->return_inputs);
11451
0
      ir_MERGE_list(jit->return_inputs);
11452
0
      jit->return_inputs = IR_UNUSED;
11453
0
    }
11454
0
  } else {
11455
0
    ir_END_list(jit->return_inputs);
11456
0
    jit->b = -1;
11457
0
  }
11458
11459
0
  return 1;
11460
0
}
11461
11462
static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11463
0
{
11464
0
  zend_jit_addr op1_addr = OP1_ADDR();
11465
0
  zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11466
0
  ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11467
0
  ir_ref if_fit, if_reference, if_same_key, fast_path;
11468
0
  ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11469
11470
  // JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11471
0
  cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11472
0
  idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11473
11474
  // JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11475
0
  num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11476
0
    ir_CONST_U32(sizeof(Bucket)));
11477
0
  if (sizeof(void*) == 8) {
11478
0
    num_used_ref = ir_ZEXT_A(num_used_ref);
11479
0
  }
11480
0
  if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11481
0
  ir_IF_FALSE_cold(if_fit);
11482
0
  ir_END_list(slow_inputs);
11483
0
  ir_IF_TRUE(if_fit);
11484
11485
  // JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11486
0
  bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11487
0
  if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11488
0
  ir_IF_FALSE_cold(if_reference);
11489
0
  ir_END_list(slow_inputs);
11490
0
  ir_IF_TRUE(if_reference);
11491
11492
  // JIT: (EXPECTED(p->key == varname))
11493
0
  if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11494
0
  ir_IF_FALSE_cold(if_same_key);
11495
0
  ir_END_list(slow_inputs);
11496
0
  ir_IF_TRUE(if_same_key);
11497
11498
  // JIT: GC_ADDREF(Z_PTR(p->val))
11499
0
  ref = jit_Z_PTR_ref(jit, bucket_ref);
11500
0
  jit_GC_ADDREF(jit, ref);
11501
11502
0
  fast_path = ir_END();
11503
0
  ir_MERGE_list(slow_inputs);
11504
11505
0
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11506
0
    ir_CONST_ADDR(varname),
11507
0
    cache_slot_ref);
11508
11509
0
  ir_MERGE_WITH(fast_path);
11510
0
  ref = ir_PHI_2(IR_ADDR, ref2, ref);
11511
11512
0
  if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11513
0
    ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11514
11515
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11516
      // JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11517
0
      if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11518
0
      ir_IF_TRUE_cold(if_refcounted);
11519
0
    }
11520
11521
    // JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11522
0
    ref2 = jit_Z_PTR(jit, op1_addr);
11523
11524
    // JIT: ZVAL_REF(variable_ptr, ref)
11525
0
    jit_set_Z_PTR(jit, op1_addr, ref);
11526
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11527
11528
    // JIT: if (GC_DELREF(garbage) == 0)
11529
0
    refcount = jit_GC_DELREF(jit, ref2);
11530
0
    if_non_zero = ir_IF(refcount);
11531
0
    if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11532
0
      ir_IF_TRUE(if_non_zero);
11533
0
      ir_END_list(end_inputs);
11534
0
    }
11535
0
    ir_IF_FALSE(if_non_zero);
11536
11537
0
    jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11538
0
    if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11539
0
      ir_END_list(end_inputs);
11540
0
      ir_IF_TRUE(if_non_zero);
11541
11542
      // JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11543
0
      if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11544
0
      ir_IF_TRUE(if_may_not_leak);
11545
0
      ir_END_list(end_inputs);
11546
0
      ir_IF_FALSE(if_may_not_leak);
11547
0
      if (opline) {
11548
0
        jit_SET_EX_OPLINE(jit, opline);
11549
0
      }
11550
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11551
0
    }
11552
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11553
0
      ir_END_list(end_inputs);
11554
0
      ir_IF_FALSE(if_refcounted);
11555
0
    }
11556
0
  }
11557
11558
0
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11559
    // JIT: ZVAL_REF(variable_ptr, ref)
11560
0
    jit_set_Z_PTR(jit, op1_addr, ref);
11561
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11562
0
  }
11563
11564
0
  if (end_inputs) {
11565
0
    ir_END_list(end_inputs);
11566
0
    ir_MERGE_list(end_inputs);
11567
0
  }
11568
11569
0
  return 1;
11570
0
}
11571
11572
static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11573
0
{
11574
0
  zend_jit_addr op1_addr = OP1_ADDR();
11575
11576
0
  if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11577
0
    if (may_throw) {
11578
0
      jit_SET_EX_OPLINE(jit, opline);
11579
0
    }
11580
0
    if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11581
0
      ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11582
11583
0
      if (op1_info & MAY_BE_ARRAY) {
11584
0
        if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11585
0
        ir_IF_TRUE(if_array);
11586
0
        ir_END_list(end_inputs);
11587
0
        ir_IF_FALSE(if_array);
11588
0
      }
11589
0
      ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11590
0
      if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11591
0
      ir_IF_TRUE(if_exists);
11592
0
      ir_END_list(end_inputs);
11593
0
      ir_IF_FALSE(if_exists);
11594
11595
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11596
11597
0
      ir_END_list(end_inputs);
11598
0
      ir_MERGE_list(end_inputs);
11599
0
    }
11600
11601
0
    jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, false, opline);
11602
11603
0
    if (may_throw) {
11604
0
      zend_jit_check_exception(jit);
11605
0
    }
11606
0
  }
11607
11608
0
  return 1;
11609
0
}
11610
11611
static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11612
0
{
11613
0
  if (opline->op1_type == IS_CONST) {
11614
0
    zval *zv;
11615
0
    size_t len;
11616
11617
0
    zv = RT_CONSTANT(opline, opline->op1);
11618
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11619
0
    len = Z_STRLEN_P(zv);
11620
11621
0
    if (len > 0) {
11622
0
      const char *str = Z_STRVAL_P(zv);
11623
11624
0
      jit_SET_EX_OPLINE(jit, opline);
11625
0
      ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11626
0
        ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11627
11628
0
      zend_jit_check_exception(jit);
11629
0
    }
11630
0
  } else {
11631
0
    zend_jit_addr op1_addr = OP1_ADDR();
11632
0
    ir_ref ref;
11633
11634
0
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11635
11636
0
    jit_SET_EX_OPLINE(jit, opline);
11637
11638
0
    ref = jit_Z_PTR(jit, op1_addr);
11639
0
    ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11640
0
      ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11641
0
      ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11642
11643
0
    if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11644
0
      jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, false, opline);
11645
0
    }
11646
11647
0
    zend_jit_check_exception(jit);
11648
0
  }
11649
0
  return 1;
11650
0
}
11651
11652
static int zend_jit_strlen(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr)
11653
0
{
11654
0
  if (opline->op1_type == IS_CONST) {
11655
0
    zval *zv;
11656
0
    size_t len;
11657
11658
0
    zv = RT_CONSTANT(opline, opline->op1);
11659
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11660
0
    len = Z_STRLEN_P(zv);
11661
11662
0
    jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11663
0
    if (Z_MODE(res_addr) != IS_REG) {
11664
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11665
0
    } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11666
0
      return 0;
11667
0
    }
11668
0
  } else {
11669
0
    ir_ref ref;
11670
11671
0
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11672
11673
0
    ref = jit_Z_PTR(jit, op1_addr);
11674
0
    ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11675
0
    jit_set_Z_LVAL(jit, res_addr, ref);
11676
11677
0
    if (Z_MODE(res_addr) == IS_REG) {
11678
0
      if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11679
0
        return 0;
11680
0
      }
11681
0
    } else {
11682
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11683
0
    }
11684
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11685
0
  }
11686
0
  return 1;
11687
0
}
11688
11689
static int zend_jit_count(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw)
11690
0
{
11691
0
  if (opline->op1_type == IS_CONST) {
11692
0
    zval *zv;
11693
0
    zend_long count;
11694
11695
0
    zv = RT_CONSTANT(opline, opline->op1);
11696
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11697
0
    count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11698
11699
0
    jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11700
0
    if (Z_MODE(res_addr) != IS_REG) {
11701
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11702
0
    } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11703
0
      return 0;
11704
0
    }
11705
0
  } else {
11706
0
    ir_ref ref;
11707
11708
0
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11709
    // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11710
11711
0
    ref = jit_Z_PTR(jit, op1_addr);
11712
0
    if (sizeof(void*) == 8) {
11713
0
      ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11714
0
      ref = ir_ZEXT_L(ref);
11715
0
    } else {
11716
0
      ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11717
0
    }
11718
0
    jit_set_Z_LVAL(jit, res_addr, ref);
11719
11720
0
    if (Z_MODE(res_addr) == IS_REG) {
11721
0
      if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11722
0
        return 0;
11723
0
      }
11724
0
    } else {
11725
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11726
0
    }
11727
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11728
0
  }
11729
11730
0
  if (may_throw) {
11731
0
    zend_jit_check_exception(jit);
11732
0
  }
11733
0
  return 1;
11734
0
}
11735
11736
static int zend_jit_in_array(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr)
11737
0
{
11738
0
  HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11739
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11740
0
  ir_ref ref;
11741
11742
0
  ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11743
0
  ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11744
11745
  // JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11746
0
  if (opline->op1_type != IS_CONST) {
11747
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11748
0
      ir_CONST_ADDR(ht),
11749
0
      jit_Z_PTR(jit, op1_addr));
11750
0
  } else {
11751
0
    zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11752
11753
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11754
0
      ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11755
0
  }
11756
11757
0
  if (exit_addr) {
11758
0
    if (smart_branch_opcode == ZEND_JMPZ) {
11759
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11760
0
    } else {
11761
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11762
0
    }
11763
0
  } else if (smart_branch_opcode) {
11764
0
    zend_basic_block *bb;
11765
11766
0
    ZEND_ASSERT(jit->b >= 0);
11767
0
    bb = &jit->ssa->cfg.blocks[jit->b];
11768
0
    ZEND_ASSERT(bb->successors_count == 2);
11769
0
    ref = jit_IF_ex(jit, ref,
11770
0
      (smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11771
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11772
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11773
0
    jit->b = -1;
11774
0
  } else {
11775
0
    jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11776
0
      ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11777
0
  }
11778
11779
0
  return 1;
11780
0
}
11781
11782
static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11783
0
{
11784
0
  uint32_t offset;
11785
11786
0
  offset = (opline->opcode == ZEND_ROPE_INIT) ?
11787
0
    opline->result.var :
11788
0
    opline->op1.var + opline->extended_value * sizeof(zend_string*);
11789
11790
0
  if (opline->op2_type == IS_CONST) {
11791
0
    zval *zv = RT_CONSTANT(opline, opline->op2);
11792
0
    zend_string *str;
11793
11794
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11795
0
    str = Z_STR_P(zv);
11796
11797
0
    ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11798
0
  } else {
11799
0
    zend_jit_addr op2_addr = OP2_ADDR();
11800
0
    ir_ref ref;
11801
11802
0
    ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11803
11804
0
    ref = jit_Z_PTR(jit, op2_addr);
11805
0
    ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11806
0
    if (opline->op2_type == IS_CV) {
11807
0
      ir_ref if_refcounted, long_path;
11808
11809
0
      if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11810
0
      ir_IF_TRUE(if_refcounted);
11811
0
      jit_GC_ADDREF(jit, ref);
11812
0
      long_path = ir_END();
11813
11814
0
      ir_IF_FALSE(if_refcounted);
11815
0
      ir_MERGE_WITH(long_path);
11816
0
    }
11817
0
  }
11818
11819
0
  if (opline->opcode == ZEND_ROPE_END) {
11820
0
    zend_jit_addr res_addr = RES_ADDR();
11821
0
    ir_ref ref;
11822
11823
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11824
0
      ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11825
0
      ir_CONST_U32(opline->extended_value));
11826
11827
0
    jit_set_Z_PTR(jit, res_addr, ref);
11828
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11829
0
  }
11830
11831
0
  return 1;
11832
0
}
11833
11834
static 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)
11835
0
{
11836
0
  ir_ref if_type, val;
11837
11838
0
  if (res_info == MAY_BE_LONG) {
11839
0
    if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_LONG)));
11840
0
    ir_IF_TRUE(if_type);
11841
0
    val = jit_ZVAL_ADDR(jit, val_addr);
11842
0
    ir_END_PHI_list(*values, val);
11843
0
    ir_IF_FALSE(if_type);
11844
0
    val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
11845
0
    ir_END_PHI_list(*values, val);
11846
0
  } else if (res_info == MAY_BE_DOUBLE) {
11847
0
    if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_DOUBLE)));
11848
0
    ir_IF_TRUE(if_type);
11849
0
    val = jit_ZVAL_ADDR(jit, val_addr);
11850
0
    ir_END_PHI_list(*values, val);
11851
0
    ir_IF_FALSE(if_type);
11852
0
    val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
11853
0
    ir_END_PHI_list(*values, val);
11854
0
  } else {
11855
0
    ZEND_UNREACHABLE();
11856
0
  }
11857
0
  return 1;
11858
0
}
11859
11860
static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
11861
0
{
11862
0
  ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
11863
0
  ir_refs *merge_inputs, *types, *ptrs;
11864
#if SIZEOF_ZEND_LONG == 4
11865
  ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
11866
  ir_refs *values; /* we need this only for zval.w2 copy */
11867
#endif
11868
11869
0
  ir_refs_init(merge_inputs, 4);
11870
0
  ir_refs_init(types, 4);
11871
0
  ir_refs_init(ptrs, 4);
11872
#if SIZEOF_ZEND_LONG == 4
11873
  ir_refs_init(values, 4);
11874
#endif
11875
11876
  // JIT: ptr = Z_PTR_P(val);
11877
0
  ptr = jit_Z_PTR(jit, val_addr);
11878
11879
  // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11880
0
  if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11881
0
  ir_IF_FALSE_cold(if_refcounted);
11882
0
  ir_refs_add(merge_inputs, ir_END());
11883
0
  ir_refs_add(types, type);
11884
0
  ir_refs_add(ptrs, ptr);
11885
#if SIZEOF_ZEND_LONG == 4
11886
  ir_refs_add(values, val);
11887
#endif
11888
11889
0
  ir_IF_TRUE(if_refcounted);
11890
11891
  // JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
11892
0
  if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
11893
//  if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
11894
0
  ir_IF_TRUE(if_reference);
11895
11896
  // JIT: val = Z_REFVAL_P(val);
11897
0
  val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
11898
0
  type2 = jit_Z_TYPE_INFO_ref(jit, val2);
11899
0
  ptr2 = jit_Z_PTR_ref(jit, val2);
11900
11901
  // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
11902
0
  if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
11903
0
  ir_IF_FALSE_cold(if_refcounted2);
11904
0
  ir_refs_add(merge_inputs, ir_END());
11905
0
  ir_refs_add(types, type2);
11906
0
  ir_refs_add(ptrs, ptr2);
11907
#if SIZEOF_ZEND_LONG == 4
11908
  ir_refs_add(values, val2);
11909
#endif
11910
11911
0
  ir_IF_TRUE(if_refcounted2);
11912
0
  ir_MERGE_WITH_EMPTY_FALSE(if_reference);
11913
0
  type = ir_PHI_2(IR_U32, type2, type);
11914
0
  ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
11915
#if SIZEOF_ZEND_LONG == 4
11916
  val = ir_PHI_2(IR_ADDR, val2, val);
11917
#endif
11918
11919
  // JIT: Z_ADDREF_P(val);
11920
0
  jit_GC_ADDREF(jit, ptr);
11921
0
  ir_refs_add(merge_inputs, ir_END());
11922
0
  ir_refs_add(types, type);
11923
0
  ir_refs_add(ptrs, ptr);
11924
#if SIZEOF_ZEND_LONG == 4
11925
  ir_refs_add(values, val);
11926
#endif
11927
11928
0
  ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
11929
0
  type = ir_PHI_N(IR_U32, types->count, types->refs);
11930
0
  ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
11931
#if SIZEOF_ZEND_LONG == 4
11932
  val = ir_PHI_N(IR_ADDR, values->count, values->refs);
11933
  val_addr = ZEND_ADDR_REF_ZVAL(val);
11934
#endif
11935
11936
  // JIT: Z_PTR_P(res) = ptr;
11937
0
  jit_set_Z_PTR(jit, res_addr, ptr);
11938
#if SIZEOF_ZEND_LONG == 4
11939
  jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
11940
#endif
11941
0
  jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
11942
11943
0
  return 1;
11944
0
}
11945
11946
static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx  *jit,
11947
                                                  const zend_op *opline,
11948
                                                  uint32_t       type,
11949
                                                  uint32_t       op1_info,
11950
                                                  uint32_t       op2_info,
11951
                                                  zend_jit_addr  op2_addr,
11952
                                                  zend_ssa_range *op2_range,
11953
                                                  uint8_t        dim_type,
11954
                                                  const void    *found_exit_addr,
11955
                                                  const void    *not_found_exit_addr,
11956
                                                  const void    *exit_addr,
11957
                                                  bool           result_type_guard,
11958
                                                  ir_ref         ht_ref,
11959
                                                  ir_refs       *found_inputs,
11960
                                                  ir_refs       *found_vals,
11961
                                                  ir_ref        *end_inputs,
11962
                                                  ir_ref        *not_found_inputs)
11963
0
{
11964
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11965
0
  ir_ref ref = IR_UNUSED, cond, if_found;
11966
0
  ir_ref if_type = IS_UNUSED;
11967
0
  ir_refs *test_zval_inputs, *test_zval_values;
11968
11969
0
  ir_refs_init(test_zval_inputs, 4);
11970
0
  ir_refs_init(test_zval_values, 4);
11971
11972
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11973
0
   && type == BP_VAR_R
11974
0
   && !exit_addr) {
11975
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11976
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11977
0
    if (!exit_addr) {
11978
0
      return 0;
11979
0
    }
11980
0
  }
11981
11982
0
  if (op2_info & MAY_BE_LONG) {
11983
0
    bool op2_loaded = false;
11984
0
    bool packed_loaded = false;
11985
0
    bool bad_packed_key = false;
11986
0
    ir_ref if_packed = IS_UNDEF;
11987
0
    ir_ref h = IR_UNUSED;
11988
0
    ir_ref idx_not_found_inputs = IR_UNUSED;
11989
11990
0
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
11991
      // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
11992
0
      if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
11993
0
      ir_IF_TRUE(if_type);
11994
0
    }
11995
0
    if (op1_info & MAY_BE_PACKED_GUARD) {
11996
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
11997
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11998
11999
0
      if (!exit_addr) {
12000
0
        return 0;
12001
0
      }
12002
0
      cond = ir_AND_U32(
12003
0
        ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
12004
0
        ir_CONST_U32(HASH_FLAG_PACKED));
12005
0
      if (op1_info & MAY_BE_ARRAY_PACKED) {
12006
0
        ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
12007
0
      } else {
12008
0
        ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
12009
0
      }
12010
0
    }
12011
0
    if (type == BP_VAR_W) {
12012
      // JIT: hval = Z_LVAL_P(dim);
12013
0
      h = jit_Z_LVAL(jit, op2_addr);
12014
0
      op2_loaded = true;
12015
0
    }
12016
0
    if (op1_info & MAY_BE_ARRAY_PACKED) {
12017
0
      zend_long val = -1;
12018
12019
0
      if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
12020
0
        val = Z_LVAL_P(Z_ZV(op2_addr));
12021
0
        if (val >= 0 && val < HT_MAX_SIZE) {
12022
0
          packed_loaded = true;
12023
0
        } else {
12024
0
          bad_packed_key = true;
12025
0
        }
12026
0
        h = ir_CONST_LONG(val);
12027
0
      } else {
12028
0
        if (!op2_loaded) {
12029
          // JIT: hval = Z_LVAL_P(dim);
12030
0
          h = jit_Z_LVAL(jit, op2_addr);
12031
0
          op2_loaded = true;
12032
0
        }
12033
0
        packed_loaded = true;
12034
0
      }
12035
12036
0
      if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
12037
        /* don't generate "fast" code for packed array */
12038
0
        packed_loaded = false;
12039
0
      }
12040
12041
0
      if (packed_loaded) {
12042
        // JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
12043
0
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12044
0
          if_packed = ir_IF(
12045
0
            ir_AND_U32(
12046
0
              ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
12047
0
              ir_CONST_U32(HASH_FLAG_PACKED)));
12048
0
          ir_IF_TRUE(if_packed);
12049
0
        }
12050
        // JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
12051
0
        ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
12052
0
#if SIZEOF_ZEND_LONG == 8
12053
0
        if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
12054
0
         || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
12055
          /* comapre only the lower 32-bits to allow load fusion on x86_64 */
12056
0
          cond = ir_ULT(ir_TRUNC_U32(h), ref);
12057
0
        } else {
12058
0
          cond = ir_ULT(h, ir_ZEXT_L(ref));
12059
0
        }
12060
#else
12061
        cond = ir_ULT(h, ref);
12062
#endif
12063
0
        if (type == BP_JIT_IS) {
12064
0
          if (not_found_exit_addr) {
12065
0
            ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12066
0
          } else {
12067
0
            ir_ref if_fit = ir_IF(cond);
12068
0
            ir_IF_FALSE(if_fit);
12069
0
            ir_END_list(*end_inputs);
12070
0
            ir_IF_TRUE(if_fit);
12071
0
          }
12072
0
        } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12073
0
          ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
12074
0
        } else if (type == BP_VAR_IS && not_found_exit_addr) {
12075
0
          ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12076
0
        } else if (type == BP_VAR_RW && not_found_exit_addr) {
12077
0
          ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12078
0
        } else if (type == BP_VAR_IS && result_type_guard) {
12079
0
          ir_ref if_fit = ir_IF(cond);
12080
0
          ir_IF_FALSE(if_fit);
12081
0
          ir_END_list(*not_found_inputs);
12082
0
          ir_IF_TRUE(if_fit);
12083
0
        } else {
12084
0
          ir_ref if_fit = ir_IF(cond);
12085
0
          ir_IF_FALSE(if_fit);
12086
0
          ir_END_list(idx_not_found_inputs);
12087
0
          ir_IF_TRUE(if_fit);
12088
0
        }
12089
        // JIT: _ret = &_ht->arPacked[h];
12090
0
        ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
12091
0
        ref = ir_BITCAST_A(ref);
12092
0
        ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
12093
0
        if (type == BP_JIT_IS) {
12094
0
          ir_refs_add(test_zval_values, ref);
12095
0
          ir_refs_add(test_zval_inputs, ir_END());
12096
0
        }
12097
0
      }
12098
0
    }
12099
0
    switch (type) {
12100
0
      case BP_JIT_IS:
12101
0
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12102
0
          if (if_packed) {
12103
0
            ir_IF_FALSE(if_packed);
12104
0
            if_packed = IR_UNUSED;
12105
0
          }
12106
0
          if (!op2_loaded) {
12107
            // JIT: hval = Z_LVAL_P(dim);
12108
0
            h = jit_Z_LVAL(jit, op2_addr);
12109
0
            op2_loaded = true;
12110
0
          }
12111
0
          if (packed_loaded) {
12112
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12113
0
          } else {
12114
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12115
0
          }
12116
0
          if (not_found_exit_addr) {
12117
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12118
0
          } else {
12119
0
            if_found = ir_IF(ref);
12120
0
            ir_IF_FALSE(if_found);
12121
0
            ir_END_list(*end_inputs);
12122
0
            ir_IF_TRUE(if_found);
12123
0
          }
12124
0
          ir_refs_add(test_zval_values, ref);
12125
0
          ir_refs_add(test_zval_inputs, ir_END());
12126
0
        } else if (!not_found_exit_addr && !packed_loaded) {
12127
0
          ir_END_list(*end_inputs);
12128
0
        }
12129
0
        break;
12130
0
      case BP_VAR_R:
12131
0
      case BP_VAR_IS:
12132
0
      case BP_VAR_UNSET:
12133
0
        if (packed_loaded) {
12134
0
          ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
12135
12136
0
          if (result_type_guard) {
12137
            /* perform IS_UNDEF check only after result type guard (during deoptimization) */
12138
0
          } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12139
0
            ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
12140
0
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12141
0
            ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
12142
0
          } else {
12143
0
            ir_ref if_def = ir_IF(type_ref);
12144
0
            ir_IF_FALSE(if_def);
12145
0
            ir_END_list(idx_not_found_inputs);
12146
0
            ir_IF_TRUE(if_def);
12147
0
          }
12148
0
          ir_refs_add(found_inputs, ir_END());
12149
0
          ir_refs_add(found_vals, ref);
12150
0
        }
12151
0
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12152
0
          if (if_packed) {
12153
0
            ir_IF_FALSE(if_packed);
12154
0
            if_packed = IR_UNUSED;
12155
0
          }
12156
0
          if (!op2_loaded) {
12157
            // JIT: hval = Z_LVAL_P(dim);
12158
0
            h = jit_Z_LVAL(jit, op2_addr);
12159
0
            op2_loaded = true;
12160
0
          }
12161
0
          if (packed_loaded) {
12162
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12163
0
          } else {
12164
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12165
0
          }
12166
0
          if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12167
0
            ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12168
0
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12169
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12170
0
          } else if (type == BP_VAR_IS && result_type_guard) {
12171
0
            if_found = ir_IF(ref);
12172
0
            ir_IF_FALSE(if_found);
12173
0
            ir_END_list(*not_found_inputs);
12174
0
            ir_IF_TRUE(if_found);
12175
0
          } else {
12176
0
            if_found = ir_IF(ref);
12177
0
            ir_IF_FALSE(if_found);
12178
0
            ir_END_list(idx_not_found_inputs);
12179
0
            ir_IF_TRUE(if_found);
12180
0
          }
12181
0
          ir_refs_add(found_inputs, ir_END());
12182
0
          ir_refs_add(found_vals, ref);
12183
0
        } else if (!packed_loaded) {
12184
0
          if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12185
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12186
0
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12187
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
12188
0
          } else if (type == BP_VAR_IS && result_type_guard) {
12189
0
            ir_END_list(*not_found_inputs);
12190
0
          } else {
12191
0
            ir_END_list(idx_not_found_inputs);
12192
0
          }
12193
0
        }
12194
12195
0
        if (idx_not_found_inputs) {
12196
0
          ir_MERGE_list(idx_not_found_inputs);
12197
0
          switch (type) {
12198
0
            case BP_VAR_R:
12199
0
              ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
12200
              // JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
12201
              // JIT: retval = &EG(uninitialized_zval);
12202
0
              jit_SET_EX_OPLINE(jit, opline);
12203
0
              if (Z_MODE(op2_addr) == IS_REG) {
12204
0
                if (!op2_loaded) {
12205
                  // JIT: hval = Z_LVAL_P(dim);
12206
0
                  h = jit_Z_LVAL(jit, op2_addr);
12207
0
                }
12208
0
                if (GCC_GLOBAL_REGS) {
12209
0
                  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h);
12210
0
                } else {
12211
0
                  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h, jit_FP(jit));
12212
0
                }
12213
0
              } else {
12214
0
                ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
12215
0
              }
12216
0
              ir_END_list(*end_inputs);
12217
0
              break;
12218
0
            case BP_VAR_IS:
12219
0
            case BP_VAR_UNSET:
12220
0
              if (!not_found_exit_addr) {
12221
                // JIT: retval = &EG(uninitialized_zval);
12222
0
                jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12223
0
                ir_END_list(*end_inputs);
12224
0
              }
12225
0
              break;
12226
0
            default:
12227
0
              ZEND_UNREACHABLE();
12228
0
          }
12229
0
                }
12230
0
        break;
12231
0
      case BP_VAR_RW:
12232
0
        if (packed_loaded) {
12233
0
          if (not_found_exit_addr) {
12234
0
            ir_refs_add(found_inputs, ir_END());
12235
0
            ir_refs_add(found_vals, ref);
12236
0
          } else {
12237
0
            ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12238
0
            ir_IF_TRUE(if_def);
12239
0
            ir_refs_add(found_inputs, ir_END());
12240
0
            ir_refs_add(found_vals, ref);
12241
0
            ir_IF_FALSE_cold(if_def);
12242
0
            ir_END_list(idx_not_found_inputs);
12243
0
          }
12244
0
        }
12245
0
        if (!packed_loaded ||
12246
0
            !not_found_exit_addr ||
12247
0
            (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
12248
0
          if (if_packed) {
12249
0
            ir_IF_FALSE(if_packed);
12250
0
            if_packed = IR_UNUSED;
12251
0
            ir_END_list(idx_not_found_inputs);
12252
0
          } else if (!packed_loaded) {
12253
0
            ir_END_list(idx_not_found_inputs);
12254
0
          }
12255
12256
0
          ir_MERGE_list(idx_not_found_inputs);
12257
0
          if (!op2_loaded) {
12258
            // JIT: hval = Z_LVAL_P(dim);
12259
0
            h = jit_Z_LVAL(jit, op2_addr);
12260
0
          }
12261
0
          if (packed_loaded) {
12262
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
12263
0
              ht_ref, h);
12264
0
          } else {
12265
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
12266
0
          }
12267
0
          if (not_found_exit_addr) {
12268
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12269
0
          } else {
12270
0
            if_found = ir_IF(ref);
12271
0
            ir_IF_FALSE(if_found);
12272
0
            ir_END_list(*end_inputs);
12273
0
            ir_IF_TRUE(if_found);
12274
0
          }
12275
0
          ir_refs_add(found_inputs, ir_END());
12276
0
          ir_refs_add(found_vals, ref);
12277
0
        }
12278
0
        break;
12279
0
      case BP_VAR_W:
12280
0
        if (packed_loaded) {
12281
0
          ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12282
0
          ir_IF_TRUE_cold(if_def);
12283
0
          ir_refs_add(found_inputs, ir_END());
12284
0
          ir_refs_add(found_vals, ref);
12285
0
          ir_IF_FALSE(if_def);
12286
0
          ir_END_list(idx_not_found_inputs);
12287
0
        }
12288
0
        if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
12289
0
          if (if_packed) {
12290
0
            ir_IF_FALSE(if_packed);
12291
0
            if_packed = IR_UNUSED;
12292
0
            ir_END_list(idx_not_found_inputs);
12293
0
          } else if (!packed_loaded) {
12294
0
            ir_END_list(idx_not_found_inputs);
12295
0
          }
12296
0
          ir_MERGE_list(idx_not_found_inputs);
12297
0
          if (!op2_loaded) {
12298
            // JIT: hval = Z_LVAL_P(dim);
12299
0
            h = jit_Z_LVAL(jit, op2_addr);
12300
0
          }
12301
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
12302
0
          ir_refs_add(found_inputs, ir_END());
12303
0
          ir_refs_add(found_vals, ref);
12304
0
        }
12305
0
        break;
12306
0
      default:
12307
0
        ZEND_UNREACHABLE();
12308
0
    }
12309
0
  }
12310
12311
0
  if (op2_info & MAY_BE_STRING) {
12312
0
    ir_ref key;
12313
12314
0
    if (if_type) {
12315
0
      ir_IF_FALSE(if_type);
12316
0
      if_type = IS_UNUSED;
12317
0
    }
12318
12319
0
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12320
      // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
12321
0
      if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
12322
0
      ir_IF_TRUE(if_type);
12323
0
    }
12324
12325
    // JIT: offset_key = Z_STR_P(dim);
12326
0
    key = jit_Z_PTR(jit, op2_addr);
12327
12328
    // JIT: retval = zend_hash_find(ht, offset_key);
12329
0
    switch (type) {
12330
0
      case BP_JIT_IS:
12331
0
        if (opline->op2_type != IS_CONST) {
12332
0
          ir_ref if_num, end1, ref2;
12333
12334
0
          if_num = ir_IF(
12335
0
            ir_ULE(
12336
0
              ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12337
0
              ir_CONST_CHAR('9')));
12338
0
          ir_IF_TRUE_cold(if_num);
12339
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12340
0
          end1 = ir_END();
12341
0
          ir_IF_FALSE(if_num);
12342
0
          ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12343
0
          ir_MERGE_WITH(end1);
12344
0
          ref = ir_PHI_2(IR_ADDR, ref2, ref);
12345
0
        } else {
12346
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12347
0
        }
12348
0
        if (not_found_exit_addr) {
12349
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12350
0
        } else {
12351
0
          if_found = ir_IF(ref);
12352
0
          ir_IF_FALSE(if_found);
12353
0
          ir_END_list(*end_inputs);
12354
0
          ir_IF_TRUE(if_found);
12355
0
        }
12356
0
        ir_refs_add(test_zval_values, ref);
12357
0
        ir_refs_add(test_zval_inputs, ir_END());
12358
0
        break;
12359
0
      case BP_VAR_R:
12360
0
      case BP_VAR_IS:
12361
0
      case BP_VAR_UNSET:
12362
0
        if (opline->op2_type != IS_CONST) {
12363
0
          ir_ref if_num, end1, ref2;
12364
12365
0
          if_num = ir_IF(
12366
0
            ir_ULE(
12367
0
              ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12368
0
              ir_CONST_CHAR('9')));
12369
0
          ir_IF_TRUE_cold(if_num);
12370
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12371
0
          end1 = ir_END();
12372
0
          ir_IF_FALSE(if_num);
12373
0
          ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12374
0
          ir_MERGE_WITH(end1);
12375
0
          ref = ir_PHI_2(IR_ADDR, ref2, ref);
12376
0
        } else {
12377
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12378
0
        }
12379
0
        if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12380
0
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12381
0
        } else if (type == BP_VAR_IS && not_found_exit_addr) {
12382
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12383
0
        } else if (type == BP_VAR_IS && result_type_guard) {
12384
0
          if_found = ir_IF(ref);
12385
0
          ir_IF_FALSE(if_found);
12386
0
          ir_END_list(*not_found_inputs);
12387
0
          ir_IF_TRUE(if_found);
12388
0
        } else {
12389
0
          if_found = ir_IF(ref);
12390
0
          switch (type) {
12391
0
            case BP_VAR_R:
12392
0
              ir_IF_FALSE_cold(if_found);
12393
              // JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12394
0
              jit_SET_EX_OPLINE(jit, opline);
12395
0
              ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12396
0
              ir_END_list(*end_inputs);
12397
0
              break;
12398
0
            case BP_VAR_IS:
12399
0
            case BP_VAR_UNSET:
12400
0
              ir_IF_FALSE(if_found);
12401
              // JIT: retval = &EG(uninitialized_zval);
12402
0
              jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12403
0
              ir_END_list(*end_inputs);
12404
0
              break;
12405
0
            default:
12406
0
              ZEND_UNREACHABLE();
12407
0
          }
12408
0
          ir_IF_TRUE(if_found);
12409
0
        }
12410
0
        ir_refs_add(found_inputs, ir_END());
12411
0
        ir_refs_add(found_vals, ref);
12412
0
        break;
12413
0
      case BP_VAR_RW:
12414
0
        if (opline->op2_type != IS_CONST) {
12415
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12416
0
        } else {
12417
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12418
0
        }
12419
0
        if (not_found_exit_addr) {
12420
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12421
0
        } else {
12422
0
          if_found = ir_IF(ref);
12423
0
          ir_IF_FALSE(if_found);
12424
0
          ir_END_list(*end_inputs);
12425
0
          ir_IF_TRUE(if_found);
12426
0
        }
12427
0
        ir_refs_add(found_inputs, ir_END());
12428
0
        ir_refs_add(found_vals, ref);
12429
0
        break;
12430
0
      case BP_VAR_W:
12431
0
        if (opline->op2_type != IS_CONST) {
12432
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12433
0
        } else {
12434
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12435
0
        }
12436
0
        ir_refs_add(found_inputs, ir_END());
12437
0
        ir_refs_add(found_vals, ref);
12438
0
        break;
12439
0
      default:
12440
0
        ZEND_UNREACHABLE();
12441
0
    }
12442
0
  }
12443
12444
0
  if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12445
0
      if (if_type) {
12446
0
      ir_IF_FALSE_cold(if_type);
12447
0
      if_type = IS_UNDEF;
12448
0
    }
12449
0
    if (type != BP_VAR_RW) {
12450
0
      jit_SET_EX_OPLINE(jit, opline);
12451
0
    }
12452
0
    ref = jit_ZVAL_ADDR(jit, op2_addr);
12453
0
    switch (type) {
12454
0
      case BP_VAR_R:
12455
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12456
0
          ht_ref,
12457
0
          ref,
12458
0
          jit_ZVAL_ADDR(jit, res_addr));
12459
0
        ir_END_list(*end_inputs);
12460
0
        break;
12461
0
      case BP_JIT_IS:
12462
0
        ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12463
0
        if (not_found_exit_addr) {
12464
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12465
0
          ir_refs_add(found_inputs, ir_END());
12466
0
        } else if (found_exit_addr) {
12467
0
          ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12468
0
          ir_END_list(*end_inputs);
12469
0
        } else {
12470
0
          if_found = ir_IF(ref);
12471
0
          ir_IF_TRUE(if_found);
12472
0
          ir_refs_add(found_inputs, ir_END());
12473
0
          ir_IF_FALSE(if_found);
12474
0
          ir_END_list(*end_inputs);
12475
0
        }
12476
0
        break;
12477
0
      case BP_VAR_IS:
12478
0
      case BP_VAR_UNSET:
12479
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12480
0
          ht_ref,
12481
0
          ref,
12482
0
          jit_ZVAL_ADDR(jit, res_addr));
12483
0
        ir_END_list(*end_inputs);
12484
0
        break;
12485
0
      case BP_VAR_RW:
12486
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12487
0
        if_found = ir_IF(ref);
12488
0
        ir_IF_TRUE(if_found);
12489
0
        ir_refs_add(found_inputs, ir_END());
12490
0
        ir_refs_add(found_vals, ref);
12491
0
        ir_IF_FALSE(if_found);
12492
0
        ir_END_list(*end_inputs);
12493
0
        break;
12494
0
      case BP_VAR_W:
12495
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12496
0
        if_found = ir_IF(ref);
12497
0
        ir_IF_TRUE(if_found);
12498
0
        ir_refs_add(found_inputs, ir_END());
12499
0
        ir_refs_add(found_vals, ref);
12500
0
        ir_IF_FALSE(if_found);
12501
0
        ir_END_list(*end_inputs);
12502
0
        break;
12503
0
      default:
12504
0
        ZEND_UNREACHABLE();
12505
0
    }
12506
0
  }
12507
12508
0
  if (type == BP_JIT_IS
12509
0
   && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12510
    /* dead code */
12511
0
    ir_END_list(*end_inputs);
12512
0
  } else if (type == BP_JIT_IS
12513
0
   && (op1_info & MAY_BE_ARRAY)
12514
0
   && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12515
0
   && test_zval_inputs->count) {
12516
12517
0
    ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12518
0
    ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12519
12520
0
    if (op1_info & MAY_BE_ARRAY_OF_REF) {
12521
0
      ref = jit_ZVAL_DEREF_ref(jit, ref);
12522
0
    }
12523
0
    cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12524
0
    if (not_found_exit_addr) {
12525
0
      ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12526
0
      ir_refs_add(found_inputs, ir_END());
12527
0
    } else if (found_exit_addr) {
12528
0
      ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12529
0
      ir_END_list(*end_inputs);
12530
0
    } else {
12531
0
      ir_ref if_set = ir_IF(cond);
12532
0
      ir_IF_FALSE(if_set);
12533
0
      ir_END_list(*end_inputs);
12534
0
      ir_IF_TRUE(if_set);
12535
0
      ir_refs_add(found_inputs, ir_END());
12536
0
    }
12537
0
  }
12538
12539
0
  return 1;
12540
0
}
12541
12542
static int zend_jit_fetch_dim_read(zend_jit_ctx       *jit,
12543
                                   const zend_op      *opline,
12544
                                   zend_ssa           *ssa,
12545
                                   const zend_ssa_op  *ssa_op,
12546
                                   uint32_t            op1_info,
12547
                                   zend_jit_addr       op1_addr,
12548
                                   bool           op1_avoid_refcounting,
12549
                                   uint32_t            op2_info,
12550
                                   zend_jit_addr       op2_addr,
12551
                                   zend_ssa_range     *op2_range,
12552
                                   uint32_t            res_info,
12553
                                   zend_jit_addr       res_addr,
12554
                                   uint8_t             dim_type)
12555
0
{
12556
0
  zend_jit_addr orig_op1_addr;
12557
0
  const void *exit_addr = NULL;
12558
0
  const void *not_found_exit_addr = NULL;
12559
0
  bool result_type_guard = false;
12560
0
  bool result_avoid_refcounting = false;
12561
0
  uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12562
0
  int may_throw = 0;
12563
0
  ir_ref if_type = IR_UNUSED;
12564
0
  ir_ref end_inputs = IR_UNUSED;
12565
0
  ir_ref not_found_inputs = IR_UNUSED;
12566
12567
0
  orig_op1_addr = OP1_ADDR();
12568
12569
0
  if (opline->opcode != ZEND_FETCH_DIM_IS
12570
0
   && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12571
0
   && !has_concrete_type(op1_info)) {
12572
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12573
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12574
0
    if (!exit_addr) {
12575
0
      return 0;
12576
0
    }
12577
0
  }
12578
12579
0
  if ((res_info & MAY_BE_GUARD)
12580
0
   && JIT_G(current_frame)
12581
0
   && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12582
12583
0
    if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12584
0
      result_type_guard = true;
12585
0
      res_info &= ~MAY_BE_GUARD;
12586
0
      ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12587
0
    }
12588
12589
0
    if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12590
0
     && (opline->opcode == ZEND_FETCH_LIST_R
12591
0
      || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12592
0
      || op1_avoid_refcounting)
12593
0
     && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12594
0
     && (ssa_op+1)->op1_use == ssa_op->result_def
12595
0
     && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12596
0
     && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12597
0
      result_avoid_refcounting = true;
12598
0
      ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12599
0
    }
12600
12601
0
    if (opline->opcode == ZEND_FETCH_DIM_IS
12602
0
     && !(res_info & MAY_BE_NULL)) {
12603
0
      uint32_t flags = 0;
12604
0
      uint32_t old_op1_info = 0;
12605
0
      uint32_t old_info;
12606
0
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12607
0
      int32_t exit_point;
12608
12609
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12610
0
       && !op1_avoid_refcounting) {
12611
0
        flags |= ZEND_JIT_EXIT_FREE_OP1;
12612
0
      }
12613
0
      if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12614
0
       && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12615
0
        flags |= ZEND_JIT_EXIT_FREE_OP2;
12616
0
      }
12617
12618
0
      if (op1_avoid_refcounting) {
12619
0
        old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12620
0
        SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12621
0
      }
12622
12623
0
      old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12624
0
      SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12625
0
      SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12626
0
      exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12627
0
      SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12628
0
      not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12629
0
      if (!not_found_exit_addr) {
12630
0
        return 0;
12631
0
      }
12632
12633
0
      if (op1_avoid_refcounting) {
12634
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12635
0
      }
12636
0
    }
12637
0
  }
12638
12639
0
  if (op1_info & MAY_BE_REF) {
12640
0
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12641
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
12642
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12643
0
  }
12644
12645
0
  if (op1_info & MAY_BE_ARRAY) {
12646
0
    ir_ref ht_ref, ref;
12647
0
    zend_jit_addr val_addr;
12648
0
    ir_refs *found_inputs, *found_vals;
12649
12650
0
    ir_refs_init(found_inputs, 10);
12651
0
    ir_refs_init(found_vals, 10);
12652
12653
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12654
0
      if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12655
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12656
0
      } else {
12657
0
        if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12658
0
        ir_IF_TRUE(if_type);
12659
0
      }
12660
0
    }
12661
12662
0
    ht_ref = jit_Z_PTR(jit, op1_addr);
12663
12664
0
    if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12665
0
        (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12666
0
      may_throw = 1;
12667
0
    }
12668
12669
0
    if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12670
0
        (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12671
0
        op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12672
0
        result_type_guard, ht_ref, found_inputs, found_vals,
12673
0
        &end_inputs, &not_found_inputs)) {
12674
0
      return 0;
12675
0
    }
12676
12677
0
    if (found_inputs->count) {
12678
0
      ir_MERGE_N(found_inputs->count, found_inputs->refs);
12679
0
      ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12680
0
      val_addr = ZEND_ADDR_REF_ZVAL(ref);
12681
12682
0
      if (result_type_guard) {
12683
0
        uint8_t type = concrete_type(res_info);
12684
0
        uint32_t flags = 0;
12685
12686
0
        if (opline->opcode != ZEND_FETCH_LIST_R
12687
0
         && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12688
0
         && !op1_avoid_refcounting) {
12689
0
          flags |= ZEND_JIT_EXIT_FREE_OP1;
12690
0
        }
12691
0
        if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12692
0
         && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12693
0
          flags |= ZEND_JIT_EXIT_FREE_OP2;
12694
0
        }
12695
12696
0
        val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12697
0
          (op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12698
0
        if (!val_addr) {
12699
0
          return 0;
12700
0
        }
12701
12702
0
        if (not_found_inputs) {
12703
0
          ir_END_list(not_found_inputs);
12704
0
          ir_MERGE_list(not_found_inputs);
12705
0
        }
12706
12707
        // ZVAL_COPY
12708
0
        jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12709
0
        if (Z_MODE(res_addr) != IS_REG) {
12710
0
        } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12711
0
          return 0;
12712
0
        }
12713
0
      } else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12714
        // ZVAL_COPY_DEREF
12715
0
        ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12716
0
        if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12717
0
          return 0;
12718
0
        }
12719
0
      } else  {
12720
        // ZVAL_COPY
12721
0
        jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, true);
12722
0
      }
12723
12724
0
      ir_END_list(end_inputs);
12725
0
    } else if (not_found_inputs) {
12726
0
      ir_MERGE_list(not_found_inputs);
12727
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12728
0
      ir_END_list(end_inputs);
12729
0
    } else if (!end_inputs && jit->ctx.control) {
12730
0
      ir_END_list(end_inputs); /* dead code */
12731
0
    }
12732
0
  }
12733
12734
0
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12735
0
    if (if_type) {
12736
0
      ir_IF_FALSE_cold(if_type);
12737
0
      if_type = IS_UNDEF;
12738
0
    }
12739
12740
0
    if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12741
0
      ir_ref str_ref;
12742
12743
0
      may_throw = 1;
12744
0
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12745
0
        if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12746
0
          jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12747
0
        } else {
12748
0
          if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12749
0
          ir_IF_TRUE(if_type);
12750
0
        }
12751
0
      }
12752
0
      jit_SET_EX_OPLINE(jit, opline);
12753
0
      str_ref = jit_Z_PTR(jit, op1_addr);
12754
0
      if (opline->opcode != ZEND_FETCH_DIM_IS) {
12755
0
        ir_ref ref;
12756
12757
0
        if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12758
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12759
0
            str_ref, jit_Z_LVAL(jit, op2_addr));
12760
0
        } else {
12761
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12762
0
            str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12763
0
        }
12764
0
        jit_set_Z_PTR(jit, res_addr, ref);
12765
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12766
0
      } else {
12767
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12768
0
          str_ref,
12769
0
          jit_ZVAL_ADDR(jit, op2_addr),
12770
0
          jit_ZVAL_ADDR(jit, res_addr));
12771
0
      }
12772
0
      ir_END_list(end_inputs);
12773
0
    }
12774
12775
0
    if (op1_info & MAY_BE_OBJECT) {
12776
0
      ir_ref arg2;
12777
12778
0
      if (if_type) {
12779
0
        ir_IF_FALSE_cold(if_type);
12780
0
        if_type = IS_UNDEF;
12781
0
      }
12782
12783
0
      may_throw = 1;
12784
0
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12785
0
        if (exit_addr) {
12786
0
          jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12787
0
        } else {
12788
0
          if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12789
0
          ir_IF_TRUE(if_type);
12790
0
        }
12791
0
      }
12792
12793
0
      jit_SET_EX_OPLINE(jit, opline);
12794
0
      if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12795
0
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12796
0
        arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12797
0
      } else {
12798
0
        arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12799
0
      }
12800
12801
0
      if (opline->opcode != ZEND_FETCH_DIM_IS) {
12802
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12803
0
          jit_ZVAL_ADDR(jit, op1_addr),
12804
0
          arg2,
12805
0
          jit_ZVAL_ADDR(jit, res_addr));
12806
0
      } else {
12807
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12808
0
          jit_ZVAL_ADDR(jit, op1_addr),
12809
0
          arg2,
12810
0
          jit_ZVAL_ADDR(jit, res_addr));
12811
0
      }
12812
12813
0
      ir_END_list(end_inputs);
12814
0
    }
12815
12816
0
    if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12817
0
     && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12818
12819
0
      if (if_type) {
12820
0
        ir_IF_FALSE_cold(if_type);
12821
0
        if_type = IS_UNDEF;
12822
0
      }
12823
12824
0
      if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
12825
0
        jit_SET_EX_OPLINE(jit, opline);
12826
0
        if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
12827
0
          may_throw = 1;
12828
0
          zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL,
12829
0
                  false, true, false);
12830
0
        }
12831
12832
0
        if (op2_info & MAY_BE_UNDEF) {
12833
0
          may_throw = 1;
12834
0
          zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL,
12835
0
                  false, true, false);
12836
0
        }
12837
0
      }
12838
12839
0
      if (opline->opcode != ZEND_FETCH_DIM_IS) {
12840
0
        ir_ref ref;
12841
12842
0
        may_throw = 1;
12843
0
        if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
12844
0
          ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
12845
0
        } else {
12846
0
          jit_SET_EX_OPLINE(jit, opline);
12847
0
          ref = jit_ZVAL_ADDR(jit, op1_addr);
12848
0
        }
12849
0
        if (opline->opcode == ZEND_FETCH_LIST_R) {
12850
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_use), ref);
12851
0
        } else {
12852
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
12853
0
        }
12854
0
      }
12855
12856
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12857
0
      ir_END_list(end_inputs);
12858
0
    }
12859
0
  }
12860
12861
0
  if (end_inputs) {
12862
0
    ir_MERGE_list(end_inputs);
12863
12864
0
#ifdef ZEND_JIT_USE_RC_INFERENCE
12865
0
    if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
12866
      /* Magic offsetGet() may increase refcount of the key */
12867
0
      op2_info |= MAY_BE_RCN;
12868
0
    }
12869
0
#endif
12870
12871
0
    if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
12872
0
      if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
12873
0
        may_throw = 1;
12874
0
      }
12875
0
      jit_FREE_OP(jit,  opline->op2_type, opline->op2, op2_info, opline);
12876
0
    }
12877
0
    if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
12878
0
      if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
12879
0
        if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
12880
0
          may_throw = 1;
12881
0
        }
12882
0
        jit_FREE_OP(jit,  opline->op1_type, opline->op1, op1_info, opline);
12883
0
      }
12884
0
    }
12885
12886
0
    if (may_throw) {
12887
0
      zend_jit_check_exception(jit);
12888
0
    }
12889
0
  } else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
12890
0
    ir_BEGIN(IR_UNUSED); /* unreachable tail */
12891
0
  }
12892
12893
0
  return 1;
12894
0
}
12895
12896
static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx   *jit,
12897
                                                   const zend_op  *opline,
12898
                                                   uint32_t       *op1_info_ptr,
12899
                                                   zend_jit_addr   op1_addr,
12900
                                                   ir_ref         *if_type,
12901
                                                   ir_ref         *ht_ref,
12902
                                                   int            *may_throw)
12903
0
{
12904
0
  ir_ref ref = IR_UNUSED;
12905
0
  ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
12906
0
  ir_refs *array_inputs, *array_values;
12907
0
  uint32_t op1_info = *op1_info_ptr;
12908
12909
0
  ir_refs_init(array_inputs, 4);
12910
0
  ir_refs_init(array_values, 4);
12911
12912
0
  ref = jit_ZVAL_ADDR(jit, op1_addr);
12913
0
  if (op1_info & MAY_BE_REF) {
12914
0
    ir_ref if_reference, if_array, end1, ref2;
12915
12916
0
    *may_throw = 1;
12917
0
    if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
12918
0
    ir_IF_FALSE(if_reference);
12919
0
    end1 = ir_END();
12920
0
    ir_IF_TRUE_cold(if_reference);
12921
0
    array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
12922
0
    if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
12923
0
    ir_IF_TRUE(if_array);
12924
0
    array_reference_end = ir_END();
12925
0
    ir_IF_FALSE_cold(if_array);
12926
0
    if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
12927
0
      jit_SET_EX_OPLINE(jit, opline);
12928
0
    }
12929
0
    ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
12930
0
    ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
12931
12932
0
    ir_MERGE_WITH(end1);
12933
0
    ref = ir_PHI_2(IR_ADDR, ref2, ref);
12934
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12935
0
  }
12936
12937
0
  if (op1_info & MAY_BE_ARRAY) {
12938
0
    ir_ref op1_ref = ref;
12939
12940
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12941
0
      *if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12942
0
      ir_IF_TRUE(*if_type);
12943
0
    }
12944
0
    if (array_reference_end) {
12945
0
      ir_MERGE_WITH(array_reference_end);
12946
0
      op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
12947
0
    }
12948
    // JIT: SEPARATE_ARRAY()
12949
0
    ref = jit_Z_PTR_ref(jit, op1_ref);
12950
0
    if (RC_MAY_BE_N(op1_info)) {
12951
0
      if (RC_MAY_BE_1(op1_info)) {
12952
0
        ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
12953
0
        ir_IF_TRUE(if_refcount_1);
12954
0
        ir_refs_add(array_inputs, ir_END());
12955
0
        ir_refs_add(array_values, ref);
12956
0
        ir_IF_FALSE(if_refcount_1);
12957
0
      }
12958
0
      ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
12959
0
    }
12960
0
    if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
12961
0
      ir_refs_add(array_inputs, ir_END());
12962
0
      ir_refs_add(array_values, ref);
12963
0
    }
12964
0
  }
12965
12966
0
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
12967
0
    if (*if_type) {
12968
0
      ir_IF_FALSE_cold(*if_type);
12969
0
      *if_type = IR_UNUSED;
12970
0
    }
12971
0
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
12972
0
      *if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
12973
0
      ir_IF_TRUE(*if_type);
12974
0
    }
12975
0
    if ((op1_info & MAY_BE_UNDEF)
12976
0
     && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
12977
0
      ir_ref end1 = IR_UNUSED;
12978
12979
0
      *may_throw = 1;
12980
0
      if (op1_info & MAY_BE_NULL) {
12981
0
        ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
12982
0
        ir_IF_TRUE(if_def);
12983
0
        end1 = ir_END();
12984
0
        ir_IF_FALSE(if_def);
12985
0
      }
12986
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
12987
0
      if (end1) {
12988
0
        ir_MERGE_WITH(end1);
12989
0
      }
12990
0
    }
12991
    // JIT: ZVAL_ARR(container, zend_new_array(8));
12992
0
    ref = ir_CALL_1(IR_ADDR,
12993
0
      jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
12994
0
      jit_ZVAL_ADDR(jit, op1_addr));
12995
0
    if (array_inputs->count) {
12996
0
      ir_refs_add(array_inputs, ir_END());
12997
0
      ir_refs_add(array_values, ref);
12998
0
    }
12999
0
    op1_info &= ~(MAY_BE_UNDEF | MAY_BE_NULL);
13000
0
    op1_info |= MAY_BE_ARRAY | MAY_BE_RC1;
13001
0
    *op1_info_ptr = op1_info;
13002
0
  }
13003
13004
0
  if (array_inputs->count) {
13005
0
    ir_MERGE_N(array_inputs->count, array_inputs->refs);
13006
0
    ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
13007
0
  }
13008
13009
0
  *ht_ref = ref;
13010
0
  return op1_addr;
13011
0
}
13012
13013
static int zend_jit_fetch_dim(zend_jit_ctx   *jit,
13014
                              const zend_op  *opline,
13015
                              uint32_t        op1_info,
13016
                              zend_jit_addr   op1_addr,
13017
                              uint32_t        op2_info,
13018
                              zend_jit_addr   op2_addr,
13019
                              zend_ssa_range *op2_range,
13020
                              zend_jit_addr   res_addr,
13021
                              uint8_t         dim_type)
13022
0
{
13023
0
  int may_throw = 0;
13024
0
  ir_ref end_inputs = IR_UNUSED;
13025
0
  ir_ref ref, if_type = IR_UNUSED, ht_ref;
13026
13027
0
  if (opline->opcode == ZEND_FETCH_DIM_RW) {
13028
0
    jit_SET_EX_OPLINE(jit, opline);
13029
0
  }
13030
13031
0
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13032
13033
0
  if (op1_info & MAY_BE_ARRAY) {
13034
0
    ir_refs *found_inputs, *found_vals;
13035
13036
0
    ir_refs_init(found_inputs, 8);
13037
0
    ir_refs_init(found_vals, 8);
13038
13039
0
    if (opline->op2_type == IS_UNUSED) {
13040
0
      ir_ref if_ok;
13041
13042
0
      may_throw = 1;
13043
      // JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13044
0
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13045
0
        ht_ref, jit_EG(uninitialized_zval));
13046
13047
      // JIT: if (UNEXPECTED(!var_ptr)) {
13048
0
      if_ok = ir_IF(ref);
13049
0
      ir_IF_FALSE_cold(if_ok);
13050
0
      if (opline->opcode != ZEND_FETCH_DIM_RW) {
13051
0
        jit_SET_EX_OPLINE(jit, opline);
13052
0
      }
13053
0
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13054
0
      ir_END_list(end_inputs);
13055
13056
0
      ir_IF_TRUE(if_ok);
13057
0
      jit_set_Z_PTR(jit, res_addr, ref);
13058
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
13059
13060
0
      ir_END_list(end_inputs);
13061
0
    } else {
13062
0
      uint32_t type;
13063
13064
0
      switch (opline->opcode) {
13065
0
        case ZEND_FETCH_DIM_W:
13066
0
        case ZEND_FETCH_LIST_W:
13067
0
          type = BP_VAR_W;
13068
0
          break;
13069
0
        case ZEND_FETCH_DIM_RW:
13070
0
          may_throw = 1;
13071
0
          type = BP_VAR_RW;
13072
0
          break;
13073
0
        case ZEND_FETCH_DIM_UNSET:
13074
0
          type = BP_VAR_UNSET;
13075
0
          break;
13076
0
        default:
13077
0
          ZEND_UNREACHABLE();
13078
0
      }
13079
13080
0
      if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
13081
0
        may_throw = 1;
13082
0
      }
13083
0
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
13084
0
          op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13085
0
          false, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
13086
0
        return 0;
13087
0
      }
13088
13089
0
      if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13090
0
        if (end_inputs) {
13091
0
          ir_MERGE_list(end_inputs);
13092
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13093
0
          end_inputs = ir_END();
13094
0
        }
13095
0
      } else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
13096
        /* impossible dead path */
13097
0
        end_inputs = ir_END();
13098
0
      } else {
13099
0
        ZEND_ASSERT(end_inputs == IR_UNUSED);
13100
0
      }
13101
13102
0
      if (found_inputs->count) {
13103
0
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13104
0
        ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
13105
0
        jit_set_Z_PTR(jit, res_addr, ref);
13106
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
13107
0
        ir_END_list(end_inputs);
13108
0
      }
13109
13110
0
    }
13111
0
  }
13112
13113
0
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13114
0
    ir_ref arg2;
13115
13116
0
    may_throw = 1;
13117
13118
0
    if (if_type) {
13119
0
      ir_IF_FALSE(if_type);
13120
0
      if_type = IR_UNUSED;
13121
0
    }
13122
13123
0
    if (opline->opcode != ZEND_FETCH_DIM_RW) {
13124
0
      jit_SET_EX_OPLINE(jit, opline);
13125
0
    }
13126
13127
0
      if (opline->op2_type == IS_UNUSED) {
13128
0
      arg2 = IR_NULL;
13129
0
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13130
0
      ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13131
0
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13132
0
    } else {
13133
0
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13134
0
    }
13135
13136
0
    switch (opline->opcode) {
13137
0
      case ZEND_FETCH_DIM_W:
13138
0
      case ZEND_FETCH_LIST_W:
13139
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
13140
0
          jit_ZVAL_ADDR(jit, op1_addr),
13141
0
          arg2,
13142
0
          jit_ZVAL_ADDR(jit, res_addr));
13143
0
        break;
13144
0
      case ZEND_FETCH_DIM_RW:
13145
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
13146
0
          jit_ZVAL_ADDR(jit, op1_addr),
13147
0
          arg2,
13148
0
          jit_ZVAL_ADDR(jit, res_addr));
13149
0
        break;
13150
//      case ZEND_FETCH_DIM_UNSET:
13151
//        | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
13152
//        break;
13153
0
      default:
13154
0
        ZEND_UNREACHABLE();
13155
0
      }
13156
13157
0
    if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13158
0
      ir_END_list(end_inputs);
13159
0
    }
13160
0
  }
13161
13162
0
#ifdef ZEND_JIT_USE_RC_INFERENCE
13163
0
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
13164
    /* ASSIGN_DIM may increase refcount of the key */
13165
0
    op2_info |= MAY_BE_RCN;
13166
0
  }
13167
0
#endif
13168
13169
0
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
13170
0
   && (op2_info & MAY_HAVE_DTOR)
13171
0
   && (op2_info & MAY_BE_RC1)) {
13172
0
    may_throw = 1;
13173
0
  }
13174
13175
0
  if (end_inputs) {
13176
0
    ir_MERGE_list(end_inputs);
13177
0
  }
13178
13179
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13180
13181
0
  if (may_throw) {
13182
0
    zend_jit_check_exception(jit);
13183
0
  }
13184
13185
0
  return 1;
13186
0
}
13187
13188
static int zend_jit_isset_isempty_dim(zend_jit_ctx   *jit,
13189
                                      const zend_op  *opline,
13190
                                      uint32_t        op1_info,
13191
                                      zend_jit_addr   op1_addr,
13192
                                      bool       op1_avoid_refcounting,
13193
                                      uint32_t        op2_info,
13194
                                      zend_jit_addr   op2_addr,
13195
                                      zend_ssa_range *op2_range,
13196
                                      uint8_t         dim_type,
13197
                                      int             may_throw,
13198
                                      uint8_t         smart_branch_opcode,
13199
                                      uint32_t        target_label,
13200
                                      uint32_t        target_label2,
13201
                                      const void     *exit_addr)
13202
0
{
13203
0
  zend_jit_addr res_addr;
13204
0
  ir_ref if_type = IR_UNUSED;
13205
0
  ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
13206
0
  ir_refs *true_inputs;
13207
13208
0
  ir_refs_init(true_inputs, 8);
13209
13210
  // TODO: support for empty() ???
13211
0
  ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
13212
13213
0
  res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13214
13215
0
  if (op1_info & MAY_BE_REF) {
13216
0
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
13217
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
13218
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13219
0
  }
13220
13221
0
  if (op1_info & MAY_BE_ARRAY) {
13222
0
    const void *found_exit_addr = NULL;
13223
0
    const void *not_found_exit_addr = NULL;
13224
0
    ir_ref ht_ref;
13225
13226
0
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13227
0
      if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13228
0
      ir_IF_TRUE(if_type);
13229
0
    }
13230
13231
0
    ht_ref = jit_Z_PTR(jit, op1_addr);
13232
13233
0
    if (exit_addr
13234
0
     && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
13235
0
     && !may_throw
13236
0
     && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
13237
0
     && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
13238
0
      if (smart_branch_opcode == ZEND_JMPNZ) {
13239
0
        found_exit_addr = exit_addr;
13240
0
      } else {
13241
0
        not_found_exit_addr = exit_addr;
13242
0
      }
13243
0
    }
13244
0
    if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
13245
0
        op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
13246
0
        false, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
13247
0
      return 0;
13248
0
    }
13249
13250
0
    if (found_exit_addr) {
13251
0
      ir_MERGE_list(false_inputs);
13252
0
      return 1;
13253
0
    } else if (not_found_exit_addr) {
13254
0
      ir_MERGE_N(true_inputs->count, true_inputs->refs);
13255
0
      return 1;
13256
0
    }
13257
0
  }
13258
13259
0
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
13260
0
    if (if_type) {
13261
0
      ir_IF_FALSE(if_type);
13262
0
      if_type = IR_UNUSED;
13263
0
    }
13264
13265
0
    if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
13266
0
      ir_ref ref, arg1, arg2, if_true;
13267
13268
0
      jit_SET_EX_OPLINE(jit, opline);
13269
0
      arg1 = jit_ZVAL_ADDR(jit, op1_addr);
13270
0
      if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13271
0
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13272
0
        arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
13273
0
      } else {
13274
0
        arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13275
0
      }
13276
0
      ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
13277
0
      if_true = ir_IF(ref);
13278
0
      ir_IF_TRUE(if_true);
13279
0
      ir_refs_add(true_inputs, ir_END());
13280
0
      ir_IF_FALSE(if_true);
13281
0
      ir_END_list(false_inputs);
13282
0
    } else {
13283
0
      if (op2_info & MAY_BE_UNDEF) {
13284
0
        ir_ref end1 = IR_UNUSED;
13285
13286
0
        if (op2_info & MAY_BE_ANY) {
13287
0
          ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
13288
0
          ir_IF_TRUE(if_def);
13289
0
          end1 = ir_END();
13290
0
          ir_IF_FALSE(if_def);
13291
0
        }
13292
0
        jit_SET_EX_OPLINE(jit, opline);
13293
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
13294
0
        if (end1) {
13295
0
          ir_MERGE_WITH(end1);
13296
0
        }
13297
0
      }
13298
0
      ir_END_list(false_inputs);
13299
0
    }
13300
0
  }
13301
13302
0
#ifdef ZEND_JIT_USE_RC_INFERENCE
13303
0
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13304
    /* Magic offsetExists() may increase refcount of the key */
13305
0
    op2_info |= MAY_BE_RCN;
13306
0
  }
13307
0
#endif
13308
13309
0
  if (true_inputs->count) {
13310
0
    ir_MERGE_N(true_inputs->count, true_inputs->refs);
13311
13312
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13313
0
    if (!op1_avoid_refcounting) {
13314
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13315
0
    }
13316
0
    if (may_throw) {
13317
0
      zend_jit_check_exception_undef_result(jit, opline);
13318
0
    }
13319
0
    if (!(opline->extended_value & ZEND_ISEMPTY)) {
13320
0
      if (exit_addr) {
13321
0
        if (smart_branch_opcode == ZEND_JMPNZ) {
13322
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13323
0
        } else {
13324
0
          ir_END_list(end_inputs);
13325
0
        }
13326
0
      } else if (smart_branch_opcode) {
13327
0
        if (smart_branch_opcode == ZEND_JMPZ) {
13328
0
          _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13329
0
        } else if (smart_branch_opcode == ZEND_JMPNZ) {
13330
0
          _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13331
0
        } else {
13332
0
          ZEND_UNREACHABLE();
13333
0
        }
13334
0
      } else {
13335
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
13336
0
        ir_END_list(end_inputs);
13337
0
      }
13338
0
    } else {
13339
0
      ZEND_UNREACHABLE(); // TODO: support for empty()
13340
0
    }
13341
0
  }
13342
13343
0
  ir_MERGE_list(false_inputs);
13344
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13345
0
  if (!op1_avoid_refcounting) {
13346
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13347
0
  }
13348
0
  if (may_throw) {
13349
0
    zend_jit_check_exception_undef_result(jit, opline);
13350
0
  }
13351
0
  if (!(opline->extended_value & ZEND_ISEMPTY)) {
13352
0
    if (exit_addr) {
13353
0
      if (smart_branch_opcode == ZEND_JMPZ) {
13354
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13355
0
      } else {
13356
0
        ir_END_list(end_inputs);
13357
0
      }
13358
0
    } else if (smart_branch_opcode) {
13359
0
      if (smart_branch_opcode == ZEND_JMPZ) {
13360
0
        _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13361
0
      } else if (smart_branch_opcode == ZEND_JMPNZ) {
13362
0
        _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13363
0
      } else {
13364
0
        ZEND_UNREACHABLE();
13365
0
      }
13366
0
    } else {
13367
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
13368
0
      ir_END_list(end_inputs);
13369
0
    }
13370
0
  } else {
13371
0
    ZEND_UNREACHABLE(); // TODO: support for empty()
13372
0
  }
13373
13374
0
    if (!exit_addr && smart_branch_opcode) {
13375
0
    jit->b = -1;
13376
0
    } else {
13377
0
    ir_MERGE_list(end_inputs);
13378
0
    }
13379
13380
0
  return 1;
13381
0
}
13382
13383
static int zend_jit_assign_dim(zend_jit_ctx  *jit,
13384
                               const zend_op *opline,
13385
                               uint32_t       op1_info,
13386
                               zend_jit_addr  op1_addr,
13387
                               bool           op1_indirect,
13388
                               uint32_t       op2_info,
13389
                               zend_jit_addr  op2_addr,
13390
                               zend_ssa_range *op2_range,
13391
                               uint32_t       val_info,
13392
                               zend_jit_addr  op3_addr,
13393
                               zend_jit_addr  op3_def_addr,
13394
                               zend_jit_addr  res_addr,
13395
                               uint8_t        dim_type,
13396
                               int            may_throw)
13397
0
{
13398
0
  ir_ref if_type = IR_UNUSED;
13399
0
  ir_ref end_inputs = IR_UNUSED, ht_ref;
13400
13401
0
  if (op3_addr != op3_def_addr && op3_def_addr) {
13402
0
    if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13403
0
      return 0;
13404
0
    }
13405
0
    if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13406
0
      op3_addr = op3_def_addr;
13407
0
    }
13408
0
  }
13409
13410
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13411
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13412
0
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13413
13414
0
    if (!exit_addr) {
13415
0
      return 0;
13416
0
    }
13417
13418
0
    jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13419
13420
0
    val_info &= ~MAY_BE_UNDEF;
13421
0
  }
13422
13423
0
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13424
13425
0
  if (op1_info & MAY_BE_ARRAY) {
13426
0
    if (opline->op2_type == IS_UNUSED) {
13427
0
      uint32_t var_info = MAY_BE_NULL;
13428
0
      ir_ref if_ok, ref;
13429
0
      zend_jit_addr var_addr;
13430
13431
      // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13432
0
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13433
0
        ht_ref, jit_EG(uninitialized_zval));
13434
13435
      // JIT: if (UNEXPECTED(!var_ptr)) {
13436
0
      if_ok = ir_IF(ref);
13437
0
      ir_IF_FALSE_cold(if_ok);
13438
13439
      // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13440
0
      jit_SET_EX_OPLINE(jit, opline);
13441
0
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13442
13443
0
      ir_END_list(end_inputs);
13444
13445
0
      ir_IF_TRUE(if_ok);
13446
0
      var_addr = ZEND_ADDR_REF_ZVAL(ref);
13447
0
      if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, false)) {
13448
0
        return 0;
13449
0
      }
13450
0
    } else {
13451
0
      uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13452
0
      zend_jit_addr var_addr;
13453
0
      ir_ref ref;
13454
0
      ir_refs *found_inputs, *found_values;
13455
13456
0
      ir_refs_init(found_inputs, 8);
13457
0
      ir_refs_init(found_values, 8);
13458
13459
0
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13460
0
          op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13461
0
          false, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13462
0
        return 0;
13463
0
      }
13464
13465
0
      if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13466
0
        var_info |= MAY_BE_REF;
13467
0
      }
13468
0
      if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13469
0
        var_info |= MAY_BE_RC1;
13470
0
      }
13471
13472
0
      if (found_inputs->count) {
13473
0
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13474
0
        ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13475
0
        var_addr = ZEND_ADDR_REF_ZVAL(ref);
13476
13477
        // JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13478
0
        if (opline->op1_type == IS_VAR
13479
0
         && Z_MODE(op3_addr) != IS_REG
13480
0
         && opline->result_type == IS_UNUSED
13481
0
         && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13482
0
          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, false)) {
13483
0
            return 0;
13484
0
          }
13485
0
        } else {
13486
0
          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, false)) {
13487
0
            return 0;
13488
0
          }
13489
0
        }
13490
0
      }
13491
0
    }
13492
13493
0
    ir_END_list(end_inputs);
13494
0
  }
13495
13496
0
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13497
0
    ir_ref arg2, arg4;
13498
13499
0
    if (if_type) {
13500
0
      ir_IF_FALSE_cold(if_type);
13501
0
      if_type = IR_UNUSED;
13502
0
    }
13503
13504
0
    jit_SET_EX_OPLINE(jit, opline);
13505
13506
0
      if (opline->op2_type == IS_UNUSED) {
13507
0
      arg2 = IR_NULL;
13508
0
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13509
0
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13510
0
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13511
0
    } else {
13512
0
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13513
0
    }
13514
13515
0
    if (opline->result_type == IS_UNUSED) {
13516
0
      arg4 = IR_NULL;
13517
0
    } else {
13518
0
      arg4 = jit_ZVAL_ADDR(jit, res_addr);
13519
0
    }
13520
0
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13521
0
      jit_ZVAL_ADDR(jit, op1_addr),
13522
0
      arg2,
13523
0
      jit_ZVAL_ADDR(jit, op3_addr),
13524
0
      arg4);
13525
13526
0
#ifdef ZEND_JIT_USE_RC_INFERENCE
13527
0
    if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13528
      /* ASSIGN_DIM may increase refcount of the value */
13529
0
      val_info |= MAY_BE_RCN;
13530
0
    }
13531
0
#endif
13532
13533
0
    jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13534
13535
0
    ir_END_list(end_inputs);
13536
0
  }
13537
13538
0
#ifdef ZEND_JIT_USE_RC_INFERENCE
13539
0
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
13540
    /* ASSIGN_DIM may increase refcount of the key */
13541
0
    op2_info |= MAY_BE_RCN;
13542
0
  }
13543
0
#endif
13544
13545
0
  ir_MERGE_list(end_inputs);
13546
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13547
13548
0
  if (!op1_indirect) {
13549
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13550
0
  }
13551
13552
0
  if (may_throw) {
13553
0
    zend_jit_check_exception(jit);
13554
0
  }
13555
13556
0
  return 1;
13557
0
}
13558
13559
static int zend_jit_assign_dim_op(zend_jit_ctx   *jit,
13560
                                  const zend_op  *opline,
13561
                                  uint32_t        op1_info,
13562
                                  uint32_t        op1_def_info,
13563
                                  zend_jit_addr   op1_addr,
13564
                                  bool            op1_indirect,
13565
                                  uint32_t        op2_info,
13566
                                  zend_jit_addr   op2_addr,
13567
                                  zend_ssa_range *op2_range,
13568
                                  uint32_t        op1_data_info,
13569
                                  zend_jit_addr   op3_addr,
13570
                                  zend_ssa_range *op1_data_range,
13571
                                  uint8_t         dim_type,
13572
                                  int             may_throw)
13573
0
{
13574
0
  zend_jit_addr var_addr = IS_UNUSED;
13575
0
  const void *not_found_exit_addr = NULL;
13576
0
  uint32_t var_info = MAY_BE_NULL;
13577
0
  ir_ref if_type = IS_UNUSED;
13578
0
  ir_ref end_inputs = IR_UNUSED, ht_ref;
13579
0
  bool emit_fast_path = true;
13580
13581
0
  ZEND_ASSERT(opline->result_type == IS_UNUSED);
13582
13583
0
  if (may_throw) {
13584
0
    jit_SET_EX_OPLINE(jit, opline);
13585
0
  }
13586
13587
0
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13588
13589
0
  if (Z_MODE(op3_addr) == IS_REG
13590
0
   && Z_LOAD(op3_addr)
13591
0
   && jit->ra[Z_SSA_VAR(op3_addr)].ref == IR_NULL) {
13592
    /* Force load */
13593
0
    zend_jit_use_reg(jit, op3_addr);
13594
0
  }
13595
13596
0
  if (op1_info & MAY_BE_ARRAY) {
13597
0
    uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13598
13599
0
    if (opline->op2_type == IS_UNUSED) {
13600
0
      var_info = MAY_BE_NULL;
13601
0
      ir_ref if_ok, ref;
13602
13603
      // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13604
0
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13605
0
        ht_ref, jit_EG(uninitialized_zval));
13606
13607
      // JIT: if (UNEXPECTED(!var_ptr)) {
13608
0
      if_ok = ir_IF(ref);
13609
0
      ir_IF_FALSE_cold(if_ok);
13610
13611
      // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13612
0
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13613
13614
0
      ir_END_list(end_inputs);
13615
13616
0
      ir_IF_TRUE(if_ok);
13617
0
      var_addr = ZEND_ADDR_REF_ZVAL(ref);
13618
0
    } else {
13619
0
      ir_ref ref;
13620
0
      ir_refs *found_inputs, *found_values;
13621
13622
0
      ir_refs_init(found_inputs, 8);
13623
0
      ir_refs_init(found_values, 8);
13624
13625
0
      var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13626
0
      if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13627
0
        var_info |= MAY_BE_REF;
13628
0
      }
13629
0
      if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13630
0
        var_info |= MAY_BE_RC1;
13631
0
      }
13632
13633
0
      if (dim_type != IS_UNKNOWN
13634
0
       && dim_type != IS_UNDEF
13635
0
       && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13636
0
       && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13637
0
       && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13638
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13639
0
        not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13640
0
        if (!not_found_exit_addr) {
13641
0
          return 0;
13642
0
        }
13643
0
      }
13644
13645
0
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13646
0
          op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13647
0
          false, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13648
0
        return 0;
13649
0
      }
13650
13651
0
      if (found_inputs->count) {
13652
0
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13653
0
        ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13654
0
        var_addr = ZEND_ADDR_REF_ZVAL(ref);
13655
13656
0
        if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13657
0
          jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13658
0
          var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13659
0
        }
13660
0
        if (var_info & MAY_BE_REF) {
13661
0
          binary_op_type binary_op = get_binary_op(opline->extended_value);
13662
0
          ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13663
13664
0
          ref = jit_ZVAL_ADDR(jit, var_addr);
13665
0
          if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13666
0
          ir_IF_FALSE(if_ref);
13667
0
          noref_path = ir_END();
13668
0
          ir_IF_TRUE(if_ref);
13669
13670
0
          reference = jit_Z_PTR_ref(jit, ref);
13671
0
          ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13672
0
          if_typed = jit_if_TYPED_REF(jit, reference);
13673
0
          ir_IF_FALSE(if_typed);
13674
0
          ref_path = ir_END();
13675
0
          ir_IF_TRUE_cold(if_typed);
13676
13677
0
          if (Z_MODE(op3_addr) == IS_REG) {
13678
0
            zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
13679
0
            if (!zend_jit_spill_store_inv(jit, op3_addr, real_addr, op1_data_info)) {
13680
0
              return 0;
13681
0
            }
13682
0
            op3_addr = real_addr;
13683
0
          }
13684
0
          arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13685
0
          ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13686
0
            reference, arg2, ir_CONST_FC_FUNC(binary_op));
13687
13688
0
          ir_END_list(end_inputs);
13689
13690
0
          ir_MERGE_2(noref_path, ref_path);
13691
0
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
13692
0
          var_addr = ZEND_ADDR_REF_ZVAL(ref);
13693
0
        }
13694
0
      } else {
13695
0
        emit_fast_path = false;
13696
0
      }
13697
0
    }
13698
13699
0
    if (emit_fast_path) {
13700
0
      uint8_t val_op_type = (opline+1)->op1_type;
13701
13702
0
      if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13703
        /* prevent FREE_OP in the helpers */
13704
0
        val_op_type = IS_CV;
13705
0
      }
13706
13707
0
      switch (opline->extended_value) {
13708
0
        case ZEND_ADD:
13709
0
        case ZEND_SUB:
13710
0
        case ZEND_MUL:
13711
0
        case ZEND_DIV:
13712
0
          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,
13713
0
              1 /* may overflow */, may_throw)) {
13714
0
            return 0;
13715
0
          }
13716
0
          break;
13717
0
        case ZEND_BW_OR:
13718
0
        case ZEND_BW_AND:
13719
0
        case ZEND_BW_XOR:
13720
0
        case ZEND_SL:
13721
0
        case ZEND_SR:
13722
0
        case ZEND_MOD:
13723
0
          if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13724
0
              IS_CV, opline->op1, var_addr, var_info, NULL,
13725
0
              val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13726
0
              op1_data_range,
13727
0
              0, var_addr, var_def_info, var_info, may_throw)) {
13728
0
            return 0;
13729
0
          }
13730
0
          break;
13731
0
        case ZEND_CONCAT:
13732
0
          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,
13733
0
              may_throw)) {
13734
0
            return 0;
13735
0
          }
13736
0
          break;
13737
0
        default:
13738
0
          ZEND_UNREACHABLE();
13739
0
      }
13740
13741
0
      ir_END_list(end_inputs);
13742
0
    }
13743
0
  }
13744
13745
0
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13746
0
    binary_op_type binary_op;
13747
0
    ir_ref arg2;
13748
13749
0
    if (if_type) {
13750
0
      ir_IF_FALSE_cold(if_type);
13751
0
      if_type = IS_UNUSED;
13752
0
    }
13753
13754
0
      if (opline->op2_type == IS_UNUSED) {
13755
0
      arg2 = IR_NULL;
13756
0
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13757
0
      ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13758
0
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13759
0
    } else {
13760
0
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13761
0
    }
13762
0
    binary_op = get_binary_op(opline->extended_value);
13763
0
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13764
0
      jit_ZVAL_ADDR(jit, op1_addr),
13765
0
      arg2,
13766
0
      jit_ZVAL_ADDR(jit, op3_addr),
13767
0
      ir_CONST_FC_FUNC(binary_op));
13768
0
    ir_END_list(end_inputs);
13769
0
  }
13770
13771
0
  if (end_inputs) {
13772
0
    ir_MERGE_list(end_inputs);
13773
0
  }
13774
13775
0
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13776
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13777
0
  if (!op1_indirect) {
13778
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
13779
0
  }
13780
0
  if (may_throw) {
13781
0
    zend_jit_check_exception(jit);
13782
0
  }
13783
13784
0
  return 1;
13785
0
}
13786
13787
static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13788
0
{
13789
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13790
13791
  // JIT: ZVAL_COPY(res, value);
13792
0
  if (opline->op1_type == IS_CONST) {
13793
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
13794
13795
0
    jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, true);
13796
0
  } else {
13797
0
    zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13798
13799
0
    jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13800
0
  }
13801
13802
  // JIT: Z_FE_POS_P(res) = 0;
13803
0
  ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13804
13805
0
  return 1;
13806
0
}
13807
13808
static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13809
0
{
13810
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13811
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13812
0
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13813
0
  ir_ref ref;
13814
13815
0
  if (!exit_addr) {
13816
0
    return 0;
13817
0
  }
13818
13819
0
  ref = ir_AND_U32(
13820
0
    ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
13821
0
    ir_CONST_U32(HASH_FLAG_PACKED));
13822
0
  if (op_info & MAY_BE_ARRAY_PACKED) {
13823
0
    ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13824
0
  } else {
13825
0
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
13826
0
  }
13827
13828
0
  return 1;
13829
0
}
13830
13831
static int zend_jit_fe_fetch(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr)
13832
0
{
13833
0
  zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13834
0
  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;
13835
0
  ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
13836
0
  ir_ref exit_inputs = IR_UNUSED;
13837
13838
0
  if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
13839
    /* empty array */
13840
0
    if (exit_addr) {
13841
0
      if (exit_opcode == ZEND_JMP) {
13842
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13843
0
      }
13844
0
    } else {
13845
0
      zend_basic_block *bb;
13846
13847
0
      ZEND_ASSERT(jit->b >= 0);
13848
0
      bb = &jit->ssa->cfg.blocks[jit->b];
13849
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
13850
0
      jit->b = -1;
13851
0
    }
13852
0
    return 1;
13853
0
  }
13854
13855
  // JIT: array = EX_VAR(opline->op1.var);
13856
  // JIT: fe_ht = Z_ARRVAL_P(array);
13857
0
  ht_ref = jit_Z_PTR(jit, op1_addr);
13858
13859
0
  if (op1_info & MAY_BE_PACKED_GUARD) {
13860
0
    if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
13861
0
      return 0;
13862
0
    }
13863
0
  }
13864
13865
  // JIT: pos = Z_FE_POS_P(array);
13866
0
  hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
13867
13868
0
  if (MAY_BE_HASH(op1_info)) {
13869
0
    ir_ref loop_ref, pos2_ref, p2_ref;
13870
13871
0
    if (MAY_BE_PACKED(op1_info)) {
13872
0
      ref = ir_AND_U32(
13873
0
        ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
13874
0
        ir_CONST_U32(HASH_FLAG_PACKED));
13875
0
      if_packed = ir_IF(ref);
13876
0
      ir_IF_FALSE(if_packed);
13877
0
    }
13878
13879
    // JIT: p = fe_ht->arData + pos;
13880
0
    if (sizeof(void*) == 8) {
13881
0
      ref = ir_ZEXT_A(hash_pos_ref);
13882
0
    } else {
13883
0
      ref = ir_BITCAST_A(hash_pos_ref);
13884
0
    }
13885
0
    hash_p_ref = ir_ADD_A(
13886
0
      ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
13887
0
      ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
13888
13889
0
    loop_ref = ir_LOOP_BEGIN(ir_END());
13890
0
    hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
13891
0
    hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
13892
13893
    // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13894
0
    ref = ir_ULT(hash_pos_ref,
13895
0
      ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13896
13897
    // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13898
    // JIT: ZEND_VM_CONTINUE();
13899
13900
0
    if (exit_addr) {
13901
0
      if (exit_opcode == ZEND_JMP) {
13902
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13903
0
      } else {
13904
0
        ir_ref if_fit = ir_IF(ref);
13905
0
        ir_IF_FALSE(if_fit);
13906
0
        ir_END_list(exit_inputs);
13907
0
        ir_IF_TRUE(if_fit);
13908
0
      }
13909
0
    } else {
13910
0
      ir_ref if_fit = ir_IF(ref);
13911
0
      ir_IF_FALSE(if_fit);
13912
0
      ir_END_list(exit_inputs);
13913
0
      ir_IF_TRUE(if_fit);
13914
0
    }
13915
13916
    // JIT: pos++;
13917
0
    pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
13918
13919
    // JIT: value_type = Z_TYPE_INFO_P(value);
13920
    // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13921
0
    if (!exit_addr || exit_opcode == ZEND_JMP) {
13922
0
      if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
13923
0
      ir_IF_FALSE(if_def_hash);
13924
0
    } else {
13925
0
      ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
13926
0
    }
13927
13928
    // JIT: p++;
13929
0
    p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
13930
13931
0
    ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13932
0
    ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
13933
0
    ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
13934
13935
0
    if (MAY_BE_PACKED(op1_info)) {
13936
0
      ir_IF_TRUE(if_packed);
13937
0
    }
13938
0
  }
13939
0
  if (MAY_BE_PACKED(op1_info)) {
13940
0
    ir_ref loop_ref, pos2_ref, p2_ref;
13941
13942
    // JIT: p = fe_ht->arPacked + pos;
13943
0
    if (sizeof(void*) == 8) {
13944
0
      ref = ir_ZEXT_A(packed_pos_ref);
13945
0
    } else {
13946
0
      ref = ir_BITCAST_A(packed_pos_ref);
13947
0
    }
13948
0
    packed_p_ref = ir_ADD_A(
13949
0
      ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
13950
0
      ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
13951
13952
0
    loop_ref = ir_LOOP_BEGIN(ir_END());
13953
0
    packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
13954
0
    packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
13955
13956
    // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
13957
0
    ref = ir_ULT(packed_pos_ref,
13958
0
      ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
13959
13960
    // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
13961
    // JIT: ZEND_VM_CONTINUE();
13962
0
    if (exit_addr) {
13963
0
      if (exit_opcode == ZEND_JMP) {
13964
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
13965
0
      } else {
13966
0
        ir_ref if_fit = ir_IF(ref);
13967
0
        ir_IF_FALSE(if_fit);
13968
0
        ir_END_list(exit_inputs);
13969
0
        ir_IF_TRUE(if_fit);
13970
0
      }
13971
0
    } else {
13972
0
      ir_ref if_fit = ir_IF(ref);
13973
0
      ir_IF_FALSE(if_fit);
13974
0
      ir_END_list(exit_inputs);
13975
0
      ir_IF_TRUE(if_fit);
13976
0
    }
13977
13978
    // JIT: pos++;
13979
0
    pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
13980
13981
    // JIT: value_type = Z_TYPE_INFO_P(value);
13982
    // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
13983
0
    if (!exit_addr || exit_opcode == ZEND_JMP) {
13984
0
      if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
13985
0
      ir_IF_FALSE(if_def_packed);
13986
0
    } else {
13987
0
      ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
13988
0
    }
13989
13990
    // JIT: p++;
13991
0
    p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
13992
13993
0
    ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
13994
0
    ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
13995
0
    ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
13996
0
  }
13997
13998
0
  if (!exit_addr || exit_opcode == ZEND_JMP) {
13999
0
    zend_jit_addr val_addr;
14000
0
    zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
14001
0
    uint32_t val_info;
14002
0
    ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
14003
14004
0
    if (RETURN_VALUE_USED(opline)) {
14005
0
      zend_jit_addr res_addr = RES_ADDR();
14006
14007
0
      if (MAY_BE_HASH(op1_info)) {
14008
0
        ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
14009
14010
0
        ZEND_ASSERT(if_def_hash);
14011
0
        ir_IF_TRUE(if_def_hash);
14012
14013
        // JIT: Z_FE_POS_P(array) = pos + 1;
14014
0
        ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14015
0
          ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
14016
14017
0
        if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14018
0
          key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
14019
0
        }
14020
0
        if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
14021
0
         && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
14022
          // JIT: if (!p->key) {
14023
0
          if_key = ir_IF(key_ref);
14024
0
          ir_IF_TRUE(if_key);
14025
0
        }
14026
0
        if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14027
0
          ir_ref if_interned, interned_path;
14028
14029
          // JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
14030
0
          jit_set_Z_PTR(jit, res_addr, key_ref);
14031
0
          ref = ir_AND_U32(
14032
0
            ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
14033
0
            ir_CONST_U32(IS_STR_INTERNED));
14034
0
          if_interned = ir_IF(ref);
14035
0
          ir_IF_TRUE(if_interned);
14036
14037
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
14038
14039
0
          interned_path = ir_END();
14040
0
          ir_IF_FALSE(if_interned);
14041
14042
0
          jit_GC_ADDREF(jit, key_ref);
14043
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
14044
14045
0
          ir_MERGE_WITH(interned_path);
14046
14047
0
          if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
14048
0
            key_path = ir_END();
14049
0
          }
14050
0
        }
14051
0
        if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
14052
0
          if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14053
0
            ir_IF_FALSE(if_key);
14054
0
          }
14055
          // JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
14056
0
          ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
14057
0
          jit_set_Z_LVAL(jit, res_addr, ref);
14058
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
14059
14060
0
          if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14061
0
            ir_MERGE_WITH(key_path);
14062
0
          }
14063
0
        }
14064
0
        if (MAY_BE_PACKED(op1_info)) {
14065
0
          hash_path = ir_END();
14066
0
        } else {
14067
0
          p_ref = hash_p_ref;
14068
0
        }
14069
0
      }
14070
0
      if (MAY_BE_PACKED(op1_info)) {
14071
0
        ZEND_ASSERT(if_def_packed);
14072
0
        ir_IF_TRUE(if_def_packed);
14073
14074
        // JIT: Z_FE_POS_P(array) = pos + 1;
14075
0
        ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14076
0
          ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
14077
14078
        // JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
14079
0
        if (sizeof(zend_long) == 8) {
14080
0
          packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
14081
0
        } else {
14082
0
          packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
14083
0
        }
14084
0
        jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
14085
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
14086
14087
0
        if (MAY_BE_HASH(op1_info)) {
14088
0
          ir_MERGE_WITH(hash_path);
14089
0
          p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
14090
0
        } else {
14091
0
          p_ref = packed_p_ref;
14092
0
        }
14093
0
      }
14094
0
    } else {
14095
0
      ir_ref pos_ref = IR_UNUSED;
14096
14097
0
      if (if_def_hash && if_def_packed) {
14098
0
        ir_IF_TRUE(if_def_hash);
14099
0
        ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
14100
0
        pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
14101
0
        p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
14102
0
      } else if (if_def_hash) {
14103
0
        ir_IF_TRUE(if_def_hash);
14104
0
        pos_ref = hash_pos_ref;
14105
0
        p_ref = hash_p_ref;
14106
0
      } else if (if_def_packed) {
14107
0
        ir_IF_TRUE(if_def_packed);
14108
0
        pos_ref = packed_pos_ref;
14109
0
        p_ref = packed_p_ref;
14110
0
      } else {
14111
0
        ZEND_UNREACHABLE();
14112
0
      }
14113
14114
      // JIT: Z_FE_POS_P(array) = pos + 1;
14115
0
      ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14116
0
        ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
14117
0
    }
14118
14119
0
    val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
14120
0
    if (val_info & MAY_BE_ARRAY) {
14121
0
      val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
14122
0
    }
14123
0
    if (op1_info & MAY_BE_ARRAY_OF_REF) {
14124
0
      val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
14125
0
        MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
14126
0
    } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14127
0
      val_info |= MAY_BE_RC1 | MAY_BE_RCN;
14128
0
    }
14129
14130
0
    val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
14131
0
    if (opline->op2_type == IS_CV) {
14132
      // JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
14133
0
      if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, true)) {
14134
0
        return 0;
14135
0
      }
14136
0
    } else {
14137
      // JIT: ZVAL_DEREF(value);
14138
0
      if (val_info & MAY_BE_REF) {
14139
0
        ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
14140
0
        ref = jit_ZVAL_DEREF_ref(jit, ref);
14141
0
        val_addr = ZEND_ADDR_REF_ZVAL(ref);
14142
0
        val_info &= ~MAY_BE_REF;
14143
0
      }
14144
      // JIT: ZVAL_COPY(res, value);
14145
0
      jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, true);
14146
0
    }
14147
14148
0
    if (!exit_addr) {
14149
0
      zend_basic_block *bb;
14150
14151
0
      ZEND_ASSERT(jit->b >= 0);
14152
0
      bb = &jit->ssa->cfg.blocks[jit->b];
14153
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
14154
0
      ZEND_ASSERT(exit_inputs);
14155
0
      if (!jit->ctx.ir_base[exit_inputs].op2) {
14156
0
        ref = exit_inputs;
14157
0
      } else {
14158
0
        ir_MERGE_list(exit_inputs);
14159
0
        ref = ir_END();
14160
0
      }
14161
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
14162
0
      jit->b = -1;
14163
0
    }
14164
0
  } else {
14165
0
    ZEND_ASSERT(exit_inputs);
14166
0
    ir_MERGE_list(exit_inputs);
14167
0
  }
14168
14169
0
  return 1;
14170
0
}
14171
14172
static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
14173
0
{
14174
0
  zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14175
0
  zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
14176
0
  ir_ref ref = jit_Z_PTR(jit, this_addr);
14177
14178
0
  jit_set_Z_PTR(jit, var_addr, ref);
14179
0
  jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
14180
0
  jit_GC_ADDREF(jit, ref);
14181
14182
0
  return 1;
14183
0
}
14184
14185
static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
14186
0
{
14187
0
  if (!op_array->scope ||
14188
0
      (op_array->fn_flags & ZEND_ACC_STATIC) ||
14189
0
      ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) {
14190
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14191
0
      if (!JIT_G(current_frame) ||
14192
0
          !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14193
14194
0
        zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14195
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14196
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14197
14198
0
        if (!exit_addr) {
14199
0
          return 0;
14200
0
        }
14201
14202
0
        jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
14203
14204
0
        if (JIT_G(current_frame)) {
14205
0
          TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14206
0
        }
14207
0
      }
14208
0
    } else {
14209
0
      zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14210
0
      ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
14211
14212
0
      ir_IF_FALSE_cold(if_object);
14213
0
      jit_SET_EX_OPLINE(jit, opline);
14214
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
14215
14216
0
      ir_IF_TRUE(if_object);
14217
0
    }
14218
0
  }
14219
14220
0
  if (!check_only) {
14221
0
    if (!zend_jit_load_this(jit, opline->result.var)) {
14222
0
      return 0;
14223
0
    }
14224
0
  }
14225
14226
0
  return 1;
14227
0
}
14228
14229
static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
14230
0
{
14231
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14232
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14233
14234
0
  if (!exit_addr) {
14235
0
    return 0;
14236
0
  }
14237
14238
0
  ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
14239
0
    ir_CONST_ADDR(exit_addr));
14240
14241
0
  return 1;
14242
0
}
14243
14244
static int zend_jit_func_arg_by_ref_guard(zend_jit_ctx *jit, const zend_op *opline)
14245
0
{
14246
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14247
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14248
0
  ir_ref rx, call_info;
14249
14250
0
  if (!exit_addr) {
14251
0
    return 0;
14252
0
  }
14253
0
  if (jit->reuse_ip) {
14254
0
    rx = jit_IP(jit);
14255
0
  } else {
14256
0
    rx = ir_LOAD_A(jit_EX(call));
14257
0
  }
14258
0
  call_info = ir_LOAD_U32(jit_CALL(rx, This.u1.type_info));
14259
0
  ir_GUARD_NOT(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)),
14260
0
    ir_CONST_ADDR(exit_addr));
14261
0
  return 1;
14262
0
}
14263
14264
static int zend_jit_fetch_obj(zend_jit_ctx         *jit,
14265
                              const zend_op        *opline,
14266
                              const zend_op_array  *op_array,
14267
                              zend_ssa             *ssa,
14268
                              const zend_ssa_op    *ssa_op,
14269
                              uint32_t              op1_info,
14270
                              zend_jit_addr         op1_addr,
14271
                              bool                  op1_indirect,
14272
                              zend_class_entry     *ce,
14273
                              bool                  ce_is_instanceof,
14274
                              bool                  on_this,
14275
                              bool                  delayed_fetch_this,
14276
                              bool                  op1_avoid_refcounting,
14277
                              zend_class_entry     *trace_ce,
14278
                              zend_jit_addr         res_addr,
14279
                              uint8_t               prop_type,
14280
                              int                   may_throw)
14281
0
{
14282
0
  zval *member;
14283
0
  zend_property_info *prop_info;
14284
0
  bool may_be_dynamic = true;
14285
0
  zend_jit_addr prop_addr;
14286
0
  uint32_t res_info = RES_INFO();
14287
0
  ir_ref prop_type_ref = IR_UNUSED;
14288
0
  ir_ref obj_ref = IR_UNUSED;
14289
0
  ir_ref prop_ref = IR_UNUSED;
14290
0
  ir_ref end_inputs = IR_UNUSED;
14291
0
  ir_ref slow_inputs = IR_UNUSED;
14292
0
  ir_ref end_values = IR_UNUSED;
14293
14294
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
14295
0
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14296
14297
0
  member = RT_CONSTANT(opline, opline->op2);
14298
0
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14299
0
  prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
14300
14301
0
  if (on_this) {
14302
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14303
0
    obj_ref = jit_Z_PTR(jit, this_addr);
14304
0
  } else {
14305
0
    if (opline->op1_type == IS_VAR
14306
0
     && opline->opcode == ZEND_FETCH_OBJ_W
14307
0
     && (op1_info & MAY_BE_INDIRECT)
14308
0
     && Z_REG(op1_addr) == ZREG_FP) {
14309
0
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14310
0
    }
14311
0
    if (op1_info & MAY_BE_REF) {
14312
0
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14313
0
    }
14314
0
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14315
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14316
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14317
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14318
14319
0
        if (!exit_addr) {
14320
0
          return 0;
14321
0
        }
14322
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14323
0
      } else {
14324
0
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14325
14326
0
        ir_IF_FALSE_cold(if_obj);
14327
0
        if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14328
0
          ir_ref op1_ref = IR_UNUSED;
14329
14330
0
          jit_SET_EX_OPLINE(jit, opline);
14331
0
          if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
14332
0
            zend_jit_addr orig_op1_addr = OP1_ADDR();
14333
0
            ir_ref fast_path = IR_UNUSED;
14334
14335
0
            if (op1_info & MAY_BE_ANY) {
14336
0
              ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
14337
0
              ir_IF_TRUE(if_def);
14338
0
              fast_path = ir_END();
14339
0
              ir_IF_FALSE_cold(if_def);
14340
0
            }
14341
0
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
14342
0
              ir_CONST_U32(opline->op1.var));
14343
0
            if (fast_path) {
14344
0
              ir_MERGE_WITH(fast_path);
14345
0
            }
14346
0
            op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
14347
0
          } else {
14348
0
            op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
14349
0
          }
14350
0
          if (opline->opcode == ZEND_FETCH_OBJ_W) {
14351
0
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
14352
0
              op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14353
0
            jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14354
0
          } else {
14355
0
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
14356
0
              op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14357
0
            jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14358
0
          }
14359
0
        } else {
14360
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14361
0
        }
14362
0
        ir_END_list(end_inputs);
14363
14364
0
        ir_IF_TRUE(if_obj);
14365
0
      }
14366
0
    }
14367
0
    obj_ref = jit_Z_PTR(jit, op1_addr);
14368
0
  }
14369
14370
0
  ZEND_ASSERT(obj_ref);
14371
0
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14372
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
14373
0
    if (prop_info) {
14374
0
      ce = trace_ce;
14375
0
      ce_is_instanceof = false;
14376
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14377
0
        if (on_this && JIT_G(current_frame)
14378
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14379
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14380
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14381
0
          if (on_this && JIT_G(current_frame)) {
14382
0
            JIT_G(current_frame)->ce = ce;
14383
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14384
0
          }
14385
0
        } else {
14386
0
          return 0;
14387
0
        }
14388
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
14389
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14390
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
14391
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14392
0
        }
14393
0
      }
14394
0
    }
14395
0
  }
14396
14397
0
  if (!prop_info) {
14398
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14399
0
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14400
0
    ir_ref if_same = ir_IF(ir_EQ(ref,
14401
0
      ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14402
14403
0
    ir_IF_FALSE_cold(if_same);
14404
0
    ir_END_list(slow_inputs);
14405
14406
0
    ir_IF_TRUE(if_same);
14407
0
    ir_ref offset_ref = ir_LOAD_A(
14408
0
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14409
14410
0
    may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
14411
0
    if (may_be_dynamic) {
14412
0
      ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14413
0
      if (opline->opcode == ZEND_FETCH_OBJ_W) {
14414
0
        ir_IF_TRUE_cold(if_dynamic);
14415
0
        ir_END_list(slow_inputs);
14416
0
      } else {
14417
0
        ir_IF_TRUE_cold(if_dynamic);
14418
0
        jit_SET_EX_OPLINE(jit, opline);
14419
14420
0
        if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14421
0
          if (Z_MODE(res_addr) == IS_REG) {
14422
0
            ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
14423
0
              obj_ref, offset_ref);
14424
0
            ir_END_PHI_list(end_values, val_addr);
14425
0
          } else {
14426
0
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
14427
0
              obj_ref, offset_ref);
14428
0
            ir_END_list(end_inputs);
14429
0
          }
14430
0
        } else {
14431
0
          if (Z_MODE(res_addr) == IS_REG) {
14432
0
            ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
14433
0
              obj_ref, offset_ref);
14434
0
            ir_END_PHI_list(end_values, val_addr);
14435
0
          } else {
14436
0
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14437
0
              obj_ref, offset_ref);
14438
0
            ir_END_list(end_inputs);
14439
0
          }
14440
0
        }
14441
0
      }
14442
0
      ir_IF_FALSE(if_dynamic);
14443
0
    }
14444
0
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
14445
0
    prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14446
0
    ir_ref if_def = ir_IF(prop_type_ref);
14447
0
    ir_IF_FALSE_cold(if_def);
14448
0
    ir_END_list(slow_inputs);
14449
0
    ir_IF_TRUE(if_def);
14450
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14451
0
    if (opline->opcode == ZEND_FETCH_OBJ_W
14452
0
     && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14453
0
      uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14454
14455
0
      ir_ref allowed_inputs = IR_UNUSED;
14456
0
      ir_ref forbidden_inputs = IR_UNUSED;
14457
14458
0
      ir_ref prop_info_ref = ir_LOAD_A(
14459
0
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14460
0
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14461
14462
0
      ir_IF_TRUE_cold(if_has_prop_info);
14463
14464
0
      ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14465
0
      ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14466
14467
0
      ir_IF_FALSE(if_readonly_or_avis);
14468
0
      ir_END_list(allowed_inputs);
14469
14470
0
      ir_IF_TRUE_cold(if_readonly_or_avis);
14471
14472
0
      ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14473
0
      ir_IF_TRUE(if_readonly);
14474
0
      ir_END_list(forbidden_inputs);
14475
14476
0
      ir_IF_FALSE(if_readonly);
14477
0
      ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14478
0
      ir_ref if_avis_access = ir_IF(has_avis_access);
14479
0
      ir_IF_TRUE(if_avis_access);
14480
0
      ir_END_list(allowed_inputs);
14481
14482
0
      ir_IF_FALSE(if_avis_access);
14483
0
      ir_END_list(forbidden_inputs);
14484
14485
0
      ir_MERGE_list(forbidden_inputs);
14486
14487
0
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14488
0
      ir_IF_TRUE(if_prop_obj);
14489
0
      ref = jit_Z_PTR(jit, prop_addr);
14490
0
      jit_GC_ADDREF(jit, ref);
14491
0
      jit_set_Z_PTR(jit, res_addr, ref);
14492
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14493
0
      ir_END_list(end_inputs);
14494
14495
0
      ir_IF_FALSE_cold(if_prop_obj);
14496
14497
0
      jit_SET_EX_OPLINE(jit, opline);
14498
0
      if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14499
0
      ir_IF_TRUE(if_readonly);
14500
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), prop_info_ref);
14501
0
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14502
0
      ir_END_list(end_inputs);
14503
14504
0
      ir_IF_FALSE(if_readonly);
14505
0
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14506
0
        prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14507
0
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14508
0
      ir_END_list(end_inputs);
14509
14510
0
      ir_MERGE_list(allowed_inputs);
14511
14512
0
      if (flags == ZEND_FETCH_DIM_WRITE) {
14513
0
        jit_SET_EX_OPLINE(jit, opline);
14514
0
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14515
0
          prop_ref, prop_info_ref);
14516
0
        ir_END_list(end_inputs);
14517
0
        ir_IF_FALSE(if_has_prop_info);
14518
0
      } else if (flags == ZEND_FETCH_REF) {
14519
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14520
0
          prop_ref,
14521
0
          prop_info_ref,
14522
0
          jit_ZVAL_ADDR(jit, res_addr));
14523
0
        ir_END_list(end_inputs);
14524
0
        ir_IF_FALSE(if_has_prop_info);
14525
0
      } else {
14526
0
        ZEND_ASSERT(flags == 0);
14527
0
        ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14528
0
      }
14529
0
    }
14530
0
  } else {
14531
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14532
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14533
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14534
0
      if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14535
        /* perform IS_UNDEF check only after result type guard (during deoptimization) */
14536
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14537
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14538
14539
0
        if (!exit_addr) {
14540
0
          return 0;
14541
0
        }
14542
0
        prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14543
0
        ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14544
0
      }
14545
0
    } else {
14546
0
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14547
0
      ir_ref if_def = ir_IF(prop_type_ref);
14548
0
      ir_IF_FALSE_cold(if_def);
14549
0
      ir_END_list(slow_inputs);
14550
0
      ir_IF_TRUE(if_def);
14551
0
    }
14552
0
    if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14553
0
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14554
0
      ir_IF_TRUE(if_prop_obj);
14555
0
      ir_ref ref = jit_Z_PTR(jit, prop_addr);
14556
0
      jit_GC_ADDREF(jit, ref);
14557
0
      jit_set_Z_PTR(jit, res_addr, ref);
14558
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14559
0
      ir_END_list(end_inputs);
14560
14561
0
      ir_IF_FALSE_cold(if_prop_obj);
14562
0
      jit_SET_EX_OPLINE(jit, opline);
14563
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), ir_CONST_ADDR(prop_info));
14564
0
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14565
0
      ir_END_list(end_inputs);
14566
14567
0
      goto result_fetched;
14568
0
    } else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14569
      /* Readonly properties which are also asymmetric are never mutable indirectly, which is
14570
       * handled by the previous branch. */
14571
0
      ir_ref has_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), ir_CONST_ADDR(prop_info));
14572
14573
0
      ir_ref if_access = ir_IF(has_access);
14574
0
      ir_IF_FALSE_cold(if_access);
14575
14576
0
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14577
0
      ir_IF_TRUE(if_prop_obj);
14578
0
      ir_ref ref = jit_Z_PTR(jit, prop_addr);
14579
0
      jit_GC_ADDREF(jit, ref);
14580
0
      jit_set_Z_PTR(jit, res_addr, ref);
14581
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14582
0
      ir_END_list(end_inputs);
14583
14584
0
      ir_IF_FALSE_cold(if_prop_obj);
14585
0
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14586
0
        ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14587
0
      ir_END_list(end_inputs);
14588
14589
0
      ir_IF_TRUE(if_access);
14590
0
    }
14591
14592
0
    if (opline->opcode == ZEND_FETCH_OBJ_W
14593
0
     && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14594
0
     && ZEND_TYPE_IS_SET(prop_info->type)) {
14595
0
      uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14596
14597
0
      if (flags == ZEND_FETCH_DIM_WRITE) {
14598
0
        if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14599
0
          if (!prop_type_ref) {
14600
0
            prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14601
0
          }
14602
0
          ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14603
0
          ir_IF_TRUE_cold(if_null_or_flase);
14604
0
          jit_SET_EX_OPLINE(jit, opline);
14605
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14606
0
            prop_ref, ir_CONST_ADDR(prop_info));
14607
0
          ir_END_list(end_inputs);
14608
0
          ir_IF_FALSE(if_null_or_flase);
14609
0
        }
14610
0
      } else if (flags == ZEND_FETCH_REF) {
14611
0
        ir_ref ref;
14612
14613
0
        if (!prop_type_ref) {
14614
0
          prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14615
0
        }
14616
14617
0
        ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14618
0
        ir_IF_FALSE(if_reference);
14619
0
        if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14620
0
          ref = ir_CONST_ADDR(prop_info);
14621
0
        } else {
14622
0
          int prop_info_offset =
14623
0
            (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14624
14625
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14626
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14627
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14628
0
        }
14629
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14630
0
          prop_ref,
14631
0
          ref,
14632
0
          jit_ZVAL_ADDR(jit, res_addr));
14633
0
        ir_END_list(end_inputs);
14634
0
        ir_IF_TRUE(if_reference);
14635
0
      } else {
14636
0
        ZEND_UNREACHABLE();
14637
0
      }
14638
0
    }
14639
0
  }
14640
14641
0
  if (opline->opcode == ZEND_FETCH_OBJ_W) {
14642
0
    ZEND_ASSERT(prop_ref);
14643
0
    jit_set_Z_PTR(jit, res_addr, prop_ref);
14644
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14645
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14646
0
      ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14647
0
    }
14648
0
    ir_END_list(end_inputs);
14649
0
  } else {
14650
0
    if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
14651
0
      ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14652
0
    } else if ((res_info & MAY_BE_GUARD) && Z_MODE(res_addr) == IS_REG) {
14653
0
      ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14654
0
    } else if (Z_MODE(res_addr) == IS_REG) {
14655
0
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14656
14657
0
      if (!zend_jit_zval_copy_deref_reg(jit, res_addr, res_info & ~MAY_BE_GUARD, prop_addr, prop_type_ref, &end_values)) {
14658
0
        return 0;
14659
0
      }
14660
0
    } else {
14661
0
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14662
14663
0
      if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14664
0
        return 0;
14665
0
      }
14666
0
      ir_END_list(end_inputs);
14667
0
    }
14668
0
  }
14669
14670
0
result_fetched:
14671
0
  if (op1_avoid_refcounting) {
14672
0
    SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14673
0
  }
14674
14675
0
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14676
0
    ir_MERGE_list(slow_inputs);
14677
0
    jit_SET_EX_OPLINE(jit, opline);
14678
14679
0
    op1_info |= MAY_BE_RC1 | MAY_BE_RCN; /* object may be captured/released in magic handler */
14680
0
    if (opline->opcode == ZEND_FETCH_OBJ_W) {
14681
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14682
0
      ir_END_list(end_inputs);
14683
0
    } else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14684
0
      if (Z_MODE(res_addr) == IS_REG) {
14685
0
        ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14686
0
        ir_END_PHI_list(end_values, val_ref);
14687
0
      } else {
14688
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14689
0
        ir_END_list(end_inputs);
14690
0
      }
14691
0
    } else {
14692
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14693
0
      ir_END_list(end_inputs);
14694
0
    }
14695
0
  }
14696
14697
0
  if (end_values) {
14698
0
    ir_ref val_ref = ir_PHI_list(end_values);
14699
0
    zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14700
0
    bool result_avoid_refcounting = false;
14701
14702
0
    ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14703
0
      || opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14704
0
      || opline->opcode == ZEND_FETCH_OBJ_IS);
14705
0
    ZEND_ASSERT(end_inputs == IR_UNUSED);
14706
0
    if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14707
0
      uint8_t type = concrete_type(res_info);
14708
0
      uint32_t flags = ZEND_JIT_EXIT_CHECK_EXCEPTION;
14709
14710
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14711
0
       && !delayed_fetch_this
14712
0
       && !op1_avoid_refcounting) {
14713
0
        flags |= ZEND_JIT_EXIT_FREE_OP1;
14714
0
      }
14715
14716
0
      if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14717
0
       && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14718
0
       && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14719
0
       && (ssa_op+1)->op1_use == ssa_op->result_def
14720
0
       && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14721
0
        result_avoid_refcounting = true;
14722
0
        ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14723
0
      }
14724
14725
0
      val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14726
0
        true, flags, op1_avoid_refcounting);
14727
0
      if (!val_addr) {
14728
0
        return 0;
14729
0
      }
14730
14731
0
      res_info &= ~MAY_BE_GUARD;
14732
0
      ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14733
0
    }
14734
14735
    // ZVAL_COPY
14736
0
    jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14737
14738
0
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14739
0
      return 0;
14740
0
    }
14741
0
  } else {
14742
0
    ir_MERGE_list(end_inputs);
14743
0
  }
14744
14745
0
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14746
0
    if (opline->op1_type == IS_VAR
14747
0
     && opline->opcode == ZEND_FETCH_OBJ_W
14748
0
     && (op1_info & MAY_BE_RC1)) {
14749
0
      zend_jit_addr orig_op1_addr = OP1_ADDR();
14750
0
      ir_ref if_refcounted, ptr, refcount, if_non_zero;
14751
0
      ir_ref merge_inputs = IR_UNUSED;
14752
14753
0
      if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14754
0
      ir_IF_FALSE( if_refcounted);
14755
0
      ir_END_list(merge_inputs);
14756
0
      ir_IF_TRUE( if_refcounted);
14757
0
      ptr = jit_Z_PTR(jit, orig_op1_addr);
14758
0
      refcount = jit_GC_DELREF(jit, ptr);
14759
0
      if_non_zero = ir_IF(refcount);
14760
0
      ir_IF_TRUE( if_non_zero);
14761
0
      ir_END_list(merge_inputs);
14762
0
      ir_IF_FALSE( if_non_zero);
14763
0
      jit_SET_EX_OPLINE(jit, opline);
14764
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14765
0
      ir_END_list(merge_inputs);
14766
0
      ir_MERGE_list(merge_inputs);
14767
0
    } else if (!op1_avoid_refcounting) {
14768
0
      if (on_this) {
14769
0
        op1_info &= ~MAY_BE_RC1;
14770
0
      }
14771
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14772
0
    }
14773
0
  }
14774
14775
0
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14776
0
   && prop_info
14777
0
   && (opline->opcode != ZEND_FETCH_OBJ_W ||
14778
0
       !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14779
0
       !ZEND_TYPE_IS_SET(prop_info->type))
14780
0
   && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14781
0
    may_throw = 0;
14782
0
  }
14783
14784
0
  if (may_throw) {
14785
0
    if (Z_MODE(res_addr) == IS_REG) {
14786
0
      zend_jit_check_exception_undef_result(jit, opline);
14787
0
    } else {
14788
0
      zend_jit_check_exception(jit);
14789
0
    }
14790
0
  }
14791
14792
0
  return 1;
14793
0
}
14794
14795
static int zend_jit_fetch_obj_func_arg(zend_jit_ctx *jit, const zend_op *opline,
14796
    const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op,
14797
    uint32_t op1_info, zend_jit_addr op1_addr, zend_class_entry *ce,
14798
    bool ce_is_instanceof, bool on_this, zend_jit_addr res_addr)
14799
0
{
14800
0
  ir_ref rx, call_info, if_by_ref, end_by_ref;
14801
14802
  /* Both runtime paths must observe a consistent frame state.  The delayed
14803
   * call chain would otherwise only be flushed inside the by-ref branch (by
14804
   * zend_jit_set_ip() in zend_jit_handler()), leaving EX(call) stale on the
14805
   * by-val path and after the merge.  Flush it before branching. */
14806
0
  if (jit->delayed_call_level) {
14807
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
14808
0
      return 0;
14809
0
    }
14810
0
  }
14811
14812
  /* JIT: if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF) */
14813
0
  if (jit->reuse_ip) {
14814
0
    rx = jit_IP(jit);
14815
0
  } else {
14816
0
    rx = ir_LOAD_A(jit_EX(call));
14817
0
  }
14818
0
  call_info = ir_LOAD_U32(jit_CALL(rx, This.u1.type_info));
14819
0
  if_by_ref = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
14820
14821
  /* by-ref path: the FUNC_ARG handler re-checks the flag and dispatches
14822
   * into FETCH_OBJ_W */
14823
0
  ir_IF_TRUE_cold(if_by_ref);
14824
0
  if (!zend_jit_handler(jit, opline, zend_may_throw(opline, ssa_op, op_array, ssa))) {
14825
0
    return 0;
14826
0
  }
14827
0
  end_by_ref = ir_END();
14828
14829
  /* zend_jit_handler() stored IP = opline + 1 on the by-ref path only;
14830
   * that compile-time knowledge is invalid for the by-val path and after
14831
   * the merge. */
14832
0
  zend_jit_reset_last_valid_opline(jit);
14833
14834
  /* by-val path */
14835
0
  ir_IF_FALSE(if_by_ref);
14836
0
  if (!zend_jit_fetch_obj(jit, opline, op_array, ssa, ssa_op,
14837
0
      op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
14838
0
      res_addr, IS_UNKNOWN,
14839
0
      zend_may_throw(opline, ssa_op, op_array, ssa))) {
14840
0
    return 0;
14841
0
  }
14842
0
  ir_MERGE_WITH(end_by_ref);
14843
14844
0
  return 1;
14845
0
}
14846
14847
14848
static int zend_jit_assign_obj(zend_jit_ctx         *jit,
14849
                               const zend_op        *opline,
14850
                               const zend_op_array  *op_array,
14851
                               zend_ssa             *ssa,
14852
                               const zend_ssa_op    *ssa_op,
14853
                               uint32_t              op1_info,
14854
                               zend_jit_addr         op1_addr,
14855
                               uint32_t              val_info,
14856
                               zend_jit_addr         val_addr,
14857
                               zend_jit_addr         val_def_addr,
14858
                               zend_jit_addr         res_addr,
14859
                               bool                  op1_indirect,
14860
                               zend_class_entry     *ce,
14861
                               bool                  ce_is_instanceof,
14862
                               bool                  on_this,
14863
                               bool                  delayed_fetch_this,
14864
                               zend_class_entry     *trace_ce,
14865
                               uint8_t               prop_type,
14866
                               int                   may_throw)
14867
0
{
14868
0
  zval *member;
14869
0
  zend_string *name;
14870
0
  zend_property_info *prop_info;
14871
0
  zend_jit_addr prop_addr;
14872
0
  ir_ref obj_ref = IR_UNUSED;
14873
0
  ir_ref prop_ref = IR_UNUSED;
14874
0
  ir_ref delayed_end_input = IR_UNUSED;
14875
0
  ir_ref end_inputs = IR_UNUSED;
14876
0
  ir_ref slow_inputs = IR_UNUSED;
14877
0
  uint32_t res_info = RES_INFO();
14878
14879
0
  if (Z_MODE(val_addr) == IS_REG
14880
0
   && Z_LOAD(val_addr)
14881
0
   && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
14882
    /* Force load */
14883
0
    zend_jit_use_reg(jit, val_addr);
14884
0
  }
14885
14886
0
  if (val_addr != val_def_addr && val_def_addr) {
14887
0
    if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14888
0
      return 0;
14889
0
    }
14890
0
    if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14891
0
      val_addr = val_def_addr;
14892
0
    }
14893
0
  }
14894
14895
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
14896
0
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14897
14898
0
  member = RT_CONSTANT(opline, opline->op2);
14899
0
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14900
0
  name = Z_STR_P(member);
14901
0
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
14902
14903
0
  if (on_this) {
14904
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14905
0
    obj_ref = jit_Z_PTR(jit, this_addr);
14906
0
  } else {
14907
0
    if (opline->op1_type == IS_VAR
14908
0
     && (op1_info & MAY_BE_INDIRECT)
14909
0
     && Z_REG(op1_addr) == ZREG_FP) {
14910
0
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14911
0
    }
14912
0
    if (op1_info & MAY_BE_REF) {
14913
0
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14914
0
    }
14915
0
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14916
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14917
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14918
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14919
14920
0
        if (!exit_addr) {
14921
0
          return 0;
14922
0
        }
14923
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14924
0
      } else {
14925
0
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14926
0
        ir_IF_FALSE_cold(if_obj);
14927
14928
0
        jit_SET_EX_OPLINE(jit, opline);
14929
0
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
14930
0
          jit_ZVAL_ADDR(jit, op1_addr),
14931
0
          ir_CONST_ADDR(ZSTR_VAL(name)));
14932
14933
0
        if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
14934
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14935
0
        }
14936
14937
0
        ir_END_list(end_inputs);
14938
14939
0
        ir_IF_TRUE(if_obj);
14940
0
      }
14941
0
    }
14942
0
    obj_ref = jit_Z_PTR(jit, op1_addr);
14943
0
  }
14944
14945
0
  ZEND_ASSERT(obj_ref);
14946
0
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14947
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
14948
0
    if (prop_info) {
14949
0
      ce = trace_ce;
14950
0
      ce_is_instanceof = false;
14951
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14952
0
        if (on_this && JIT_G(current_frame)
14953
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14954
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14955
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14956
0
          if (on_this && JIT_G(current_frame)) {
14957
0
            JIT_G(current_frame)->ce = ce;
14958
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14959
0
          }
14960
0
        } else {
14961
0
          return 0;
14962
0
        }
14963
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
14964
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14965
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
14966
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14967
0
        }
14968
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
14969
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
14970
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
14971
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
14972
0
        }
14973
0
      }
14974
0
    }
14975
0
  }
14976
14977
0
  if (!prop_info) {
14978
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14979
0
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14980
0
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14981
14982
0
    ir_IF_FALSE_cold(if_same);
14983
0
    ir_END_list(slow_inputs);
14984
14985
0
    ir_IF_TRUE(if_same);
14986
0
    ir_ref offset_ref = ir_LOAD_A(
14987
0
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14988
14989
0
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14990
0
    ir_IF_TRUE_cold(if_dynamic);
14991
0
    ir_END_list(slow_inputs);
14992
14993
0
    ir_IF_FALSE(if_dynamic);
14994
0
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
14995
0
    ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
14996
0
    ir_IF_FALSE_cold(if_def);
14997
0
    ir_END_list(slow_inputs);
14998
14999
0
    ir_IF_TRUE(if_def);
15000
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15001
15002
0
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15003
0
      ir_ref arg3, arg4;
15004
0
      ir_ref prop_info_ref = ir_LOAD_A(
15005
0
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15006
0
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15007
0
      ir_IF_TRUE_cold(if_has_prop_info);
15008
15009
0
      if (Z_MODE(val_addr) == IS_REG) {
15010
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15011
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15012
0
          return 0;
15013
0
        }
15014
0
        arg3 = jit_ZVAL_ADDR(jit, real_addr);
15015
0
      } else {
15016
0
        arg3 = jit_ZVAL_ADDR(jit, val_addr);
15017
0
      }
15018
15019
0
      if (!RETURN_VALUE_USED(opline)) {
15020
0
        arg4 = IR_NULL;
15021
0
      } else if (Z_MODE(res_addr) == IS_REG) {
15022
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15023
0
        arg4 = jit_ZVAL_ADDR(jit, real_addr);
15024
0
      } else {
15025
0
        arg4 = jit_ZVAL_ADDR(jit, res_addr);
15026
0
      }
15027
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15028
0
      jit_SET_EX_OPLINE(jit, opline);
15029
0
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
15030
0
        prop_ref,
15031
0
        prop_info_ref,
15032
0
        arg3,
15033
0
        arg4);
15034
15035
0
      if ((opline+1)->op1_type == IS_CONST) {
15036
        // TODO: ???
15037
        // if (Z_TYPE_P(value) == orig_type) {
15038
        // CACHE_PTR_EX(cache_slot + 2, NULL);
15039
0
      }
15040
15041
0
      ir_END_list(end_inputs);
15042
0
      ir_IF_FALSE(if_has_prop_info);
15043
0
    }
15044
0
  } else {
15045
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15046
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15047
    /* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
15048
     * the fast path. Thus, the fast path is not useful. */
15049
0
    if (prop_info->flags & ZEND_ACC_READONLY) {
15050
0
      ZEND_ASSERT(slow_inputs == IR_UNUSED);
15051
0
      goto slow_path;
15052
0
    }
15053
15054
    // Undefined property with potential magic __get()/__set() or lazy object
15055
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_type != IS_UNDEF) {
15056
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15057
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15058
15059
0
      if (!exit_addr) {
15060
0
        return 0;
15061
0
      }
15062
0
      ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15063
0
    } else {
15064
0
      ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15065
0
      ir_IF_FALSE_cold(if_def);
15066
0
      ir_END_list(slow_inputs);
15067
0
      ir_IF_TRUE(if_def);
15068
0
    }
15069
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
15070
0
      ir_ref ref, arg3, arg4;
15071
15072
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15073
0
      jit_SET_EX_OPLINE(jit, opline);
15074
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15075
0
        ref = ir_CONST_ADDR(prop_info);
15076
0
      } else {
15077
0
        int prop_info_offset =
15078
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15079
15080
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15081
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15082
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15083
0
      }
15084
0
      if (Z_MODE(val_addr) == IS_REG) {
15085
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15086
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15087
0
          return 0;
15088
0
        }
15089
0
        arg3 = jit_ZVAL_ADDR(jit, real_addr);
15090
0
      } else {
15091
0
        arg3 = jit_ZVAL_ADDR(jit, val_addr);
15092
0
      }
15093
0
      if (!RETURN_VALUE_USED(opline)) {
15094
0
        arg4 = IR_NULL;
15095
0
      } else if (Z_MODE(res_addr) == IS_REG) {
15096
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15097
0
        arg4 = jit_ZVAL_ADDR(jit, real_addr);
15098
0
      } else {
15099
0
        arg4 = jit_ZVAL_ADDR(jit, res_addr);
15100
0
      }
15101
0
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
15102
0
        prop_ref,
15103
0
        ref,
15104
0
        arg3,
15105
0
        arg4);
15106
15107
0
      ir_END_list(end_inputs);
15108
0
    }
15109
0
  }
15110
15111
0
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15112
0
    if (Z_MODE(val_addr) != IS_REG
15113
0
     && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
15114
0
     && opline->result_type == IS_UNUSED) {
15115
0
      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, false)) {
15116
0
        return 0;
15117
0
      }
15118
0
    } else {
15119
0
      zend_jit_addr real_res_addr;
15120
15121
0
      if (res_addr && Z_MODE(res_addr) == IS_REG) {
15122
0
        real_res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15123
0
      } else {
15124
0
        real_res_addr = res_addr;
15125
0
      }
15126
0
      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, false)) {
15127
0
        return 0;
15128
0
      }
15129
0
    }
15130
0
    if (end_inputs || slow_inputs) {
15131
0
      if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
15132
0
       && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15133
        /* skip FREE_OP_DATA() */
15134
0
        delayed_end_input = ir_END();
15135
0
      } else {
15136
0
        ir_END_list(end_inputs);
15137
0
      }
15138
0
    }
15139
0
  }
15140
15141
0
  if (slow_inputs) {
15142
0
    ir_ref arg3, arg5;
15143
15144
0
    ir_MERGE_list(slow_inputs);
15145
15146
0
slow_path:
15147
0
    jit_SET_EX_OPLINE(jit, opline);
15148
15149
0
    if (Z_MODE(val_addr) == IS_REG) {
15150
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15151
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15152
0
        return 0;
15153
0
      }
15154
0
      arg3 = jit_ZVAL_ADDR(jit, real_addr);
15155
0
    } else {
15156
0
      arg3 = jit_ZVAL_ADDR(jit, val_addr);
15157
0
    }
15158
0
    if (!RETURN_VALUE_USED(opline)) {
15159
0
      arg5 = IR_NULL;
15160
0
    } else if (Z_MODE(res_addr) == IS_REG) {
15161
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15162
0
      arg5 = jit_ZVAL_ADDR(jit, real_addr);
15163
0
    } else {
15164
0
      arg5 = jit_ZVAL_ADDR(jit, res_addr);
15165
0
    }
15166
15167
    // JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
15168
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15169
0
    ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
15170
0
      obj_ref,
15171
0
      ir_CONST_ADDR(name),
15172
0
      arg3,
15173
0
      ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15174
0
      arg5);
15175
15176
0
    ir_END_list(end_inputs);
15177
0
  }
15178
15179
0
  if (end_inputs) {
15180
0
    ir_MERGE_list(end_inputs);
15181
15182
0
    if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15183
0
      val_info |= MAY_BE_RC1|MAY_BE_RCN;
15184
0
    }
15185
0
    jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15186
15187
0
    if (delayed_end_input) {
15188
0
      ir_MERGE_WITH(delayed_end_input);
15189
0
    }
15190
0
  }
15191
15192
0
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15193
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15194
0
  }
15195
15196
0
  if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
15197
0
    zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15198
0
    if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
15199
0
      return 0;
15200
0
    }
15201
0
  }
15202
15203
0
  if (may_throw) {
15204
0
    zend_jit_check_exception(jit);
15205
0
  }
15206
15207
0
  return 1;
15208
0
}
15209
15210
static int zend_jit_assign_obj_op(zend_jit_ctx         *jit,
15211
                                  const zend_op        *opline,
15212
                                  const zend_op_array  *op_array,
15213
                                  zend_ssa             *ssa,
15214
                                  const zend_ssa_op    *ssa_op,
15215
                                  uint32_t              op1_info,
15216
                                  zend_jit_addr         op1_addr,
15217
                                  uint32_t              val_info,
15218
                                  zend_jit_addr         val_addr,
15219
                                  zend_ssa_range       *val_range,
15220
                                  bool                  op1_indirect,
15221
                                  zend_class_entry     *ce,
15222
                                  bool                  ce_is_instanceof,
15223
                                  bool                  on_this,
15224
                                  bool                  delayed_fetch_this,
15225
                                  zend_class_entry     *trace_ce,
15226
                                  uint8_t               prop_type)
15227
0
{
15228
0
  zval *member;
15229
0
  zend_string *name;
15230
0
  zend_property_info *prop_info;
15231
0
  zend_jit_addr prop_addr;
15232
0
  bool use_prop_guard = false;
15233
0
  bool may_throw = false;
15234
0
  binary_op_type binary_op = get_binary_op(opline->extended_value);
15235
0
  ir_ref obj_ref = IR_UNUSED;
15236
0
  ir_ref prop_ref = IR_UNUSED;
15237
0
  ir_ref end_inputs = IR_UNUSED;
15238
0
  ir_ref slow_inputs = IR_UNUSED;
15239
15240
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
15241
0
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15242
0
  ZEND_ASSERT(opline->result_type == IS_UNUSED);
15243
15244
0
  member = RT_CONSTANT(opline, opline->op2);
15245
0
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15246
0
  name = Z_STR_P(member);
15247
0
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15248
15249
0
  if (on_this) {
15250
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15251
0
    obj_ref = jit_Z_PTR(jit, this_addr);
15252
0
  } else {
15253
0
    if (opline->op1_type == IS_VAR
15254
0
     && (op1_info & MAY_BE_INDIRECT)
15255
0
     && Z_REG(op1_addr) == ZREG_FP) {
15256
0
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15257
0
    }
15258
0
    if (op1_info & MAY_BE_REF) {
15259
0
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15260
0
    }
15261
0
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15262
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15263
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15264
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15265
15266
0
        if (!exit_addr) {
15267
0
          return 0;
15268
0
        }
15269
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15270
0
      } else {
15271
0
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15272
0
        ir_IF_FALSE_cold(if_obj);
15273
15274
0
        jit_SET_EX_OPLINE(jit, opline);
15275
0
        ir_CALL_2(IR_VOID,
15276
0
          (op1_info & MAY_BE_UNDEF) ?
15277
0
            ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
15278
0
            ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15279
0
          jit_ZVAL_ADDR(jit, op1_addr),
15280
0
          ir_CONST_ADDR(ZSTR_VAL(name)));
15281
15282
0
        may_throw = true;
15283
15284
0
        ir_END_list(end_inputs);
15285
0
        ir_IF_TRUE(if_obj);
15286
0
      }
15287
0
    }
15288
0
    obj_ref = jit_Z_PTR(jit, op1_addr);
15289
0
  }
15290
15291
0
  ZEND_ASSERT(obj_ref);
15292
0
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15293
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15294
0
    if (prop_info) {
15295
0
      ce = trace_ce;
15296
0
      ce_is_instanceof = false;
15297
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15298
0
        if (on_this && JIT_G(current_frame)
15299
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15300
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15301
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15302
0
          if (on_this && JIT_G(current_frame)) {
15303
0
            JIT_G(current_frame)->ce = ce;
15304
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15305
0
          }
15306
0
        } else {
15307
0
          return 0;
15308
0
        }
15309
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
15310
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15311
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
15312
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15313
0
        }
15314
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
15315
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15316
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
15317
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15318
0
        }
15319
0
      }
15320
0
    }
15321
0
  }
15322
15323
0
  use_prop_guard = (prop_type != IS_UNKNOWN
15324
0
    && prop_type != IS_UNDEF
15325
0
    && prop_type != IS_REFERENCE
15326
0
    && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15327
15328
0
  if (Z_MODE(val_addr) == IS_REG
15329
0
   && Z_LOAD(val_addr)
15330
0
   && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
15331
    /* Force load */
15332
0
    zend_jit_use_reg(jit, val_addr);
15333
0
  }
15334
15335
0
  if (!prop_info) {
15336
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15337
0
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15338
0
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15339
15340
0
    ir_IF_FALSE_cold(if_same);
15341
0
    ir_END_list(slow_inputs);
15342
15343
0
    ir_IF_TRUE(if_same);
15344
0
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15345
0
      ir_ref prop_info_ref = ir_LOAD_A(
15346
0
        ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15347
0
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15348
0
      ir_IF_TRUE_cold(if_has_prop_info);
15349
0
      ir_END_list(slow_inputs);
15350
15351
0
      ir_IF_FALSE(if_has_prop_info);
15352
0
    }
15353
0
    ir_ref offset_ref = ir_LOAD_A(
15354
0
      ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15355
15356
0
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15357
0
    ir_IF_TRUE_cold(if_dynamic);
15358
0
    ir_END_list(slow_inputs);
15359
15360
0
    ir_IF_FALSE(if_dynamic);
15361
15362
0
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
15363
0
    if (!use_prop_guard) {
15364
0
      ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15365
0
      ir_IF_FALSE_cold(if_def);
15366
0
      ir_END_list(slow_inputs);
15367
15368
0
      ir_IF_TRUE(if_def);
15369
0
    }
15370
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15371
0
  } else {
15372
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15373
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15374
15375
0
    if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15376
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15377
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15378
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15379
15380
0
        if (!exit_addr) {
15381
0
          return 0;
15382
0
        }
15383
0
        ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15384
0
      } else {
15385
0
        ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15386
0
        ir_IF_FALSE_cold(if_def);
15387
0
        ir_END_list(slow_inputs);
15388
0
        ir_IF_TRUE(if_def);
15389
0
      }
15390
0
    }
15391
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
15392
0
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15393
15394
0
      may_throw = true;
15395
15396
0
      jit_SET_EX_OPLINE(jit, opline);
15397
15398
0
      if (Z_MODE(val_addr) == IS_REG) {
15399
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15400
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15401
0
          return 0;
15402
0
        }
15403
0
        arg2 = jit_ZVAL_ADDR(jit, real_addr);
15404
0
      } else {
15405
0
        arg2 = jit_ZVAL_ADDR(jit, val_addr);
15406
0
      }
15407
15408
0
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15409
0
      ir_IF_FALSE(if_ref);
15410
0
      noref_path = ir_END();
15411
0
      ir_IF_TRUE(if_ref);
15412
15413
0
      reference = jit_Z_PTR(jit, prop_addr);
15414
0
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15415
0
      if_typed = jit_if_TYPED_REF(jit, reference);
15416
0
      ir_IF_FALSE(if_typed);
15417
0
      ref_path = ir_END();
15418
0
      ir_IF_TRUE_cold(if_typed);
15419
15420
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15421
0
        reference,
15422
0
        arg2,
15423
0
        ir_CONST_FC_FUNC(binary_op));
15424
15425
0
      ir_END_list(end_inputs);
15426
15427
0
      ir_MERGE_2(noref_path, ref_path);
15428
0
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15429
0
      prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15430
15431
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15432
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15433
0
        ref = ir_CONST_ADDR(prop_info);
15434
0
      } else {
15435
0
        int prop_info_offset =
15436
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15437
15438
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15439
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15440
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15441
0
      }
15442
15443
0
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
15444
0
        prop_ref,
15445
0
        ref,
15446
0
        arg2,
15447
0
        ir_CONST_FC_FUNC(binary_op));
15448
15449
0
      ir_END_list(end_inputs);
15450
0
    }
15451
0
  }
15452
15453
0
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15454
0
    zend_jit_addr var_addr = prop_addr;
15455
0
    uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15456
0
    uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15457
15458
0
    if (use_prop_guard) {
15459
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15460
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15461
0
      if (!exit_addr) {
15462
0
        return 0;
15463
0
      }
15464
15465
0
      jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15466
0
      var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15467
0
    }
15468
15469
0
    if (var_info & MAY_BE_REF) {
15470
0
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15471
15472
0
      may_throw = true;
15473
15474
0
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15475
0
      ir_IF_FALSE(if_ref);
15476
0
      noref_path = ir_END();
15477
0
      ir_IF_TRUE(if_ref);
15478
15479
0
      reference = jit_Z_PTR(jit, var_addr);
15480
0
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15481
0
      if_typed = jit_if_TYPED_REF(jit, reference);
15482
0
      ir_IF_FALSE(if_typed);
15483
0
      ref_path = ir_END();
15484
0
      ir_IF_TRUE_cold(if_typed);
15485
15486
0
      jit_SET_EX_OPLINE(jit, opline);
15487
15488
0
      if (Z_MODE(val_addr) == IS_REG) {
15489
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15490
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15491
0
          return 0;
15492
0
        }
15493
0
        arg2 = jit_ZVAL_ADDR(jit, real_addr);
15494
0
      } else {
15495
0
        arg2 = jit_ZVAL_ADDR(jit, val_addr);
15496
0
      }
15497
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15498
0
        reference,
15499
0
        arg2,
15500
0
        ir_CONST_FC_FUNC(binary_op));
15501
15502
0
      ir_END_list(end_inputs);
15503
15504
0
      ir_MERGE_2(noref_path, ref_path);
15505
0
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15506
0
      var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15507
15508
0
      var_info &= ~MAY_BE_REF;
15509
0
    }
15510
15511
0
    uint8_t val_op_type = (opline+1)->op1_type;
15512
0
    if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15513
      /* prevent FREE_OP in the helpers */
15514
0
      val_op_type = IS_CV;
15515
0
    }
15516
15517
0
    switch (opline->extended_value) {
15518
0
      case ZEND_ADD:
15519
0
      case ZEND_SUB:
15520
0
      case ZEND_MUL:
15521
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15522
0
            (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15523
0
          if (opline->extended_value != ZEND_ADD ||
15524
0
              (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15525
0
              (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15526
0
            may_throw = true;
15527
0
          }
15528
0
        }
15529
0
        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,
15530
0
            1 /* may overflow */, 0)) {
15531
0
          return 0;
15532
0
        }
15533
0
        break;
15534
0
      case ZEND_BW_OR:
15535
0
      case ZEND_BW_AND:
15536
0
      case ZEND_BW_XOR:
15537
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15538
0
            (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15539
0
          if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15540
0
              (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15541
0
            may_throw = true;
15542
0
          }
15543
0
        }
15544
0
        goto long_math;
15545
0
      case ZEND_SL:
15546
0
      case ZEND_SR:
15547
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15548
0
            (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15549
0
          may_throw = true;
15550
0
        }
15551
0
        if (val_op_type != IS_CONST ||
15552
0
            Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15553
0
            Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15554
0
          may_throw = true;
15555
0
        }
15556
0
        goto long_math;
15557
0
      case ZEND_MOD:
15558
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15559
0
            (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15560
0
          may_throw = true;
15561
0
        }
15562
0
        if (val_op_type != IS_CONST ||
15563
0
            Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15564
0
            Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15565
0
          may_throw = true;
15566
0
        }
15567
0
long_math:
15568
0
        if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15569
0
            IS_CV, opline->op1, var_addr, var_info, NULL,
15570
0
            val_op_type, (opline+1)->op1, val_addr, val_info,
15571
0
            val_range,
15572
0
            0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15573
0
          return 0;
15574
0
        }
15575
0
        break;
15576
0
      case ZEND_CONCAT:
15577
0
        may_throw = true;
15578
0
        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,
15579
0
            0)) {
15580
0
          return 0;
15581
0
        }
15582
0
        break;
15583
0
      default:
15584
0
        ZEND_UNREACHABLE();
15585
0
    }
15586
0
    if (end_inputs || slow_inputs) {
15587
0
      ir_END_list(end_inputs);
15588
0
    }
15589
0
  }
15590
15591
0
  if (slow_inputs) {
15592
0
    ir_ref arg3;
15593
15594
0
    ir_MERGE_list(slow_inputs);
15595
15596
0
    may_throw = true;
15597
15598
0
    if (Z_MODE(val_addr) == IS_REG) {
15599
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15600
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15601
0
        return 0;
15602
0
      }
15603
0
      arg3 = jit_ZVAL_ADDR(jit, real_addr);
15604
0
    } else {
15605
0
      arg3 = jit_ZVAL_ADDR(jit, val_addr);
15606
0
    }
15607
0
    jit_SET_EX_OPLINE(jit, opline);
15608
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15609
0
    ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15610
0
      obj_ref,
15611
0
      ir_CONST_ADDR(name),
15612
0
      arg3,
15613
0
      ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15614
0
      ir_CONST_FC_FUNC(binary_op));
15615
15616
0
    ir_END_list(end_inputs);
15617
0
  }
15618
15619
0
  if (end_inputs) {
15620
0
    ir_MERGE_list(end_inputs);
15621
0
  }
15622
15623
0
  if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15624
0
    val_info |= MAY_BE_RC1|MAY_BE_RCN;
15625
0
  }
15626
15627
  // JIT: FREE_OP_DATA();
15628
0
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15629
15630
0
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15631
0
    if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15632
0
      may_throw = true;
15633
0
    }
15634
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15635
0
  }
15636
15637
0
  if (may_throw) {
15638
0
    zend_jit_check_exception(jit);
15639
0
  }
15640
15641
0
  return 1;
15642
0
}
15643
15644
static int zend_jit_incdec_obj(zend_jit_ctx         *jit,
15645
                               const zend_op        *opline,
15646
                               const zend_op_array  *op_array,
15647
                               zend_ssa             *ssa,
15648
                               const zend_ssa_op    *ssa_op,
15649
                               uint32_t              op1_info,
15650
                               zend_jit_addr         op1_addr,
15651
                               bool                  op1_indirect,
15652
                               zend_class_entry     *ce,
15653
                               bool                  ce_is_instanceof,
15654
                               bool                  on_this,
15655
                               bool                  delayed_fetch_this,
15656
                               zend_class_entry     *trace_ce,
15657
                               uint8_t               prop_type)
15658
0
{
15659
0
  zval *member;
15660
0
  zend_string *name;
15661
0
  zend_property_info *prop_info;
15662
0
  zend_jit_addr res_addr = 0;
15663
0
  zend_jit_addr prop_addr;
15664
0
  bool use_prop_guard = false;
15665
0
  bool may_throw = false;
15666
0
  uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15667
0
  ir_ref obj_ref = IR_UNUSED;
15668
0
  ir_ref prop_ref = IR_UNUSED;
15669
0
  ir_ref end_inputs = IR_UNUSED;
15670
0
  ir_ref slow_inputs = IR_UNUSED;
15671
15672
0
  ZEND_ASSERT(opline->op2_type == IS_CONST);
15673
0
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15674
15675
0
  if (opline->result_type != IS_UNUSED) {
15676
0
    res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15677
0
  }
15678
15679
0
  member = RT_CONSTANT(opline, opline->op2);
15680
0
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15681
0
  name = Z_STR_P(member);
15682
0
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15683
15684
0
  if (on_this) {
15685
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15686
0
    obj_ref = jit_Z_PTR(jit, this_addr);
15687
0
  } else {
15688
0
    if (opline->op1_type == IS_VAR
15689
0
     && (op1_info & MAY_BE_INDIRECT)
15690
0
     && Z_REG(op1_addr) == ZREG_FP) {
15691
0
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15692
0
    }
15693
0
    if (op1_info & MAY_BE_REF) {
15694
0
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15695
0
    }
15696
0
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15697
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15698
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15699
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15700
15701
0
        if (!exit_addr) {
15702
0
          return 0;
15703
0
        }
15704
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15705
0
      } else {
15706
0
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15707
0
        ir_IF_FALSE_cold(if_obj);
15708
15709
0
        jit_SET_EX_OPLINE(jit, opline);
15710
0
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15711
0
          jit_ZVAL_ADDR(jit, op1_addr),
15712
0
          ir_CONST_ADDR(ZSTR_VAL(name)));
15713
15714
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15715
0
        ir_IF_TRUE(if_obj);
15716
0
      }
15717
0
    }
15718
0
    obj_ref = jit_Z_PTR(jit, op1_addr);
15719
0
  }
15720
15721
0
  ZEND_ASSERT(obj_ref);
15722
0
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15723
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15724
0
    if (prop_info) {
15725
0
      ce = trace_ce;
15726
0
      ce_is_instanceof = false;
15727
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15728
0
        if (on_this && JIT_G(current_frame)
15729
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15730
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15731
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15732
0
          if (on_this && JIT_G(current_frame)) {
15733
0
            JIT_G(current_frame)->ce = ce;
15734
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15735
0
          }
15736
0
        } else {
15737
0
          return 0;
15738
0
        }
15739
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
15740
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15741
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
15742
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15743
0
        }
15744
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
15745
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15746
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
15747
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15748
0
        }
15749
0
      }
15750
0
    }
15751
0
  }
15752
15753
0
  use_prop_guard = (prop_type != IS_UNKNOWN
15754
0
    && prop_type != IS_UNDEF
15755
0
    && prop_type != IS_REFERENCE
15756
0
    && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15757
15758
0
  if (!prop_info) {
15759
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15760
0
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15761
0
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15762
15763
0
    ir_IF_FALSE_cold(if_same);
15764
0
    ir_END_list(slow_inputs);
15765
15766
0
    ir_IF_TRUE(if_same);
15767
0
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15768
0
      ir_ref prop_info_ref = ir_LOAD_A(
15769
0
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15770
0
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15771
0
      ir_IF_TRUE_cold(if_has_prop_info);
15772
0
      ir_END_list(slow_inputs);
15773
15774
0
      ir_IF_FALSE(if_has_prop_info);
15775
0
    }
15776
0
    ir_ref offset_ref = ir_LOAD_A(
15777
0
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15778
15779
0
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15780
0
    ir_IF_TRUE_cold(if_dynamic);
15781
0
    ir_END_list(slow_inputs);
15782
15783
0
    ir_IF_FALSE(if_dynamic);
15784
15785
0
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
15786
0
    if (!use_prop_guard) {
15787
0
      ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15788
0
      ir_IF_FALSE_cold(if_def);
15789
0
      ir_END_list(slow_inputs);
15790
15791
0
      ir_IF_TRUE(if_def);
15792
0
    }
15793
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15794
0
  } else {
15795
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15796
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15797
15798
0
    if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15799
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15800
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15801
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15802
15803
0
        if (!exit_addr) {
15804
0
          return 0;
15805
0
        }
15806
0
        ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15807
0
      } else {
15808
0
        ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15809
0
        ir_IF_FALSE_cold(if_def);
15810
0
        ir_END_list(slow_inputs);
15811
0
        ir_IF_TRUE(if_def);
15812
0
      }
15813
0
    }
15814
15815
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
15816
0
      const void *func;
15817
0
      ir_ref ref;
15818
15819
0
      may_throw = true;
15820
0
      jit_SET_EX_OPLINE(jit, opline);
15821
15822
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15823
0
        ref = ir_CONST_ADDR(prop_info);
15824
0
      } else {
15825
0
        int prop_info_offset =
15826
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15827
15828
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15829
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15830
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15831
0
      }
15832
15833
0
      if (opline->result_type == IS_UNUSED) {
15834
0
        switch (opline->opcode) {
15835
0
          case ZEND_PRE_INC_OBJ:
15836
0
          case ZEND_POST_INC_OBJ:
15837
0
            func = zend_jit_inc_typed_prop;
15838
0
            break;
15839
0
          case ZEND_PRE_DEC_OBJ:
15840
0
          case ZEND_POST_DEC_OBJ:
15841
0
            func = zend_jit_dec_typed_prop;
15842
0
            break;
15843
0
          default:
15844
0
            ZEND_UNREACHABLE();
15845
0
        }
15846
15847
0
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
15848
0
      } else {
15849
0
        switch (opline->opcode) {
15850
0
          case ZEND_PRE_INC_OBJ:
15851
0
            func = zend_jit_pre_inc_typed_prop;
15852
0
            break;
15853
0
          case ZEND_PRE_DEC_OBJ:
15854
0
            func = zend_jit_pre_dec_typed_prop;
15855
0
            break;
15856
0
          case ZEND_POST_INC_OBJ:
15857
0
            func = zend_jit_post_inc_typed_prop;
15858
0
            break;
15859
0
          case ZEND_POST_DEC_OBJ:
15860
0
            func = zend_jit_post_dec_typed_prop;
15861
0
            break;
15862
0
          default:
15863
0
            ZEND_UNREACHABLE();
15864
0
        }
15865
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
15866
0
          prop_ref,
15867
0
          ref,
15868
0
          jit_ZVAL_ADDR(jit, res_addr));
15869
0
      }
15870
0
      ir_END_list(end_inputs);
15871
0
    }
15872
0
  }
15873
15874
0
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15875
0
    uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15876
0
    zend_jit_addr var_addr = prop_addr;
15877
0
    ir_ref if_long = IR_UNUSED;
15878
0
    ir_ref if_overflow = IR_UNUSED;
15879
15880
0
    if (use_prop_guard) {
15881
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15882
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15883
0
      if (!exit_addr) {
15884
0
        return 0;
15885
0
      }
15886
15887
0
      jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15888
0
      var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15889
0
    }
15890
15891
0
    if (var_info & MAY_BE_REF) {
15892
0
      const void *func;
15893
0
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
15894
15895
0
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15896
0
      ir_IF_FALSE(if_ref);
15897
0
      noref_path = ir_END();
15898
0
      ir_IF_TRUE(if_ref);
15899
15900
0
      reference = jit_Z_PTR(jit, var_addr);
15901
0
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15902
0
      if_typed = jit_if_TYPED_REF(jit, reference);
15903
0
      ir_IF_FALSE(if_typed);
15904
0
      ref_path = ir_END();
15905
0
      ir_IF_TRUE_cold(if_typed);
15906
15907
0
      switch (opline->opcode) {
15908
0
        case ZEND_PRE_INC_OBJ:
15909
0
          func = zend_jit_pre_inc_typed_ref;
15910
0
          break;
15911
0
        case ZEND_PRE_DEC_OBJ:
15912
0
          func = zend_jit_pre_dec_typed_ref;
15913
0
          break;
15914
0
        case ZEND_POST_INC_OBJ:
15915
0
          func = zend_jit_post_inc_typed_ref;
15916
0
          break;
15917
0
        case ZEND_POST_DEC_OBJ:
15918
0
          func = zend_jit_post_dec_typed_ref;
15919
0
          break;
15920
0
        default:
15921
0
          ZEND_UNREACHABLE();
15922
0
      }
15923
15924
0
      may_throw = true;
15925
0
      jit_SET_EX_OPLINE(jit, opline);
15926
0
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
15927
0
        reference,
15928
0
        (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
15929
15930
0
      ir_END_list(end_inputs);
15931
15932
0
      ir_MERGE_2(noref_path, ref_path);
15933
0
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15934
0
      var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15935
15936
0
      var_info &= ~MAY_BE_REF;
15937
0
    }
15938
15939
0
    if (var_info & MAY_BE_LONG) {
15940
0
      ir_ref addr, ref;
15941
15942
0
      if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15943
0
        if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
15944
0
        ir_IF_TRUE(if_long);
15945
0
      }
15946
15947
0
      addr = jit_ZVAL_ADDR(jit, var_addr);
15948
0
      ref = ir_LOAD_L(addr);
15949
0
      if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15950
0
        if (opline->result_type != IS_UNUSED) {
15951
0
          jit_set_Z_LVAL(jit, res_addr, ref);
15952
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15953
0
        }
15954
0
      }
15955
0
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15956
0
        ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
15957
0
      } else {
15958
0
        ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
15959
0
      }
15960
15961
0
      ir_STORE(addr, ref);
15962
0
      if_overflow = ir_IF(ir_OVERFLOW(ref));
15963
0
      ir_IF_FALSE(if_overflow);
15964
15965
0
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
15966
0
        if (opline->result_type != IS_UNUSED) {
15967
0
          jit_set_Z_LVAL(jit, res_addr, ref);
15968
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
15969
0
        }
15970
0
      }
15971
0
      ir_END_list(end_inputs);
15972
0
    }
15973
15974
0
    if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
15975
0
      if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15976
0
        may_throw = true;
15977
0
      }
15978
0
      if (if_long) {
15979
0
        ir_IF_FALSE_cold(if_long);
15980
0
      }
15981
0
      if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
15982
0
        jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, true);
15983
0
      }
15984
0
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
15985
0
        if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
15986
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
15987
0
            jit_ZVAL_ADDR(jit, var_addr),
15988
0
            jit_ZVAL_ADDR(jit, res_addr));
15989
0
        } else {
15990
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
15991
0
            jit_ZVAL_ADDR(jit, var_addr));
15992
0
        }
15993
0
      } else {
15994
0
        if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
15995
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
15996
0
            jit_ZVAL_ADDR(jit, var_addr),
15997
0
            jit_ZVAL_ADDR(jit, res_addr));
15998
0
        } else {
15999
0
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
16000
0
            jit_ZVAL_ADDR(jit, var_addr));
16001
0
        }
16002
0
      }
16003
16004
0
      ir_END_list(end_inputs);
16005
0
    }
16006
0
    if (var_info & MAY_BE_LONG) {
16007
0
      ir_IF_TRUE_cold(if_overflow);
16008
0
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
16009
#if SIZEOF_ZEND_LONG == 4
16010
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
16011
        jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
16012
#else
16013
0
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
16014
0
#endif
16015
0
        jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
16016
0
        if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
16017
#if SIZEOF_ZEND_LONG == 4
16018
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
16019
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
16020
#else
16021
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
16022
0
#endif
16023
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
16024
0
        }
16025
0
      } else {
16026
#if SIZEOF_ZEND_LONG == 4
16027
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
16028
        jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
16029
#else
16030
0
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
16031
0
#endif
16032
0
        jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
16033
0
        if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
16034
#if SIZEOF_ZEND_LONG == 4
16035
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
16036
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
16037
#else
16038
0
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
16039
0
#endif
16040
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
16041
0
        }
16042
0
      }
16043
0
      if (opline->result_type != IS_UNUSED
16044
0
       && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
16045
0
       && prop_info
16046
0
       && !ZEND_TYPE_IS_SET(prop_info->type)
16047
0
       && (res_info & MAY_BE_GUARD)
16048
0
       && (res_info & MAY_BE_LONG)) {
16049
0
        zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16050
0
        uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
16051
0
        int32_t exit_point;
16052
0
        const void *exit_addr;
16053
16054
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
16055
0
        exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16056
0
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16057
0
        if (!exit_addr) {
16058
0
          return 0;
16059
0
        }
16060
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
16061
0
        ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
16062
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16063
0
      } else {
16064
0
        ir_END_list(end_inputs);
16065
0
      }
16066
0
    }
16067
0
  }
16068
16069
0
  if (slow_inputs) {
16070
0
    const void *func;
16071
16072
0
    ir_MERGE_list(slow_inputs);
16073
16074
    // JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
16075
0
    switch (opline->opcode) {
16076
0
      case ZEND_PRE_INC_OBJ:
16077
0
        func = zend_jit_pre_inc_obj_helper;
16078
0
        break;
16079
0
      case ZEND_PRE_DEC_OBJ:
16080
0
        func = zend_jit_pre_dec_obj_helper;
16081
0
        break;
16082
0
      case ZEND_POST_INC_OBJ:
16083
0
        func = zend_jit_post_inc_obj_helper;
16084
0
        break;
16085
0
      case ZEND_POST_DEC_OBJ:
16086
0
        func = zend_jit_post_dec_obj_helper;
16087
0
        break;
16088
0
      default:
16089
0
        ZEND_UNREACHABLE();
16090
0
    }
16091
16092
0
    may_throw = true;
16093
0
    jit_SET_EX_OPLINE(jit, opline);
16094
0
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
16095
0
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
16096
0
      obj_ref,
16097
0
      ir_CONST_ADDR(name),
16098
0
      ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
16099
0
      (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
16100
16101
0
    ir_END_list(end_inputs);
16102
0
  }
16103
16104
0
  if (end_inputs) {
16105
0
    ir_MERGE_list(end_inputs);
16106
0
  }
16107
16108
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
16109
0
    if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
16110
0
      may_throw = true;
16111
0
    }
16112
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
16113
0
  }
16114
16115
0
  if (may_throw) {
16116
0
    zend_jit_check_exception(jit);
16117
0
  }
16118
16119
0
  return 1;
16120
0
}
16121
16122
static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
16123
0
{
16124
0
  zend_jit_addr res_addr = RES_ADDR();
16125
0
  uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
16126
0
  uint32_t flags;
16127
0
  ir_ref ref, ref2, if_cached, fast_path, cold_path, prop_info_ref, if_typed, if_def;
16128
0
  int fetch_type;
16129
0
  zend_property_info *known_prop_info = NULL;
16130
0
  zend_class_entry *ce;
16131
16132
0
  ce = zend_get_known_class(op_array, opline, opline->op2_type, opline->op2);
16133
0
  if (ce && (opline->op2_type == IS_CONST || !(ce->ce_flags & ZEND_ACC_TRAIT))) {
16134
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
16135
0
    zend_string *prop_name;
16136
16137
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
16138
0
    prop_name = Z_STR_P(zv);
16139
0
    zv = zend_hash_find(&ce->properties_info, prop_name);
16140
0
    if (zv) {
16141
0
      zend_property_info *prop_info = Z_PTR_P(zv);
16142
16143
0
      if (prop_info->flags & ZEND_ACC_STATIC) {
16144
0
        if (prop_info->ce == op_array->scope
16145
0
         || (prop_info->flags & ZEND_ACC_PUBLIC)
16146
0
         || ((prop_info->flags & ZEND_ACC_PROTECTED)
16147
0
          && op_array->scope
16148
0
          && instanceof_function_slow(op_array->scope, prop_info->ce))) {
16149
0
          known_prop_info = prop_info;
16150
0
        }
16151
0
      }
16152
0
    }
16153
0
  }
16154
16155
0
  switch (opline->opcode) {
16156
0
    case ZEND_FETCH_STATIC_PROP_R:
16157
0
    case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
16158
0
      fetch_type = BP_VAR_R;
16159
0
      break;
16160
0
    case ZEND_FETCH_STATIC_PROP_IS:
16161
0
      fetch_type = BP_VAR_IS;
16162
0
      break;
16163
0
    case ZEND_FETCH_STATIC_PROP_W:
16164
0
      fetch_type = BP_VAR_W;
16165
0
      break;
16166
0
    case ZEND_FETCH_STATIC_PROP_RW:
16167
0
      fetch_type = BP_VAR_RW;
16168
0
      break;
16169
0
    case ZEND_FETCH_STATIC_PROP_UNSET:
16170
0
      fetch_type = BP_VAR_UNSET;
16171
0
      break;
16172
0
    default: ZEND_UNREACHABLE();
16173
0
  }
16174
16175
  // JIT: result = CACHED_PTR(cache_slot + sizeof(void *));
16176
0
  ref = ir_LOAD_A(
16177
0
    ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*)));
16178
16179
  // JIT: if (result)
16180
0
  if_cached = ir_IF(ref);
16181
0
  ir_IF_TRUE(if_cached);
16182
16183
0
  if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) {
16184
0
    if (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type)) {
16185
0
      ir_ref merge = IR_UNUSED;
16186
16187
      // JIT: if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
16188
0
      if_typed = IR_UNUSED;
16189
0
      if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
16190
0
      ir_IF_FALSE_cold(if_def);
16191
0
      if (!known_prop_info) {
16192
        // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
16193
0
        prop_info_ref = ir_LOAD_L(
16194
0
          ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16195
0
        if_typed = ir_IF(ir_AND_U32(
16196
0
          ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16197
0
          ir_CONST_U32(_ZEND_TYPE_MASK)));
16198
0
        ir_IF_FALSE(if_typed);
16199
0
        ir_END_list(merge);
16200
0
        ir_IF_TRUE(if_typed);
16201
0
      }
16202
      // JIT: zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
16203
      //      ZSTR_VAL(property_info->ce->name),
16204
      //      zend_get_unmangled_property_name(property_info->name));
16205
0
      jit_SET_EX_OPLINE(jit, opline);
16206
0
      ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_uninit_static_prop));
16207
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
16208
16209
0
      ir_IF_TRUE(if_def);
16210
0
      if (!known_prop_info) {
16211
0
        ir_END_list(merge);
16212
0
        ir_MERGE_list(merge);
16213
0
      }
16214
0
    }
16215
0
  } else if (fetch_type == BP_VAR_W) {
16216
0
    flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
16217
0
    if (flags && (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type))) {
16218
0
        ir_ref merge = IR_UNUSED;
16219
16220
0
      if (!known_prop_info) {
16221
        // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
16222
0
        prop_info_ref = ir_LOAD_L(
16223
0
          ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16224
0
        if_typed = ir_IF(ir_AND_U32(
16225
0
          ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16226
0
          ir_CONST_U32(_ZEND_TYPE_MASK)));
16227
0
        ir_IF_FALSE(if_typed);
16228
0
        ir_END_list(merge);
16229
0
        ir_IF_TRUE(if_typed);
16230
0
      } else {
16231
0
        prop_info_ref = ir_CONST_ADDR(known_prop_info);
16232
0
      }
16233
16234
      // JIT: zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
16235
0
      ir_ref if_ok = ir_IF(ir_CALL_5(IR_BOOL, ir_CONST_FUNC(zend_handle_fetch_obj_flags),
16236
0
        IR_NULL, ref, IR_NULL, prop_info_ref, ir_CONST_U32(flags)));
16237
0
      ir_IF_FALSE_cold(if_ok);
16238
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
16239
0
      ir_IF_TRUE(if_ok);
16240
0
      if (!known_prop_info) {
16241
0
        ir_END_list(merge);
16242
0
        ir_MERGE_list(merge);
16243
0
      }
16244
0
    }
16245
0
  }
16246
16247
0
  fast_path = ir_END();
16248
16249
0
  ir_IF_FALSE_cold(if_cached);
16250
0
  jit_SET_EX_OPLINE(jit, opline);
16251
0
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_fetch_static_property), jit_FP(jit), ir_CONST_I32(fetch_type));
16252
0
  zend_jit_check_exception_undef_result(jit, opline);
16253
0
  cold_path = ir_END();
16254
16255
0
  ir_MERGE_2(fast_path, cold_path);
16256
0
  ref = ir_PHI_2(IR_ADDR, ref, ref2);
16257
16258
0
  if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_IS) {
16259
    // JIT: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), result);
16260
0
    if (!zend_jit_zval_copy_deref(jit, res_addr, ZEND_ADDR_REF_ZVAL(ref),
16261
0
        jit_Z_TYPE_INFO_ref(jit, ref))) {
16262
0
      return 0;
16263
0
    }
16264
0
  } else {
16265
    // JIT: ZVAL_INDIRECT(EX_VAR(opline->result.var), result);
16266
0
    jit_set_Z_PTR(jit, res_addr, ref);
16267
0
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
16268
0
  }
16269
16270
0
  return 1;
16271
0
}
16272
16273
static int zend_jit_switch(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info)
16274
0
{
16275
0
  HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
16276
0
  const zend_op *next_opline = NULL;
16277
0
  ir_refs *slow_inputs;
16278
16279
0
  ir_refs_init(slow_inputs, 8);
16280
16281
0
  if (trace) {
16282
0
    ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
16283
0
    ZEND_ASSERT(trace->opline != NULL);
16284
0
    next_opline = trace->opline;
16285
0
  }
16286
16287
0
  if (opline->op1_type == IS_CONST) {
16288
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
16289
0
    zval *jump_zv = NULL;
16290
0
    int b;
16291
16292
0
    if (opline->opcode == ZEND_SWITCH_LONG) {
16293
0
      if (Z_TYPE_P(zv) == IS_LONG) {
16294
0
        jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16295
0
      }
16296
0
    } else if (opline->opcode == ZEND_SWITCH_STRING) {
16297
0
      if (Z_TYPE_P(zv) == IS_STRING) {
16298
0
        jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16299
0
      }
16300
0
    } else if (opline->opcode == ZEND_MATCH) {
16301
0
      if (Z_TYPE_P(zv) == IS_LONG) {
16302
0
        jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16303
0
      } else if (Z_TYPE_P(zv) == IS_STRING) {
16304
0
        jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16305
0
      }
16306
0
    } else {
16307
0
      ZEND_UNREACHABLE();
16308
0
    }
16309
0
    if (next_opline) {
16310
0
      const zend_op *target;
16311
16312
0
      if (jump_zv != NULL) {
16313
0
        target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
16314
0
      } else {
16315
0
        target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16316
0
      }
16317
0
      ZEND_ASSERT(target == next_opline);
16318
0
    } else {
16319
0
      if (jump_zv != NULL) {
16320
0
        b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes];
16321
0
      } else {
16322
0
        b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes];
16323
0
      }
16324
0
      _zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
16325
0
      jit->b = -1;
16326
0
    }
16327
0
  } else {
16328
0
    zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
16329
0
    uint32_t op1_info = OP1_INFO();
16330
0
    zend_jit_addr op1_addr = OP1_ADDR();
16331
0
    const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16332
0
    const zend_op *target;
16333
0
    int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
16334
0
    int b;
16335
0
    int32_t exit_point;
16336
0
    const void *exit_addr;
16337
0
    const void *default_label = NULL;
16338
0
    zval *zv;
16339
16340
0
    if (next_opline) {
16341
0
      if (next_opline != default_opline) {
16342
0
        exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
16343
0
        default_label = zend_jit_trace_get_exit_addr(exit_point);
16344
0
        if (!default_label) {
16345
0
          return 0;
16346
0
        }
16347
0
      }
16348
0
    }
16349
16350
0
    if (opline->opcode == ZEND_SWITCH_LONG) {
16351
0
      if (op1_info & MAY_BE_LONG) {
16352
0
        const void *fallback_label = NULL;
16353
16354
0
        if (next_opline) {
16355
0
          if (next_opline != opline + 1) {
16356
0
            exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16357
0
            fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16358
0
            if (!fallback_label) {
16359
0
              return 0;
16360
0
            }
16361
0
          }
16362
0
        }
16363
0
        if (op1_info & MAY_BE_REF) {
16364
0
          ir_ref ref, if_long, fast_path, ref2;
16365
16366
0
          ref = jit_ZVAL_ADDR(jit, op1_addr);
16367
0
          if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16368
0
          ir_IF_TRUE(if_long);
16369
0
          fast_path = ir_END();
16370
0
          ir_IF_FALSE_cold(if_long);
16371
16372
          // JIT: ZVAL_DEREF(op)
16373
0
          if (fallback_label) {
16374
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16375
0
          } else {
16376
0
            ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
16377
0
            ir_IF_FALSE_cold(if_ref);
16378
0
            ir_refs_add(slow_inputs, ir_END());
16379
0
            ir_IF_TRUE(if_ref);
16380
0
          }
16381
16382
0
          ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16383
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16384
16385
0
          if (fallback_label) {
16386
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16387
0
          } else {
16388
0
            if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16389
0
            ir_IF_FALSE_cold(if_long);
16390
0
            ir_refs_add(slow_inputs, ir_END());
16391
0
            ir_IF_TRUE(if_long);
16392
0
          }
16393
16394
0
          ir_MERGE_2(fast_path, ir_END());
16395
0
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
16396
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16397
0
        } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16398
0
          if (fallback_label) {
16399
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16400
0
          } else {
16401
0
            ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16402
0
            ir_IF_FALSE_cold(if_long);
16403
0
            ir_refs_add(slow_inputs, ir_END());
16404
0
            ir_IF_TRUE(if_long);
16405
0
          }
16406
0
        }
16407
0
        ir_ref ref = jit_Z_LVAL(jit, op1_addr);
16408
16409
0
        if (!HT_IS_PACKED(jumptable)) {
16410
0
          ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16411
0
            ir_CONST_ADDR(jumptable), ref);
16412
0
          ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16413
          /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16414
0
          if (sizeof(Bucket) == 32) {
16415
0
            ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16416
0
          } else {
16417
0
            ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16418
0
          }
16419
0
        }
16420
0
        ref = ir_SWITCH(ref);
16421
16422
0
        if (next_opline) {
16423
0
          ir_ref continue_list = IR_UNUSED;
16424
16425
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16426
0
            ir_ref idx;
16427
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16428
16429
0
            if (HT_IS_PACKED(jumptable)) {
16430
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16431
0
            } else {
16432
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16433
0
            }
16434
0
            ir_CASE_VAL(ref, idx);
16435
0
            if (target == next_opline) {
16436
0
              ir_END_list(continue_list);
16437
0
            } else {
16438
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16439
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16440
0
              if (!exit_addr) {
16441
0
                return 0;
16442
0
              }
16443
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16444
0
            }
16445
0
          } ZEND_HASH_FOREACH_END();
16446
16447
0
          ir_CASE_DEFAULT(ref);
16448
0
          if (next_opline == default_opline) {
16449
0
            ir_END_list(continue_list);
16450
0
          } else {
16451
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16452
0
          }
16453
0
          if (continue_list) {
16454
0
            ir_MERGE_list(continue_list);
16455
0
          } else {
16456
0
            ZEND_ASSERT(slow_inputs->count);
16457
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16458
0
          }
16459
0
        } else {
16460
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16461
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16462
0
            b = ssa->cfg.map[target - op_array->opcodes];
16463
0
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16464
0
          } ZEND_HASH_FOREACH_END();
16465
16466
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16467
0
          if (slow_inputs->count) {
16468
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16469
0
            _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16470
0
          }
16471
0
          jit->b = -1;
16472
0
        }
16473
0
      } else if (!next_opline) {
16474
0
        _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16475
0
        jit->b = -1;
16476
0
      }
16477
0
    } else if (opline->opcode == ZEND_SWITCH_STRING) {
16478
0
      if (op1_info & MAY_BE_STRING) {
16479
0
        const void *fallback_label = NULL;
16480
16481
0
        if (next_opline) {
16482
0
          if (next_opline != opline + 1) {
16483
0
            exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16484
0
            fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16485
0
            if (!fallback_label) {
16486
0
              return 0;
16487
0
            }
16488
0
          }
16489
0
        }
16490
0
        if (op1_info & MAY_BE_REF) {
16491
0
          ir_ref ref, if_string, fast_path, ref2;
16492
16493
0
          ref = jit_ZVAL_ADDR(jit, op1_addr);
16494
0
          if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16495
0
          ir_IF_TRUE(if_string);
16496
0
          fast_path = ir_END();
16497
0
          ir_IF_FALSE_cold(if_string);
16498
16499
          // JIT: ZVAL_DEREF(op)
16500
0
          if (fallback_label) {
16501
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16502
0
          } else {
16503
0
            ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16504
0
            ir_IF_FALSE_cold(if_ref);
16505
0
            ir_refs_add(slow_inputs, ir_END());
16506
0
            ir_IF_TRUE(if_ref);
16507
0
          }
16508
16509
0
          ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16510
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16511
16512
0
          if (fallback_label) {
16513
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16514
0
          } else {
16515
0
            if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16516
0
            ir_IF_FALSE_cold(if_string);
16517
0
            ir_refs_add(slow_inputs, ir_END());
16518
0
            ir_IF_TRUE(if_string);
16519
0
          }
16520
16521
0
          ir_MERGE_2(fast_path, ir_END());
16522
0
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
16523
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16524
0
        } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
16525
0
          if (fallback_label) {
16526
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16527
0
          } else {
16528
0
            ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16529
0
            ir_IF_FALSE_cold(if_string);
16530
0
            ir_refs_add(slow_inputs, ir_END());
16531
0
            ir_IF_TRUE(if_string);
16532
0
          }
16533
0
        }
16534
16535
0
        ir_ref ref = jit_Z_PTR(jit, op1_addr);
16536
0
        ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16537
0
          ir_CONST_ADDR(jumptable), ref);
16538
0
        ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16539
        /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16540
0
        if (sizeof(Bucket) == 32) {
16541
0
          ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16542
0
        } else {
16543
0
          ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16544
0
        }
16545
0
        ref = ir_SWITCH(ref);
16546
16547
0
        if (next_opline) {
16548
0
          ir_ref continue_list = IR_UNUSED;
16549
16550
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16551
0
            ir_ref idx;
16552
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16553
16554
0
            if (HT_IS_PACKED(jumptable)) {
16555
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16556
0
            } else {
16557
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16558
0
            }
16559
0
            ir_CASE_VAL(ref, idx);
16560
0
            if (target == next_opline) {
16561
0
              ir_END_list(continue_list);
16562
0
            } else {
16563
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16564
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16565
0
              if (!exit_addr) {
16566
0
                return 0;
16567
0
              }
16568
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16569
0
            }
16570
0
          } ZEND_HASH_FOREACH_END();
16571
16572
0
          ir_CASE_DEFAULT(ref);
16573
0
          if (next_opline == default_opline) {
16574
0
            ir_END_list(continue_list);
16575
0
          } else {
16576
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16577
0
          }
16578
0
          if (continue_list) {
16579
0
            ir_MERGE_list(continue_list);
16580
0
          } else {
16581
0
            ZEND_ASSERT(slow_inputs->count);
16582
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16583
0
          }
16584
0
        } else {
16585
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16586
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16587
0
            b = ssa->cfg.map[target - op_array->opcodes];
16588
0
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16589
0
          } ZEND_HASH_FOREACH_END();
16590
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16591
0
          if (slow_inputs->count) {
16592
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16593
0
            _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16594
0
          }
16595
0
          jit->b = -1;
16596
0
        }
16597
0
      } else if (!next_opline) {
16598
0
        _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16599
0
        jit->b = -1;
16600
0
      }
16601
0
    } else if (opline->opcode == ZEND_MATCH) {
16602
0
      ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
16603
0
      ir_ref continue_list = IR_UNUSED;
16604
16605
0
      if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
16606
0
        ir_ref long_path = IR_UNUSED;
16607
16608
0
        if (op1_info & MAY_BE_REF) {
16609
0
          op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
16610
0
        }
16611
0
        if (op1_info & MAY_BE_LONG) {
16612
0
          if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16613
0
            if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
16614
0
              if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16615
0
              ir_IF_TRUE(if_type);
16616
0
            } else if (default_label) {
16617
0
              jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
16618
0
            } else if (next_opline) {
16619
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16620
0
              ir_IF_FALSE(if_type);
16621
0
              ir_END_list(continue_list);
16622
0
              ir_IF_TRUE(if_type);
16623
0
            } else {
16624
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16625
0
              ir_IF_FALSE(if_type);
16626
0
              ir_END_list(default_input_list);
16627
0
              ir_IF_TRUE(if_type);
16628
0
            }
16629
0
          }
16630
0
          ref = jit_Z_LVAL(jit, op1_addr);
16631
0
          ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16632
0
            ir_CONST_ADDR(jumptable), ref);
16633
0
          if (op1_info & MAY_BE_STRING) {
16634
0
            long_path = ir_END();
16635
0
          }
16636
0
        }
16637
0
        if (op1_info & MAY_BE_STRING) {
16638
0
          if (if_type) {
16639
0
            ir_IF_FALSE(if_type);
16640
0
            if_type = IS_UNUSED;
16641
0
          }
16642
0
          if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
16643
0
            if (op1_info & MAY_BE_UNDEF) {
16644
0
              if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16645
0
              ir_IF_TRUE(if_type);
16646
0
            } else if (default_label) {
16647
0
              jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
16648
0
            } else if (next_opline) {
16649
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16650
0
              ir_IF_FALSE(if_type);
16651
0
              ir_END_list(continue_list);
16652
0
              ir_IF_TRUE(if_type);
16653
0
            } else {
16654
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16655
0
              ir_IF_FALSE(if_type);
16656
0
              ir_END_list(default_input_list);
16657
0
              ir_IF_TRUE(if_type);
16658
0
            }
16659
0
          }
16660
0
          ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16661
0
          ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16662
0
            ir_CONST_ADDR(jumptable), ref2);
16663
0
          if (op1_info & MAY_BE_LONG) {
16664
0
            ir_MERGE_WITH(long_path);
16665
0
            ref = ir_PHI_2(IR_LONG, ref2, ref);
16666
0
          } else {
16667
0
            ref = ref2;
16668
0
          }
16669
0
        }
16670
16671
0
        ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16672
        /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16673
0
        if (HT_IS_PACKED(jumptable)) {
16674
0
          ZEND_ASSERT(sizeof(zval) == 16);
16675
0
          ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16676
0
        } else {
16677
0
          if (sizeof(Bucket) == 32) {
16678
0
            ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16679
0
          } else {
16680
0
            ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16681
0
          }
16682
0
        }
16683
0
        ref = ir_SWITCH(ref);
16684
16685
0
        if (next_opline) {
16686
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16687
0
            ir_ref idx;
16688
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16689
16690
0
            if (HT_IS_PACKED(jumptable)) {
16691
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16692
0
            } else {
16693
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16694
0
            }
16695
0
            ir_CASE_VAL(ref, idx);
16696
0
            if (target == next_opline) {
16697
0
              ir_END_list(continue_list);
16698
0
            } else {
16699
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16700
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16701
0
              if (!exit_addr) {
16702
0
                return 0;
16703
0
              }
16704
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16705
0
            }
16706
0
          } ZEND_HASH_FOREACH_END();
16707
16708
0
          ir_CASE_DEFAULT(ref);
16709
0
          if (next_opline == default_opline) {
16710
0
            ir_END_list(continue_list);
16711
0
          } else {
16712
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16713
0
          }
16714
0
        } else {
16715
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16716
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16717
0
            b = ssa->cfg.map[target - op_array->opcodes];
16718
0
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16719
0
          } ZEND_HASH_FOREACH_END();
16720
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16721
0
        }
16722
0
      } else if (!(op1_info & MAY_BE_UNDEF)) {
16723
0
        if (next_opline) {
16724
0
          if (next_opline == default_opline) {
16725
0
            ir_END_list(continue_list);
16726
0
          } else {
16727
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16728
0
          }
16729
0
        } else {
16730
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16731
0
        }
16732
0
      }
16733
16734
0
      if (op1_info & MAY_BE_UNDEF) {
16735
0
        if (if_type) {
16736
0
          ir_IF_FALSE(if_type);
16737
0
          if_type = IS_UNUSED;
16738
0
        }
16739
0
        if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16740
0
          if (default_label) {
16741
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16742
0
          } else if (next_opline) {
16743
0
            ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16744
0
            ir_IF_TRUE(if_def);
16745
0
            ir_END_list(continue_list);
16746
0
            ir_IF_FALSE_cold(if_def);
16747
0
          } else {
16748
0
            ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16749
0
            ir_IF_TRUE(if_def);
16750
0
            ir_END_list(default_input_list);
16751
0
            ir_IF_FALSE_cold(if_def);
16752
0
          }
16753
0
        }
16754
16755
0
        jit_SET_EX_OPLINE(jit, opline);
16756
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16757
0
          ir_CONST_U32(opline->op1.var));
16758
0
        zend_jit_check_exception_undef_result(jit, opline);
16759
0
        if (default_label) {
16760
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16761
0
        } else if (next_opline) {
16762
0
          ir_END_list(continue_list);
16763
0
        } else {
16764
0
          ir_END_list(default_input_list);
16765
0
        }
16766
0
      }
16767
0
      if (next_opline) {
16768
0
        ZEND_ASSERT(continue_list);
16769
0
        ir_MERGE_list(continue_list);
16770
0
      } else {
16771
0
        if (default_input_list) {
16772
0
          if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16773
0
            ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16774
0
            jit->ctx.ir_base[ref].op3 = default_input_list;
16775
0
          } else {
16776
0
            ir_MERGE_list(default_input_list);
16777
0
            _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16778
0
          }
16779
0
        }
16780
0
        jit->b = -1;
16781
0
      }
16782
0
    } else {
16783
0
      ZEND_UNREACHABLE();
16784
0
    }
16785
0
  }
16786
0
  return 1;
16787
0
}
16788
16789
static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16790
0
{
16791
0
  uint32_t i, count;
16792
0
  zend_basic_block *bb;
16793
16794
0
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : (IR_START_BR_TARGET|IR_ENTRY_BR_TARGET));
16795
16796
0
  jit->ctx.spill_base = ZREG_FP;
16797
16798
0
  jit->op_array = jit->current_op_array = op_array;
16799
0
  jit->ssa = ssa;
16800
0
  jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16801
0
  jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16802
16803
0
  count = 0;
16804
0
  for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
16805
0
    jit->bb_predecessors[i] = count;
16806
0
    count += bb->predecessors_count;
16807
0
  }
16808
0
  jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
16809
16810
0
  if (!GCC_GLOBAL_REGS) {
16811
0
    if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
16812
0
      ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
16813
0
      ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
16814
0
      jit_STORE_FP(jit, execute_data_ref);
16815
0
      jit_STORE_IP(jit, opline_ref);
16816
0
    }
16817
0
    jit->ctx.flags |= IR_FASTCALL_FUNC;
16818
0
  }
16819
16820
0
  return 1;
16821
0
}
16822
16823
static zend_vm_opcode_handler_t zend_jit_finish(zend_jit_ctx *jit)
16824
0
{
16825
0
  void *entry;
16826
0
  size_t size;
16827
0
  zend_string *str = NULL;
16828
16829
0
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
16830
0
      ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
16831
0
      ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
16832
0
    if (jit->name) {
16833
0
      str = zend_string_copy(jit->name);
16834
0
    } else {
16835
0
      str = zend_jit_func_name(jit->op_array);
16836
0
    }
16837
0
  }
16838
16839
0
  if (jit->op_array) {
16840
    /* Only for function JIT */
16841
0
    _zend_jit_fix_merges(jit);
16842
#if defined(IR_TARGET_AARCH64)
16843
  } else if (jit->trace) {
16844
    jit->ctx.deoptimization_exits = jit->trace->exit_count;
16845
    jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
16846
#endif
16847
0
  } else {
16848
0
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
16849
0
    jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
16850
0
#endif
16851
0
  }
16852
16853
0
  entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
16854
0
  if (entry) {
16855
0
    if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16856
#ifdef HAVE_CAPSTONE
16857
      if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16858
        if (str) {
16859
          ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
16860
        }
16861
        ir_disasm(str ? ZSTR_VAL(str) : "unknown",
16862
          entry, size,
16863
          (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
16864
          &jit->ctx, stderr);
16865
      }
16866
#endif
16867
0
#ifndef _WIN32
16868
0
      if (str) {
16869
0
        if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
16870
0
          uintptr_t sp_offset = 0;
16871
16872
//          ir_mem_unprotect(entry, size);
16873
0
          if (!(jit->ctx.flags & IR_FUNCTION)
16874
0
           && ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
16875
0
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
16876
0
            sp_offset = zend_jit_hybrid_vm_sp_adj;
16877
#else
16878
            sp_offset = sizeof(void*);
16879
#endif
16880
0
          } else {
16881
0
            sp_offset = sizeof(void*);
16882
0
          }
16883
0
          ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
16884
//          ir_mem_protect(entry, size);
16885
0
        }
16886
16887
0
        if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
16888
0
          ir_perf_map_register(ZSTR_VAL(str), entry, size);
16889
0
          if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
16890
0
            ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
16891
0
          }
16892
0
        }
16893
0
      }
16894
0
#endif
16895
0
    }
16896
16897
0
    if (jit->op_array) {
16898
      /* Only for function JIT */
16899
0
      const zend_op_array *op_array = jit->op_array;
16900
0
      zend_op *opline = (zend_op*)op_array->opcodes;
16901
16902
0
      if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
16903
0
        while (opline->opcode == ZEND_RECV) {
16904
0
          opline++;
16905
0
        }
16906
0
      }
16907
0
      opline->handler = (zend_vm_opcode_handler_t)entry;
16908
16909
0
      if (jit->ctx.entries_count) {
16910
        /* For all entries */
16911
0
        int i = jit->ctx.entries_count;
16912
0
        do {
16913
0
          ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
16914
0
          op_array->opcodes[insn->op2].handler = (zend_vm_opcode_handler_t)((char*)entry + insn->op3);
16915
0
        } while (i != 0);
16916
0
      }
16917
0
    } else {
16918
      /* Only for tracing JIT */
16919
0
      zend_jit_trace_info *t = jit->trace;
16920
0
      zend_jit_trace_stack *stack;
16921
0
      uint32_t i;
16922
16923
0
      if (t) {
16924
0
        for (i = 0; i < t->stack_map_size; i++) {
16925
0
          stack = t->stack_map + i;
16926
0
          if (stack->flags & ZREG_SPILL_SLOT) {
16927
0
            stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
16928
0
            stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
16929
0
          }
16930
0
        }
16931
0
      }
16932
16933
0
      zend_jit_trace_add_code(entry, size);
16934
0
    }
16935
0
  }
16936
16937
0
  if (str) {
16938
0
    zend_string_release(str);
16939
0
  }
16940
16941
0
  return (zend_vm_opcode_handler_t)entry;
16942
0
}
16943
16944
static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
16945
0
{
16946
0
  const void *entry;
16947
0
  size_t size;
16948
0
  ir_code_buffer code_buffer;
16949
16950
0
  code_buffer.start = dasm_buf;
16951
0
  code_buffer.end = dasm_end;
16952
0
  code_buffer.pos = *dasm_ptr;
16953
16954
0
  entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
16955
0
    &code_buffer, &size);
16956
16957
0
  *dasm_ptr = code_buffer.pos;
16958
16959
0
  if (entry) {
16960
#ifdef HAVE_CAPSTONE
16961
    if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
16962
      uint32_t i;
16963
      char name[32];
16964
16965
      for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
16966
        snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
16967
        ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
16968
      }
16969
    }
16970
#endif
16971
0
  }
16972
16973
0
  return entry;
16974
0
}
16975
16976
static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
16977
0
{
16978
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16979
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16980
0
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16981
16982
0
  if (!exit_addr) {
16983
0
    return 0;
16984
0
  }
16985
0
  ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
16986
16987
0
  return 1;
16988
0
}
16989
16990
static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
16991
0
{
16992
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16993
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16994
0
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
16995
16996
0
  if (!exit_addr) {
16997
0
    return 0;
16998
0
  }
16999
0
  ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
17000
17001
0
  return 1;
17002
0
}
17003
17004
static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
17005
0
{
17006
0
  uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17007
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17008
17009
0
  if (!exit_addr) {
17010
0
    return false;
17011
0
  }
17012
0
  ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17013
17014
0
  return true;
17015
0
}
17016
17017
static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
17018
0
{
17019
0
  uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
17020
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17021
17022
0
  if (!exit_addr) {
17023
0
    return 0;
17024
0
  }
17025
17026
0
  ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
17027
0
  zend_jit_set_last_valid_opline(jit, opline);
17028
17029
0
  return 1;
17030
0
}
17031
17032
static bool zend_jit_guard_reference(zend_jit_ctx  *jit,
17033
                                     const zend_op *opline,
17034
                                     zend_jit_addr *var_addr_ptr,
17035
                                     zend_jit_addr *ref_addr_ptr,
17036
                                     bool           add_ref_guard)
17037
0
{
17038
0
  zend_jit_addr var_addr = *var_addr_ptr;
17039
0
  const void *exit_addr = NULL;
17040
0
  ir_ref ref;
17041
17042
0
  if (add_ref_guard) {
17043
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17044
17045
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17046
0
    if (!exit_addr) {
17047
0
      return false;
17048
0
    }
17049
17050
0
    ref = jit_Z_TYPE(jit, var_addr);
17051
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17052
0
  }
17053
17054
0
  ref = jit_Z_PTR(jit, var_addr);
17055
0
  *ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
17056
0
  ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
17057
0
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
17058
0
  *var_addr_ptr = var_addr;
17059
17060
0
  return true;
17061
0
}
17062
17063
static bool zend_jit_fetch_reference(zend_jit_ctx  *jit,
17064
                                     const zend_op *opline,
17065
                                     uint8_t        var_type,
17066
                                     uint32_t      *var_info_ptr,
17067
                                     zend_jit_addr *var_addr_ptr,
17068
                                     bool           add_ref_guard,
17069
                                     bool           add_type_guard)
17070
0
{
17071
0
  zend_jit_addr var_addr = *var_addr_ptr;
17072
0
  uint32_t var_info = *var_info_ptr;
17073
0
  const void *exit_addr = NULL;
17074
0
  ir_ref ref;
17075
17076
0
  if (add_ref_guard || add_type_guard) {
17077
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17078
17079
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17080
0
    if (!exit_addr) {
17081
0
      return false;
17082
0
    }
17083
0
  }
17084
17085
0
  if (add_ref_guard) {
17086
0
    ref = jit_Z_TYPE(jit, var_addr);
17087
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17088
0
  }
17089
0
  if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
17090
    /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
17091
0
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
17092
0
      jit_ZVAL_ADDR(jit, var_addr));
17093
0
    *var_addr_ptr = var_addr;
17094
0
  } else {
17095
0
    ref = jit_Z_PTR(jit, var_addr);
17096
0
    ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
17097
0
    var_addr = ZEND_ADDR_REF_ZVAL(ref);
17098
0
    *var_addr_ptr = var_addr;
17099
0
  }
17100
17101
0
  if (var_type != IS_UNKNOWN) {
17102
0
    var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
17103
0
  }
17104
0
  if (add_type_guard
17105
0
   && var_type != IS_UNKNOWN
17106
0
   && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
17107
0
    ref = jit_Z_TYPE(jit, var_addr);
17108
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
17109
17110
0
    ZEND_ASSERT(var_info & (1 << var_type));
17111
0
    if (var_type < IS_STRING) {
17112
0
      var_info = (1 << var_type);
17113
0
    } else if (var_type != IS_ARRAY) {
17114
0
      var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
17115
0
    } else {
17116
0
      var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
17117
0
    }
17118
17119
0
    *var_info_ptr = var_info;
17120
0
  } else {
17121
0
    var_info &= ~MAY_BE_REF;
17122
0
    *var_info_ptr = var_info;
17123
0
  }
17124
0
  *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
17125
17126
0
  return true;
17127
0
}
17128
17129
static bool zend_jit_fetch_indirect_var(zend_jit_ctx *jit, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_indirect_guard)
17130
0
{
17131
0
  zend_jit_addr var_addr = *var_addr_ptr;
17132
0
  uint32_t var_info = *var_info_ptr;
17133
0
  int32_t exit_point;
17134
0
  const void *exit_addr;
17135
0
  ir_ref ref = IR_UNUSED;
17136
17137
0
  if (add_indirect_guard) {
17138
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17139
0
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17140
17141
0
    if (!exit_addr) {
17142
0
      return false;
17143
0
    }
17144
0
    jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
17145
0
    ref = jit_Z_PTR(jit, var_addr);
17146
0
  } else {
17147
    /* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
17148
     * is eliminated by store forwarding (S2L) */
17149
0
    ref = jit_Z_PTR(jit, var_addr);
17150
0
  }
17151
0
  *var_info_ptr &= ~MAY_BE_INDIRECT;
17152
0
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
17153
0
  *var_addr_ptr = var_addr;
17154
17155
0
  if (var_type != IS_UNKNOWN) {
17156
0
    var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
17157
0
  }
17158
0
  if (!(var_type & IS_TRACE_REFERENCE)
17159
0
   && var_type != IS_UNKNOWN
17160
0
   && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
17161
0
    exit_point = zend_jit_trace_get_exit_point(opline, 0);
17162
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17163
17164
0
    if (!exit_addr) {
17165
0
      return false;
17166
0
    }
17167
17168
0
    jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
17169
17170
    //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
17171
0
    ZEND_ASSERT(var_info & (1 << var_type));
17172
0
    if (var_type < IS_STRING) {
17173
0
      var_info = (1 << var_type);
17174
0
    } else if (var_type != IS_ARRAY) {
17175
0
      var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
17176
0
    } else {
17177
0
      var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
17178
0
    }
17179
17180
0
    *var_info_ptr = var_info;
17181
0
  }
17182
17183
0
  return true;
17184
0
}
17185
17186
static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace)
17187
0
{
17188
0
  zend_jit_op_array_trace_extension *jit_extension =
17189
0
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
17190
0
  size_t offset = jit_extension->offset;
17191
0
  zend_vm_opcode_handler_func_t handler =
17192
0
    ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
17193
0
  ir_ref ref;
17194
17195
0
  zend_jit_set_ip(jit, opline);
17196
0
  if (GCC_GLOBAL_REGS) {
17197
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
17198
0
  } else {
17199
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
17200
0
    if (opline->opcode == ZEND_RETURN ||
17201
0
        opline->opcode == ZEND_RETURN_BY_REF ||
17202
0
        opline->opcode == ZEND_DO_UCALL ||
17203
0
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
17204
0
        opline->opcode == ZEND_DO_FCALL ||
17205
0
        opline->opcode == ZEND_GENERATOR_CREATE ||
17206
0
        opline->opcode == ZEND_INCLUDE_OR_EVAL) {
17207
17208
0
      jit_STORE_IP(jit, ir_AND_A(ref, ir_CONST_ADDR(~ZEND_VM_ENTER_BIT)));
17209
0
    } else {
17210
0
      jit_STORE_IP(jit, ref);
17211
0
    }
17212
0
  }
17213
0
  if (may_throw
17214
0
   && opline->opcode != ZEND_RETURN
17215
0
   && opline->opcode != ZEND_RETURN_BY_REF) {
17216
0
    zend_jit_check_exception(jit);
17217
0
  }
17218
17219
0
  while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
17220
0
    trace++;
17221
0
  }
17222
17223
0
  if ((!GCC_GLOBAL_REGS
17224
0
   && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN))
17225
0
   || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
17226
0
    if (opline->opcode == ZEND_RETURN ||
17227
0
        opline->opcode == ZEND_RETURN_BY_REF ||
17228
0
        opline->opcode == ZEND_DO_UCALL ||
17229
0
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
17230
0
        opline->opcode == ZEND_DO_FCALL ||
17231
0
        opline->opcode == ZEND_GENERATOR_CREATE ||
17232
0
        opline->opcode == ZEND_INCLUDE_OR_EVAL) {
17233
17234
0
      ir_ref addr = jit_EG(current_execute_data);
17235
17236
0
      jit_STORE_FP(jit, ir_LOAD_A(addr));
17237
0
    }
17238
0
  }
17239
17240
0
  if (zend_jit_trace_may_exit(op_array, opline)) {
17241
0
    if (opline->opcode == ZEND_RETURN ||
17242
0
        opline->opcode == ZEND_RETURN_BY_REF ||
17243
0
        opline->opcode == ZEND_GENERATOR_CREATE) {
17244
17245
0
      if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
17246
0
        if (trace->op != ZEND_JIT_TRACE_END ||
17247
0
            (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
17248
0
             trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
17249
          /* this check may be handled by the following OPLINE guard or jmp [IP] */
17250
0
          ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
17251
0
            jit_STUB_ADDR(jit, jit_stub_trace_halt));
17252
0
        }
17253
0
      } else {
17254
        /* IP has been cleared of ZEND_VM_ENTER_BIT already */
17255
0
        ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
17256
0
      }
17257
0
    } else if (opline->opcode == ZEND_GENERATOR_RETURN ||
17258
0
               opline->opcode == ZEND_YIELD ||
17259
0
               opline->opcode == ZEND_YIELD_FROM) {
17260
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
17261
0
      ir_BEGIN(IR_UNUSED); /* unreachable block */
17262
0
    }
17263
0
    if (trace->op != ZEND_JIT_TRACE_END ||
17264
0
        (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
17265
0
         trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
17266
17267
0
      const zend_op *next_opline = trace->opline;
17268
0
      const zend_op *exit_opline = NULL;
17269
0
      uint32_t exit_point;
17270
0
      const void *exit_addr;
17271
0
      uint32_t old_info = 0;
17272
0
      uint32_t old_res_info = 0;
17273
0
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
17274
17275
0
      if (zend_is_smart_branch(opline)) {
17276
0
        bool exit_if_true = false;
17277
0
        exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
17278
0
      } else {
17279
0
        switch (opline->opcode) {
17280
0
          case ZEND_JMPZ:
17281
0
          case ZEND_JMPNZ:
17282
0
          case ZEND_JMPZ_EX:
17283
0
          case ZEND_JMPNZ_EX:
17284
0
          case ZEND_JMP_SET:
17285
0
          case ZEND_COALESCE:
17286
0
          case ZEND_JMP_NULL:
17287
0
          case ZEND_FE_RESET_R:
17288
0
          case ZEND_FE_RESET_RW:
17289
0
            exit_opline = (trace->opline == opline + 1) ?
17290
0
              OP_JMP_ADDR(opline, opline->op2) :
17291
0
              opline + 1;
17292
0
            break;
17293
0
          case ZEND_FE_FETCH_R:
17294
0
          case ZEND_FE_FETCH_RW:
17295
0
            exit_opline = (trace->opline == opline + 1) ?
17296
0
              ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
17297
0
              opline + 1;
17298
0
            break;
17299
17300
0
        }
17301
0
      }
17302
17303
0
      switch (opline->opcode) {
17304
0
        case ZEND_FE_FETCH_R:
17305
0
        case ZEND_FE_FETCH_RW:
17306
0
          if (opline->op2_type != IS_UNUSED) {
17307
0
            old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
17308
0
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
17309
0
          }
17310
0
          break;
17311
0
        case ZEND_FE_RESET_RW:
17312
0
        case ZEND_BIND_INIT_STATIC_OR_JMP:
17313
0
          if (opline->op1_type == IS_CV) {
17314
0
            old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
17315
0
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17316
0
          }
17317
0
          break;
17318
0
      }
17319
0
      if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17320
0
        old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
17321
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
17322
0
      }
17323
0
      exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
17324
0
      exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17325
17326
0
      if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17327
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
17328
0
      }
17329
0
      switch (opline->opcode) {
17330
0
        case ZEND_FE_FETCH_R:
17331
0
        case ZEND_FE_FETCH_RW:
17332
0
          if (opline->op2_type != IS_UNUSED) {
17333
0
            SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
17334
0
          }
17335
0
          break;
17336
0
        case ZEND_FE_RESET_RW:
17337
0
        case ZEND_BIND_INIT_STATIC_OR_JMP:
17338
0
          if (opline->op1_type == IS_CV) {
17339
0
            SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
17340
0
          }
17341
0
          break;
17342
0
      }
17343
17344
0
      if (!exit_addr) {
17345
0
        return 0;
17346
0
      }
17347
0
      ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
17348
0
    }
17349
0
  }
17350
17351
0
  zend_jit_set_last_valid_opline(jit, trace->opline);
17352
17353
0
  return 1;
17354
0
}
17355
17356
static int zend_jit_deoptimizer_start(zend_jit_ctx        *jit,
17357
                                      zend_string         *name,
17358
                                      uint32_t             trace_num,
17359
                                      zend_jit_trace_info *parent,
17360
                                      uint32_t             exit_num)
17361
0
{
17362
0
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : IR_START_BR_TARGET);
17363
17364
0
  jit->ctx.spill_base = ZREG_FP;
17365
17366
0
  jit->op_array = NULL;
17367
0
  jit->ssa = NULL;
17368
0
  jit->name = zend_string_copy(name);
17369
17370
0
  jit->ctx.flags |= IR_SKIP_PROLOGUE;
17371
17372
0
  zend_jit_preserve_parent_regs(jit, NULL, parent, exit_num);
17373
17374
0
  return 1;
17375
0
}
17376
17377
static int zend_jit_trace_start(zend_jit_ctx        *jit,
17378
                                const zend_op_array *op_array,
17379
                                zend_ssa            *ssa,
17380
                                zend_string         *name,
17381
                                uint32_t             trace_num,
17382
                                zend_jit_trace_info *parent,
17383
                                uint32_t             exit_num)
17384
0
{
17385
0
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : IR_START_BR_TARGET);
17386
17387
0
  jit->ctx.spill_base = ZREG_FP;
17388
17389
0
  jit->op_array = NULL;
17390
0
  jit->current_op_array = op_array;
17391
0
  jit->ssa = ssa;
17392
0
  jit->name = zend_string_copy(name);
17393
17394
0
  if (!GCC_GLOBAL_REGS) {
17395
0
    if (!parent) {
17396
0
      if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
17397
0
        ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
17398
0
        ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
17399
0
        jit_STORE_FP(jit, execute_data_ref);
17400
0
        jit_STORE_IP(jit, opline_ref);
17401
0
      }
17402
0
      jit->ctx.flags |= IR_FASTCALL_FUNC;
17403
0
    }
17404
0
  }
17405
17406
0
  if (parent) {
17407
0
    jit->ctx.flags |= IR_SKIP_PROLOGUE;
17408
0
  }
17409
17410
0
  zend_jit_preserve_parent_regs(jit, ssa, parent, exit_num);
17411
17412
0
  ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
17413
17414
0
  return 1;
17415
0
}
17416
17417
static void zend_jit_preserve_parent_regs(zend_jit_ctx *jit,
17418
                                          zend_ssa *ssa,
17419
                                          zend_jit_trace_info *parent,
17420
                                          uint32_t exit_num)
17421
0
{
17422
  /* Emit early RLOADs of registers used for deoptimization to prevent
17423
   * clobbering. zend_jit_deopt_rload() will reference these. */
17424
17425
0
  if (parent) {
17426
0
    int i;
17427
0
    int parent_vars_count = parent->exit_info[exit_num].stack_size;
17428
0
    zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
17429
0
      parent->stack_map +
17430
0
      parent->exit_info[exit_num].stack_offset;
17431
17432
0
    for (i = 0; i < parent_vars_count; i++) {
17433
0
      if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
17434
0
       && STACK_REG(parent_stack, i) != ZREG_NONE) {
17435
0
        int32_t reg = STACK_REG(parent_stack, i);
17436
0
        ir_type type;
17437
17438
0
        if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
17439
0
          type = IR_ADDR;
17440
0
        } else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
17441
0
          type = IR_LONG;
17442
0
        } else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
17443
0
          type = IR_DOUBLE;
17444
0
        } else {
17445
0
          ZEND_UNREACHABLE();
17446
0
        }
17447
0
        if (ssa && ssa->vars[i].no_val) {
17448
          /* pass */
17449
0
        } else {
17450
0
          ir_ref ref = ir_RLOAD(type, reg);
17451
17452
0
          if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
17453
            /* op3 is used as a flag that the value is already stored in memory.
17454
             * In case the IR framework decides to spill the result of IR_LOAD,
17455
             * it doesn't have to store the value once again.
17456
             *
17457
             * See: insn->op3 check in ir_emit_rload()
17458
             */
17459
0
            ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
17460
0
          }
17461
0
        }
17462
0
      }
17463
0
    }
17464
0
  }
17465
17466
0
  if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17467
0
    ZEND_ASSERT(parent->exit_info[exit_num].poly_func.reg >= 0 && parent->exit_info[exit_num].poly_this.reg >= 0);
17468
0
    if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_func.reg)) {
17469
0
      ir_RLOAD_A(parent->exit_info[exit_num].poly_func.reg);
17470
0
    }
17471
0
    if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_this.reg)) {
17472
0
      ir_RLOAD_A(parent->exit_info[exit_num].poly_this.reg);
17473
0
    }
17474
0
  }
17475
0
}
17476
17477
static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
17478
0
{
17479
0
  return ir_LOOP_BEGIN(ir_END());
17480
0
}
17481
17482
static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
17483
0
{
17484
0
  int dst_var = phi->ssa_var;
17485
0
  int src_var = phi->sources[0];
17486
0
  ir_ref ref;
17487
17488
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
17489
0
  ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
17490
17491
0
  ref = ir_PHI_2(
17492
0
    (jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
17493
0
    zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
17494
17495
0
  src_var = phi->sources[1];
17496
0
  ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
17497
0
  jit->ra[src_var].flags |= ZREG_FORWARD;
17498
17499
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
17500
0
}
17501
17502
static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
17503
0
{
17504
0
  if (timeout_exit_addr) {
17505
0
    zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17506
0
  }
17507
0
  ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
17508
0
  ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
17509
0
  return 1;
17510
0
}
17511
17512
static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
17513
0
{
17514
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
17515
0
    if (!original_handler) {
17516
0
      zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
17517
0
    } else {
17518
0
      zend_jit_tailcall_handler(jit, zend_jit_orig_opline_handler(jit));
17519
0
    }
17520
0
  } else {
17521
0
    if (original_handler) {
17522
0
      ir_ref ref;
17523
0
      ir_ref addr = zend_jit_orig_opline_handler(jit);
17524
17525
#if defined(IR_TARGET_X86)
17526
      addr = ir_CAST_FC_FUNC(addr);
17527
#endif
17528
0
      ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit));
17529
0
      zend_jit_vm_enter(jit, ref);
17530
0
      return 1;
17531
0
    }
17532
0
    zend_jit_vm_enter(jit, jit_IP(jit));
17533
0
  }
17534
0
  return 1;
17535
0
}
17536
17537
static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr)
17538
0
{
17539
0
  return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
17540
0
}
17541
17542
static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
17543
0
{
17544
0
  const void *link_addr;
17545
17546
  /* Skip prologue. */
17547
0
  ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
17548
0
  link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
17549
17550
0
  if (timeout_exit_addr) {
17551
0
    zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17552
0
  }
17553
0
  ir_IJMP(ir_CONST_ADDR(link_addr));
17554
17555
0
  return 1;
17556
0
}
17557
17558
static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace)
17559
0
{
17560
0
  uint32_t op1_info, op2_info;
17561
17562
0
  switch (opline->opcode) {
17563
0
    case ZEND_SEND_VAR:
17564
0
    case ZEND_SEND_VAL:
17565
0
    case ZEND_SEND_VAL_EX:
17566
0
      return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
17567
0
    case ZEND_QM_ASSIGN:
17568
0
    case ZEND_IS_SMALLER:
17569
0
    case ZEND_IS_SMALLER_OR_EQUAL:
17570
0
    case ZEND_IS_EQUAL:
17571
0
    case ZEND_IS_NOT_EQUAL:
17572
0
    case ZEND_IS_IDENTICAL:
17573
0
    case ZEND_IS_NOT_IDENTICAL:
17574
0
    case ZEND_CASE:
17575
0
      return true;
17576
0
    case ZEND_RETURN:
17577
0
      return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
17578
0
    case ZEND_ASSIGN:
17579
0
      return (opline->op1_type == IS_CV);
17580
0
    case ZEND_ASSIGN_OP:
17581
0
      if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
17582
0
        return false;
17583
0
      }
17584
0
      op1_info = OP1_INFO();
17585
0
      op2_info = OP2_INFO();
17586
0
      return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
17587
0
    case ZEND_ADD:
17588
0
    case ZEND_SUB:
17589
0
    case ZEND_MUL:
17590
0
      op1_info = OP1_INFO();
17591
0
      op2_info = OP2_INFO();
17592
0
      if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
17593
0
        return false;
17594
0
      }
17595
0
      if (trace && trace->op1_type != IS_UNKNOWN) {
17596
0
        op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17597
0
      }
17598
0
      if (trace && trace->op2_type != IS_UNKNOWN) {
17599
0
        op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17600
0
      }
17601
0
      return !(op1_info & MAY_BE_UNDEF)
17602
0
        && !(op2_info & MAY_BE_UNDEF)
17603
0
        && (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
17604
0
        && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
17605
0
    case ZEND_BW_OR:
17606
0
    case ZEND_BW_AND:
17607
0
    case ZEND_BW_XOR:
17608
0
    case ZEND_SL:
17609
0
    case ZEND_SR:
17610
0
    case ZEND_MOD:
17611
0
      op1_info = OP1_INFO();
17612
0
      op2_info = OP2_INFO();
17613
0
      if (trace && trace->op1_type != IS_UNKNOWN) {
17614
0
        op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17615
0
      }
17616
0
      if (trace && trace->op2_type != IS_UNKNOWN) {
17617
0
        op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17618
0
      }
17619
0
      return (op1_info & MAY_BE_LONG)
17620
0
        && (op2_info & MAY_BE_LONG);
17621
0
    case ZEND_PRE_INC:
17622
0
    case ZEND_PRE_DEC:
17623
0
    case ZEND_POST_INC:
17624
0
    case ZEND_POST_DEC:
17625
0
      op1_info = OP1_INFO();
17626
0
      return opline->op1_type == IS_CV
17627
0
        && (op1_info & MAY_BE_LONG)
17628
0
        && !(op1_info & MAY_BE_REF);
17629
0
    case ZEND_STRLEN:
17630
0
      op1_info = OP1_INFO();
17631
0
      return (opline->op1_type & (IS_CV|IS_CONST))
17632
0
        && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
17633
0
    case ZEND_COUNT:
17634
0
      op1_info = OP1_INFO();
17635
0
      return (opline->op1_type & (IS_CV|IS_CONST))
17636
0
        && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
17637
0
    case ZEND_JMPZ:
17638
0
    case ZEND_JMPNZ:
17639
0
      if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17640
0
        if (!ssa->cfg.map) {
17641
0
          return false;
17642
0
        }
17643
0
        if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
17644
0
            ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
17645
0
          return false;
17646
0
        }
17647
0
      }
17648
0
      ZEND_FALLTHROUGH;
17649
0
    case ZEND_BOOL:
17650
0
    case ZEND_BOOL_NOT:
17651
0
    case ZEND_JMPZ_EX:
17652
0
    case ZEND_JMPNZ_EX:
17653
0
      return true;
17654
0
    case ZEND_FETCH_CONSTANT:
17655
0
      return true;
17656
0
    case ZEND_ISSET_ISEMPTY_DIM_OBJ:
17657
0
      if ((opline->extended_value & ZEND_ISEMPTY)) {
17658
0
        return false;
17659
0
      }
17660
0
      ZEND_FALLTHROUGH;
17661
0
    case ZEND_FETCH_DIM_R:
17662
0
    case ZEND_FETCH_DIM_IS:
17663
0
    case ZEND_FETCH_LIST_R:
17664
0
      op1_info = OP1_INFO();
17665
0
      op2_info = OP2_INFO();
17666
0
      if (trace
17667
0
       && trace->op1_type != IS_UNKNOWN
17668
0
       && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17669
0
        op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17670
0
      }
17671
0
      return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17672
0
          (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17673
0
           ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17674
0
    case ZEND_ASSIGN_DIM_OP:
17675
0
      if (opline->result_type != IS_UNUSED) {
17676
0
        return false;
17677
0
      }
17678
0
      if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17679
0
        return false;
17680
0
      }
17681
0
      ZEND_FALLTHROUGH;
17682
0
    case ZEND_ASSIGN_DIM:
17683
0
    case ZEND_FETCH_DIM_W:
17684
0
    case ZEND_FETCH_DIM_RW:
17685
0
    case ZEND_FETCH_LIST_W:
17686
0
      op1_info = OP1_INFO();
17687
0
      op2_info = OP2_INFO();
17688
0
      if (trace) {
17689
0
        if (opline->op1_type == IS_CV) {
17690
0
          if ((opline->opcode == ZEND_ASSIGN_DIM
17691
0
            || opline->opcode == ZEND_ASSIGN_DIM_OP)
17692
0
           && (opline+1)->op1_type == IS_CV
17693
0
           && (opline+1)->op1.var == opline->op1.var) {
17694
            /* skip $a[x] = $a; */
17695
0
            return false;
17696
0
          }
17697
0
        } else if (opline->op1_type == IS_VAR) {
17698
0
          if (trace->op1_type == IS_UNKNOWN
17699
0
           || !(trace->op1_type & IS_TRACE_INDIRECT)
17700
0
           || opline->result_type != IS_UNUSED) {
17701
0
            return false;
17702
0
          }
17703
0
        }
17704
0
        if (trace->op1_type != IS_UNKNOWN
17705
0
         && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17706
0
          op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17707
0
        }
17708
0
      } else {
17709
0
        if (opline->op1_type != IS_CV) {
17710
0
          return false;
17711
0
        }
17712
0
      }
17713
0
      return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17714
0
          (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17715
0
           ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17716
0
    case ZEND_ASSIGN_OBJ_OP:
17717
0
      if (opline->result_type != IS_UNUSED) {
17718
0
        return false;
17719
0
      }
17720
0
      if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17721
0
        return false;
17722
0
      }
17723
0
      ZEND_FALLTHROUGH;
17724
0
    case ZEND_FETCH_OBJ_R:
17725
0
    case ZEND_ASSIGN_OBJ:
17726
0
      if (opline->op2_type != IS_CONST
17727
0
       || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17728
0
       || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17729
0
        return false;
17730
0
      }
17731
0
      op1_info = OP1_INFO();
17732
0
      return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17733
0
  }
17734
0
  return false;
17735
0
}
17736
17737
static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17738
0
{
17739
0
  if (ssa->vars[var].no_val) {
17740
    /* we don't need the value */
17741
0
    return false;
17742
0
  }
17743
17744
0
  if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17745
    /* Disable global register allocation,
17746
     * register allocation for SSA variables connected through Phi functions
17747
     */
17748
0
    if (ssa->vars[var].definition_phi) {
17749
0
      return false;
17750
0
    }
17751
0
    if (ssa->vars[var].phi_use_chain) {
17752
0
      zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17753
0
      do {
17754
0
        if (!ssa->vars[phi->ssa_var].no_val) {
17755
0
          return false;
17756
0
        }
17757
0
        phi = zend_ssa_next_use_phi(ssa, var, phi);
17758
0
      } while (phi);
17759
0
    }
17760
0
  }
17761
17762
0
  if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17763
0
      ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
17764
      /* bad type */
17765
0
    return false;
17766
0
  }
17767
17768
0
  return true;
17769
0
}
17770
17771
static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17772
0
{
17773
0
  if (!zend_jit_var_supports_reg(ssa, var)) {
17774
0
    return false;
17775
0
  }
17776
17777
0
  if (ssa->vars[var].definition >= 0) {
17778
0
    uint32_t def = ssa->vars[var].definition;
17779
0
    if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17780
0
      return false;
17781
0
    }
17782
0
  }
17783
17784
0
  if (ssa->vars[var].use_chain >= 0) {
17785
0
    int use = ssa->vars[var].use_chain;
17786
17787
0
    do {
17788
0
      if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17789
0
          !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17790
0
        return false;
17791
0
      }
17792
0
      use = zend_ssa_next_use(ssa->ops, var, use);
17793
0
    } while (use >= 0);
17794
0
  }
17795
17796
0
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17797
0
    uint32_t def_block, use_block;
17798
0
    int b, use;
17799
0
    uint32_t j;
17800
0
    zend_basic_block *bb;
17801
0
    zend_ssa_phi *p;
17802
0
    bool ret = true;
17803
0
    zend_worklist worklist;
17804
0
    ALLOCA_FLAG(use_heap)
17805
17806
    /* Check if live range is split by ENTRY block */
17807
0
    if (ssa->vars[var].definition >= 0) {
17808
0
      def_block =ssa->cfg.map[ssa->vars[var].definition];
17809
0
    } else {
17810
0
      ZEND_ASSERT(ssa->vars[var].definition_phi);
17811
0
      def_block = ssa->vars[var].definition_phi->block;
17812
0
    }
17813
17814
0
    ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
17815
17816
0
    if (ssa->vars[var].use_chain >= 0) {
17817
0
      use = ssa->vars[var].use_chain;
17818
0
      do {
17819
0
        use_block = ssa->cfg.map[use];
17820
0
        if (use_block != def_block) {
17821
0
          zend_worklist_push(&worklist, use_block);
17822
0
        }
17823
0
        use = zend_ssa_next_use(ssa->ops, var, use);
17824
0
      } while (use >= 0);
17825
0
    }
17826
17827
0
    p = ssa->vars[var].phi_use_chain;
17828
0
    while (p) {
17829
0
      use_block = p->block;
17830
0
      if (use_block != def_block) {
17831
0
        bb = &ssa->cfg.blocks[use_block];
17832
0
        for (j = 0; j < bb->predecessors_count; j++) {
17833
0
          if (p->sources[j] == var) {
17834
0
            use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
17835
0
            if (use_block != def_block) {
17836
0
              zend_worklist_push(&worklist, use_block);
17837
0
            }
17838
0
          }
17839
0
        }
17840
0
      }
17841
0
      p = zend_ssa_next_use_phi(ssa, var, p);
17842
0
    }
17843
17844
0
    while (zend_worklist_len(&worklist) != 0) {
17845
0
      b = zend_worklist_pop(&worklist);
17846
0
      bb = &ssa->cfg.blocks[b];
17847
0
      if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
17848
0
        ret = false;
17849
0
        break;
17850
0
      }
17851
0
      for (j = 0; j < bb->predecessors_count; j++) {
17852
0
        b = ssa->cfg.predecessors[bb->predecessor_offset + j];
17853
0
        if (b != def_block) {
17854
0
          zend_worklist_push(&worklist, b);
17855
0
        }
17856
0
      }
17857
0
    }
17858
17859
0
    ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
17860
17861
0
    return ret;
17862
0
  }
17863
17864
0
  return true;
17865
0
}
17866
17867
0
static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
17868
  // JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
17869
0
  ir_ref observer_handler;
17870
0
  zend_function *fbc = ZEND_FLF_FUNC(opline);
17871
  // Not need for runtime cache or generator checks here, we just need if_unobserved
17872
0
  ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17873
17874
  // Call zend_frameless_observed_call for the main logic.
17875
0
  ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
17876
17877
0
  ir_ref skip = ir_END();
17878
0
  ir_IF_TRUE(if_unobserved);
17879
0
  return skip;
17880
0
}
17881
17882
static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
17883
0
{
17884
0
  jit_SET_EX_OPLINE(jit, opline);
17885
17886
0
  void *function = ZEND_FLF_HANDLER(opline);
17887
0
  zend_jit_addr res_addr = RES_ADDR();
17888
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17889
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17890
17891
0
  ir_ref skip_observer = IR_UNUSED;
17892
0
  if (ZEND_OBSERVER_ENABLED) {
17893
0
    skip_observer = jit_frameless_observer(jit, opline);
17894
0
  }
17895
17896
0
  ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17897
17898
0
  if (skip_observer != IR_UNUSED) {
17899
0
    ir_MERGE_WITH(skip_observer);
17900
0
  }
17901
17902
0
  zend_jit_check_exception(jit);
17903
0
}
17904
17905
static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
17906
0
{
17907
0
  jit_SET_EX_OPLINE(jit, opline);
17908
17909
  /* Avoid dropping RC check in case op escapes. */
17910
0
  if (op1_info & MAY_BE_RC1) {
17911
0
    op1_info |= MAY_BE_RCN;
17912
0
  }
17913
17914
0
  void *function = ZEND_FLF_HANDLER(opline);
17915
0
  zend_jit_addr res_addr = RES_ADDR();
17916
0
  zend_jit_addr op1_addr = OP1_ADDR();
17917
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17918
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17919
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17920
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17921
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
17922
0
    op1_info &= ~MAY_BE_UNDEF;
17923
0
    op1_info |= MAY_BE_NULL;
17924
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17925
0
  }
17926
0
  if (op1_info & MAY_BE_REF) {
17927
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17928
0
  }
17929
17930
0
  ir_ref skip_observer = IR_UNUSED;
17931
0
  if (ZEND_OBSERVER_ENABLED) {
17932
0
    skip_observer = jit_frameless_observer(jit, opline);
17933
0
  }
17934
17935
0
  ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17936
17937
0
  if (skip_observer != IR_UNUSED) {
17938
0
    ir_MERGE_WITH(skip_observer);
17939
0
  }
17940
17941
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17942
0
  zend_jit_check_exception(jit);
17943
0
}
17944
17945
static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
17946
0
{
17947
0
  jit_SET_EX_OPLINE(jit, opline);
17948
17949
  /* Avoid dropping RC check in case op escapes. */
17950
0
  if (op1_info & MAY_BE_RC1) {
17951
0
    op1_info |= MAY_BE_RCN;
17952
0
  }
17953
0
  if (op2_info & MAY_BE_RC1) {
17954
0
    op2_info |= MAY_BE_RCN;
17955
0
  }
17956
17957
0
  void *function = ZEND_FLF_HANDLER(opline);
17958
0
  zend_jit_addr res_addr = RES_ADDR();
17959
0
  zend_jit_addr op1_addr = OP1_ADDR();
17960
0
  zend_jit_addr op2_addr = OP2_ADDR();
17961
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
17962
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
17963
0
  ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
17964
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
17965
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17966
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
17967
0
    op1_info &= ~MAY_BE_UNDEF;
17968
0
    op1_info |= MAY_BE_NULL;
17969
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
17970
0
  }
17971
0
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17972
0
    op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, true);
17973
0
    op2_info &= ~MAY_BE_UNDEF;
17974
0
    op2_info |= MAY_BE_NULL;
17975
0
    op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
17976
0
  }
17977
0
  if (op1_info & MAY_BE_REF) {
17978
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
17979
0
  }
17980
0
  if (op2_info & MAY_BE_REF) {
17981
0
    op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
17982
0
  }
17983
17984
0
  ir_ref skip_observer = IR_UNUSED;
17985
0
  if (ZEND_OBSERVER_ENABLED) {
17986
0
    skip_observer = jit_frameless_observer(jit, opline);
17987
0
  }
17988
17989
0
  ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17990
17991
0
  if (skip_observer != IR_UNUSED) {
17992
0
    ir_MERGE_WITH(skip_observer);
17993
0
  }
17994
17995
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17996
  /* Set OP1 to UNDEF in case FREE_OP2() throws. */
17997
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0
17998
0
   && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
17999
0
   && (op2_info & MAY_BE_RC1)
18000
0
   && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
18001
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
18002
0
    if (JIT_G(current_frame)) {
18003
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18004
0
        EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
18005
0
    }
18006
0
  }
18007
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
18008
0
  zend_jit_check_exception(jit);
18009
0
}
18010
18011
static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, uint32_t op1_data_info)
18012
0
{
18013
0
  jit_SET_EX_OPLINE(jit, opline);
18014
18015
  /* Avoid dropping RC check in case op escapes. */
18016
0
  if (op1_info & MAY_BE_RC1) {
18017
0
    op1_info |= MAY_BE_RCN;
18018
0
  }
18019
0
  if (op2_info & MAY_BE_RC1) {
18020
0
    op2_info |= MAY_BE_RCN;
18021
0
  }
18022
0
  if (op1_data_info & MAY_BE_RC1) {
18023
0
    op1_data_info |= MAY_BE_RCN;
18024
0
  }
18025
18026
0
  void *function = ZEND_FLF_HANDLER(opline);
18027
0
  uint8_t op_data_type = (opline + 1)->op1_type;
18028
0
  zend_jit_addr res_addr = RES_ADDR();
18029
0
  zend_jit_addr op1_addr = OP1_ADDR();
18030
0
  zend_jit_addr op2_addr = OP2_ADDR();
18031
0
  zend_jit_addr op3_addr = OP1_DATA_ADDR();
18032
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
18033
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
18034
0
  ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
18035
0
  ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
18036
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
18037
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
18038
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
18039
0
    op1_info &= ~MAY_BE_UNDEF;
18040
0
    op1_info |= MAY_BE_NULL;
18041
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
18042
0
  }
18043
0
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
18044
0
    op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, true);
18045
0
    op2_info &= ~MAY_BE_UNDEF;
18046
0
    op2_info |= MAY_BE_NULL;
18047
0
    op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
18048
0
  }
18049
0
  if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
18050
0
    op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, true);
18051
0
    op1_data_info &= ~MAY_BE_UNDEF;
18052
0
    op1_data_info |= MAY_BE_NULL;
18053
0
    op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
18054
0
  }
18055
0
  if (op1_info & MAY_BE_REF) {
18056
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
18057
0
  }
18058
0
  if (op2_info & MAY_BE_REF) {
18059
0
    op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
18060
0
  }
18061
0
  if (op1_data_info & MAY_BE_REF) {
18062
0
    op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
18063
0
  }
18064
18065
0
  ir_ref skip_observer = IR_UNUSED;
18066
0
  if (ZEND_OBSERVER_ENABLED) {
18067
0
    skip_observer = jit_frameless_observer(jit, opline);
18068
0
  }
18069
18070
0
  ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
18071
18072
0
  if (skip_observer != IR_UNUSED) {
18073
0
    ir_MERGE_WITH(skip_observer);
18074
0
  }
18075
18076
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
18077
  /* Set OP1 to UNDEF in case FREE_OP2() throws. */
18078
0
  bool op1_undef = false;
18079
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
18080
0
   && (((opline->op2_type & (IS_VAR|IS_TMP_VAR))
18081
0
     && (op2_info & MAY_BE_RC1)
18082
0
     && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
18083
0
    || ((op_data_type & (IS_VAR|IS_TMP_VAR))
18084
0
     && (op1_data_info & MAY_BE_RC1)
18085
0
     && (op1_data_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))))) {
18086
0
      op1_undef = true;
18087
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
18088
0
    if (JIT_G(current_frame)) {
18089
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18090
0
        EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
18091
0
    }
18092
0
  }
18093
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
18094
  /* If OP1 is set to UNDEF, we don't need to set OP2 to UNDEF on free because
18095
   * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
18096
0
  if (!op1_undef
18097
0
   && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
18098
0
   && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0
18099
0
   && (op1_data_info & MAY_BE_RC1)
18100
0
   && (op1_data_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
18101
0
    jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
18102
0
    if (JIT_G(current_frame)) {
18103
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18104
0
        EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
18105
0
    }
18106
0
  }
18107
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
18108
0
  zend_jit_check_exception(jit);
18109
0
}
18110
18111
/*
18112
 * Local variables:
18113
 * tab-width: 4
18114
 * c-basic-offset: 4
18115
 * indent-tabs-mode: t
18116
 * End:
18117
 */