Coverage Report

Created: 2026-10-28 06:20

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
8
# define IR_REG_SP            4 /* IR_REG_RSP */
36
9.93k
# 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
122k
#  define ZREG_FP             12 /* IR_REG_R12 */
41
20.8k
#  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
10.8k
#define ZREG_RX ZREG_IP
79
80
#define OPTIMIZE_FOR_SIZE 0
81
82
/* IR builder defines */
83
#undef  _ir_CTX
84
1.65M
#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
#define ir_CONST_FUNC(_addr)    jit_CONST_FUNC(jit, (uintptr_t)(_addr), 0)
93
6.03k
#define ir_CONST_FC_FUNC(_addr) jit_CONST_FUNC(jit, (uintptr_t)(_addr), IR_FASTCALL_FUNC)
94
#define ir_CAST_FC_FUNC(_addr)  ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
95
  ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_I32))
96
# define ir_CONST_OPCODE_HANDLER_FUNC(_addr) \
97
7.27k
  jit_CONST_OPCODE_HANDLER_FUNC(jit, _addr)
98
# define ir_CAST_OPCODE_HANDLER_FUNC(_addr)  ir_fold2(_ir_CTX, IR_OPT(IR_PROTO, IR_ADDR), (_addr), \
99
  ir_proto_0(_ir_CTX, IR_FASTCALL_FUNC, IR_OPCODE_HANDLER_RET))
100
101
#define ir_CONST_FUNC_PROTO(_addr, _proto) \
102
  ir_const_func_addr(_ir_CTX, (uintptr_t)(_addr), (_proto))
103
104
#undef  ir_ADD_OFFSET
105
#define ir_ADD_OFFSET(_addr, _offset) \
106
67.2k
  jit_ADD_OFFSET(jit, _addr, _offset)
107
108
#ifdef ZEND_ENABLE_ZVAL_LONG64
109
8
# define IR_LONG           IR_I64
110
2.79k
# define ir_CONST_LONG     ir_CONST_I64
111
# define ir_UNARY_OP_L     ir_UNARY_OP_I64
112
1.48k
# define ir_BINARY_OP_L    ir_BINARY_OP_I64
113
8
# define ir_ADD_L          ir_ADD_I64
114
6
# define ir_SUB_L          ir_SUB_I64
115
364
# define ir_MUL_L          ir_MUL_I64
116
0
# define ir_DIV_L          ir_DIV_I64
117
1.21k
# define ir_MOD_L          ir_MOD_I64
118
# define ir_NEG_L          ir_NEG_I64
119
# define ir_ABS_L          ir_ABS_I64
120
# define ir_SEXT_L         ir_SEXT_I64
121
0
# define ir_ZEXT_L         ir_ZEXT_I64
122
# define ir_TRUNC_L        ir_TRUNC_I64
123
0
# define ir_BITCAST_L      ir_BITCAST_I64
124
# define ir_FP2L           ir_FP2I64
125
5
# define ir_ADD_OV_L       ir_ADD_OV_I64
126
4
# define ir_SUB_OV_L       ir_SUB_OV_I64
127
# define ir_MUL_OV_L       ir_MUL_OV_I64
128
# define ir_NOT_L          ir_NOT_I64
129
# define ir_OR_L           ir_OR_I64
130
0
# define ir_AND_L          ir_AND_I64
131
# define ir_XOR_L          ir_XOR_I64
132
126
# define ir_SHL_L          ir_SHL_I64
133
6
# define ir_SHR_L          ir_SHR_I64
134
60
# define ir_SAR_L          ir_SAR_I64
135
# define ir_ROL_L          ir_ROL_I64
136
# define ir_ROR_L          ir_ROR_I64
137
# define ir_MIN_L          ir_MIN_I64
138
# define ir_MAX_L          ir_MAX_I64
139
5.65k
# define ir_LOAD_L         ir_LOAD_I64
140
#else
141
# define IR_LONG           IR_I32
142
# define ir_CONST_LONG     ir_CONST_I32
143
# define ir_UNARY_OP_L     ir_UNARY_OP_I32
144
# define ir_BINARY_OP_L    ir_BINARY_OP_I32
145
# define ir_ADD_L          ir_ADD_I32
146
# define ir_SUB_L          ir_SUB_I32
147
# define ir_MUL_L          ir_MUL_I32
148
# define ir_DIV_L          ir_DIV_I32
149
# define ir_MOD_L          ir_MOD_I32
150
# define ir_NEG_L          ir_NEG_I32
151
# define ir_ABS_L          ir_ABS_I32
152
# define ir_SEXT_L         ir_SEXT_I32
153
# define ir_ZEXT_L         ir_ZEXT_I32
154
# define ir_TRUNC_L        ir_TRUNC_I32
155
# define ir_BITCAST_L      ir_BITCAST_I32
156
# define ir_FP2L           ir_FP2I32
157
# define ir_ADD_OV_L       ir_ADD_OV_I32
158
# define ir_SUB_OV_L       ir_SUB_OV_I32
159
# define ir_MUL_OV_L       ir_MUL_OV_I32
160
# define ir_NOT_L          ir_NOT_I32
161
# define ir_OR_L           ir_OR_I32
162
# define ir_AND_L          ir_AND_I32
163
# define ir_XOR_L          ir_XOR_I32
164
# define ir_SHL_L          ir_SHL_I32
165
# define ir_SHR_L          ir_SHR_I32
166
# define ir_SAR_L          ir_SAR_I32
167
# define ir_ROL_L          ir_ROL_I32
168
# define ir_ROR_L          ir_ROR_I32
169
# define ir_MIN_L          ir_MIN_I32
170
# define ir_MAX_L          ir_MAX_I32
171
# define ir_LOAD_L         ir_LOAD_I32
172
#endif
173
174
/* A helper structure to collect IT rers for the following use in (MERGE/PHI)_N */
175
typedef struct _ir_refs {
176
  uint32_t count;
177
  uint32_t limit;
178
  ir_ref   refs[] ZEND_ELEMENT_COUNT(count);
179
} ir_refs;
180
181
#define ir_refs_size(_n)          (offsetof(ir_refs, refs) + sizeof(ir_ref) * (_n))
182
11.1k
#define ir_refs_init(_name, _n)   _name = alloca(ir_refs_size(_n)); \
183
11.1k
                                  do {_name->count = 0; _name->limit = (_n);} while (0)
184
185
static void ir_refs_add(ir_refs *refs, ir_ref ref)
186
13.9k
{
187
13.9k
  ir_ref *ptr;
188
189
13.9k
  ZEND_ASSERT(refs->count < refs->limit);
190
13.9k
  ptr = refs->refs;
191
13.9k
  ptr[refs->count++] = ref;
192
13.9k
}
193
194
static size_t zend_jit_trace_prologue_size = (size_t)-1;
195
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
196
static uint32_t allowed_opt_flags = 0;
197
static uint32_t default_mflags = 0;
198
#endif
199
static bool delayed_call_chain = false; // TODO: remove this var (use jit->delayed_call_level) ???
200
201
#ifdef ZTS
202
static size_t tsrm_ls_cache_tcb_offset = 0;
203
static size_t tsrm_tls_index = -1;
204
static size_t tsrm_tls_offset = -1;
205
206
# define EG_TLS_OFFSET(field) \
207
  (executor_globals_offset + offsetof(zend_executor_globals, field))
208
209
# define CG_TLS_OFFSET(field) \
210
  (compiler_globals_offset + offsetof(zend_compiler_globals, field))
211
212
# define jit_EG(_field) \
213
  ir_ADD_OFFSET(jit_TLS(jit), EG_TLS_OFFSET(_field))
214
215
# define jit_CG(_field) \
216
  ir_ADD_OFFSET(jit_TLS(jit), CG_TLS_OFFSET(_field))
217
218
#else
219
220
# define jit_EG(_field) \
221
6.78k
  ir_CONST_ADDR(&EG(_field))
222
223
# define jit_CG(_field) \
224
  ir_CONST_ADDR(&CG(_field))
225
226
#endif
227
228
#define jit_CALL(_call, _field) \
229
62
  ir_ADD_OFFSET(_call, offsetof(zend_execute_data, _field))
230
231
#define jit_EX(_field) \
232
  jit_CALL(jit_FP(jit), _field)
233
234
#define jit_RX(_field) \
235
  jit_CALL(jit_IP(jit), _field)
236
237
#define JIT_STUBS(_) \
238
  _(exception_handler,              IR_SKIP_PROLOGUE) \
239
  _(exception_handler_undef,        IR_SKIP_PROLOGUE) \
240
  _(exception_handler_free_op2,     IR_SKIP_PROLOGUE) \
241
  _(exception_handler_free_op1_op2, IR_SKIP_PROLOGUE) \
242
  _(interrupt_handler,              IR_SKIP_PROLOGUE) \
243
  _(leave_function_handler,         IR_SKIP_PROLOGUE) \
244
  _(negative_shift,                 IR_SKIP_PROLOGUE) \
245
  _(mod_by_zero,                    IR_SKIP_PROLOGUE) \
246
  _(invalid_this,                   IR_SKIP_PROLOGUE) \
247
  _(undefined_function,             IR_SKIP_PROLOGUE) \
248
  _(throw_cannot_pass_by_ref,       IR_SKIP_PROLOGUE) \
249
  _(icall_throw,                    IR_SKIP_PROLOGUE) \
250
  _(leave_throw,                    IR_SKIP_PROLOGUE) \
251
  _(hybrid_runtime_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
252
  _(hybrid_profile_jit,             IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
253
  _(hybrid_func_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
254
  _(hybrid_loop_hot_counter,        IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
255
  _(hybrid_func_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
256
  _(hybrid_ret_trace_counter,       IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
257
  _(hybrid_loop_trace_counter,      IR_SKIP_PROLOGUE | IR_START_BR_TARGET) \
258
  _(trace_halt,                     IR_SKIP_PROLOGUE) \
259
  _(trace_escape,                   IR_SKIP_PROLOGUE) \
260
  _(trace_exit,                     IR_SKIP_PROLOGUE) \
261
  _(undefined_offset,               IR_FUNCTION | IR_FASTCALL_FUNC) \
262
  _(undefined_key,                  IR_FUNCTION | IR_FASTCALL_FUNC) \
263
  _(cannot_add_element,             IR_FUNCTION | IR_FASTCALL_FUNC) \
264
  _(assign_const,                   IR_FUNCTION | IR_FASTCALL_FUNC) \
265
  _(assign_tmp,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
266
  _(assign_var,                     IR_FUNCTION | IR_FASTCALL_FUNC) \
267
  _(assign_cv_noref,                IR_FUNCTION | IR_FASTCALL_FUNC) \
268
  _(assign_cv,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
269
  _(new_array,                      IR_FUNCTION | IR_FASTCALL_FUNC) \
270
271
#define JIT_STUB_ID(name, flags) \
272
  jit_stub_ ## name,
273
274
#define JIT_STUB_FORWARD(name, flags) \
275
  static int zend_jit_ ## name ## _stub(zend_jit_ctx *jit);
276
277
#define JIT_STUB(name, flags) \
278
  {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, flags},
279
280
typedef enum _jit_stub_id {
281
  JIT_STUBS(JIT_STUB_ID)
282
  jit_last_stub
283
} jit_stub_id;
284
285
typedef struct _zend_jit_reg_var {
286
  ir_ref   ref;
287
  uint32_t flags;
288
} zend_jit_reg_var;
289
290
typedef struct _zend_jit_ctx {
291
  ir_ctx               ctx;
292
  const zend_op       *last_valid_opline;
293
  bool                 use_last_valid_opline;
294
  bool                 track_last_valid_opline;
295
  bool                 reuse_ip;
296
  uint32_t             delayed_call_level;
297
  int                  b;           /* current basic block number or -1 */
298
#ifdef ZTS
299
  ir_ref               tls;
300
#endif
301
  ir_ref               fp;
302
  ir_ref               poly_func_ref; /* restored from parent trace snapshot */
303
  ir_ref               poly_this_ref; /* restored from parent trace snapshot */
304
  ir_ref               trace_loop_ref;
305
  ir_ref               return_inputs;
306
  const zend_op_array *op_array;
307
  const zend_op_array *current_op_array;
308
  zend_ssa            *ssa;
309
  zend_string         *name;
310
  ir_ref              *bb_start_ref;      /* PHP BB -> IR ref mapping */
311
  ir_ref              *bb_predecessors;   /* PHP BB -> index in bb_edges -> IR refs of predessors */
312
  ir_ref              *bb_edges;
313
  zend_jit_trace_info *trace;
314
  zend_jit_reg_var    *ra;
315
  int                  delay_var;
316
  ir_refs             *delay_refs;
317
  ir_ref               eg_exception_addr;
318
  ir_ref               stub_addr[jit_last_stub];
319
} zend_jit_ctx;
320
321
typedef int8_t zend_reg;
322
323
typedef struct _zend_jit_registers_buf {
324
#if defined(IR_TARGET_X64)
325
  uint64_t gpr[16]; /* general purpose integer register */
326
  double   fpr[16]; /* floating point registers */
327
#elif defined(IR_TARGET_X86)
328
  uint32_t gpr[8]; /* general purpose integer register */
329
  double   fpr[8]; /* floating point registers */
330
#elif defined (IR_TARGET_AARCH64)
331
  uint64_t gpr[32]; /* general purpose integer register */
332
  double   fpr[32]; /* floating point registers */
333
#else
334
# error "Unknown IR target"
335
#endif
336
} zend_jit_registers_buf;
337
338
/* Keep 32 exit points in a single code block */
339
6.96k
#define ZEND_JIT_EXIT_POINTS_SPACING   4  // push byte + short jmp = bytes
340
13.9k
#define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points
341
342
static uint32_t zend_jit_exit_point_by_addr(const void *addr);
343
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs);
344
345
static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
346
                                       const zend_op  *opline,
347
                                       zend_jit_addr   var_use_addr,
348
                                       zend_jit_addr   var_addr,
349
                                       uint32_t        var_info,
350
                                       uint32_t        var_def_info,
351
                                       uint8_t         val_type,
352
                                       zend_jit_addr   val_addr,
353
                                       uint32_t        val_info,
354
                                       zend_jit_addr   res_addr,
355
                                       zend_jit_addr   ref_addr,
356
                                       bool       check_exception);
357
358
static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags);
359
360
static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset);
361
362
static void zend_jit_preserve_parent_regs(zend_jit_ctx *jit,
363
                                          zend_ssa *ssa,
364
                                          zend_jit_trace_info *parent,
365
                                          uint32_t exit_num);
366
367
typedef struct _zend_jit_stub {
368
  const char *name;
369
  int (*stub)(zend_jit_ctx *jit);
370
  uint32_t flags;
371
} zend_jit_stub;
372
373
JIT_STUBS(JIT_STUB_FORWARD)
374
375
static const zend_jit_stub zend_jit_stubs[] = {
376
  JIT_STUBS(JIT_STUB)
377
};
378
379
#if defined(_WIN32) || defined(IR_TARGET_AARCH64)
380
/* We keep addresses in SHM to share them between sepaeate processes (on Windows) or to support veneers (on AArch64) */
381
static void** zend_jit_stub_handlers = NULL;
382
#else
383
static void* zend_jit_stub_handlers[sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])];
384
#endif
385
386
#if defined(IR_TARGET_AARCH64)
387
388
# ifdef __FreeBSD__
389
/* https://github.com/freebsd/freebsd-src/blob/c52ca7dd09066648b1cc40f758289404d68ab886/libexec/rtld-elf/aarch64/reloc.c#L180-L184 */
390
typedef struct TLSDescriptor {
391
  void*   thunk;
392
  int     index;
393
  size_t  offset;
394
} TLSDescriptor;
395
# endif
396
397
#define IR_HAS_VENEERS (1U<<31) /* IR_RESERVED_FLAG_1 */
398
399
static const void *zend_jit_get_veneer(ir_ctx *ctx, const void *addr)
400
{
401
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
402
403
  for (i = 0; i < count; i++) {
404
    if (zend_jit_stub_handlers[i] == addr) {
405
      return zend_jit_stub_handlers[count + i];
406
    }
407
  }
408
409
  if (((zend_jit_ctx*)ctx)->trace
410
   && (void*)addr >= dasm_buf && (void*)addr < dasm_end) {
411
    uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
412
413
    if (exit_point != (uint32_t)-1) {
414
      zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
415
416
      ZEND_ASSERT(exit_point < t->exit_count);
417
      return (const void*)((char*)ctx->deoptimization_exits_base + (exit_point * 4));
418
    }
419
  }
420
421
  return NULL;
422
}
423
424
static bool zend_jit_set_veneer(ir_ctx *ctx, const void *addr, const void *veneer)
425
{
426
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
427
  uint32_t exit_point = zend_jit_exit_point_by_addr(addr);
428
429
  if (exit_point != (uint32_t)-1) {
430
    return true;
431
  }
432
  for (i = 0; i < count; i++) {
433
    if (zend_jit_stub_handlers[i] == addr) {
434
      const void **ptr = (const void**)&zend_jit_stub_handlers[count + i];
435
      *ptr = veneer;
436
      ctx->flags2 |= IR_HAS_VENEERS;
437
#ifdef HAVE_CAPSTONE
438
      int64_t offset;
439
        if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
440
        const char *name = ir_disasm_find_symbol((uint64_t)(uintptr_t)addr, &offset);
441
442
        if (name && !offset) {
443
          if (strstr(name, "@veneer") == NULL) {
444
            char *new_name;
445
446
            zend_spprintf(&new_name, 0, "%s@veneer", name);
447
            ir_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4);
448
            efree(new_name);
449
          } else {
450
            ir_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4);
451
          }
452
        }
453
      }
454
#endif
455
      return true;
456
    }
457
  }
458
459
  return false;
460
}
461
462
static void zend_jit_commit_veneers(void)
463
{
464
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
465
466
  for (i = 0; i < count; i++) {
467
    if (zend_jit_stub_handlers[count + i]) {
468
      zend_jit_stub_handlers[i] = zend_jit_stub_handlers[count + i];
469
      zend_jit_stub_handlers[count + i] = NULL;
470
    }
471
  }
472
}
473
474
static void zend_jit_discard_veneers(void)
475
{
476
  int i, count = sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
477
478
  for (i = 0; i < count; i++) {
479
    zend_jit_stub_handlers[count + i] = NULL;
480
  }
481
}
482
#endif
483
484
static bool zend_jit_prefer_const_addr_load(zend_jit_ctx *jit, uintptr_t addr)
485
3
{
486
#if defined(IR_TARGET_X86)
487
  return false; /* always use immediate value */
488
#elif defined(IR_TARGET_X64)
489
  return addr > 0xffffffff; /* prefer loading long constant from memory */
490
#elif defined(IR_TARGET_AARCH64)
491
  return addr > 0xffff;
492
#else
493
# error "Unknown IR target"
494
#endif
495
3
}
496
497
static const char* zend_reg_name(int8_t reg)
498
0
{
499
0
  return ir_reg_name(reg, ir_reg_is_int(reg) ? IR_LONG : IR_DOUBLE);
500
0
}
501
502
/* IR helpers */
503
504
#ifdef ZTS
505
static void * ZEND_FASTCALL zend_jit_get_tsrm_ls_cache(void)
506
{
507
  return _tsrm_ls_cache;
508
}
509
510
static ir_ref jit_TLS(zend_jit_ctx *jit)
511
{
512
  ZEND_ASSERT(jit->ctx.control);
513
  if (jit->tls) {
514
    /* Emit "TLS" once for basic block */
515
    ir_insn *insn;
516
    ir_ref ref = jit->ctx.control;
517
518
    while (1) {
519
      if (ref == jit->tls) {
520
        return jit->tls;
521
      }
522
      insn = &jit->ctx.ir_base[ref];
523
      if (insn->op >= IR_START || insn->op == IR_CALL) {
524
        break;
525
      }
526
      ref = insn->op1;
527
    }
528
  }
529
530
  if (tsrm_ls_cache_tcb_offset == 0 && tsrm_tls_index == -1) {
531
    jit->tls = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_tsrm_ls_cache));
532
  } else {
533
# ifdef ZEND_OPCACHE_SHM_REATTACHMENT
534
    /* Different processes may load TLS variables in a different order, so
535
     * they may have a different module index. Fetch the module index at
536
     * runtime from tsrm_tls_index. Its address is stable as it's in the same
537
     * module as execute_ex (whose address is checked before SHM reattachment). */
538
539
#  ifdef _WIN64
540
    const int offset = 0x58;
541
#  else
542
    const int offset = 0x2c;
543
#  endif
544
545
    /* NtCurrentTeb()->ThreadLocalStoragePointer */
546
    ir_ref tls_array = ir_TLS(-1, offset);
547
548
    ir_ref index = ir_LOAD_A(ir_CONST_ADDR(&tsrm_tls_index));
549
    jit->tls = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(ir_ADD_A(tls_array, index)), tsrm_tls_offset));
550
# else
551
    jit->tls = ir_TLS(
552
        tsrm_ls_cache_tcb_offset ? tsrm_ls_cache_tcb_offset : tsrm_tls_index,
553
        tsrm_ls_cache_tcb_offset ? IR_NULL : tsrm_tls_offset);
554
# endif
555
  }
556
557
  return jit->tls;
558
}
559
#endif
560
561
static ir_ref jit_CONST_FUNC(zend_jit_ctx *jit, uintptr_t addr, uint16_t flags)
562
88.1k
{
563
#if defined(IR_TARGET_X86)
564
  /* TODO: dummy prototype (only flags matter) ??? */
565
  ir_ref proto = flags ? ir_proto_0(&jit->ctx, flags, IR_I32) : 0;
566
#else
567
88.1k
  ir_ref proto = 0;
568
88.1k
#endif
569
570
88.1k
  return ir_const_func_addr(&jit->ctx, addr, proto);
571
88.1k
}
572
573
static ir_ref jit_CONST_OPCODE_HANDLER_FUNC(zend_jit_ctx *jit, zend_vm_opcode_handler_t handler)
574
7.27k
{
575
7.27k
  return jit_CONST_FUNC(jit, (uintptr_t)handler, IR_FASTCALL_FUNC);
576
7.27k
}
577
578
static ir_ref jit_ADD_OFFSET(zend_jit_ctx *jit, ir_ref addr, uintptr_t offset)
579
263k
{
580
263k
  if (offset) {
581
214k
    addr = ir_ADD_A(addr, ir_CONST_ADDR(offset));
582
214k
  }
583
263k
  return addr;
584
263k
}
585
586
static ir_ref jit_EG_exception(zend_jit_ctx *jit)
587
32.0k
{
588
#ifdef ZTS
589
  return jit_EG(exception);
590
#else
591
32.0k
  ir_ref ref = jit->eg_exception_addr;
592
593
32.0k
  if (UNEXPECTED(!ref)) {
594
9.11k
    ref = ir_CONST_ADDR(&EG(exception));
595
9.11k
    jit->eg_exception_addr = ref;
596
9.11k
  }
597
32.0k
  return ref;
598
32.0k
#endif
599
32.0k
}
600
601
static ir_ref jit_STUB_ADDR(zend_jit_ctx *jit, jit_stub_id id)
602
47.1k
{
603
47.1k
  ir_ref ref = jit->stub_addr[id];
604
605
47.1k
  if (UNEXPECTED(!ref)) {
606
20.4k
    ref = ir_CONST_ADDR(zend_jit_stub_handlers[id]);
607
20.4k
    jit->stub_addr[id] = ref;
608
20.4k
  }
609
47.1k
  return ref;
610
47.1k
}
611
612
static ir_ref jit_STUB_FUNC_ADDR(zend_jit_ctx *jit, jit_stub_id id, uint16_t flags)
613
941
{
614
941
  ir_ref ref = jit->stub_addr[id];
615
616
941
  if (UNEXPECTED(!ref)) {
617
718
    ref = jit_CONST_FUNC(jit, (uintptr_t)zend_jit_stub_handlers[id], flags);
618
718
    jit->stub_addr[id] = ref;
619
718
  }
620
941
  return ref;
621
941
}
622
623
static void jit_SNAPSHOT(zend_jit_ctx *jit, ir_ref addr)
624
44.8k
{
625
44.8k
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) {
626
9.03k
    const void *ptr = (const void*)jit->ctx.ir_base[addr].val.addr;
627
9.03k
    const zend_op_array *op_array = &JIT_G(current_frame)->func->op_array;
628
9.03k
    uint32_t stack_size = op_array->last_var + op_array->T;
629
630
9.03k
    if (ptr == zend_jit_stub_handlers[jit_stub_exception_handler]
631
4.94k
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_undef]
632
4.79k
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op1_op2]
633
4.79k
       || ptr == zend_jit_stub_handlers[jit_stub_exception_handler_free_op2]
634
4.74k
       || ptr == zend_jit_stub_handlers[jit_stub_interrupt_handler]
635
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_leave_function_handler]
636
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_negative_shift]
637
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_mod_by_zero]
638
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_invalid_this]
639
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_undefined_function]
640
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_throw_cannot_pass_by_ref]
641
4.71k
       || ptr == zend_jit_stub_handlers[jit_stub_icall_throw]
642
4.53k
       || ptr == zend_jit_stub_handlers[jit_stub_leave_throw]
643
4.52k
       || ptr == zend_jit_stub_handlers[jit_stub_trace_halt]
644
6.87k
       || ptr == zend_jit_stub_handlers[jit_stub_trace_escape]) {
645
      /* This is a GUARD that trigger exit through a stub code (without deoptimization) */
646
6.87k
      return;
647
6.87k
    }
648
649
    /* Check if we need snapshot entries for polymorphic method call */
650
2.15k
    zend_jit_trace_info *t = jit->trace;
651
2.15k
    uint32_t exit_point = 0, n = 0;
652
653
2.15k
    if (addr < 0) {
654
      /* addr is not always the address of the *last* exit point,
655
       * so we can not optimize this to 'exit_point = t->exit_count-1' */
656
2.15k
      exit_point = zend_jit_exit_point_by_addr(ptr);
657
2.15k
      ZEND_ASSERT(exit_point != -1);
658
2.15k
      if (t->exit_info[exit_point].flags & ZEND_JIT_EXIT_METHOD_CALL) {
659
2
        n = 2;
660
2
      }
661
2.15k
    }
662
663
2.15k
    if (stack_size || n) {
664
1.87k
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
665
1.87k
      uint32_t snapshot_size, i;
666
667
1.87k
      snapshot_size = stack_size;
668
8.71k
      while (snapshot_size > 0) {
669
7.03k
        ir_ref ref = STACK_REF(stack, snapshot_size - 1);
670
671
7.03k
        if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, snapshot_size - 1) & (/*ZREG_LOAD|*/ZREG_STORE))) {
672
6.84k
          snapshot_size--;
673
6.84k
        } else {
674
186
          break;
675
186
        }
676
7.03k
      }
677
1.87k
      if (snapshot_size || n) {
678
188
        ir_ref snapshot;
679
680
188
        snapshot = ir_SNAPSHOT(snapshot_size + n);
681
779
        for (i = 0; i < snapshot_size; i++) {
682
591
          ir_ref ref = STACK_REF(stack, i);
683
684
591
          if (!ref || ref == IR_NULL || (STACK_FLAGS(stack, i) & (/*ZREG_LOAD|*/ZREG_STORE))) {
685
382
            ref = IR_UNUSED;
686
382
          }
687
591
          ir_SNAPSHOT_SET_OP(snapshot, i + 1, ref);
688
591
        }
689
188
        if (n) {
690
2
          ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 1, t->exit_info[exit_point].poly_func.ref);
691
2
          ir_SNAPSHOT_SET_OP(snapshot, snapshot_size + 2, t->exit_info[exit_point].poly_this.ref);
692
2
        }
693
188
      }
694
1.87k
    }
695
2.15k
  }
696
44.8k
}
697
698
static int32_t _add_trace_const(zend_jit_trace_info *t, int64_t val)
699
34
{
700
34
  int32_t i;
701
702
36
  for (i = 0; i < t->consts_count; i++) {
703
13
    if (t->constants[i].i == val) {
704
11
      return i;
705
11
    }
706
13
  }
707
23
  ZEND_ASSERT(i < 0x7fffffff);
708
23
  t->consts_count = i + 1;
709
23
  t->constants = erealloc(t->constants, (i + 1) * sizeof(zend_jit_exit_const));
710
23
  t->constants[i].i = val;
711
23
  return i;
712
23
}
713
714
uint32_t zend_jit_duplicate_exit_point(ir_ctx *ctx, zend_jit_trace_info *t, uint32_t exit_point, ir_ref snapshot_ref)
715
0
{
716
0
  uint32_t stack_size, stack_offset;
717
0
  uint32_t new_exit_point = t->exit_count;
718
719
0
  if (new_exit_point >= ZEND_JIT_TRACE_MAX_EXITS) {
720
0
    ctx->status = -ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
721
0
    return exit_point;
722
0
  }
723
724
0
  t->exit_count++;
725
0
  memcpy(&t->exit_info[new_exit_point], &t->exit_info[exit_point], sizeof(zend_jit_trace_exit_info));
726
0
  stack_size = t->exit_info[new_exit_point].stack_size;
727
0
  if (stack_size != 0) {
728
0
    stack_offset = t->stack_map_size;
729
0
    t->stack_map_size += stack_size;
730
    // TODO: reduce number of reallocations ???
731
0
    t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
732
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));
733
0
    t->exit_info[new_exit_point].stack_offset = stack_offset;
734
0
  }
735
0
  t->exit_info[new_exit_point].flags &= ~ZEND_JIT_EXIT_FIXED;
736
737
0
  return new_exit_point;
738
0
}
739
740
static void zend_jit_resolve_ref_snapshot(zend_jit_ref_snapshot *dest, ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, int op)
741
4
{
742
4
  int8_t *reg_ops = ctx->regs[snapshot_ref];
743
4
  ZEND_ASSERT(reg_ops[op] != ZREG_NONE);
744
745
4
  int8_t reg = reg_ops[op];
746
4
  int32_t offset;
747
748
4
  if (IR_REG_SPILLED(reg)) {
749
0
    reg = ((ctx->flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP) | IR_REG_SPILL_LOAD;
750
0
    offset = ir_get_spill_slot_offset(ctx, ir_insn_op(snapshot, op));
751
4
  } else {
752
4
    offset = 0;
753
4
  }
754
755
4
  dest->reg = reg;
756
4
  dest->offset = offset;
757
4
}
758
759
static bool zend_jit_ref_snapshot_equals(const zend_jit_ref_snapshot *a, const zend_jit_ref_snapshot *b)
760
0
{
761
0
  return a->reg == b->reg
762
0
    && (!IR_REG_SPILLED(a->reg) || (a->offset == b->offset));
763
0
}
764
765
void *zend_jit_snapshot_handler(ir_ctx *ctx, ir_ref snapshot_ref, ir_insn *snapshot, void *addr)
766
188
{
767
188
  zend_jit_trace_info *t = ((zend_jit_ctx*)ctx)->trace;
768
188
  uint32_t exit_point, exit_flags;
769
188
  ir_ref n = snapshot->inputs_count;
770
188
  ir_ref i;
771
772
188
  exit_point = zend_jit_exit_point_by_addr(addr);
773
188
  ZEND_ASSERT(exit_point < t->exit_count);
774
188
  exit_flags = t->exit_info[exit_point].flags;
775
776
188
  if (exit_flags & ZEND_JIT_EXIT_METHOD_CALL) {
777
2
    zend_jit_ref_snapshot func, this;
778
2
    zend_jit_resolve_ref_snapshot(&func, ctx, snapshot_ref, snapshot, n - 1);
779
2
    zend_jit_resolve_ref_snapshot(&this, ctx, snapshot_ref, snapshot, n);
780
781
2
    if ((exit_flags & ZEND_JIT_EXIT_FIXED)
782
0
     && (!zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_func, &func)
783
0
       || !zend_jit_ref_snapshot_equals(&t->exit_info[exit_point].poly_this, &this))) {
784
0
      exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
785
0
      addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
786
0
      exit_flags &= ~ZEND_JIT_EXIT_FIXED;
787
0
    }
788
2
    t->exit_info[exit_point].poly_func = func;
789
2
    t->exit_info[exit_point].poly_this = this;
790
2
    n -= 2;
791
2
  }
792
793
779
  for (i = 2; i <= n; i++) {
794
591
    ir_ref ref = ir_insn_op(snapshot, i);
795
796
591
    if (ref) {
797
209
      int8_t *reg_ops = ctx->regs[snapshot_ref];
798
209
      int8_t reg = reg_ops[i];
799
209
      ir_ref var = i - 2;
800
801
209
      ZEND_ASSERT(var < t->exit_info[exit_point].stack_size);
802
209
      if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags == ZREG_ZVAL_COPY) {
803
8
        ZEND_ASSERT(reg != ZREG_NONE);
804
8
        if ((exit_flags & ZEND_JIT_EXIT_FIXED)
805
0
         && t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)) {
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
8
        t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
811
201
      } else if (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_CONST) {
812
201
        ZEND_ASSERT(t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_LONG ||
813
201
          t->stack_map[t->exit_info[exit_point].stack_offset + var].type == IS_DOUBLE);
814
815
201
        if (ref > 0) {
816
167
          if (reg != ZREG_NONE) {
817
167
            if (reg & IR_REG_SPILL_LOAD) {
818
4
              ZEND_ASSERT(!(reg & IR_REG_SPILL_SPECIAL));
819
              /* spill slot on a CPU stack */
820
4
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
821
0
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].ref != ref
822
0
                || t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
823
0
                || !(t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ZREG_SPILL_SLOT))) {
824
0
                exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
825
0
                addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
826
0
                exit_flags &= ~ZEND_JIT_EXIT_FIXED;
827
0
              }
828
4
              t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = ref;
829
4
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
830
4
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags |= ZREG_SPILL_SLOT;
831
163
            } else if (reg & IR_REG_SPILL_SPECIAL) {
832
              /* spill slot on a VM stack */
833
0
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
834
0
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
835
0
               || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
836
0
                exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
837
0
                addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
838
0
                exit_flags &= ~ZEND_JIT_EXIT_FIXED;
839
0
              }
840
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
841
0
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
842
163
            } else {
843
163
              if ((exit_flags & ZEND_JIT_EXIT_FIXED)
844
13
               && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != IR_REG_NUM(reg)
845
13
               || (t->stack_map[t->exit_info[exit_point].stack_offset + var].flags & ~(ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE)))) {
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
163
              t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = IR_REG_NUM(reg);
851
163
              t->stack_map[t->exit_info[exit_point].stack_offset + var].flags &= (ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE);
852
163
            }
853
167
          } else {
854
0
            if ((exit_flags & ZEND_JIT_EXIT_FIXED)
855
0
             && (t->stack_map[t->exit_info[exit_point].stack_offset + var].reg != ZREG_NONE
856
0
             || t->stack_map[t->exit_info[exit_point].stack_offset + var].flags != ZREG_TYPE_ONLY)) {
857
0
              exit_point = zend_jit_duplicate_exit_point(ctx, t, exit_point, snapshot_ref);
858
0
              addr = (void*)zend_jit_trace_get_exit_addr(exit_point);
859
0
              exit_flags &= ~ZEND_JIT_EXIT_FIXED;
860
0
            }
861
0
            t->stack_map[t->exit_info[exit_point].stack_offset + var].reg = ZREG_NONE;
862
0
            t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_TYPE_ONLY;
863
0
          }
864
167
        } else if (!(exit_flags & ZEND_JIT_EXIT_FIXED)) {
865
34
          int32_t idx = _add_trace_const(t, ctx->ir_base[ref].val.i64);
866
34
          t->stack_map[t->exit_info[exit_point].stack_offset + var].flags = ZREG_CONST;
867
34
          t->stack_map[t->exit_info[exit_point].stack_offset + var].ref = idx;
868
34
        }
869
201
      }
870
209
    }
871
591
  }
872
188
  t->exit_info[exit_point].flags |= ZEND_JIT_EXIT_FIXED;
873
188
  return addr;
874
188
}
875
876
static void jit_SIDE_EXIT(zend_jit_ctx *jit, ir_ref addr)
877
6
{
878
6
  jit_SNAPSHOT(jit, addr);
879
6
  ir_IJMP(addr);
880
6
}
881
882
/* PHP JIT helpers */
883
884
static ir_ref jit_EMALLOC(zend_jit_ctx *jit, size_t size, const zend_op_array *op_array, const zend_op *opline)
885
49
{
886
49
#if ZEND_DEBUG
887
49
  return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_emalloc),
888
49
    ir_CONST_ADDR(size),
889
49
    op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
890
49
    ir_CONST_U32(opline ? opline->lineno : 0),
891
49
    IR_NULL,
892
49
    ir_CONST_U32(0));
893
#elif defined(HAVE_BUILTIN_CONSTANT_P)
894
  if (size > 24 && size <= 32) {
895
    return ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_emalloc_32));
896
  } else {
897
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
898
  }
899
#else
900
  return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_emalloc), ir_CONST_ADDR(size));
901
#endif
902
49
}
903
904
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)
905
58
{
906
58
#if ZEND_DEBUG
907
58
  return ir_CALL_5(IR_ADDR, ir_CONST_FC_FUNC(_efree),
908
58
    ptr,
909
58
    op_array && op_array->filename ? ir_CONST_ADDR(op_array->filename->val) : IR_NULL,
910
58
    ir_CONST_U32(opline ? opline->lineno : 0),
911
58
    IR_NULL,
912
58
    ir_CONST_U32(0));
913
#elif defined(HAVE_BUILTIN_CONSTANT_P)
914
  if (size > 24 && size <= 32) {
915
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree_32), ptr);
916
  } else {
917
    return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
918
  }
919
#else
920
  return ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(_efree), ptr);
921
#endif
922
58
}
923
924
static ir_ref jit_FP(zend_jit_ctx *jit)
925
163k
{
926
163k
  ZEND_ASSERT(jit->ctx.control);
927
163k
  if (jit->fp == IR_UNUSED) {
928
    /* Emit "RLOAD FP" once for basic block */
929
12.8k
    jit->fp = ir_RLOAD_A(ZREG_FP);
930
150k
  } else {
931
150k
    ir_insn *insn;
932
150k
    ir_ref ref = jit->ctx.control;
933
934
352k
    while (1) {
935
352k
      if (ref == jit->fp) {
936
44.0k
        break;
937
44.0k
      }
938
308k
      insn = &jit->ctx.ir_base[ref];
939
308k
      if (insn->op >= IR_START || insn->op == IR_CALL) {
940
106k
        jit->fp = ir_RLOAD_A(ZREG_FP);
941
106k
        break;
942
106k
      }
943
202k
      ref = insn->op1;
944
202k
    }
945
150k
  }
946
163k
  return jit->fp;
947
163k
}
948
949
static void jit_STORE_FP(zend_jit_ctx *jit, ir_ref ref)
950
5.69k
{
951
5.69k
  ir_RSTORE(ZREG_FP, ref);
952
5.69k
  jit->fp = IR_UNUSED;
953
5.69k
}
954
955
static ir_ref jit_IP(zend_jit_ctx *jit)
956
77.3k
{
957
77.3k
  return ir_RLOAD_A(ZREG_IP);
958
77.3k
}
959
960
static void jit_STORE_IP(zend_jit_ctx *jit, ir_ref ref)
961
49.4k
{
962
49.4k
  ir_RSTORE(ZREG_IP, ref);
963
49.4k
}
964
965
static ir_ref jit_IP32(zend_jit_ctx *jit)
966
486
{
967
486
  return ir_RLOAD_U32(ZREG_IP);
968
486
}
969
970
static void jit_LOAD_IP_ADDR(zend_jit_ctx *jit, const zend_op *target)
971
7.01k
{
972
7.01k
  jit_STORE_IP(jit, ir_CONST_ADDR(target));
973
7.01k
}
974
975
static void zend_jit_track_last_valid_opline(zend_jit_ctx *jit)
976
2.48k
{
977
2.48k
  jit->use_last_valid_opline = false;
978
2.48k
  jit->track_last_valid_opline = true;
979
2.48k
}
980
981
static void zend_jit_use_last_valid_opline(zend_jit_ctx *jit)
982
41.1k
{
983
41.1k
  if (jit->track_last_valid_opline) {
984
21.7k
    jit->use_last_valid_opline = true;
985
21.7k
    jit->track_last_valid_opline = false;
986
21.7k
  }
987
41.1k
}
988
989
static bool zend_jit_trace_uses_initial_ip(zend_jit_ctx *jit)
990
2.49k
{
991
2.49k
  return jit->use_last_valid_opline;
992
2.49k
}
993
994
static void zend_jit_set_last_valid_opline(zend_jit_ctx *jit, const zend_op *opline)
995
50.1k
{
996
50.1k
  if (!jit->reuse_ip) {
997
50.1k
    jit->track_last_valid_opline = true;
998
50.1k
    jit->last_valid_opline = opline;
999
50.1k
  }
1000
50.1k
}
1001
1002
static void zend_jit_reset_last_valid_opline(zend_jit_ctx *jit)
1003
15.6k
{
1004
15.6k
  jit->track_last_valid_opline = false;
1005
15.6k
  jit->last_valid_opline = NULL;
1006
15.6k
}
1007
1008
static void zend_jit_start_reuse_ip(zend_jit_ctx *jit)
1009
3.96k
{
1010
3.96k
  zend_jit_reset_last_valid_opline(jit);
1011
3.96k
  jit->reuse_ip = true;
1012
3.96k
}
1013
1014
static int zend_jit_reuse_ip(zend_jit_ctx *jit)
1015
3.74k
{
1016
3.74k
  if (!jit->reuse_ip) {
1017
2.85k
    zend_jit_start_reuse_ip(jit);
1018
    // RX = EX(call);
1019
2.85k
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
1020
2.85k
  }
1021
3.74k
  return 1;
1022
3.74k
}
1023
1024
static void zend_jit_stop_reuse_ip(zend_jit_ctx *jit)
1025
3.63k
{
1026
3.63k
  jit->reuse_ip = false;
1027
3.63k
}
1028
1029
static int zend_jit_save_call_chain(zend_jit_ctx *jit, uint32_t call_level)
1030
448
{
1031
448
  ir_ref rx, call;
1032
1033
448
  if (call_level == 1) {
1034
    // JIT: call = NULL;
1035
390
    call = IR_NULL;
1036
390
  } else {
1037
    // JIT: call = EX(call);
1038
58
    call = ir_LOAD_A(jit_EX(call));
1039
58
  }
1040
1041
448
  rx = jit_IP(jit);
1042
1043
  // JIT: call->prev_execute_data = call;
1044
448
  ir_STORE(jit_CALL(rx, prev_execute_data), call);
1045
1046
  // JIT: EX(call) = call;
1047
448
  ir_STORE(jit_EX(call), rx);
1048
1049
448
  jit->delayed_call_level = 0;
1050
448
  delayed_call_chain = false;
1051
1052
448
  return 1;
1053
448
}
1054
1055
static int zend_jit_set_ip(zend_jit_ctx *jit, const zend_op *target)
1056
21.9k
{
1057
21.9k
  ir_ref ref;
1058
1059
21.9k
  if (jit->delayed_call_level) {
1060
79
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
1061
0
      return 0;
1062
0
    }
1063
79
  }
1064
1065
21.9k
  if (jit->last_valid_opline) {
1066
21.0k
    zend_jit_use_last_valid_opline(jit);
1067
21.0k
    if (jit->last_valid_opline != target) {
1068
12.7k
      ref = jit_IP(jit);
1069
12.7k
      if (target > jit->last_valid_opline) {
1070
12.7k
        ref = ir_ADD_OFFSET(ref, (uintptr_t)target - (uintptr_t)jit->last_valid_opline);
1071
12.7k
      } else {
1072
27
        ref = ir_SUB_A(ref, ir_CONST_ADDR((uintptr_t)jit->last_valid_opline - (uintptr_t)target));
1073
27
      }
1074
12.7k
      jit_STORE_IP(jit, ref);
1075
12.7k
    }
1076
21.0k
  } else {
1077
932
    jit_STORE_IP(jit, ir_CONST_ADDR(target));
1078
932
  }
1079
21.9k
  jit->reuse_ip = false;
1080
21.9k
  zend_jit_set_last_valid_opline(jit, target);
1081
21.9k
  return 1;
1082
21.9k
}
1083
1084
static void jit_SET_EX_OPLINE(zend_jit_ctx *jit, const zend_op *target)
1085
44.6k
{
1086
44.6k
  if (jit->last_valid_opline == target) {
1087
20.0k
    zend_jit_use_last_valid_opline(jit);
1088
    // EX(opline) = opline
1089
20.0k
    ir_STORE(jit_EX(opline), jit_IP(jit));
1090
24.5k
  } else {
1091
24.5k
    ir_STORE(jit_EX(opline), ir_CONST_ADDR(target));
1092
24.5k
  }
1093
44.6k
}
1094
1095
static ir_ref jit_ZVAL_ADDR(zend_jit_ctx *jit, zend_jit_addr addr)
1096
86.2k
{
1097
86.2k
  if (Z_MODE(addr) == IS_MEM_ZVAL) {
1098
45.4k
    ir_ref reg;
1099
1100
45.4k
    if (Z_REG(addr) == ZREG_FP) {
1101
41.3k
      reg = jit_FP(jit);
1102
41.3k
    } else if (Z_REG(addr) == ZREG_RX) {
1103
4.17k
      reg = jit_IP(jit);
1104
4.17k
    } else {
1105
0
      ZEND_UNREACHABLE();
1106
0
    }
1107
45.4k
    return ir_ADD_OFFSET(reg, Z_OFFSET(addr));
1108
45.4k
  } else if (Z_MODE(addr) == IS_REF_ZVAL) {
1109
37.9k
    return Z_IR_REF(addr);
1110
37.9k
  } else {
1111
2.82k
    ZEND_ASSERT(Z_MODE(addr) == IS_CONST_ZVAL);
1112
2.82k
    return ir_CONST_ADDR(Z_ZV(addr));
1113
2.82k
  }
1114
86.2k
}
1115
1116
static ir_ref jit_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref)
1117
8.20k
{
1118
8.20k
  return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type)));
1119
8.20k
}
1120
1121
static ir_ref jit_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr)
1122
17.3k
{
1123
17.3k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1124
0
    return ir_CONST_U8(Z_TYPE_P(Z_ZV(addr)));
1125
17.3k
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1126
12.0k
    ir_ref reg;
1127
1128
12.0k
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1129
12.0k
    if (Z_REG(addr) == ZREG_FP) {
1130
12.0k
      reg = jit_FP(jit);
1131
12.0k
    } else if (Z_REG(addr) == ZREG_RX) {
1132
32
      reg = jit_IP(jit);
1133
32
    } else {
1134
0
      ZEND_UNREACHABLE();
1135
0
    }
1136
12.0k
    return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type)));
1137
12.0k
  } else {
1138
5.30k
    return jit_Z_TYPE_ref(jit, jit_ZVAL_ADDR(jit, addr));
1139
5.30k
  }
1140
17.3k
}
1141
1142
static ir_ref jit_Z_TYPE_FLAGS_ref(zend_jit_ctx *jit, ir_ref ref)
1143
6.28k
{
1144
6.28k
  return ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zval, u1.v.type_flags)));
1145
6.28k
}
1146
1147
static ir_ref jit_Z_TYPE_FLAGS(zend_jit_ctx *jit, zend_jit_addr addr)
1148
13.7k
{
1149
13.7k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1150
0
    return ir_CONST_U8(Z_TYPE_FLAGS_P(Z_ZV(addr)));
1151
13.7k
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1152
10.2k
    ir_ref reg;
1153
1154
10.2k
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1155
10.2k
    if (Z_REG(addr) == ZREG_FP) {
1156
9.90k
      reg = jit_FP(jit);
1157
9.90k
    } else if (Z_REG(addr) == ZREG_RX) {
1158
349
      reg = jit_IP(jit);
1159
349
    } else {
1160
0
      ZEND_UNREACHABLE();
1161
0
    }
1162
10.2k
    return ir_LOAD_U8(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.v.type_flags)));
1163
10.2k
  } else {
1164
3.45k
    return jit_Z_TYPE_FLAGS_ref(jit, jit_ZVAL_ADDR(jit, addr));
1165
3.45k
  }
1166
13.7k
}
1167
1168
static ir_ref jit_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref)
1169
5.44k
{
1170
5.44k
  return ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)));
1171
5.44k
}
1172
1173
static ir_ref jit_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr)
1174
6.05k
{
1175
6.05k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1176
0
    return ir_CONST_U32(Z_TYPE_INFO_P(Z_ZV(addr)));
1177
6.05k
  } else if (Z_MODE(addr) == IS_MEM_ZVAL) {
1178
1.09k
    ir_ref reg;
1179
1180
1.09k
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1181
1.09k
    if (Z_REG(addr) == ZREG_FP) {
1182
1.09k
      reg = jit_FP(jit);
1183
1.09k
    } else if (Z_REG(addr) == ZREG_RX) {
1184
0
      reg = jit_IP(jit);
1185
0
    } else {
1186
0
      ZEND_UNREACHABLE();
1187
0
    }
1188
1.09k
    return ir_LOAD_U32(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)));
1189
4.96k
  } else {
1190
4.96k
    return jit_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr));
1191
4.96k
  }
1192
6.05k
}
1193
1194
static void jit_set_Z_TYPE_INFO_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type_info)
1195
7.83k
{
1196
7.83k
  ir_STORE(ir_ADD_OFFSET(ref, offsetof(zval, u1.type_info)), type_info);
1197
7.83k
}
1198
1199
static void jit_set_Z_TYPE_INFO_ex(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref type_info)
1200
19.9k
{
1201
19.9k
  if (Z_MODE(addr) == IS_MEM_ZVAL) {
1202
14.5k
    ir_ref reg;
1203
1204
14.5k
    ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL);
1205
14.5k
    if (Z_REG(addr) == ZREG_FP) {
1206
10.6k
      reg = jit_FP(jit);
1207
10.6k
    } else if (Z_REG(addr) == ZREG_RX) {
1208
3.95k
      reg = jit_IP(jit);
1209
3.95k
    } else {
1210
0
      ZEND_UNREACHABLE();
1211
0
    }
1212
14.5k
    ir_STORE(ir_ADD_OFFSET(reg, Z_OFFSET(addr) + offsetof(zval, u1.type_info)), type_info);
1213
14.5k
  } else {
1214
5.38k
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, addr), type_info);
1215
5.38k
  }
1216
19.9k
}
1217
1218
static void jit_set_Z_TYPE_INFO(zend_jit_ctx *jit, zend_jit_addr addr, uint32_t type_info)
1219
13.5k
{
1220
13.5k
  if (type_info < IS_STRING
1221
9.64k
   && Z_MODE(addr) == IS_MEM_ZVAL
1222
5.48k
   && Z_REG(addr) == ZREG_FP
1223
5.08k
   && JIT_G(current_frame)
1224
553
   && STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(addr))) == type_info) {
1225
    /* type is already set */
1226
19
    return;
1227
19
  }
1228
13.5k
  jit_set_Z_TYPE_INFO_ex(jit, addr, ir_CONST_U32(type_info));
1229
13.5k
}
1230
1231
static ir_ref jit_if_Z_TYPE_ref(zend_jit_ctx *jit, ir_ref ref, ir_ref type)
1232
707
{
1233
707
  return ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), type));
1234
707
}
1235
1236
static ir_ref jit_if_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1237
10.5k
{
1238
10.5k
  ZEND_ASSERT(type != IS_UNDEF);
1239
10.5k
  return ir_IF(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)));
1240
10.5k
}
1241
1242
static ir_ref jit_if_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type)
1243
3.85k
{
1244
3.85k
  ir_ref ref = jit_Z_TYPE(jit, addr);
1245
1246
3.85k
  if (type != IS_UNDEF) {
1247
0
    ref = ir_NE(ref, ir_CONST_U8(type));
1248
0
  }
1249
3.85k
  return ir_IF(ref);
1250
3.85k
}
1251
1252
static void jit_guard_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1253
91
{
1254
91
  ir_ref ref = jit_Z_TYPE(jit, addr);
1255
1256
91
  if (type != IS_UNDEF) {
1257
89
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
1258
89
  } else {
1259
2
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1260
2
  }
1261
91
}
1262
1263
static void jit_guard_not_Z_TYPE(zend_jit_ctx *jit, zend_jit_addr addr, uint8_t type, const void *exit_addr)
1264
15
{
1265
15
  ir_ref ref = jit_Z_TYPE(jit, addr);
1266
1267
15
  if (type != IS_UNDEF) {
1268
0
    ref = ir_NE(ref, ir_CONST_U8(type));
1269
0
  }
1270
15
  ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
1271
15
}
1272
1273
static ir_ref jit_if_REFCOUNTED(zend_jit_ctx *jit, zend_jit_addr addr)
1274
13.7k
{
1275
13.7k
  return ir_IF(jit_Z_TYPE_FLAGS(jit, addr));
1276
13.7k
}
1277
1278
static ir_ref jit_if_COLLECTABLE_ref(zend_jit_ctx *jit, ir_ref addr_ref)
1279
2.83k
{
1280
2.83k
  return ir_IF(ir_AND_U8(jit_Z_TYPE_FLAGS_ref(jit, addr_ref), ir_CONST_U8(IS_TYPE_COLLECTABLE)));
1281
2.83k
}
1282
1283
static ir_ref jit_Z_LVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1284
5.62k
{
1285
5.62k
  return ir_LOAD_L(ref);
1286
5.62k
}
1287
1288
static ir_ref jit_Z_DVAL_ref(zend_jit_ctx *jit, ir_ref ref)
1289
1.77k
{
1290
1.77k
  return ir_LOAD_D(ref);
1291
1.77k
}
1292
1293
static bool zend_jit_spilling_may_cause_conflict(zend_jit_ctx *jit, int var, ir_ref val)
1294
291
{
1295
291
  if (jit->ctx.ir_base[val].op == IR_RLOAD) {
1296
    /* Deoptimization */
1297
4
    return false;
1298
4
  }
1299
//  if (jit->ctx.ir_base[val].op == IR_LOAD
1300
//   && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1301
//   && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1302
//   && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1303
//   && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1304
//   && 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)) {
1305
//    /* LOAD from the same location (the LOAD is pinned) */
1306
//    // TODO: should be anti-dependent with the following stores ???
1307
//    return 0;
1308
//  }
1309
287
  if (jit->ssa->vars[var].var < jit->current_op_array->last_var) {
1310
    /* IS_CV */
1311
11
    if (jit->ctx.ir_base[val].op == IR_LOAD
1312
2
     && jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op == IR_ADD
1313
2
     && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op == IR_RLOAD
1314
2
     && jit->ctx.ir_base[jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op1].op2 == ZREG_FP
1315
2
     && IR_IS_CONST_REF(jit->ctx.ir_base[jit->ctx.ir_base[val].op2].op2)
1316
2
     && 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)
1317
1
     && 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) {
1318
      /* binding between different CVs may cause spill conflict */
1319
1
      return true;
1320
10
    } else if (jit->ssa->vars[var].definition >= 0
1321
10
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1322
5
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1323
5
     && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].no_val
1324
3
     && jit->ssa->vars[jit->ssa->ops[jit->ssa->vars[var].definition].op1_use].definition_phi
1325
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)) {
1326
      /* Avoid moving spill store out of loop */
1327
0
      return true;
1328
10
    } else if (jit->ssa->vars[var].definition >= 0
1329
10
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_def == var
1330
5
     && jit->ssa->ops[jit->ssa->vars[var].definition].op1_use >= 0
1331
5
     && jit->ssa->ops[jit->ssa->vars[var].definition].op2_use >= 0
1332
3
     && jit->ra[jit->ssa->ops[jit->ssa->vars[var].definition].op2_use].ref == val) {
1333
      /* Avoid spill conflict between of ASSIGN.op1_def and ASSIGN.op1_use */
1334
0
      return true;
1335
0
    }
1336
10
    return false;
1337
11
  }
1338
276
  return true;
1339
287
}
1340
1341
static void zend_jit_def_reg(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref val)
1342
472
{
1343
472
  int var;
1344
1345
472
  ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1346
472
  var = Z_SSA_VAR(addr);
1347
472
  if (var == jit->delay_var) {
1348
153
    ir_refs_add(jit->delay_refs, val);
1349
153
    return;
1350
153
  }
1351
319
  ZEND_ASSERT(jit->ra && jit->ra[var].ref == IR_NULL);
1352
1353
  /* Negative "var" has special meaning for IR */
1354
319
  if (val > 0) {
1355
291
    if (jit->ctx.binding) {
1356
13
      ir_ref old = ir_binding_find(&jit->ctx, val);
1357
13
      if (old && old != -EX_NUM_TO_VAR(jit->ssa->vars[var].var)) {
1358
6
        val = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[val].type), val, 1);
1359
6
      }
1360
13
    }
1361
291
    if (!zend_jit_spilling_may_cause_conflict(jit, var, val)) {
1362
14
      val = ir_bind(&jit->ctx, -EX_NUM_TO_VAR(jit->ssa->vars[var].var), val);
1363
14
    }
1364
291
  }
1365
319
  jit->ra[var].ref = val;
1366
1367
319
  if (jit->ra[var].flags & ZREG_FORWARD) {
1368
0
    zend_ssa_phi *phi = jit->ssa->vars[var].phi_use_chain;
1369
0
    zend_basic_block *bb;
1370
0
    int n, j, *p;
1371
0
    ir_ref *q;
1372
1373
0
    jit->ra[var].flags &= ~ZREG_FORWARD;
1374
0
    while (phi != NULL) {
1375
0
      zend_ssa_phi *dst_phi = phi;
1376
0
      int src_var = var;
1377
1378
0
      if (dst_phi->pi >= 0) {
1379
0
        jit->ra[src_var].ref = val;
1380
0
        src_var = dst_phi->ssa_var;
1381
0
        if (!(jit->ra[src_var].flags & ZREG_FORWARD)
1382
         /* Pi in a block that is not generated yet. It forwards later on its own. */
1383
0
         || (jit->bb_start_ref && !jit->bb_start_ref[dst_phi->block])) {
1384
0
          phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1385
0
          continue;
1386
0
        }
1387
0
        dst_phi = jit->ssa->vars[src_var].phi_use_chain;
1388
0
        ZEND_ASSERT(dst_phi != NULL && "reg forwarding");
1389
0
        ZEND_ASSERT(!zend_ssa_next_use_phi(jit->ssa, src_var, dst_phi) && "reg forwarding");
1390
0
        jit->ra[src_var].flags &= ~ZREG_FORWARD;
1391
0
      }
1392
1393
0
      if (jit->ra[dst_phi->ssa_var].ref > 0) {
1394
0
        ir_insn *phi_insn = &jit->ctx.ir_base[jit->ra[dst_phi->ssa_var].ref];
1395
0
        if (phi_insn->op == IR_PHI) {
1396
//          ZEND_ASSERT(ir_operands_count(ctx, phi_insn) == n + 1);
1397
0
          bb = &jit->ssa->cfg.blocks[dst_phi->block];
1398
0
          n = bb->predecessors_count;
1399
0
          for (j = 0, p = &dst_phi->sources[0], q = phi_insn->ops + 2; j < n; j++, p++, q++) {
1400
0
            if (*p == src_var) {
1401
0
              *q = val;
1402
0
            }
1403
0
          }
1404
0
        }
1405
0
      }
1406
1407
0
      phi = zend_ssa_next_use_phi(jit->ssa, var, phi);
1408
0
    }
1409
0
  }
1410
319
}
1411
1412
static ir_ref zend_jit_use_reg(zend_jit_ctx *jit, zend_jit_addr addr)
1413
336
{
1414
336
  int var = Z_SSA_VAR(addr);
1415
1416
336
  ZEND_ASSERT(Z_MODE(addr) == IS_REG);
1417
336
  ZEND_ASSERT(jit->ra && jit->ra[var].ref);
1418
336
  if (jit->ra[var].ref == IR_NULL) {
1419
0
    zend_jit_addr mem_addr;
1420
0
    ir_ref ref;
1421
1422
0
    ZEND_ASSERT(jit->ra[var].flags & ZREG_LOAD);
1423
0
    mem_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(jit->ssa->vars[var].var));
1424
0
    if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_LONG) {
1425
0
      ref = jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1426
0
    } else if ((jit->ssa->var_info[var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) {
1427
0
      ref = jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, mem_addr));
1428
0
    } else {
1429
0
      ZEND_UNREACHABLE();
1430
0
    }
1431
0
    zend_jit_def_reg(jit, addr, ref);
1432
0
    return ref;
1433
0
  }
1434
336
  return jit->ra[Z_SSA_VAR(addr)].ref;
1435
336
}
1436
1437
static void zend_jit_gen_pi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1438
0
{
1439
0
  int src_var = phi->sources[0];
1440
0
  int dst_var = phi->ssa_var;
1441
1442
0
  ZEND_ASSERT(phi->pi >= 0);
1443
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1444
0
  ZEND_ASSERT(jit->ra[src_var].ref);
1445
1446
0
  if (jit->ra[src_var].ref == IR_NULL) {
1447
    /* Not defined yet */
1448
0
    if (jit->ssa->vars[dst_var].use_chain < 0
1449
0
     && jit->ssa->vars[dst_var].phi_use_chain) {
1450
0
      zend_ssa_phi *phi = jit->ssa->vars[dst_var].phi_use_chain;
1451
0
      if (!zend_ssa_next_use_phi(jit->ssa, dst_var, phi)) {
1452
        /* This is a Pi forwarded to Phi */
1453
0
        jit->ra[src_var].flags |= ZREG_FORWARD;
1454
0
        return;
1455
0
      }
1456
0
    }
1457
0
    ZEND_ASSERT(0 && "Not defined Pi source");
1458
0
  }
1459
  /* Reuse register */
1460
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var),
1461
0
    zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)));
1462
0
}
1463
1464
static void zend_jit_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
1465
0
{
1466
0
  int dst_var = phi->ssa_var;
1467
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[phi->block];
1468
0
  uint32_t n = bb->predecessors_count;
1469
0
  ir_type type = (jit->ssa->var_info[phi->ssa_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE;
1470
0
  ir_ref merge = jit->bb_start_ref[phi->block];
1471
0
  ir_ref ref;
1472
0
  ir_ref old_insns_count = jit->ctx.insns_count;
1473
0
  ir_ref same_src_ref = IR_UNUSED;
1474
0
  bool phi_inputs_are_the_same = true;
1475
1476
0
  ZEND_ASSERT(phi->pi < 0);
1477
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
1478
0
  ZEND_ASSERT(merge);
1479
0
  ZEND_ASSERT(jit->ctx.ir_base[merge].op == IR_MERGE || jit->ctx.ir_base[merge].op == IR_LOOP_BEGIN);
1480
0
  ZEND_ASSERT(n == jit->ctx.ir_base[merge].inputs_count);
1481
1482
0
  ref = ir_emit_N(&jit->ctx, IR_OPT(IR_PHI, type), n + 1);
1483
0
  ir_set_op(&jit->ctx, ref, 1, merge);
1484
1485
0
  for (uint32_t i = 0; i < n; i++) {
1486
0
    int src_var = phi->sources[i];
1487
1488
0
    ZEND_ASSERT(jit->ra[src_var].ref);
1489
0
    if (jit->ra[src_var].ref == IR_NULL) {
1490
0
      jit->ra[src_var].flags |= ZREG_FORWARD;
1491
0
      phi_inputs_are_the_same = false;
1492
0
    } else {
1493
0
      ir_ref src_ref = zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var));
1494
0
      if (i == 0) {
1495
0
        same_src_ref = src_ref;
1496
0
      } else if (same_src_ref != src_ref) {
1497
0
        phi_inputs_are_the_same = false;
1498
0
      }
1499
0
      ir_set_op(&jit->ctx, ref, i + 2, src_ref);
1500
0
    }
1501
0
  }
1502
0
  if (phi_inputs_are_the_same) {
1503
0
    ref = same_src_ref;
1504
0
    jit->ctx.insns_count = old_insns_count;
1505
0
  }
1506
1507
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
1508
0
}
1509
1510
static ir_ref jit_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1511
7.86k
{
1512
7.86k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1513
1.94k
    return ir_CONST_LONG(Z_LVAL_P(Z_ZV(addr)));
1514
5.92k
  } else if (Z_MODE(addr) == IS_REG) {
1515
301
    return zend_jit_use_reg(jit, addr);
1516
5.62k
  } else {
1517
5.62k
    return jit_Z_LVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1518
5.62k
  }
1519
7.86k
}
1520
1521
static void jit_set_Z_LVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1522
3.50k
{
1523
3.50k
  if (Z_MODE(addr) == IS_REG) {
1524
281
    zend_jit_def_reg(jit, addr, lval);
1525
3.22k
  } else {
1526
3.22k
    ir_STORE(jit_ZVAL_ADDR(jit, addr), lval);
1527
3.22k
  }
1528
3.50k
}
1529
1530
#if SIZEOF_ZEND_LONG == 4
1531
static ir_ref jit_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr)
1532
{
1533
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1534
    return ir_CONST_U32((Z_ZV(addr))->value.ww.w2);
1535
  } else {
1536
    return ir_LOAD_L(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)));
1537
  }
1538
}
1539
1540
static void jit_set_Z_W2(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref lval)
1541
{
1542
  ir_STORE(ir_ADD_OFFSET(jit_ZVAL_ADDR(jit, addr), offsetof(zval, value.ww.w2)), lval);
1543
}
1544
#endif
1545
1546
static ir_ref jit_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr)
1547
1.91k
{
1548
1.91k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1549
101
    return ir_CONST_DOUBLE(Z_DVAL_P(Z_ZV(addr)));
1550
1.81k
  } else if (Z_MODE(addr) == IS_REG) {
1551
31
    return zend_jit_use_reg(jit, addr);
1552
1.77k
  } else {
1553
1.77k
    return jit_Z_DVAL_ref(jit, jit_ZVAL_ADDR(jit, addr));
1554
1.77k
  }
1555
1.91k
}
1556
1557
static void jit_set_Z_DVAL(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref dval)
1558
317
{
1559
317
  if (Z_MODE(addr) == IS_REG) {
1560
31
    zend_jit_def_reg(jit, addr, dval);
1561
286
  } else {
1562
286
    ir_STORE(jit_ZVAL_ADDR(jit, addr), dval);
1563
286
  }
1564
317
}
1565
1566
static ir_ref jit_Z_PTR_ref(zend_jit_ctx *jit, ir_ref ref)
1567
26.7k
{
1568
26.7k
  return ir_LOAD_A(ref);
1569
26.7k
}
1570
1571
static ir_ref jit_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr)
1572
21.2k
{
1573
21.2k
  if (Z_MODE(addr) == IS_CONST_ZVAL) {
1574
222
    return ir_CONST_ADDR(Z_PTR_P(Z_ZV(addr)));
1575
21.0k
  } else {
1576
21.0k
    return jit_Z_PTR_ref(jit, jit_ZVAL_ADDR(jit, addr));
1577
21.0k
  }
1578
21.2k
}
1579
1580
static void jit_set_Z_PTR(zend_jit_ctx *jit, zend_jit_addr addr, ir_ref ptr)
1581
10.0k
{
1582
10.0k
  ir_STORE(jit_ZVAL_ADDR(jit, addr), ptr);
1583
10.0k
}
1584
1585
static ir_ref jit_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref)
1586
332
{
1587
332
  return ir_LOAD_U32(ref);
1588
332
}
1589
1590
static void jit_set_GC_REFCOUNT(zend_jit_ctx *jit, ir_ref ref, uint32_t refcount)
1591
49
{
1592
49
  ir_STORE(ref, ir_CONST_U32(refcount));
1593
49
}
1594
1595
static void jit_GC_ADDREF(zend_jit_ctx *jit, ir_ref ref)
1596
4.98k
{
1597
4.98k
  ir_STORE(ref, ir_ADD_U32(ir_LOAD_U32(ref), ir_CONST_U32(1)));
1598
4.98k
}
1599
1600
static void jit_GC_ADDREF2(zend_jit_ctx *jit, ir_ref ref)
1601
132
{
1602
132
  ir_ref counter = ir_LOAD_U32(ref);
1603
132
  ir_STORE(ref, ir_ADD_U32(counter, ir_CONST_U32(2)));
1604
132
}
1605
1606
static ir_ref jit_GC_DELREF(zend_jit_ctx *jit, ir_ref ref)
1607
17.9k
{
1608
17.9k
  ir_ref counter = ir_LOAD_U32(ref);
1609
17.9k
  counter = ir_SUB_U32(counter, ir_CONST_U32(1));
1610
17.9k
  ir_STORE(ref, counter);
1611
17.9k
  return counter;
1612
17.9k
}
1613
1614
static ir_ref jit_if_GC_MAY_NOT_LEAK(zend_jit_ctx *jit, ir_ref ref)
1615
6.98k
{
1616
6.98k
  return ir_IF(
1617
6.98k
    ir_AND_U32(
1618
6.98k
      ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_refcounted, gc.u.type_info))),
1619
6.98k
      ir_CONST_U32(GC_INFO_MASK | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT))));
1620
6.98k
}
1621
1622
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)
1623
3.85k
{
1624
3.85k
  ir_ref ref = IR_UNUSED;
1625
1626
3.85k
  if (Z_TYPE_P(zv) > IS_TRUE) {
1627
3.61k
    if (Z_TYPE_P(zv) == IS_DOUBLE) {
1628
67
      jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE(Z_DVAL_P(zv)));
1629
3.54k
    } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) {
1630
0
      jit_set_Z_DVAL(jit, dst, ir_CONST_DOUBLE((double)Z_LVAL_P(zv)));
1631
3.54k
    } else if (Z_TYPE_P(zv) == IS_LONG) {
1632
407
      jit_set_Z_LVAL(jit, dst, ir_CONST_LONG(Z_LVAL_P(zv)));
1633
3.13k
    } else {
1634
3.13k
      ref = ir_CONST_ADDR(Z_PTR_P(zv));
1635
3.13k
      jit_set_Z_PTR(jit, dst, ref);
1636
3.13k
      if (addref && Z_REFCOUNTED_P(zv)) {
1637
0
        jit_GC_ADDREF(jit, ref);
1638
0
      }
1639
3.13k
    }
1640
3.61k
  }
1641
3.85k
  if (Z_MODE(dst) != IS_REG) {
1642
3.85k
    if (dst_def_info == MAY_BE_DOUBLE) {
1643
0
      if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
1644
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
1645
0
      }
1646
3.85k
    } 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) {
1647
3.84k
      jit_set_Z_TYPE_INFO(jit, dst, Z_TYPE_INFO_P(zv));
1648
3.84k
    }
1649
3.85k
  }
1650
3.85k
}
1651
1652
static ir_ref jit_if_TYPED_REF(zend_jit_ctx *jit, ir_ref ref)
1653
463
{
1654
463
  return ir_IF(ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr))));
1655
463
}
1656
1657
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)
1658
5.40k
{
1659
5.40k
  ir_ref ref = IR_UNUSED;
1660
1661
5.40k
  if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1662
5.29k
    if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1663
28
      jit_set_Z_LVAL(jit, dst, jit_Z_LVAL(jit, src));
1664
5.27k
    } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1665
0
      jit_set_Z_DVAL(jit, dst, jit_Z_DVAL(jit, src));
1666
5.27k
    } else {
1667
#if SIZEOF_ZEND_LONG == 4
1668
      if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1669
        jit_set_Z_W2(jit, dst, jit_Z_W2(jit, src));
1670
      }
1671
#endif
1672
5.27k
      ref = jit_Z_PTR(jit, src);
1673
5.27k
      jit_set_Z_PTR(jit, dst, ref);
1674
5.27k
    }
1675
5.29k
  }
1676
5.40k
  if (has_concrete_type(src_info & MAY_BE_ANY)
1677
143
   && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1678
77
     && !(src_info & MAY_BE_GUARD)) {
1679
77
    if (Z_MODE(dst) != IS_REG
1680
73
     && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1681
62
      uint8_t type = concrete_type(src_info);
1682
62
      jit_set_Z_TYPE_INFO(jit, dst, type);
1683
62
    }
1684
5.32k
  } else {
1685
5.32k
    ir_ref type = jit_Z_TYPE_INFO(jit, src);
1686
5.32k
    jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1687
5.32k
    if (addref) {
1688
4.33k
      if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1689
4.27k
        ir_ref if_refcounted = IR_UNUSED;
1690
1691
4.27k
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1692
4.27k
          if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1693
4.27k
          ir_IF_TRUE(if_refcounted);
1694
4.27k
        }
1695
1696
4.27k
        jit_GC_ADDREF(jit, ref);
1697
1698
4.27k
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1699
4.27k
          ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1700
4.27k
        }
1701
4.27k
      }
1702
4.33k
    }
1703
5.32k
  }
1704
5.40k
}
1705
1706
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)
1707
304
{
1708
304
  ir_ref ref = IR_UNUSED;
1709
1710
304
  if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
1711
259
    if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) {
1712
17
      ref = jit_Z_LVAL(jit, src);
1713
17
      jit_set_Z_LVAL(jit, dst, ref);
1714
17
      jit_set_Z_LVAL(jit, dst2, ref);
1715
242
    } else if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) {
1716
0
      ref = jit_Z_DVAL(jit, src);
1717
0
      jit_set_Z_DVAL(jit, dst, ref);
1718
0
      jit_set_Z_DVAL(jit, dst2, ref);
1719
242
    } else {
1720
#if SIZEOF_ZEND_LONG == 4
1721
      if (src_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) {
1722
        ref = jit_Z_W2(jit, src);
1723
        jit_set_Z_W2(jit, dst, ref);
1724
        jit_set_Z_W2(jit, dst2, ref);
1725
      }
1726
#endif
1727
242
      ref = jit_Z_PTR(jit, src);
1728
242
      jit_set_Z_PTR(jit, dst, ref);
1729
242
      jit_set_Z_PTR(jit, dst2, ref);
1730
242
    }
1731
259
  }
1732
304
  if (has_concrete_type(src_info & MAY_BE_ANY)
1733
46
   && (src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))
1734
37
     && !(src_info & MAY_BE_GUARD)) {
1735
37
    uint8_t type = concrete_type(src_info);
1736
37
    ir_ref type_ref = ir_CONST_U32(type);
1737
1738
37
    if (Z_MODE(dst) != IS_REG
1739
37
     && (dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) {
1740
28
      jit_set_Z_TYPE_INFO_ex(jit, dst, type_ref);
1741
28
    }
1742
37
    if (Z_MODE(dst2) != IS_REG) {
1743
37
      jit_set_Z_TYPE_INFO_ex(jit, dst2, type_ref);
1744
37
    }
1745
267
  } else {
1746
267
    ir_ref type = jit_Z_TYPE_INFO(jit, src);
1747
267
    jit_set_Z_TYPE_INFO_ex(jit, dst, type);
1748
267
    jit_set_Z_TYPE_INFO_ex(jit, dst2, type);
1749
267
    if (addref) {
1750
267
      if (src_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
1751
242
        ir_ref if_refcounted = IR_UNUSED;
1752
1753
242
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1754
242
          if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(0xff00)));
1755
242
          ir_IF_TRUE(if_refcounted);
1756
242
        }
1757
1758
242
        if (addref == 2) {
1759
132
          jit_GC_ADDREF2(jit, ref);
1760
132
        } else {
1761
110
          jit_GC_ADDREF(jit, ref);
1762
110
        }
1763
1764
242
        if (src_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1765
242
          ir_MERGE_WITH_EMPTY_FALSE(if_refcounted);
1766
242
        }
1767
242
      }
1768
267
    }
1769
267
  }
1770
304
}
1771
1772
static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const zend_op *opline)
1773
14.2k
{
1774
14.2k
  if (!((op_info) & MAY_BE_GUARD)
1775
14.2k
   && has_concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1776
574
    uint8_t type = concrete_type((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE));
1777
574
    if (type == IS_STRING && !ZEND_DEBUG) {
1778
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(_efree), ref);
1779
0
        return;
1780
574
    } else if (type == IS_ARRAY) {
1781
86
      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)) {
1782
86
        if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) {
1783
25
          jit_SET_EX_OPLINE(jit, opline);
1784
25
        }
1785
86
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref);
1786
86
      } else {
1787
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_array_free), ref);
1788
0
      }
1789
86
      return;
1790
488
    } else if (type == IS_OBJECT) {
1791
160
      if (opline) {
1792
124
        jit_SET_EX_OPLINE(jit, opline);
1793
124
      }
1794
160
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1795
160
      return;
1796
160
    }
1797
574
  }
1798
13.9k
  if (opline) {
1799
9.85k
    jit_SET_EX_OPLINE(jit, opline);
1800
9.85k
  }
1801
13.9k
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(rc_dtor_func), ref);
1802
13.9k
}
1803
1804
static void jit_ZVAL_PTR_DTOR(zend_jit_ctx  *jit,
1805
                              zend_jit_addr  addr,
1806
                              uint32_t       op_info,
1807
                              bool           gc,
1808
                              const zend_op *opline)
1809
13.3k
{
1810
13.3k
    ir_ref ref, ref2;
1811
13.3k
  ir_ref if_refcounted = IR_UNUSED;
1812
13.3k
  ir_ref if_not_zero = IR_UNUSED;
1813
13.3k
  ir_ref end_inputs = IR_UNUSED;
1814
1815
13.3k
  if (op_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) {
1816
13.2k
    if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
1817
13.2k
      if_refcounted = jit_if_REFCOUNTED(jit, addr);
1818
13.2k
      ir_IF_FALSE(if_refcounted);
1819
13.2k
      ir_END_list(end_inputs);
1820
13.2k
      ir_IF_TRUE(if_refcounted);
1821
13.2k
    }
1822
13.2k
    ref = jit_Z_PTR(jit, addr);
1823
13.2k
    ref2 = jit_GC_DELREF(jit, ref);
1824
1825
13.2k
    if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) {
1826
13.2k
      if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) {
1827
13.0k
        if_not_zero = ir_IF(ref2);
1828
13.0k
        ir_IF_FALSE(if_not_zero);
1829
13.0k
      }
1830
      // zval_dtor_func(r);
1831
13.2k
      jit_ZVAL_DTOR(jit, ref, op_info, opline);
1832
13.2k
      if (if_not_zero) {
1833
13.0k
        ir_END_list(end_inputs);
1834
13.0k
        ir_IF_TRUE(if_not_zero);
1835
13.0k
      }
1836
13.2k
    }
1837
13.2k
    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))) {
1838
2.96k
      ir_ref if_may_not_leak;
1839
1840
2.96k
      if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) {
1841
2.83k
        ir_ref if_ref, if_collectable;
1842
1843
2.83k
        if_ref = jit_if_Z_TYPE(jit, addr, IS_REFERENCE);
1844
2.83k
        ir_IF_TRUE(if_ref);
1845
1846
2.83k
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
1847
1848
2.83k
        if_collectable = jit_if_COLLECTABLE_ref(jit, ref2);
1849
2.83k
        ir_IF_FALSE(if_collectable);
1850
2.83k
        ir_END_list(end_inputs);
1851
2.83k
        ir_IF_TRUE(if_collectable);
1852
1853
2.83k
        ref2 = jit_Z_PTR_ref(jit, ref2);
1854
1855
2.83k
        ir_MERGE_WITH_EMPTY_FALSE(if_ref);
1856
2.83k
        ref = ir_PHI_2(IR_ADDR, ref2, ref);
1857
2.83k
      }
1858
1859
2.96k
      if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1860
2.96k
      ir_IF_TRUE(if_may_not_leak);
1861
2.96k
      ir_END_list(end_inputs);
1862
2.96k
      ir_IF_FALSE(if_may_not_leak);
1863
1864
2.96k
      if (opline) {
1865
2.88k
        jit_SET_EX_OPLINE(jit, opline);
1866
2.88k
      }
1867
2.96k
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1868
2.96k
    }
1869
1870
13.2k
    if (end_inputs) {
1871
13.2k
      ir_END_list(end_inputs);
1872
13.2k
      ir_MERGE_list(end_inputs);
1873
13.2k
    }
1874
13.2k
  }
1875
13.3k
}
1876
1877
static void jit_FREE_OP(zend_jit_ctx  *jit,
1878
                        uint8_t        op_type,
1879
                        znode_op       op,
1880
                        uint32_t       op_info,
1881
                        const zend_op *opline)
1882
8.48k
{
1883
8.48k
  if (op_type & (IS_VAR|IS_TMP_VAR)) {
1884
4.66k
    jit_ZVAL_PTR_DTOR(jit,
1885
4.66k
      ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var),
1886
4.66k
      op_info, false, opline);
1887
4.66k
  }
1888
8.48k
}
1889
1890
static void jit_OBJ_RELEASE(zend_jit_ctx  *jit, ir_ref ref)
1891
3.63k
{
1892
3.63k
  ir_ref end_inputs = IR_UNUSED;
1893
3.63k
    ir_ref if_not_zero, if_may_not_leak;
1894
1895
  // JIT: if (GC_DELREF(obj) == 0) {
1896
3.63k
  if_not_zero = ir_IF(jit_GC_DELREF(jit, ref));
1897
3.63k
  ir_IF_FALSE(if_not_zero);
1898
1899
  // JIT: zend_objects_store_del(obj)
1900
3.63k
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_objects_store_del), ref);
1901
3.63k
  ir_END_list(end_inputs);
1902
1903
3.63k
  ir_IF_TRUE(if_not_zero);
1904
3.63k
  if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
1905
1906
3.63k
  ir_IF_TRUE(if_may_not_leak);
1907
3.63k
  ir_END_list(end_inputs);
1908
1909
3.63k
  ir_IF_FALSE(if_may_not_leak);
1910
3.63k
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
1911
3.63k
  ir_END_list(end_inputs);
1912
1913
3.63k
  ir_MERGE_list(end_inputs);
1914
3.63k
}
1915
1916
static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
1917
3.80k
{
1918
3.80k
  ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
1919
1920
3.80k
  if (exit_addr) {
1921
215
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
1922
3.59k
  } else if (!opline || jit->last_valid_opline == opline) {
1923
4
    ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1924
3.58k
  } else {
1925
3.58k
    ir_ref if_timeout = ir_IF(ref);
1926
1927
3.58k
    ir_IF_TRUE_cold(if_timeout);
1928
3.58k
    jit_LOAD_IP_ADDR(jit, opline);
1929
3.58k
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
1930
3.58k
    ir_IF_FALSE(if_timeout);
1931
3.58k
  }
1932
3.80k
}
1933
1934
static void zend_jit_vm_enter(zend_jit_ctx *jit, ir_ref to_opline)
1935
28
{
1936
  // ZEND_VM_ENTER()
1937
28
  ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)));
1938
28
}
1939
1940
static void zend_jit_vm_leave(zend_jit_ctx *jit, ir_ref to_opline)
1941
0
{
1942
0
  // ZEND_VM_LEAVE()
1943
0
  ir_RETURN(ir_OR_A(to_opline, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)));
1944
0
}
1945
1946
static void zend_jit_tailcall_handler(zend_jit_ctx *jit, ir_ref handler)
1947
12.9k
{
1948
#if defined(IR_TARGET_X86)
1949
  if (!IR_IS_CONST_REF(handler)) {
1950
    handler = ir_CAST_OPCODE_HANDLER_FUNC(handler);
1951
  }
1952
#endif
1953
12.9k
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
1954
12.9k
    ir_TAILCALL(IR_OPCODE_HANDLER_RET, handler);
1955
12.9k
  } else {
1956
0
    ir_TAILCALL_2(IR_ADDR, handler, jit_FP(jit), jit_IP(jit));
1957
0
  }
1958
12.9k
}
1959
1960
/* stubs */
1961
1962
static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
1963
4
{
1964
4
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
1965
0
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(EG(exception_op));
1966
1967
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
1968
0
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
1969
4
  } else {
1970
4
    zend_vm_opcode_handler_t handler = EG(exception_op)->handler;
1971
1972
4
    if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
1973
4
      zend_jit_tailcall_handler(jit, ir_CONST_OPCODE_HANDLER_FUNC(handler));
1974
4
    } else {
1975
0
      ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
1976
0
      zend_jit_vm_enter(jit, ref);
1977
0
    }
1978
4
  }
1979
4
  return 1;
1980
4
}
1981
1982
static int zend_jit_exception_handler_undef_stub(zend_jit_ctx *jit)
1983
4
{
1984
4
  ir_ref ref, result_type, if_result_used;
1985
1986
4
  ref = jit_EG(opline_before_exception);
1987
4
  result_type = ir_LOAD_U8(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result_type)));
1988
1989
4
  if_result_used = ir_IF(ir_AND_U8(result_type, ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
1990
4
  ir_IF_TRUE(if_result_used);
1991
1992
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref), offsetof(zend_op, result.var)));
1993
4
  if (sizeof(void*) == 8) {
1994
4
    ref = ir_ZEXT_A(ref);
1995
4
  }
1996
4
  ir_STORE(ir_ADD_OFFSET(ir_ADD_A(jit_FP(jit), ref), offsetof(zval, u1.type_info)), ir_CONST_U32(IS_UNDEF));
1997
4
  ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
1998
1999
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2000
2001
4
  return 1;
2002
4
}
2003
2004
static int zend_jit_exception_handler_free_op1_op2_stub(zend_jit_ctx *jit)
2005
4
{
2006
4
  ir_ref ref, if_dtor;
2007
4
  zend_jit_addr var_addr;
2008
2009
4
  ref = ir_LOAD_A(jit_EG(opline_before_exception));
2010
4
  if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op1_type))),
2011
4
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2012
4
  ir_IF_TRUE(if_dtor);
2013
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op1.var)));
2014
4
  if (sizeof(void*) == 8) {
2015
4
    ref = ir_ZEXT_A(ref);
2016
4
  }
2017
4
  ref = ir_ADD_A(jit_FP(jit), ref);
2018
4
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
2019
4
  jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2020
4
  ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
2021
2022
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
2023
2024
4
  return 1;
2025
4
}
2026
2027
static int zend_jit_exception_handler_free_op2_stub(zend_jit_ctx *jit)
2028
4
{
2029
4
  ir_ref ref, if_dtor;
2030
4
  zend_jit_addr var_addr;
2031
2032
4
  ref = ir_LOAD_A(jit_EG(opline_before_exception));
2033
4
  if_dtor = ir_IF(ir_AND_U8(ir_LOAD_U8(ir_ADD_OFFSET(ref, offsetof(zend_op, op2_type))),
2034
4
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2035
4
  ir_IF_TRUE(if_dtor);
2036
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.var)));
2037
4
  if (sizeof(void*) == 8) {
2038
4
    ref = ir_ZEXT_A(ref);
2039
4
  }
2040
4
  ref = ir_ADD_A(jit_FP(jit), ref);
2041
4
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
2042
4
  jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2043
4
  ir_MERGE_WITH_EMPTY_FALSE(if_dtor);
2044
2045
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2046
2047
4
  return 1;
2048
4
}
2049
2050
static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit)
2051
4
{
2052
4
  ir_ref if_timeout, if_exception;
2053
2054
  // EX(opline) = opline
2055
4
  ir_STORE(jit_EX(opline), jit_IP(jit));
2056
2057
4
  ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0));
2058
4
  if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0)));
2059
4
  ir_IF_FALSE(if_timeout);
2060
4
  ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout)); // noreturn
2061
4
  ir_MERGE_WITH_EMPTY_TRUE(if_timeout);
2062
2063
  // if (ZEND_HAS_OOM()) {
2064
4
  ir_ref if_delayed_oom = ir_IF(ir_LOAD_U8(ir_ADD_OFFSET(jit_EG(delayed_oom), offsetof(zend_oom_info, state))));
2065
4
  ir_IF_TRUE(if_delayed_oom);
2066
4
  ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_handle_delayed_oom));
2067
  // LOAD_OPLINE()
2068
4
  jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2069
4
  ir_ref if_delayed_oom_end = ir_END();
2070
4
  ir_IF_FALSE(if_delayed_oom);
2071
2072
4
  if (zend_interrupt_function) {
2073
0
    ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit));
2074
0
    if_exception = ir_IF(ir_LOAD_A(jit_EG(exception)));
2075
0
    ir_IF_TRUE(if_exception);
2076
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper));
2077
0
    ir_MERGE_WITH_EMPTY_FALSE(if_exception);
2078
2079
0
    jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
2080
0
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2081
0
  }
2082
2083
4
  ir_MERGE_WITH(if_delayed_oom_end);
2084
2085
4
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2086
4
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2087
4
  } else {
2088
0
    zend_jit_vm_enter(jit, jit_IP(jit));
2089
0
  }
2090
4
  return 1;
2091
4
}
2092
2093
static int zend_jit_leave_function_handler_stub(zend_jit_ctx *jit)
2094
4
{
2095
4
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
2096
4
  ir_TAILCALL(IR_OPCODE_HANDLER_RET, ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_leave_func_helper_tailcall));
2097
4
  return 1;
2098
#else
2099
  ir_ref call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
2100
  ir_ref if_top = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_TOP)));
2101
2102
  ir_IF_FALSE(if_top);
2103
2104
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2105
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2106
    jit_STORE_IP(jit,
2107
      ir_LOAD_A(jit_EX(opline)));
2108
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2109
  } else if (GCC_GLOBAL_REGS) {
2110
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), call_info);
2111
  } else {
2112
    ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_nested_func_helper), jit_FP(jit), jit_IP(jit), call_info);
2113
  }
2114
2115
  ir_IF_TRUE(if_top);
2116
2117
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2118
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2119
    ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2120
  } else if (GCC_GLOBAL_REGS) {
2121
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), call_info);
2122
  } else {
2123
    ir_TAILCALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_top_func_helper), jit_FP(jit), jit_IP(jit), call_info);
2124
  }
2125
2126
  return 1;
2127
#endif /* ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL */
2128
4
}
2129
2130
static int zend_jit_negative_shift_stub(zend_jit_ctx *jit)
2131
4
{
2132
4
  ir_CALL_2(IR_VOID,
2133
4
    ir_CONST_FUNC_PROTO(zend_throw_error,
2134
4
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2135
4
    ir_CONST_ADDR(zend_ce_arithmetic_error),
2136
4
    ir_CONST_ADDR("Bit shift by negative number"));
2137
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2138
4
  return 1;
2139
4
}
2140
2141
static int zend_jit_mod_by_zero_stub(zend_jit_ctx *jit)
2142
4
{
2143
4
  ir_CALL_2(IR_VOID,
2144
4
    ir_CONST_FUNC_PROTO(zend_throw_error,
2145
4
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2146
4
    ir_CONST_ADDR(zend_ce_division_by_zero_error),
2147
4
    ir_CONST_ADDR("Modulo by zero"));
2148
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op1_op2));
2149
4
  return 1;
2150
4
}
2151
2152
static int zend_jit_invalid_this_stub(zend_jit_ctx *jit)
2153
4
{
2154
4
  ir_CALL_2(IR_VOID,
2155
4
    ir_CONST_FUNC_PROTO(zend_throw_error,
2156
4
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2157
4
    IR_NULL,
2158
4
    ir_CONST_ADDR("Using $this when not in object context"));
2159
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
2160
4
  return 1;
2161
4
}
2162
2163
static int zend_jit_undefined_function_stub(zend_jit_ctx *jit)
2164
4
{
2165
  // JIT: load EX(opline)
2166
4
  ir_ref ref = ir_LOAD_A(jit_FP(jit));
2167
4
  ir_ref arg3 = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(zend_op, op2.constant)));
2168
2169
4
  if (sizeof(void*) == 8) {
2170
4
    arg3 = ir_LOAD_A(ir_ADD_A(ref, ir_SEXT_A(arg3)));
2171
4
  } else {
2172
0
    arg3 = ir_LOAD_A(arg3);
2173
0
  }
2174
4
  arg3 = ir_ADD_OFFSET(arg3, offsetof(zend_string, val));
2175
2176
4
  ir_CALL_3(IR_VOID,
2177
4
    ir_CONST_FUNC_PROTO(zend_throw_error,
2178
4
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2179
4
    IR_NULL,
2180
4
    ir_CONST_ADDR("Call to undefined function %s()"),
2181
4
    arg3);
2182
2183
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2184
2185
4
  return 1;
2186
4
}
2187
2188
static int zend_jit_throw_cannot_pass_by_ref_stub(zend_jit_ctx *jit)
2189
4
{
2190
4
  ir_ref opline, ref, rx, if_eq, if_tmp;
2191
2192
  // JIT: opline = EX(opline)
2193
4
  opline = ir_LOAD_A(jit_FP(jit));
2194
2195
  // JIT: ZVAL_UNDEF(ZEND_CALL_VAR(RX, opline->result.var))
2196
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2197
4
  if (sizeof(void*) == 8) {
2198
4
    ref = ir_ZEXT_A(ref);
2199
4
  }
2200
4
  rx = jit_IP(jit);
2201
4
  jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(rx, ref), ir_CONST_U32(IS_UNDEF));
2202
2203
  // last EX(call) frame may be delayed
2204
  // JIT: if (EX(call) == RX)
2205
4
  ref = ir_LOAD_A(jit_EX(call));
2206
4
  if_eq = ir_IF(ir_EQ(rx, ref));
2207
4
  ir_IF_FALSE(if_eq);
2208
2209
  // JIT: RX->prev_execute_data == EX(call)
2210
4
  ir_STORE(jit_CALL(rx, prev_execute_data), ref);
2211
2212
  // JIT: EX(call) = RX
2213
4
  ir_STORE(jit_EX(call), rx);
2214
4
  ir_MERGE_WITH_EMPTY_TRUE(if_eq);
2215
2216
  // JIT: IP = opline
2217
4
  jit_STORE_IP(jit, opline);
2218
2219
  // JIT: zend_cannot_pass_by_reference(opline->op2.num)
2220
4
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_cannot_pass_by_reference),
2221
4
    ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, op2.num))));
2222
2223
  // JIT: if (IP->op1_type == IS_TMP_VAR)
2224
4
  ref = ir_LOAD_U8(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1_type)));
2225
4
  if_tmp = ir_IF(ir_EQ(ref, ir_CONST_U8(IS_TMP_VAR)));
2226
4
  ir_IF_TRUE(if_tmp);
2227
2228
  // JIT: zval_ptr_dtor(EX_VAR(IP->op1.var))
2229
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_IP(jit), offsetof(zend_op, op1.var)));
2230
4
  if (sizeof(void*) == 8) {
2231
4
    ref = ir_ZEXT_A(ref);
2232
4
  }
2233
4
  ref = ir_ADD_A(jit_FP(jit), ref);
2234
4
  jit_ZVAL_PTR_DTOR(jit,
2235
4
    ZEND_ADDR_REF_ZVAL(ref),
2236
4
    MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, false, NULL);
2237
4
  ir_MERGE_WITH_EMPTY_FALSE(if_tmp);
2238
2239
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2240
2241
4
  return 1;
2242
4
}
2243
2244
static int zend_jit_icall_throw_stub(zend_jit_ctx *jit)
2245
4
{
2246
4
  ir_ref ip, if_set;
2247
2248
  // JIT: zend_rethrow_exception(zend_execute_data *execute_data)
2249
  // JIT: if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) {
2250
4
  jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2251
4
  ip = jit_IP(jit);
2252
4
  if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2253
4
    ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2254
4
  ir_IF_FALSE(if_set);
2255
2256
  // JIT: EG(opline_before_exception) = opline;
2257
4
  ir_STORE(jit_EG(opline_before_exception), ip);
2258
4
  ir_MERGE_WITH_EMPTY_TRUE(if_set);
2259
2260
  // JIT: opline = EG(exception_op);
2261
4
  jit_STORE_IP(jit, jit_EG(exception_op));
2262
2263
4
  ir_STORE(jit_EX(opline), jit_IP(jit));
2264
2265
4
  ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2266
2267
4
  return 1;
2268
4
}
2269
2270
static int zend_jit_leave_throw_stub(zend_jit_ctx *jit)
2271
4
{
2272
4
  ir_ref ip, if_set;
2273
2274
  // JIT: if (opline->opcode != ZEND_HANDLE_EXCEPTION) {
2275
4
  jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
2276
4
  ip = jit_IP(jit);
2277
4
  if_set = ir_IF(ir_EQ(ir_LOAD_U8(ir_ADD_OFFSET(ip, offsetof(zend_op, opcode))),
2278
4
    ir_CONST_U8(ZEND_HANDLE_EXCEPTION)));
2279
4
  ir_IF_FALSE(if_set);
2280
2281
  // JIT: EG(opline_before_exception) = opline;
2282
4
  ir_STORE(jit_EG(opline_before_exception), ip);
2283
4
  ir_MERGE_WITH_EMPTY_TRUE(if_set);
2284
2285
  // JIT: opline = EG(exception_op);
2286
4
  jit_STORE_IP(jit, jit_EG(exception_op));
2287
2288
4
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2289
4
    ir_STORE(jit_EX(opline), jit_IP(jit));
2290
2291
    // JIT: HANDLE_EXCEPTION()
2292
4
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
2293
4
  } else {
2294
0
    zend_jit_vm_leave(jit, jit_IP(jit));
2295
0
  }
2296
2297
4
  return 1;
2298
4
}
2299
2300
static int zend_jit_hybrid_runtime_jit_stub(zend_jit_ctx *jit)
2301
4
{
2302
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) {
2303
4
    return 0;
2304
4
  }
2305
2306
0
  ir_CALL(IR_VOID, ir_CONST_OPCODE_HANDLER_FUNC(zend_runtime_jit));
2307
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2308
0
  return 1;
2309
4
}
2310
2311
static int zend_jit_hybrid_profile_jit_stub(zend_jit_ctx *jit)
2312
4
{
2313
4
  ir_ref addr, func, run_time_cache, jit_extension;
2314
2315
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) {
2316
4
    return 0;
2317
4
  }
2318
2319
0
  addr = ir_CONST_ADDR(&zend_jit_profile_counter),
2320
0
  ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2321
2322
0
  func = ir_LOAD_A(jit_EX(func));
2323
0
  run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
2324
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2325
2326
0
  if (zend_jit_profile_counter_rid) {
2327
0
    addr = ir_ADD_OFFSET(run_time_cache, zend_jit_profile_counter_rid * sizeof(void*));
2328
0
  } else {
2329
0
    addr = run_time_cache;
2330
0
  }
2331
0
  ir_STORE(addr, ir_ADD_L(ir_LOAD_L(addr), ir_CONST_LONG(1)));
2332
2333
0
  addr = ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_extension, orig_handler));
2334
0
  ir_IJMP(ir_LOAD_A(addr));
2335
2336
0
  return 1;
2337
4
}
2338
2339
static int _zend_jit_hybrid_hot_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2340
0
{
2341
0
  ir_ref func, jit_extension, addr, ref, if_overflow;
2342
0
2343
0
  func = ir_LOAD_A(jit_EX(func));
2344
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2345
0
  addr = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, counter)));
2346
0
  ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2347
0
  ir_STORE(addr, ref);
2348
0
  if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2349
0
2350
0
  ir_IF_TRUE_cold(if_overflow);
2351
0
  ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2352
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_hot_func),
2353
0
    jit_FP(jit),
2354
0
    jit_IP(jit));
2355
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2356
0
2357
0
  ir_IF_FALSE(if_overflow);
2358
0
  ref = ir_SUB_A(jit_IP(jit),
2359
0
    ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, opcodes))));
2360
0
  ref = ir_DIV_A(ref, ir_CONST_ADDR(sizeof(zend_op) / sizeof(void*)));
2361
0
2362
0
  addr = ir_ADD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_hot_extension, orig_handlers)),
2363
0
    ref);
2364
0
  ir_IJMP(ir_LOAD_A(addr));
2365
0
2366
0
  return 1;
2367
0
}
2368
2369
static int zend_jit_hybrid_func_hot_counter_stub(zend_jit_ctx *jit)
2370
4
{
2371
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2372
4
    return 0;
2373
4
  }
2374
2375
0
  return _zend_jit_hybrid_hot_counter_stub(jit,
2376
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2377
4
}
2378
2379
static int zend_jit_hybrid_loop_hot_counter_stub(zend_jit_ctx *jit)
2380
4
{
2381
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2382
4
    return 0;
2383
4
  }
2384
2385
0
  return _zend_jit_hybrid_hot_counter_stub(jit,
2386
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2387
4
}
2388
2389
static ir_ref _zend_jit_orig_opline_handler(zend_jit_ctx *jit, ir_ref offset)
2390
4
{
2391
4
  ir_ref addr = ir_ADD_A(offset, jit_IP(jit));
2392
2393
4
  return ir_LOAD_A(addr);
2394
4
}
2395
2396
static ir_ref zend_jit_orig_opline_handler(zend_jit_ctx *jit)
2397
4
{
2398
4
  ir_ref func, jit_extension, offset;
2399
2400
4
  func = ir_LOAD_A(jit_EX(func));
2401
4
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2402
4
  offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2403
4
  return _zend_jit_orig_opline_handler(jit, offset);
2404
4
}
2405
2406
static int _zend_jit_hybrid_trace_counter_stub(zend_jit_ctx *jit, uint32_t cost)
2407
0
{
2408
0
  ir_ref func, jit_extension, offset, addr, ref, if_overflow, ret, if_halt;
2409
0
2410
0
  func = ir_LOAD_A(jit_EX(func));
2411
0
  jit_extension = ir_LOAD_A(ir_ADD_OFFSET(func, offsetof(zend_op_array, reserved[zend_func_info_rid])));
2412
0
  offset = ir_LOAD_A(ir_ADD_OFFSET(jit_extension, offsetof(zend_jit_op_array_trace_extension, offset)));
2413
0
  addr = ir_LOAD_A(ir_ADD_OFFSET(ir_ADD_A(offset, jit_IP(jit)), offsetof(zend_op_trace_info, counter)));
2414
0
  ref = ir_SUB_I16(ir_LOAD_I16(addr), ir_CONST_I16(cost));
2415
0
  ir_STORE(addr, ref);
2416
0
  if_overflow = ir_IF(ir_LE(ref, ir_CONST_I16(0)));
2417
0
2418
0
  ir_IF_TRUE_cold(if_overflow);
2419
0
  ir_STORE(addr, ir_CONST_I16(ZEND_JIT_COUNTER_INIT));
2420
0
  ret = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_trace_hot_root),
2421
0
    jit_FP(jit),
2422
0
    jit_IP(jit));
2423
0
  if_halt = ir_IF(ir_LT(ret, ir_CONST_I32(0)));
2424
0
  ir_IF_FALSE(if_halt);
2425
0
2426
0
  ref = jit_EG(current_execute_data);
2427
0
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2428
0
  ref = ir_LOAD_A(jit_EX(opline));
2429
0
  jit_STORE_IP(jit, ref);
2430
0
  ir_IJMP(ir_LOAD_A(jit_IP(jit)));
2431
0
2432
0
  ir_IF_FALSE(if_overflow);
2433
0
  ir_IJMP(_zend_jit_orig_opline_handler(jit, offset));
2434
0
2435
0
  ir_IF_TRUE(if_halt);
2436
0
  ir_IJMP(ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_halt_op->handler));
2437
0
2438
0
  return 1;
2439
0
}
2440
2441
static int zend_jit_hybrid_func_trace_counter_stub(zend_jit_ctx *jit)
2442
4
{
2443
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) {
2444
4
    return 0;
2445
4
  }
2446
2447
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2448
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func)));
2449
4
}
2450
2451
static int zend_jit_hybrid_ret_trace_counter_stub(zend_jit_ctx *jit)
2452
4
{
2453
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) {
2454
4
    return 0;
2455
4
  }
2456
2457
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2458
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
2459
4
}
2460
2461
static int zend_jit_hybrid_loop_trace_counter_stub(zend_jit_ctx *jit)
2462
4
{
2463
4
  if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) {
2464
4
    return 0;
2465
4
  }
2466
2467
0
  return _zend_jit_hybrid_trace_counter_stub(jit,
2468
0
    ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
2469
4
}
2470
2471
static int zend_jit_trace_halt_stub(zend_jit_ctx *jit)
2472
4
{
2473
4
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
2474
0
    ir_TAILCALL(IR_VOID, ir_CONST_OPCODE_HANDLER_FUNC(zend_jit_halt_op->handler));
2475
4
  } else if (GCC_GLOBAL_REGS) {
2476
0
    jit_STORE_IP(jit, IR_NULL);
2477
0
    ir_RETURN(IR_VOID);
2478
4
  } else {
2479
4
    ir_RETURN(ir_CONST_ADDR(ZEND_VM_ENTER_BIT)); // ZEND_VM_RETURN
2480
4
  }
2481
4
  return 1;
2482
4
}
2483
2484
static int zend_jit_trace_escape_stub(zend_jit_ctx *jit)
2485
4
{
2486
4
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2487
4
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2488
4
  } else {
2489
0
    zend_jit_vm_enter(jit, jit_IP(jit));
2490
0
  }
2491
2492
4
  return 1;
2493
4
}
2494
2495
static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
2496
4
{
2497
4
  ir_ref ref, ret, if_zero, addr;
2498
2499
  // EX(opline) = opline
2500
4
  ir_STORE(jit_EX(opline), jit_IP(jit));
2501
2502
4
  ret = ir_EXITCALL(ir_CONST_FC_FUNC(zend_jit_trace_exit));
2503
2504
4
  if_zero = ir_IF(ir_EQ(ret, ir_CONST_I32(0)));
2505
2506
4
  ir_IF_TRUE(if_zero);
2507
2508
4
  ref = jit_EG(current_execute_data);
2509
4
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2510
4
  ref = ir_LOAD_A(jit_EX(opline));
2511
4
  jit_STORE_IP(jit, ref);
2512
2513
4
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2514
4
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
2515
4
  } else {
2516
0
    zend_jit_vm_enter(jit, ref);
2517
0
  }
2518
2519
4
  ir_IF_FALSE(if_zero);
2520
2521
4
  ir_GUARD(ir_GE(ret, ir_CONST_I32(0)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
2522
2523
4
  ref = jit_EG(current_execute_data);
2524
4
  jit_STORE_FP(jit, ir_LOAD_A(ref));
2525
2526
4
  ref = ir_LOAD_A(jit_EX(opline));
2527
4
  jit_STORE_IP(jit, ref);
2528
2529
  // check for interrupt (try to avoid this ???)
2530
4
  zend_jit_check_timeout(jit, NULL, NULL);
2531
2532
4
  addr = zend_jit_orig_opline_handler(jit);
2533
4
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2534
4
    zend_jit_tailcall_handler(jit, addr);
2535
4
  } else {
2536
#if defined(IR_TARGET_X86)
2537
    addr = ir_CAST_OPCODE_HANDLER_FUNC(addr);
2538
#endif
2539
0
    ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit));
2540
0
    zend_jit_vm_enter(jit, ref);
2541
0
  }
2542
2543
4
  return 1;
2544
4
}
2545
2546
static int zend_jit_undefined_offset_stub(zend_jit_ctx *jit)
2547
4
{
2548
4
  if (GCC_GLOBAL_REGS) {
2549
0
    ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key));
2550
4
  } else {
2551
4
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key), jit_FP(jit));
2552
4
  }
2553
2554
4
  return 1;
2555
4
}
2556
2557
static int zend_jit_undefined_key_stub(zend_jit_ctx *jit)
2558
4
{
2559
4
  if (GCC_GLOBAL_REGS) {
2560
0
    ir_TAILCALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key));
2561
4
  } else {
2562
4
    ir_TAILCALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_string_key), jit_FP(jit));
2563
4
  }
2564
2565
4
  return 1;
2566
4
}
2567
2568
static int zend_jit_cannot_add_element_stub(zend_jit_ctx *jit)
2569
4
{
2570
4
  ir_ref opline = ir_LOAD_A(jit_EX(opline));
2571
4
  ir_ref ref, if_result_used;
2572
2573
4
  if_result_used = ir_IF(ir_AND_U8(
2574
4
    ir_LOAD_U8(ir_ADD_OFFSET(opline, offsetof(zend_op, result_type))),
2575
4
    ir_CONST_U8(IS_TMP_VAR|IS_VAR)));
2576
4
  ir_IF_TRUE(if_result_used);
2577
2578
4
  ref = ir_LOAD_U32(ir_ADD_OFFSET(opline, offsetof(zend_op, result.var)));
2579
4
  if (sizeof(void*) == 8) {
2580
4
    ref = ir_ZEXT_A(ref);
2581
4
  }
2582
4
  jit_set_Z_TYPE_INFO_ref(jit, ir_ADD_A(jit_FP(jit), ref), ir_CONST_U32(IS_UNDEF));
2583
4
  ir_MERGE_WITH_EMPTY_FALSE(if_result_used);
2584
2585
4
  ir_CALL_2(IR_VOID,
2586
4
    ir_CONST_FUNC_PROTO(zend_throw_error,
2587
4
      ir_proto_2(&jit->ctx, IR_VARARG_FUNC, IR_VOID, IR_ADDR, IR_ADDR)),
2588
4
    IR_NULL,
2589
4
    ir_CONST_ADDR("Cannot add element to the array as the next element is already occupied"));
2590
4
  ir_RETURN(IR_VOID);
2591
2592
4
  return 1;
2593
4
}
2594
2595
static int zend_jit_assign_const_stub(zend_jit_ctx *jit)
2596
4
{
2597
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2598
4
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2599
2600
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2601
4
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2602
4
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2603
2604
4
  if (!zend_jit_assign_to_variable(
2605
4
      jit, NULL,
2606
4
      var_addr, var_addr, -1, -1,
2607
4
      IS_CONST, val_addr, val_info,
2608
4
      0, 0, false)) {
2609
0
    return 0;
2610
0
  }
2611
4
  ir_RETURN(IR_VOID);
2612
4
  return 1;
2613
4
}
2614
2615
static int zend_jit_assign_tmp_stub(zend_jit_ctx *jit)
2616
4
{
2617
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2618
4
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2619
2620
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2621
4
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2622
4
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN;
2623
2624
4
  if (!zend_jit_assign_to_variable(
2625
4
      jit, NULL,
2626
4
      var_addr, var_addr, -1, -1,
2627
4
      IS_TMP_VAR, val_addr, val_info,
2628
4
      0, 0, false)) {
2629
0
    return 0;
2630
0
  }
2631
4
  ir_RETURN(IR_VOID);
2632
4
  return 1;
2633
4
}
2634
2635
static int zend_jit_assign_var_stub(zend_jit_ctx *jit)
2636
4
{
2637
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2638
4
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2639
2640
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2641
4
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2642
4
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF;
2643
2644
4
  if (!zend_jit_assign_to_variable(
2645
4
      jit, NULL,
2646
4
      var_addr, var_addr, -1, -1,
2647
4
      IS_VAR, val_addr, val_info,
2648
4
      0, 0, false)) {
2649
0
    return 0;
2650
0
  }
2651
4
  ir_RETURN(IR_VOID);
2652
4
  return 1;
2653
4
}
2654
2655
static int zend_jit_assign_cv_noref_stub(zend_jit_ctx *jit)
2656
4
{
2657
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2658
4
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2659
2660
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2661
4
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2662
4
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/;
2663
2664
4
  if (!zend_jit_assign_to_variable(
2665
4
      jit, NULL,
2666
4
      var_addr, var_addr, -1, -1,
2667
4
      IS_CV, val_addr, val_info,
2668
4
      0, 0, false)) {
2669
0
    return 0;
2670
0
  }
2671
4
  ir_RETURN(IR_VOID);
2672
4
  return 1;
2673
4
}
2674
2675
static int zend_jit_new_array_stub(zend_jit_ctx *jit)
2676
4
{
2677
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2678
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2679
4
  ir_ref ref = ir_CALL(IR_ADDR, ir_CONST_FC_FUNC(_zend_new_array_0));
2680
2681
4
  jit_set_Z_PTR(jit, var_addr, ref);
2682
4
  jit_set_Z_TYPE_INFO(jit, var_addr, IS_ARRAY_EX);
2683
4
  ir_RETURN(ref);
2684
4
  return 1;
2685
4
}
2686
2687
static int zend_jit_assign_cv_stub(zend_jit_ctx *jit)
2688
4
{
2689
4
  ir_ref var = ir_PARAM(IR_ADDR, "var", 1);
2690
4
  ir_ref val = ir_PARAM(IR_ADDR, "val", 2);
2691
2692
4
  zend_jit_addr var_addr = ZEND_ADDR_REF_ZVAL(var);
2693
4
  zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val);
2694
4
  uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/;
2695
2696
4
  if (!zend_jit_assign_to_variable(
2697
4
      jit, NULL,
2698
4
      var_addr, var_addr, -1, -1,
2699
4
      IS_CV, val_addr, val_info,
2700
4
      0, 0, false)) {
2701
0
    return 0;
2702
0
  }
2703
4
  ir_RETURN(IR_VOID);
2704
4
  return 1;
2705
4
}
2706
2707
static void zend_jit_init_ctx(zend_jit_ctx *jit, uint32_t flags)
2708
9.96k
{
2709
#if defined (__CET__) && (__CET__ & 1) != 0
2710
  flags |= IR_GEN_ENDBR;
2711
#endif
2712
9.96k
  flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
2713
2714
9.96k
  ir_init(&jit->ctx, flags, 256, 1024);
2715
9.96k
  jit->ctx.ret_type = -1;
2716
2717
9.96k
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2718
9.96k
  jit->ctx.mflags |= default_mflags;
2719
9.96k
  if (JIT_G(opt_flags) & allowed_opt_flags & ZEND_JIT_CPU_AVX) {
2720
9.83k
    jit->ctx.mflags |= IR_X86_AVX;
2721
9.83k
  }
2722
#elif defined(IR_TARGET_AARCH64)
2723
  jit->ctx.get_veneer = zend_jit_get_veneer;
2724
  jit->ctx.set_veneer = zend_jit_set_veneer;
2725
#endif
2726
2727
9.96k
  jit->ctx.fixed_regset = (1<<ZREG_FP) | (1<<ZREG_IP);
2728
9.96k
  if (!(flags & IR_FUNCTION)) {
2729
9.93k
    jit->ctx.flags |= IR_NO_STACK_COMBINE;
2730
9.93k
    if (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2731
9.93k
      jit->ctx.flags |= IR_FUNCTION;
2732
      /* Stack must be 16 byte aligned */
2733
      /* TODO: select stack size ??? */
2734
9.93k
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
2735
# if defined(IR_TARGET_AARCH64)
2736
      /* Must save LR */
2737
      jit->ctx.flags |= IR_USE_FRAME_POINTER;
2738
      /* Same as HYBRID VM */
2739
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 4; /* 4 spill slots */
2740
# else
2741
      /* Same as HYBRID VM, plus 1 slot for re-alignment (caller pushes return address, frame is not aligned on entry) */
2742
9.93k
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 5; /* 5 spill slots (8 bytes) or 10 spill slots (4 bytes) */
2743
9.93k
# endif
2744
#elif defined(IR_TARGET_AARCH64)
2745
      jit->ctx.flags |= IR_USE_FRAME_POINTER;
2746
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 16; /* 10 saved registers and 6 spill slots (8 bytes) */
2747
#elif defined(_WIN64)
2748
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 8 saved registers and 3 spill slots (8 bytes) */
2749
#elif defined(IR_TARGET_X86_64)
2750
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 9;  /* 6 saved registers and 3 spill slots (8 bytes) */
2751
#else /* IR_TARGET_x86 */
2752
      jit->ctx.fixed_stack_frame_size = sizeof(void*) * 11; /* 4 saved registers and 7 spill slots (4 bytes) */
2753
#endif
2754
      /* JIT-ed code is called only from execute_ex, which takes care
2755
       * of saving ZREG_FP, ZREG_IP when GCC_GLOBAL_REGS is 1, so we don't
2756
       * have to save them.
2757
       */
2758
9.93k
      if (GCC_GLOBAL_REGS) {
2759
0
        jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED & ~((1<<ZREG_FP) | (1<<ZREG_IP));
2760
9.93k
      } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
2761
        /* The only preserved register on x86 is RBP:
2762
         * https://github.com/llvm/llvm-project/blob/a414877a7a5f000d01370acb1162eb1dea87f48c/llvm/lib/Target/X86/X86RegisterInfo.cpp#L319
2763
         * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/X86/X86CallingConv.td#L1183
2764
         * On AArch64 it's LR, FP:
2765
         * https://github.com/llvm/llvm-project/blob/68bfe91b5a34f80dbcc4f0a7fa5d7aa1cdf959c2/llvm/lib/Target/AArch64/AArch64CallingConvention.td#L681
2766
         *
2767
         * Add them to the fixed_regset to prevent usage or these regs.
2768
         * It's cheaper to not use them than to save them.
2769
         */
2770
9.93k
#if defined(IR_TARGET_X64)
2771
9.93k
        jit->ctx.fixed_regset |= (1<<IR_REG_FP);
2772
#elif defined(IR_TARGET_AARCH64)
2773
        jit->ctx.fixed_regset |= (1<<IR_REG_FP) | (1<<IR_REG_LR);
2774
#else
2775
        ZEND_UNREACHABLE();
2776
#endif
2777
9.93k
      } else {
2778
0
        jit->ctx.fixed_save_regset = IR_REGSET_PRESERVED;
2779
//#ifdef _WIN64
2780
//        jit->ctx.fixed_save_regset &= 0xffff; // TODO: don't save FP registers ???
2781
//#endif
2782
0
      }
2783
#ifdef _WIN64
2784
      jit->ctx.fixed_call_stack_size = 16 + IR_SHADOW_ARGS;
2785
#else
2786
9.93k
      jit->ctx.fixed_call_stack_size = 16;
2787
9.93k
#endif
2788
9.93k
    } else {
2789
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
2790
      jit->ctx.fixed_stack_red_zone = ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE;
2791
      if (jit->ctx.fixed_stack_red_zone > 16) {
2792
        jit->ctx.fixed_stack_frame_size = jit->ctx.fixed_stack_red_zone - 16;
2793
        jit->ctx.fixed_call_stack_size = 16;
2794
      }
2795
      jit->ctx.flags |= IR_MERGE_EMPTY_ENTRIES;
2796
#else
2797
0
      jit->ctx.fixed_stack_red_zone = 0;
2798
0
      jit->ctx.fixed_stack_frame_size = 32; /* 4 spill slots (8 bytes) or 8 spill slots (4 bytes) */
2799
0
      jit->ctx.fixed_call_stack_size = 16;
2800
0
#endif
2801
0
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
2802
0
      jit->ctx.fixed_regset |= (1<<IR_REG_FP); /* prevent %rbp (%r5) usage */
2803
0
#endif
2804
0
    }
2805
9.93k
  }
2806
2807
9.96k
  jit->ctx.snapshot_create = (ir_snapshot_create_t)jit_SNAPSHOT;
2808
2809
9.96k
  jit->op_array = NULL;
2810
9.96k
  jit->current_op_array = NULL;
2811
9.96k
  jit->ssa = NULL;
2812
9.96k
  jit->name = NULL;
2813
9.96k
  jit->last_valid_opline = NULL;
2814
9.96k
  jit->use_last_valid_opline = false;
2815
9.96k
  jit->track_last_valid_opline = false;
2816
9.96k
  jit->reuse_ip = false;
2817
9.96k
  jit->delayed_call_level = 0;
2818
9.96k
  delayed_call_chain = false;
2819
9.96k
  jit->b = -1;
2820
#ifdef ZTS
2821
  jit->tls = IR_UNUSED;
2822
#endif
2823
9.96k
  jit->fp = IR_UNUSED;
2824
9.96k
  jit->poly_func_ref = IR_UNUSED;
2825
9.96k
  jit->poly_this_ref = IR_UNUSED;
2826
9.96k
  jit->trace_loop_ref = IR_UNUSED;
2827
9.96k
  jit->return_inputs = IR_UNUSED;
2828
9.96k
  jit->bb_start_ref = NULL;
2829
9.96k
  jit->bb_predecessors = NULL;
2830
9.96k
  jit->bb_edges = NULL;
2831
9.96k
  jit->trace = NULL;
2832
9.96k
  jit->ra = NULL;
2833
9.96k
  jit->delay_var = -1;
2834
9.96k
  jit->delay_refs = NULL;
2835
9.96k
  jit->eg_exception_addr = 0;
2836
9.96k
  memset(jit->stub_addr, 0, sizeof(jit->stub_addr));
2837
2838
9.96k
  ir_START();
2839
9.96k
}
2840
2841
static int zend_jit_free_ctx(zend_jit_ctx *jit)
2842
9.96k
{
2843
9.96k
  if (jit->name) {
2844
2.50k
    zend_string_release(jit->name);
2845
2.50k
  }
2846
9.96k
  ir_free(&jit->ctx);
2847
9.96k
  return 1;
2848
9.96k
}
2849
2850
static void *zend_jit_ir_compile(ir_ctx *ctx, size_t *size, const char *name)
2851
9.93k
{
2852
9.93k
  void *entry;
2853
9.93k
  ir_code_buffer code_buffer;
2854
2855
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_SRC) {
2856
0
    if (name) fprintf(stderr, "%s: ; after folding\n", name);
2857
0
    ir_save(ctx, 0, stderr);
2858
0
  }
2859
2860
9.93k
#if ZEND_DEBUG
2861
9.93k
  ir_check(ctx);
2862
9.93k
#endif
2863
2864
9.93k
  ir_build_def_use_lists(ctx);
2865
2866
9.93k
#if ZEND_DEBUG
2867
9.93k
  ir_check(ctx);
2868
9.93k
#endif
2869
2870
9.93k
#if 1
2871
9.93k
  ir_sccp(ctx);
2872
9.93k
#endif
2873
2874
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCCP) {
2875
0
    if (name) fprintf(stderr, "%s: ; after SCCP\n", name);
2876
0
    ir_save(ctx, 0, stderr);
2877
0
  }
2878
2879
9.93k
  ir_build_cfg(ctx);
2880
9.93k
  ir_build_dominators_tree(ctx);
2881
9.93k
  ir_find_loops(ctx);
2882
2883
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_CFG) {
2884
0
    if (name) fprintf(stderr, "%s: ; after CFG\n", name);
2885
0
    ir_save(ctx, IR_SAVE_CFG, stderr);
2886
0
  }
2887
2888
9.93k
  ir_gcm(ctx);
2889
2890
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_GCM) {
2891
0
    if (name) fprintf(stderr, "%s: ; after GCM\n", name);
2892
0
    ir_save(ctx, IR_SAVE_CFG|IR_SAVE_CFG_MAP, stderr);
2893
0
  }
2894
2895
9.93k
  ir_schedule(ctx);
2896
2897
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE) {
2898
0
    if (name) fprintf(stderr, "%s: ; after schedule\n", name);
2899
0
    ir_save(ctx, IR_SAVE_CFG, stderr);
2900
0
  }
2901
2902
9.93k
  ir_match(ctx);
2903
9.93k
#if !defined(IR_TARGET_AARCH64)
2904
9.93k
  ctx->flags &= ~IR_USE_FRAME_POINTER; /* don't use FRAME_POINTER even with ALLOCA, TODO: cleanup this ??? */
2905
9.93k
#endif
2906
9.93k
  ir_assign_virtual_registers(ctx);
2907
9.93k
  ir_compute_live_ranges(ctx);
2908
9.93k
  ir_coalesce(ctx);
2909
9.93k
  ir_reg_alloc(ctx);
2910
2911
9.93k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_AFTER_REGS) {
2912
0
    if (name) fprintf(stderr, "%s: ; after register allocation\n", name);
2913
0
    ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2914
0
    ir_dump_live_ranges(ctx, stderr);
2915
0
  }
2916
2917
9.93k
  ir_schedule_blocks(ctx);
2918
2919
9.93k
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
2920
0
    if (JIT_G(debug) & ZEND_JIT_DEBUG_IR_CODEGEN) {
2921
0
      if (name) fprintf(stderr, "%s: ; codegen\n", name);
2922
0
      ir_dump_codegen(ctx, stderr);
2923
0
    } else {
2924
0
      if (name) fprintf(stderr, "%s: ; final\n", name);
2925
0
      ir_save(ctx, IR_SAVE_CFG|IR_SAVE_RULES|IR_SAVE_REGS, stderr);
2926
0
    }
2927
0
  }
2928
2929
9.93k
#if ZEND_DEBUG
2930
9.93k
  ir_check(ctx);
2931
9.93k
#endif
2932
2933
9.93k
  code_buffer.start = dasm_buf;
2934
9.93k
  code_buffer.end = dasm_end;
2935
9.93k
  code_buffer.pos = *dasm_ptr;
2936
9.93k
  ctx->code_buffer = &code_buffer;
2937
2938
9.93k
  entry = ir_emit_code(ctx, size);
2939
2940
9.93k
  *dasm_ptr = code_buffer.pos;
2941
2942
#if defined(IR_TARGET_AARCH64)
2943
  if (ctx->flags2 & IR_HAS_VENEERS) {
2944
    if (entry) {
2945
      zend_jit_commit_veneers();
2946
    } else {
2947
      zend_jit_discard_veneers();
2948
    }
2949
  }
2950
#endif
2951
2952
9.93k
  return entry;
2953
9.93k
}
2954
2955
static void zend_jit_setup_stubs(void)
2956
4
{
2957
4
  zend_jit_ctx jit;
2958
4
  void *entry;
2959
4
  size_t size;
2960
4
  uint32_t i;
2961
2962
132
  for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) {
2963
128
    zend_jit_init_ctx(&jit, zend_jit_stubs[i].flags);
2964
2965
128
    if (!zend_jit_stubs[i].stub(&jit)) {
2966
28
      zend_jit_free_ctx(&jit);
2967
28
      zend_jit_stub_handlers[i] = NULL;
2968
28
      continue;
2969
28
    }
2970
2971
100
    entry = zend_jit_ir_compile(&jit.ctx, &size, zend_jit_stubs[i].name);
2972
100
    if (!entry) {
2973
0
      zend_jit_free_ctx(&jit);
2974
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile stub");
2975
0
    }
2976
2977
100
    zend_jit_stub_handlers[i] = entry;
2978
2979
100
    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)) {
2980
#ifdef HAVE_CAPSTONE
2981
      if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
2982
        ir_disasm_add_symbol(zend_jit_stubs[i].name, (uintptr_t)entry, size);
2983
      }
2984
      if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_STUBS) {
2985
        ir_disasm(zend_jit_stubs[i].name,
2986
          entry, size, (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0, &jit.ctx, stderr);
2987
      }
2988
#endif
2989
0
#ifndef _WIN32
2990
0
      if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
2991
//        ir_mem_unprotect(entry, size);
2992
0
        ir_gdb_register(zend_jit_stubs[i].name, entry, size, 0, 0);
2993
//        ir_mem_protect(entry, size);
2994
0
      }
2995
2996
0
      if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
2997
0
        ir_perf_map_register(zend_jit_stubs[i].name, entry, size);
2998
0
        if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
2999
0
          ir_perf_jitdump_register(zend_jit_stubs[i].name, entry, size);
3000
0
        }
3001
0
      }
3002
0
#endif
3003
0
    }
3004
100
    zend_jit_free_ctx(&jit);
3005
100
  }
3006
4
}
3007
3008
#define REGISTER_HELPER(n)  \
3009
  ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)n, sizeof(void*));
3010
#define REGISTER_DATA(n)  \
3011
  ir_disasm_add_symbol(#n, (uint64_t)(uintptr_t)&n, sizeof(n));
3012
3013
static void zend_jit_setup_disasm(void)
3014
0
{
3015
#ifdef HAVE_CAPSTONE
3016
  ir_disasm_init();
3017
3018
  if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) {
3019
    zend_op opline;
3020
3021
    memset(&opline, 0, sizeof(opline));
3022
3023
    opline.opcode = ZEND_DO_UCALL;
3024
    opline.result_type = IS_UNUSED;
3025
    zend_vm_set_opcode_handler(&opline);
3026
    ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3027
3028
    opline.opcode = ZEND_DO_UCALL;
3029
    opline.result_type = IS_VAR;
3030
    zend_vm_set_opcode_handler(&opline);
3031
    ir_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3032
3033
    opline.opcode = ZEND_DO_FCALL_BY_NAME;
3034
    opline.result_type = IS_UNUSED;
3035
    zend_vm_set_opcode_handler(&opline);
3036
    ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3037
3038
    opline.opcode = ZEND_DO_FCALL_BY_NAME;
3039
    opline.result_type = IS_VAR;
3040
    zend_vm_set_opcode_handler(&opline);
3041
    ir_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3042
3043
    opline.opcode = ZEND_DO_FCALL;
3044
    opline.result_type = IS_UNUSED;
3045
    zend_vm_set_opcode_handler(&opline);
3046
    ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3047
3048
    opline.opcode = ZEND_DO_FCALL;
3049
    opline.result_type = IS_VAR;
3050
    zend_vm_set_opcode_handler(&opline);
3051
    ir_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3052
3053
    opline.opcode = ZEND_RETURN;
3054
    opline.op1_type = IS_CONST;
3055
    zend_vm_set_opcode_handler(&opline);
3056
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3057
3058
    opline.opcode = ZEND_RETURN;
3059
    opline.op1_type = IS_TMP_VAR;
3060
    zend_vm_set_opcode_handler(&opline);
3061
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3062
3063
    opline.opcode = ZEND_RETURN;
3064
    opline.op1_type = IS_VAR;
3065
    zend_vm_set_opcode_handler(&opline);
3066
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3067
3068
    opline.opcode = ZEND_RETURN;
3069
    opline.op1_type = IS_CV;
3070
    zend_vm_set_opcode_handler(&opline);
3071
    ir_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*));
3072
3073
    ir_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*));
3074
  }
3075
3076
  REGISTER_DATA(zend_jit_profile_counter);
3077
3078
  REGISTER_HELPER(zend_runtime_jit);
3079
  REGISTER_HELPER(zend_jit_hot_func);
3080
  REGISTER_HELPER(zend_jit_trace_hot_root);
3081
  REGISTER_HELPER(zend_jit_trace_exit);
3082
3083
  REGISTER_HELPER(zend_jit_array_free);
3084
  REGISTER_HELPER(zend_jit_undefined_op_helper);
3085
  REGISTER_HELPER(zend_jit_pre_inc_typed_ref);
3086
  REGISTER_HELPER(zend_jit_pre_dec_typed_ref);
3087
  REGISTER_HELPER(zend_jit_post_inc_typed_ref);
3088
  REGISTER_HELPER(zend_jit_post_dec_typed_ref);
3089
  REGISTER_HELPER(zend_jit_pre_inc);
3090
  REGISTER_HELPER(zend_jit_pre_dec);
3091
  REGISTER_HELPER(zend_jit_add_arrays_helper);
3092
  REGISTER_HELPER(zend_jit_fast_assign_concat_helper);
3093
  REGISTER_HELPER(zend_jit_fast_concat_helper);
3094
  REGISTER_HELPER(zend_jit_fast_concat_tmp_helper);
3095
  REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp);
3096
  REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
3097
  REGISTER_HELPER(zend_jit_assign_const_to_typed_ref);
3098
  REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref);
3099
  REGISTER_HELPER(zend_jit_assign_var_to_typed_ref);
3100
  REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref);
3101
  REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2);
3102
  REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2);
3103
  REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2);
3104
  REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2);
3105
  REGISTER_HELPER(zend_jit_check_constant);
3106
  REGISTER_HELPER(zend_jit_get_constant);
3107
  REGISTER_HELPER(zend_jit_int_extend_stack_helper);
3108
  REGISTER_HELPER(zend_jit_extend_stack_helper);
3109
  REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper);
3110
  REGISTER_HELPER(zend_jit_find_func_helper);
3111
  REGISTER_HELPER(zend_jit_find_ns_func_helper);
3112
  REGISTER_HELPER(zend_jit_jmp_frameless_helper);
3113
  REGISTER_HELPER(zend_jit_unref_helper);
3114
  REGISTER_HELPER(zend_jit_invalid_method_call);
3115
  REGISTER_HELPER(zend_jit_invalid_method_call_tmp);
3116
  REGISTER_HELPER(zend_jit_find_method_helper);
3117
  REGISTER_HELPER(zend_jit_find_method_tmp_helper);
3118
  REGISTER_HELPER(zend_jit_push_static_method_call_frame);
3119
  REGISTER_HELPER(zend_jit_push_static_method_call_frame_tmp);
3120
  REGISTER_HELPER(zend_jit_find_class_helper);
3121
  REGISTER_HELPER(zend_jit_find_static_method_helper);
3122
  REGISTER_HELPER(zend_jit_push_this_method_call_frame);
3123
  REGISTER_HELPER(zend_jit_free_trampoline_helper);
3124
  REGISTER_HELPER(zend_jit_verify_return_slow);
3125
  REGISTER_HELPER(zend_jit_deprecated_helper);
3126
  REGISTER_HELPER(zend_jit_undefined_long_key);
3127
  REGISTER_HELPER(zend_jit_undefined_long_key_ex);
3128
  REGISTER_HELPER(zend_jit_undefined_string_key);
3129
  REGISTER_HELPER(zend_jit_copy_extra_args_helper);
3130
  REGISTER_HELPER(zend_jit_copy_extra_args_helper_no_skip_recv);
3131
  REGISTER_HELPER(zend_jit_vm_stack_free_args_helper);
3132
  REGISTER_HELPER(zend_free_extra_named_params);
3133
  REGISTER_HELPER(zend_jit_free_call_frame);
3134
  REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper);
3135
  REGISTER_HELPER(zend_jit_verify_arg_slow);
3136
  REGISTER_HELPER(zend_missing_arg_error);
3137
  REGISTER_HELPER(zend_jit_only_vars_by_reference);
3138
  REGISTER_HELPER(zend_jit_leave_func_helper);
3139
  REGISTER_HELPER(zend_jit_leave_nested_func_helper);
3140
  REGISTER_HELPER(zend_jit_leave_top_func_helper);
3141
  REGISTER_HELPER(zend_jit_fetch_global_helper);
3142
  REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed);
3143
  REGISTER_HELPER(zend_jit_hash_index_lookup_rw);
3144
  REGISTER_HELPER(zend_jit_hash_lookup_rw);
3145
  REGISTER_HELPER(zend_jit_symtable_find);
3146
  REGISTER_HELPER(zend_jit_symtable_lookup_w);
3147
  REGISTER_HELPER(zend_jit_symtable_lookup_rw);
3148
  REGISTER_HELPER(zend_jit_fetch_dim_r_helper);
3149
  REGISTER_HELPER(zend_jit_fetch_dim_is_helper);
3150
  REGISTER_HELPER(zend_jit_fetch_dim_isset_helper);
3151
  REGISTER_HELPER(zend_jit_fetch_dim_rw_helper);
3152
  REGISTER_HELPER(zend_jit_fetch_dim_w_helper);
3153
  REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper);
3154
  REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper);
3155
  REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper);
3156
  REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper);
3157
  REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper);
3158
  REGISTER_HELPER(zend_jit_invalid_array_access);
3159
  REGISTER_HELPER(zend_jit_zval_array_dup);
3160
  REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
3161
  REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper);
3162
  REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper);
3163
  REGISTER_HELPER(zend_jit_isset_dim_helper);
3164
  REGISTER_HELPER(zend_jit_assign_dim_helper);
3165
  REGISTER_HELPER(zend_jit_assign_dim_op_helper);
3166
  REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
3167
  REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3168
  REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
3169
  REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3170
  REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
3171
  REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3172
  REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
3173
  REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3174
  REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
3175
  REGISTER_HELPER(zend_jit_check_array_promotion);
3176
  REGISTER_HELPER(zend_jit_create_typed_ref);
3177
  REGISTER_HELPER(zend_jit_invalid_property_write);
3178
  REGISTER_HELPER(zend_jit_invalid_property_read);
3179
  REGISTER_HELPER(zend_jit_extract_helper);
3180
  REGISTER_HELPER(zend_jit_invalid_property_assign);
3181
  REGISTER_HELPER(zend_jit_assign_to_typed_prop);
3182
  REGISTER_HELPER(zend_jit_assign_obj_helper);
3183
  REGISTER_HELPER(zend_jit_invalid_property_assign_op);
3184
  REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
3185
  REGISTER_HELPER(zend_jit_assign_obj_op_helper);
3186
  REGISTER_HELPER(zend_jit_invalid_property_incdec);
3187
  REGISTER_HELPER(zend_jit_inc_typed_prop);
3188
  REGISTER_HELPER(zend_jit_dec_typed_prop);
3189
  REGISTER_HELPER(zend_jit_pre_inc_typed_prop);
3190
  REGISTER_HELPER(zend_jit_post_inc_typed_prop);
3191
  REGISTER_HELPER(zend_jit_pre_dec_typed_prop);
3192
  REGISTER_HELPER(zend_jit_post_dec_typed_prop);
3193
  REGISTER_HELPER(zend_jit_pre_inc_obj_helper);
3194
  REGISTER_HELPER(zend_jit_post_inc_obj_helper);
3195
  REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
3196
  REGISTER_HELPER(zend_jit_post_dec_obj_helper);
3197
  REGISTER_HELPER(zend_jit_uninit_static_prop);
3198
  REGISTER_HELPER(zend_jit_rope_end);
3199
  REGISTER_HELPER(zend_fcall_interrupt);
3200
3201
#ifndef ZTS
3202
  REGISTER_DATA(EG(current_execute_data));
3203
  REGISTER_DATA(EG(exception));
3204
  REGISTER_DATA(EG(opline_before_exception));
3205
  REGISTER_DATA(EG(vm_interrupt));
3206
  REGISTER_DATA(EG(timed_out));
3207
  REGISTER_DATA(EG(delayed_oom));
3208
  REGISTER_DATA(EG(uninitialized_zval));
3209
  REGISTER_DATA(EG(zend_constants));
3210
  REGISTER_DATA(EG(jit_trace_num));
3211
  REGISTER_DATA(EG(vm_stack_top));
3212
  REGISTER_DATA(EG(vm_stack_end));
3213
  REGISTER_DATA(EG(exception_op));
3214
  REGISTER_DATA(EG(symbol_table));
3215
3216
  REGISTER_DATA(CG(map_ptr_base));
3217
#else /* ZTS */
3218
  REGISTER_HELPER(zend_jit_get_tsrm_ls_cache);
3219
#endif
3220
#endif
3221
0
}
3222
3223
static void zend_jit_calc_trace_prologue_size(void)
3224
4
{
3225
4
  zend_jit_ctx jit_ctx;
3226
4
  zend_jit_ctx *jit = &jit_ctx;
3227
4
  void *entry;
3228
4
  size_t size;
3229
3230
4
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : IR_START_BR_TARGET);
3231
3232
4
  if (!GCC_GLOBAL_REGS) {
3233
4
    if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
3234
0
      ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
3235
0
      ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
3236
0
      jit_STORE_FP(jit, execute_data_ref);
3237
0
      jit_STORE_IP(jit, opline_ref);
3238
0
    }
3239
4
    jit->ctx.flags |= IR_FASTCALL_FUNC;
3240
4
  }
3241
3242
4
  ir_UNREACHABLE();
3243
3244
4
  entry = zend_jit_ir_compile(&jit->ctx, &size, "JIT$trace_prologue");
3245
4
  zend_jit_free_ctx(jit);
3246
3247
4
  if (!entry) {
3248
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: could not compile prologue");
3249
0
  }
3250
3251
4
  zend_jit_trace_prologue_size = size;
3252
4
}
3253
3254
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3255
static uintptr_t zend_jit_hybrid_vm_sp_adj = 0;
3256
3257
typedef struct _Unwind_Context _Unwind_Context;
3258
typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *);
3259
extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
3260
extern uintptr_t _Unwind_GetCFA(_Unwind_Context *);
3261
3262
typedef struct _zend_jit_unwind_arg {
3263
  int cnt;
3264
  uintptr_t cfa[3];
3265
} zend_jit_unwind_arg;
3266
3267
static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a)
3268
0
{
3269
0
  zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a;
3270
0
  arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx);
3271
0
  arg->cnt++;
3272
0
  if (arg->cnt == 3) {
3273
0
    return 5; // _URC_END_OF_STACK
3274
0
  }
3275
0
  return 0; // _URC_NO_REASON;
3276
0
}
3277
3278
static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data)
3279
0
{
3280
0
  zend_jit_unwind_arg arg;
3281
0
3282
0
  memset(&arg, 0, sizeof(arg));
3283
0
  _Unwind_Backtrace(zend_jit_unwind_cb, &arg);
3284
0
  if (arg.cnt == 3) {
3285
0
    zend_jit_hybrid_vm_sp_adj = arg.cfa[2] - arg.cfa[1];
3286
0
  }
3287
0
}
3288
3289
extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data);
3290
3291
static zend_never_inline void zend_jit_set_sp_adj_vm(void)
3292
0
{
3293
0
  void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *);
3294
0
3295
0
  orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data;
3296
0
  zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data;
3297
0
  execute_ex(NULL);                                        // set sp_adj[SP_ADJ_VM]
3298
0
  zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data;
3299
0
}
3300
#endif
3301
3302
#ifdef _WIN64
3303
/*
3304
 * We use a single unwind entry for the whole JIT buffer.
3305
 * This works, because all the JIT-ed PHP functions have the same "fixed stack frame".
3306
 */
3307
static PRUNTIME_FUNCTION zend_jit_uw_func = NULL;
3308
3309
#ifdef ZEND_JIT_RT_UNWINDER
3310
static PRUNTIME_FUNCTION zend_jit_unwind_callback(DWORD64 pc, PVOID context)
3311
{
3312
  return zend_jit_uw_func;
3313
}
3314
#endif
3315
3316
static void zend_jit_setup_unwinder(void)
3317
{
3318
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
3319
  /* TAILCALL VM: fixed_save_regset=0, no registers pushed in prologue.
3320
   * fixed_stack_frame_size=40, fixed_call_stack_size=48 (16+IR_SHADOW_ARGS).
3321
   * Prologue is: sub rsp, 0x58 (88 bytes = 40+48). */
3322
  static const unsigned char uw_data[] = {
3323
    0x01, // Version=1, Flags=0
3324
    0x04, // Size of prolog (sub rsp,imm8 = 4 bytes: 48 83 ec 58)
3325
    0x01, // Count of unwind codes
3326
    0x00, // Frame Register=none
3327
    0x04, 0xa2, // offset 4: UWOP_ALLOC_SMALL info=10, alloc=(10+1)*8=88
3328
    0x00, 0x00, // padding
3329
  };
3330
  /* Exit call variant: base 88 + 304 (shadow+GP+FP+padding) = 392 (0x188) */
3331
  static const unsigned char uw_data_exitcall[] = {
3332
    0x01, // Version=1, Flags=0
3333
    0x07, // Size of prolog (sub rsp,imm32 = 7 bytes: 48 81 ec 88 01 00 00)
3334
    0x02, // Count of unwind codes
3335
    0x00, // Frame Register=none
3336
    0x07, 0x01, 0x31, 0x00, // offset 7: UWOP_ALLOC_LARGE info=0, size/8=49, alloc=392
3337
  };
3338
#else
3339
  /* Hardcoded SEH unwind data for JIT-ed PHP functions with "fixed stack frame" */
3340
  static const unsigned char uw_data[] = {
3341
    0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3342
    0x10, // UBYTE Size of prolog
3343
    0x09, // UBYTE Count of unwind codes
3344
    0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3345
    // USHORT * n Unwind codes array
3346
    0x10, 0x82, // c: subq $0x48, %rsp
3347
    0x0c, 0xf0, // a: pushq %r15
3348
    0x0a, 0xe0, // 8: pushq %r14
3349
    0x08, 0xd0, // 6: pushq %r13
3350
    0x06, 0xc0, // 4: pushq %r12
3351
    0x04, 0x70, // 3: pushq %rdi
3352
    0x03, 0x60, // 2: pushq %rsi
3353
    0x02, 0x50, // 1: pushq %rbp
3354
    0x01, 0x30, // 0: pushq %rbx
3355
    0x00, 0x00,
3356
  };
3357
  static const unsigned char uw_data_exitcall[] = {
3358
    0x01, // UBYTE: 3 Version , UBYTE: 5 Flags
3359
    0x10, // UBYTE Size of prolog
3360
    0x0a, // UBYTE Count of unwind codes
3361
    0x00, // UBYTE: 4 Frame Register, UBYTE: 4 Frame Register offset (scaled)
3362
    // USHORT * n Unwind codes array
3363
    0x10, 0x01, 0x2f, 0x00, // c: subq 376, %rsp ; 0x48 + 32+16*8+16*8+8+8
3364
    0x0c, 0xf0, // a: pushq %r15
3365
    0x0a, 0xe0, // 8: pushq %r14
3366
    0x08, 0xd0, // 6: pushq %r13
3367
    0x06, 0xc0, // 4: pushq %r12
3368
    0x04, 0x70, // 3: pushq %rdi
3369
    0x03, 0x60, // 2: pushq %rsi
3370
    0x02, 0x50, // 1: pushq %rbp
3371
    0x01, 0x30, // 0: pushq %rbx
3372
  };
3373
#endif
3374
3375
  zend_jit_uw_func = (PRUNTIME_FUNCTION)*dasm_ptr;
3376
  *dasm_ptr = (char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(sizeof(RUNTIME_FUNCTION) * 4 +
3377
    sizeof(uw_data) + sizeof(uw_data_exitcall) + sizeof(uw_data), 16);
3378
3379
  zend_jit_uw_func[0].BeginAddress = 0;
3380
  zend_jit_uw_func[1].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_trace_exit] - (uintptr_t)dasm_buf;
3381
  zend_jit_uw_func[2].BeginAddress = (uintptr_t)zend_jit_stub_handlers[jit_stub_undefined_offset] - (uintptr_t)dasm_buf;
3382
3383
  zend_jit_uw_func[0].EndAddress = zend_jit_uw_func[1].BeginAddress;
3384
  zend_jit_uw_func[1].EndAddress = zend_jit_uw_func[2].BeginAddress;
3385
  zend_jit_uw_func[2].EndAddress = (uintptr_t)dasm_end - (uintptr_t)dasm_buf;
3386
3387
  zend_jit_uw_func[0].UnwindData = (uintptr_t)zend_jit_uw_func  - (uintptr_t)dasm_buf + sizeof(RUNTIME_FUNCTION) * 4;
3388
  zend_jit_uw_func[1].UnwindData = zend_jit_uw_func[0].UnwindData + sizeof(uw_data);
3389
  zend_jit_uw_func[2].UnwindData = zend_jit_uw_func[1].UnwindData + sizeof(uw_data_exitcall);
3390
3391
  memcpy((char*)dasm_buf + zend_jit_uw_func[0].UnwindData, uw_data, sizeof(uw_data));
3392
  memcpy((char*)dasm_buf + zend_jit_uw_func[1].UnwindData, uw_data_exitcall, sizeof(uw_data_exitcall));
3393
  memcpy((char*)dasm_buf + zend_jit_uw_func[2].UnwindData, uw_data, sizeof(uw_data));
3394
3395
#ifdef ZEND_JIT_RT_UNWINDER
3396
  RtlInstallFunctionTableCallback(
3397
    (uintptr_t)dasm_buf | 3,
3398
    (uintptr_t) dasm_buf,
3399
    (uintptr_t)dasm_end - (uintptr_t)dasm_buf,
3400
    zend_jit_unwind_callback,
3401
    NULL,
3402
    NULL);
3403
#else
3404
  RtlAddFunctionTable(zend_jit_uw_func, 3, (uintptr_t)dasm_buf);
3405
#endif
3406
}
3407
#endif
3408
3409
static void zend_jit_setup(bool reattached)
3410
4
{
3411
#if defined(IR_TARGET_X86)
3412
  if (!zend_cpu_supports_sse2()) {
3413
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not enable JIT: CPU doesn't support SSE2");
3414
  }
3415
#endif
3416
4
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
3417
4
  allowed_opt_flags = 0;
3418
4
  if (zend_cpu_supports_avx()) {
3419
4
    allowed_opt_flags |= ZEND_JIT_CPU_AVX;
3420
4
  }
3421
4
# ifdef HAVE_ZEND_CPU_SUPPORTS_CLDEMOTE
3422
4
  if (zend_cpu_supports_cldemote()) {
3423
0
    default_mflags |= IR_X86_CLDEMOTE;
3424
0
  }
3425
4
# endif
3426
4
#endif
3427
3428
#ifdef ZTS
3429
  zend_result result = zend_jit_resolve_tsrm_ls_cache_offsets(
3430
    &tsrm_ls_cache_tcb_offset,
3431
    &tsrm_tls_index,
3432
    &tsrm_tls_offset
3433
  );
3434
  if (result == FAILURE) {
3435
    zend_accel_error(ACCEL_LOG_INFO,
3436
        "Could not get _tsrm_ls_cache offsets, will fallback to runtime resolution");
3437
  }
3438
#endif
3439
3440
4
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
3441
4
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
3442
0
    zend_jit_set_sp_adj_vm(); // set zend_jit_hybrid_vm_sp_adj
3443
0
  }
3444
4
#endif
3445
3446
4
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3447
0
    zend_jit_setup_disasm();
3448
0
  }
3449
3450
4
#ifndef _WIN32
3451
4
  if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3452
0
    ir_perf_jitdump_open();
3453
0
  }
3454
3455
4
#endif
3456
4
  zend_long debug = JIT_G(debug);
3457
4
  if (!(debug & ZEND_JIT_DEBUG_ASM_STUBS)) {
3458
4
    JIT_G(debug) &= ~(ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_FINAL|
3459
4
      ZEND_JIT_DEBUG_IR_CODEGEN|
3460
4
      ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_CFG|ZEND_JIT_DEBUG_IR_AFTER_GCM|
3461
4
      ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS);
3462
4
  }
3463
3464
4
  zend_jit_calc_trace_prologue_size();
3465
4
  if (!reattached) {
3466
4
    zend_jit_setup_stubs();
3467
4
  }
3468
4
  JIT_G(debug) = debug;
3469
3470
#ifdef _WIN64
3471
  zend_jit_setup_unwinder();
3472
#endif
3473
4
}
3474
3475
static void zend_jit_shutdown_ir(void)
3476
0
{
3477
0
#ifndef _WIN32
3478
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
3479
0
    ir_perf_jitdump_close();
3480
0
  }
3481
0
  if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
3482
0
    ir_gdb_unregister_all();
3483
0
  }
3484
0
#endif
3485
#ifdef HAVE_CAPSTONE
3486
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) {
3487
    ir_disasm_free();
3488
  }
3489
#endif
3490
0
}
3491
3492
/* PHP control flow reconstruction helpers */
3493
static ir_ref jit_IF_ex(zend_jit_ctx *jit, ir_ref condition, ir_ref true_block)
3494
730
{
3495
730
  ir_ref ref = ir_IF(condition);
3496
  /* op3 is used as a temporary storage for PHP BB number to reconstruct PHP control flow.
3497
   *
3498
   * It's used in jit_IF_TRUE_FALSE_ex() to select IF_TRUE or IF_FALSE instructions
3499
   * to start target block
3500
   */
3501
730
  ir_set_op(&jit->ctx, ref, 3, true_block);
3502
730
  return ref;
3503
730
}
3504
3505
static void jit_IF_TRUE_FALSE_ex(zend_jit_ctx *jit, ir_ref if_ref, ir_ref true_block)
3506
1.28k
{
3507
1.28k
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3508
1.28k
  ZEND_ASSERT(if_ref);
3509
1.28k
  ZEND_ASSERT(jit->ctx.ir_base[if_ref].op == IR_IF);
3510
1.28k
  ZEND_ASSERT(jit->ctx.ir_base[if_ref].op3);
3511
1.28k
  if (jit->ctx.ir_base[if_ref].op3 == true_block) {
3512
644
    ir_IF_TRUE(if_ref);
3513
644
  } else {
3514
644
    ir_IF_FALSE(if_ref);
3515
644
  }
3516
1.28k
}
3517
3518
static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref);
3519
3520
static void _zend_jit_add_predecessor_ref(zend_jit_ctx *jit, int b, int pred, ir_ref ref)
3521
5.39k
{
3522
5.39k
  int *p;
3523
5.39k
  zend_basic_block *bb;
3524
5.39k
  ir_ref *r, header;
3525
3526
5.39k
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3527
5.39k
  bb = &jit->ssa->cfg.blocks[b];
3528
5.39k
  p = &jit->ssa->cfg.predecessors[bb->predecessor_offset];
3529
5.39k
  r = &jit->bb_edges[jit->bb_predecessors[b]];
3530
6.19k
  for (uint32_t i = 0; i < bb->predecessors_count; i++, p++, r++) {
3531
6.19k
    if (*p == pred) {
3532
5.39k
      ZEND_ASSERT(*r == IR_UNUSED || *r == ref);
3533
5.39k
      header = jit->bb_start_ref[b];
3534
5.39k
      if (header) {
3535
        /* this is back edge */
3536
179
        ZEND_ASSERT(jit->ctx.ir_base[header].op == IR_LOOP_BEGIN);
3537
179
        if (jit->ctx.ir_base[ref].op == IR_END) {
3538
178
          jit->ctx.ir_base[ref].op = IR_LOOP_END;
3539
178
        } else if (jit->ctx.ir_base[ref].op == IR_IF) {
3540
1
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3541
1
          ref = ir_LOOP_END();
3542
1
        } else if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
3543
0
          zend_jit_case_start(jit, pred, b, ref);
3544
0
          ref = ir_LOOP_END();
3545
0
        } else if (jit->ctx.ir_base[ref].op == IR_UNREACHABLE) {
3546
0
          ir_BEGIN(ref);
3547
0
          ref = ir_LOOP_END();
3548
0
        } else {
3549
0
          ZEND_UNREACHABLE();
3550
0
        }
3551
179
        ir_MERGE_SET_OP(header, i + 1, ref);
3552
179
      }
3553
5.39k
      *r = ref;
3554
5.39k
      return;
3555
5.39k
    }
3556
6.19k
  }
3557
0
  ZEND_UNREACHABLE();
3558
0
}
3559
3560
static void _zend_jit_merge_smart_branch_inputs(zend_jit_ctx *jit,
3561
                                                uint32_t      true_label,
3562
                                                uint32_t      false_label,
3563
                                                ir_ref        true_inputs,
3564
                                                ir_ref        false_inputs)
3565
182
{
3566
182
  ir_ref true_path = IR_UNUSED, false_path = IR_UNUSED;
3567
3568
182
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3569
182
  if (true_inputs) {
3570
180
    ZEND_ASSERT(jit->ctx.ir_base[true_inputs].op == IR_END);
3571
180
    if (!jit->ctx.ir_base[true_inputs].op2) {
3572
0
      true_path = true_inputs;
3573
180
    } else {
3574
180
      ir_MERGE_list(true_inputs);
3575
180
      true_path = ir_END();
3576
180
    }
3577
180
  }
3578
182
  if (false_inputs) {
3579
180
    ZEND_ASSERT(jit->ctx.ir_base[false_inputs].op == IR_END);
3580
180
    if (!jit->ctx.ir_base[false_inputs].op2) {
3581
0
      false_path = false_inputs;
3582
180
    } else {
3583
180
      ir_MERGE_list(false_inputs);
3584
180
      false_path = ir_END();
3585
180
    }
3586
180
  }
3587
3588
182
  if (true_label == false_label && true_path && false_path) {
3589
0
    ir_MERGE_2(true_path, false_path);
3590
0
    _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
3591
182
  } else if (!true_path && !false_path) {
3592
    /* dead code */
3593
2
    true_path = ir_END();
3594
2
    _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3595
180
  } else {
3596
180
    if (true_path) {
3597
180
      _zend_jit_add_predecessor_ref(jit, true_label, jit->b, true_path);
3598
180
    }
3599
180
    if (false_path) {
3600
180
      _zend_jit_add_predecessor_ref(jit, false_label, jit->b, false_path);
3601
180
    }
3602
180
  }
3603
3604
182
  jit->b = -1;
3605
182
}
3606
3607
static void _zend_jit_fix_merges(zend_jit_ctx *jit)
3608
7.32k
{
3609
7.32k
  int i, count;
3610
7.32k
  ir_ref j, k, n, *p, *q, *r;
3611
7.32k
  ir_ref ref;
3612
7.32k
  ir_insn *insn, *phi;
3613
3614
7.32k
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3615
7.32k
  count = jit->ssa->cfg.blocks_count;
3616
19.4k
  for (i = 0, p = jit->bb_start_ref; i < count; i++, p++) {
3617
12.1k
    ref = *p;
3618
12.1k
    if (ref) {
3619
12.1k
      insn = &jit->ctx.ir_base[ref];
3620
12.1k
      if (insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN) {
3621
3.76k
        n = insn->inputs_count;
3622
        /* Remove IS_UNUSED inputs */
3623
11.6k
        for (j = k = 0, q = r = insn->ops + 1; j < n; j++, q++) {
3624
7.84k
          if (*q) {
3625
7.84k
            if (q != r) {
3626
4
              *r = *q;
3627
4
              phi = insn + 1 + (n >> 2);
3628
4
              while (phi->op == IR_PI) {
3629
0
                phi++;
3630
0
              }
3631
4
              while (phi->op == IR_PHI) {
3632
0
                ir_insn_set_op(phi, k + 2, ir_insn_op(phi, j + 2));
3633
0
                phi += 1 + ((n + 1) >> 2);
3634
0
              }
3635
4
            }
3636
7.84k
            k++;
3637
7.84k
            r++;
3638
7.84k
          }
3639
7.84k
        }
3640
3.76k
        if (k != n) {
3641
4
          ir_ref n2, k2;
3642
3643
4
          if (k <= 1) {
3644
4
            insn->op = IR_BEGIN;
3645
4
            insn->inputs_count = 0;
3646
4
          } else {
3647
0
            insn->inputs_count = k;
3648
0
          }
3649
4
          n2 = 1 + (n >> 2);
3650
4
          k2 = 1 + (k >> 2);
3651
4
          while (k2 != n2) {
3652
0
            (insn+k2)->optx = IR_NOP;
3653
0
            k2++;
3654
0
          }
3655
4
          phi = insn + 1 + (n >> 2);
3656
4
          while (phi->op == IR_PI) {
3657
0
            phi++;
3658
0
          }
3659
4
          while (phi->op == IR_PHI) {
3660
0
            if (k <= 1) {
3661
0
              phi->op = IR_COPY;
3662
0
              phi->op1 = phi->op2;
3663
0
              phi->op2 = 1;
3664
0
              phi->inputs_count = 0;
3665
0
            } else {
3666
0
              phi->inputs_count = k + 1;
3667
0
            }
3668
0
            n2 = 1 + ((n + 1) >> 2);
3669
0
            k2 = 1 + ((k + 1) >> 2);
3670
0
            while (k2 != n2) {
3671
0
              (phi+k2)->optx = IR_NOP;
3672
0
              k2++;
3673
0
            }
3674
0
            phi += 1 + ((n + 1) >> 2);
3675
0
          }
3676
4
        }
3677
3.76k
      }
3678
12.1k
    }
3679
12.1k
  }
3680
7.32k
}
3681
3682
static void zend_jit_case_start(zend_jit_ctx *jit, int switch_b, int case_b, ir_ref switch_ref)
3683
8
{
3684
8
  zend_basic_block *bb = &jit->ssa->cfg.blocks[switch_b];
3685
8
  const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3686
3687
8
  if (opline->opcode == ZEND_SWITCH_LONG
3688
8
   || opline->opcode == ZEND_SWITCH_STRING
3689
8
   || opline->opcode == ZEND_MATCH) {
3690
8
    HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
3691
8
    const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
3692
8
    int default_b = jit->ssa->cfg.map[default_opline - jit->op_array->opcodes];
3693
8
    zval *zv;
3694
8
    ir_ref list = IR_UNUSED, idx;
3695
8
    bool first = true;
3696
3697
41
    ZEND_HASH_FOREACH_VAL(jumptable, zv) {
3698
41
      const zend_op *target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
3699
41
      int b = jit->ssa->cfg.map[target - jit->op_array->opcodes];
3700
3701
41
      if (b == case_b) {
3702
8
        if (!first) {
3703
2
          ir_END_list(list);
3704
2
        }
3705
8
        if (HT_IS_PACKED(jumptable)) {
3706
6
          idx = ir_CONST_LONG(zv - jumptable->arPacked);
3707
6
        } else {
3708
2
          idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
3709
2
        }
3710
8
        ir_CASE_VAL(switch_ref, idx);
3711
8
        first = false;
3712
8
      }
3713
41
    } ZEND_HASH_FOREACH_END();
3714
8
    if (default_b == case_b) {
3715
6
      if (!first) {
3716
4
        ir_END_list(list);
3717
4
      }
3718
6
      if (jit->ctx.ir_base[switch_ref].op3) {
3719
        /* op3 may contain a list of additional "default" path inputs for MATCH */
3720
6
        ir_ref ref = jit->ctx.ir_base[switch_ref].op3;
3721
6
        jit->ctx.ir_base[switch_ref].op3 = IS_UNDEF;
3722
6
        ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
3723
6
        ir_ref end = ref;
3724
12
        while (jit->ctx.ir_base[end].op2) {
3725
6
          ZEND_ASSERT(jit->ctx.ir_base[end].op == IR_END);
3726
6
          end = jit->ctx.ir_base[end].op2;
3727
6
        }
3728
6
        jit->ctx.ir_base[end].op2 = list;
3729
6
        list = ref;
3730
6
      }
3731
6
      ir_CASE_DEFAULT(switch_ref);
3732
6
    }
3733
8
    if (list) {
3734
6
      ir_END_list(list);
3735
6
      ir_MERGE_list(list);
3736
6
    }
3737
8
  } else {
3738
0
    ZEND_UNREACHABLE();
3739
0
  }
3740
8
}
3741
3742
static int zend_jit_bb_start(zend_jit_ctx *jit, int b)
3743
12.1k
{
3744
12.1k
  zend_basic_block *bb;
3745
12.1k
  int *p, pred;
3746
12.1k
  ir_ref ref, bb_start;
3747
3748
12.1k
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3749
12.1k
  ZEND_ASSERT(b < jit->ssa->cfg.blocks_count);
3750
12.1k
  bb = &jit->ssa->cfg.blocks[b];
3751
12.1k
  ZEND_ASSERT((bb->flags & ZEND_BB_REACHABLE) != 0);
3752
12.1k
  uint32_t n = bb->predecessors_count;
3753
3754
12.1k
  if (n == 0) {
3755
    /* pass */
3756
7.32k
    ZEND_ASSERT(jit->ctx.control);
3757
7.32k
#if ZEND_DEBUG
3758
7.32k
    ref = jit->ctx.control;
3759
7.32k
    ir_insn *insn = &jit->ctx.ir_base[ref];
3760
7.32k
    while (insn->op >= IR_CALL && insn->op <= IR_TRAP) {
3761
0
      ref = insn->op1;
3762
0
      insn = &jit->ctx.ir_base[ref];
3763
0
    }
3764
7.32k
    ZEND_ASSERT(insn->op == IR_START);
3765
7.32k
    ZEND_ASSERT(ref == 1);
3766
7.32k
#endif
3767
7.32k
    bb_start = 1;
3768
7.32k
    if (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY) {
3769
      /* prvent END/BEGIN merging */
3770
0
      jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ir_END());
3771
0
      bb_start = jit->ctx.control;
3772
0
    }
3773
7.32k
  } else if (n == 1) {
3774
4.27k
    ZEND_ASSERT(!jit->ctx.control);
3775
4.27k
    pred = jit->ssa->cfg.predecessors[bb->predecessor_offset];
3776
4.27k
    ref = jit->bb_edges[jit->bb_predecessors[b]];
3777
4.27k
    if (ref == IR_UNUSED) {
3778
7
      if (!jit->ctx.control) {
3779
7
        ir_BEGIN(IR_UNUSED); /* unreachable block */
3780
7
      }
3781
4.26k
    } else {
3782
4.26k
      ir_op op = jit->ctx.ir_base[ref].op;
3783
3784
4.26k
      if (op == IR_IF) {
3785
384
        if (!jit->ctx.control) {
3786
384
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3787
384
        } else {
3788
0
          ir_ref entry_path = ir_END();
3789
0
          jit_IF_TRUE_FALSE_ex(jit, ref, b);
3790
0
          ir_MERGE_WITH(entry_path);
3791
0
        }
3792
3.88k
      } else if (op == IR_SWITCH) {
3793
8
        zend_jit_case_start(jit, pred, b, ref);
3794
3.87k
      } else {
3795
3.87k
        if (!jit->ctx.control) {
3796
3.87k
          ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3797
3.87k
          if ((jit->ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY)
3798
48
           && (jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)) {
3799
            /* prvent END/BEGIN merging */
3800
0
            jit->ctx.control = ir_emit1(&jit->ctx, IR_BEGIN, ref);
3801
3.87k
          } else {
3802
3.87k
            ir_BEGIN(ref);
3803
3.87k
          }
3804
3.87k
        } else {
3805
0
          ir_MERGE_WITH(ref);
3806
0
        }
3807
3.87k
      }
3808
4.26k
    }
3809
4.27k
    bb_start = jit->ctx.control;
3810
4.27k
  } else {
3811
564
    int forward_edges_count = 0;
3812
564
    int back_edges_count = 0;
3813
564
    ir_ref *pred_refs;
3814
564
    ir_ref entry_path = IR_UNUSED;
3815
564
    ALLOCA_FLAG(use_heap);
3816
3817
564
    ZEND_ASSERT(!jit->ctx.control);
3818
564
    if (jit->ctx.control) {
3819
0
      entry_path = ir_END();
3820
0
    }
3821
564
    pred_refs = (ir_ref *)do_alloca(sizeof(ir_ref) * n, use_heap);
3822
564
    uint32_t i;
3823
1.77k
    for (i = 0, p = jit->ssa->cfg.predecessors + bb->predecessor_offset; i < n; p++, i++) {
3824
1.20k
      pred = *p;
3825
1.20k
      if (jit->bb_start_ref[pred]) {
3826
        /* forward edge */
3827
1.02k
        forward_edges_count++;
3828
1.02k
        ref = jit->bb_edges[jit->bb_predecessors[b] + i];
3829
1.02k
        if (ref == IR_UNUSED) {
3830
          /* dead edge */
3831
4
          pred_refs[i] = IR_UNUSED;
3832
1.02k
        } else {
3833
1.02k
          ir_op op = jit->ctx.ir_base[ref].op;
3834
3835
1.02k
          if (op == IR_IF) {
3836
307
            jit_IF_TRUE_FALSE_ex(jit, ref, b);
3837
307
            pred_refs[i] = ir_END();
3838
718
          } else if (op == IR_SWITCH) {
3839
0
            zend_jit_case_start(jit, pred, b, ref);
3840
0
            pred_refs[i] = ir_END();
3841
718
          } else {
3842
718
            ZEND_ASSERT(op == IR_END || op == IR_UNREACHABLE || op == IR_RETURN);
3843
718
            pred_refs[i] = ref;
3844
718
          }
3845
1.02k
        }
3846
1.02k
      } else {
3847
        /* backward edge */
3848
179
        back_edges_count++;
3849
179
        pred_refs[i] = IR_UNUSED;
3850
179
      }
3851
1.20k
    }
3852
3853
564
    if (bb->flags & ZEND_BB_LOOP_HEADER) {
3854
178
      ZEND_ASSERT(back_edges_count != 0);
3855
178
      ZEND_ASSERT(forward_edges_count != 0);
3856
178
      ir_MERGE_N(n, pred_refs);
3857
178
      jit->ctx.ir_base[jit->ctx.control].op = IR_LOOP_BEGIN;
3858
178
      bb_start = jit->ctx.control;
3859
178
      if (entry_path) {
3860
0
        ir_MERGE_WITH(entry_path);
3861
0
      }
3862
386
    } else {
3863
//      ZEND_ASSERT(back_edges_count != 0);
3864
      /* edges from exceptional blocks may be counted as back edges */
3865
386
      ir_MERGE_N(n, pred_refs);
3866
386
      bb_start = jit->ctx.control;
3867
386
      if (entry_path) {
3868
0
        ir_MERGE_WITH(entry_path);
3869
0
      }
3870
386
    }
3871
564
    free_alloca(pred_refs, use_heap);
3872
564
  }
3873
12.1k
  jit->b = b;
3874
12.1k
  jit->bb_start_ref[b] = bb_start;
3875
3876
12.1k
  if ((bb->flags & ZEND_BB_ENTRY) || (bb->idom >= 0 && jit->bb_start_ref[bb->idom] < jit->ctx.fold_cse_limit)) {
3877
3.53k
    jit->ctx.fold_cse_limit = bb_start;
3878
3.53k
  }
3879
3880
12.1k
  return 1;
3881
12.1k
}
3882
3883
static int zend_jit_bb_end(zend_jit_ctx *jit, int b)
3884
12.1k
{
3885
12.1k
  int succ;
3886
12.1k
  zend_basic_block *bb;
3887
3888
12.1k
  ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
3889
12.1k
  if (jit->b != b) {
3890
8.13k
    return 1;
3891
8.13k
  }
3892
3893
4.03k
  bb = &jit->ssa->cfg.blocks[b];
3894
4.03k
  ZEND_ASSERT(bb->successors_count != 0);
3895
4.03k
  if (bb->successors_count == 1) {
3896
4.02k
    succ = bb->successors[0];
3897
4.02k
  } else {
3898
1
    const zend_op *opline = &jit->op_array->opcodes[bb->start + bb->len - 1];
3899
3900
    /* Use only the following successor of SWITCH and FE_RESET_R */
3901
1
    ZEND_ASSERT(opline->opcode == ZEND_SWITCH_LONG
3902
1
     || opline->opcode == ZEND_SWITCH_STRING
3903
1
     || opline->opcode == ZEND_MATCH
3904
1
     || opline->opcode == ZEND_FE_RESET_R);
3905
1
    succ = b + 1;
3906
1
  }
3907
4.03k
  _zend_jit_add_predecessor_ref(jit, succ, b, ir_END());
3908
4.03k
  jit->b = -1;
3909
4.03k
  return 1;
3910
4.03k
}
3911
3912
static int jit_CMP_IP(zend_jit_ctx *jit, ir_op op, const zend_op *next_opline)
3913
486
{
3914
486
  ir_ref ref;
3915
3916
486
#if 1
3917
486
  ref = jit_IP32(jit);
3918
486
  ref = ir_CMP_OP(op, ref, ir_CONST_U32((uint32_t)(uintptr_t)next_opline));
3919
#else
3920
  ref = jit_IP(jit);
3921
  ref = ir_CMP_OP(op, ref, ir_CONST_ADDR(next_opline));
3922
#endif
3923
486
  return ref;
3924
486
}
3925
3926
static int zend_jit_jmp_frameless(
3927
  zend_jit_ctx *jit,
3928
  const zend_op *opline,
3929
  const void *exit_addr,
3930
  zend_jmp_fl_result guard
3931
0
) {
3932
0
  ir_ref ref, if_ref, cache_result, function_result, phi_result, cache_slot_ref;
3933
0
  zend_basic_block *bb;
3934
3935
  // JIT: CACHED_PTR(opline->extended_value)
3936
0
  cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
3937
0
  cache_result = ir_LOAD_L(cache_slot_ref);
3938
3939
  // JIT: if (UNEXPECTED(!result))
3940
0
  if_ref = ir_IF(cache_result);
3941
0
  ir_IF_FALSE_cold(if_ref);
3942
0
  zval *func_name_zv = RT_CONSTANT(opline, opline->op1);
3943
0
  function_result = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_jit_jmp_frameless_helper),
3944
0
    ir_CONST_ADDR(func_name_zv),
3945
0
    cache_slot_ref);
3946
0
  ir_MERGE_WITH_EMPTY_TRUE(if_ref);
3947
3948
0
  phi_result = ir_PHI_2(IR_LONG, function_result, cache_result);
3949
3950
0
  if (exit_addr) {
3951
0
    ir_GUARD(ir_EQ(phi_result, ir_CONST_LONG(guard)), ir_CONST_ADDR(exit_addr));
3952
0
  } else {
3953
0
    ZEND_ASSERT(jit->b >= 0);
3954
0
    bb = &jit->ssa->cfg.blocks[jit->b];
3955
    // JIT: if (result == ZEND_JMP_FL_HIT)
3956
0
    ref = jit_IF_ex(jit, ir_EQ(phi_result, ir_CONST_LONG(ZEND_JMP_FL_HIT)), bb->successors[0]);
3957
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3958
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3959
0
    jit->b = -1;
3960
0
  }
3961
3962
0
  return 1;
3963
0
}
3964
3965
static int zend_jit_cond_jmp(zend_jit_ctx *jit, const zend_op *next_opline, int target_block)
3966
294
{
3967
294
  ir_ref ref;
3968
294
  zend_basic_block *bb;
3969
3970
294
  ZEND_ASSERT(jit->b >= 0);
3971
294
  bb = &jit->ssa->cfg.blocks[jit->b];
3972
3973
294
  ZEND_ASSERT(bb->successors_count == 2);
3974
294
  if (bb->successors[0] == bb->successors[1]) {
3975
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
3976
0
    jit->b = -1;
3977
0
    zend_jit_set_last_valid_opline(jit, next_opline);
3978
0
    return 1;
3979
0
  }
3980
3981
294
  ref = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, next_opline), target_block);
3982
3983
294
  _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
3984
294
  _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
3985
3986
294
  jit->b = -1;
3987
294
  zend_jit_set_last_valid_opline(jit, next_opline);
3988
3989
294
  return 1;
3990
294
}
3991
3992
static int zend_jit_set_cond(zend_jit_ctx *jit, const zend_op *opline, const zend_op *next_opline, uint32_t var)
3993
0
{
3994
0
  ir_ref ref;
3995
3996
0
  ir_op op = (opline->result_type & IS_SMART_BRANCH_JMPZ) ? IR_EQ : IR_NE;
3997
0
  ref = ir_ADD_U32(ir_ZEXT_U32(jit_CMP_IP(jit, op, next_opline)), ir_CONST_U32(IS_FALSE));
3998
3999
  // EX_VAR(var) = ...
4000
0
  ir_STORE(ir_ADD_OFFSET(jit_FP(jit), var + offsetof(zval, u1.type_info)), ref);
4001
4002
0
  zend_jit_reset_last_valid_opline(jit);
4003
0
  return zend_jit_set_ip(jit, next_opline - 1);
4004
0
}
4005
4006
/* PHP JIT handlers */
4007
static void zend_jit_check_exception(zend_jit_ctx *jit)
4008
26.6k
{
4009
26.6k
  ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4010
26.6k
    jit_STUB_ADDR(jit, jit_stub_exception_handler));
4011
26.6k
}
4012
4013
static void zend_jit_check_exception_undef_result(zend_jit_ctx *jit, const zend_op *opline)
4014
1.66k
{
4015
1.66k
  ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
4016
1.66k
    jit_STUB_ADDR(jit,
4017
1.66k
      (opline->result_type & (IS_TMP_VAR|IS_VAR)) ? jit_stub_exception_handler_undef : jit_stub_exception_handler));
4018
1.66k
}
4019
4020
static void zend_jit_type_check_undef(zend_jit_ctx  *jit,
4021
                                      ir_ref         type,
4022
                                      uint32_t       var,
4023
                                      const zend_op *opline,
4024
                                      bool           check_exception,
4025
                                      bool           in_cold_path,
4026
                                      bool           undef_result)
4027
742
{
4028
742
  ir_ref if_def = ir_IF(type);
4029
4030
742
  if (!in_cold_path) {
4031
318
    ir_IF_FALSE_cold(if_def);
4032
424
  } else {
4033
424
    ir_IF_FALSE(if_def);
4034
424
  }
4035
742
  if (opline) {
4036
318
    jit_SET_EX_OPLINE(jit, opline);
4037
318
  }
4038
742
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4039
742
  if (check_exception) {
4040
318
    if (undef_result) {
4041
318
      zend_jit_check_exception_undef_result(jit, opline);
4042
318
    } else {
4043
0
      zend_jit_check_exception(jit);
4044
0
    }
4045
318
  }
4046
742
  ir_MERGE_WITH_EMPTY_TRUE(if_def);
4047
742
}
4048
4049
static ir_ref zend_jit_zval_check_undef(zend_jit_ctx  *jit,
4050
                                        ir_ref         ref,
4051
                                        uint32_t       var,
4052
                                        const zend_op *opline,
4053
                                        bool           check_exception)
4054
282
{
4055
282
  ir_ref if_def, ref2;
4056
4057
282
  if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
4058
282
  ir_IF_FALSE_cold(if_def);
4059
4060
282
  if (opline) {
4061
35
    jit_SET_EX_OPLINE(jit, opline);
4062
35
  }
4063
4064
282
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(var));
4065
4066
282
  if (check_exception) {
4067
0
    zend_jit_check_exception(jit);
4068
0
  }
4069
4070
282
  ref2 = jit_EG(uninitialized_zval);
4071
4072
282
  ir_MERGE_WITH_EMPTY_TRUE(if_def);
4073
4074
282
  return ir_PHI_2(IR_ADDR, ref2, ref);
4075
282
}
4076
4077
static void zend_jit_recv_entry(zend_jit_ctx *jit, int b)
4078
33
{
4079
33
  zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4080
33
  int pred;
4081
33
  ir_ref ref;
4082
4083
33
  ZEND_ASSERT(bb->predecessors_count > 0);
4084
4085
33
  pred = jit->bb_predecessors[b];
4086
33
  ref = jit->bb_edges[pred];
4087
4088
33
  ZEND_ASSERT(ref);
4089
33
  ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_END);
4090
4091
  /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4092
33
  ir_ENTRY(ref, bb->start);
4093
33
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4094
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4095
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4096
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4097
0
    jit_STORE_FP(jit, 2);
4098
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4099
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4100
0
    jit_STORE_IP(jit, 3);
4101
0
  }
4102
4103
33
  ir_MERGE_WITH(ref);
4104
33
  jit->bb_edges[pred] = ir_END();
4105
33
}
4106
4107
static void zend_jit_osr_entry(zend_jit_ctx *jit, int b)
4108
0
{
4109
0
  zend_basic_block *bb = &jit->ssa->cfg.blocks[b];
4110
0
  ir_ref ref = ir_END();
4111
4112
  /* Insert a MERGE block with additional ENTRY input between predecessor and this one */
4113
0
  ir_ENTRY(ref, bb->start);
4114
0
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4115
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4116
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4117
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4118
0
    jit_STORE_FP(jit, 2);
4119
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4120
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4121
0
    jit_STORE_IP(jit, 3);
4122
0
  }
4123
4124
0
  ir_MERGE_WITH(ref);
4125
0
}
4126
4127
static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned int label)
4128
3.12k
{
4129
3.12k
  ir_ENTRY(src, label);
4130
3.12k
  if (!GCC_GLOBAL_REGS && ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
4131
    /* 2 and 3 are hardcoded reference to IR_PARAMs */
4132
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op == IR_PARAM);
4133
0
    ZEND_ASSERT(jit->ctx.ir_base[2].op3 == 1);
4134
0
    jit_STORE_FP(jit, 2);
4135
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op == IR_PARAM);
4136
0
    ZEND_ASSERT(jit->ctx.ir_base[3].op3 == 2);
4137
0
    jit_STORE_IP(jit, 3);
4138
0
  }
4139
3.12k
  return ir_END();
4140
3.12k
}
4141
4142
static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
4143
9.41k
{
4144
9.41k
  zend_jit_set_ip(jit, opline);
4145
9.41k
  if (GCC_GLOBAL_REGS) {
4146
0
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4147
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4148
9.41k
  } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
4149
9.41k
    zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4150
9.41k
    ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
4151
9.41k
    jit_STORE_IP(jit, ip);
4152
9.41k
  } else {
4153
0
    zend_vm_opcode_handler_t handler = opline->handler;
4154
0
    ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
4155
0
    jit_STORE_IP(jit, ip);
4156
0
  }
4157
9.41k
  if (may_throw) {
4158
8.73k
    zend_jit_check_exception(jit);
4159
8.73k
  }
4160
  /* Skip the following OP_DATA */
4161
9.41k
  switch (opline->opcode) {
4162
64
    case ZEND_ASSIGN_DIM:
4163
70
    case ZEND_ASSIGN_OBJ:
4164
73
    case ZEND_ASSIGN_STATIC_PROP:
4165
130
    case ZEND_ASSIGN_DIM_OP:
4166
138
    case ZEND_ASSIGN_OBJ_OP:
4167
138
    case ZEND_ASSIGN_STATIC_PROP_OP:
4168
138
    case ZEND_ASSIGN_STATIC_PROP_REF:
4169
142
    case ZEND_ASSIGN_OBJ_REF:
4170
142
    case ZEND_FRAMELESS_ICALL_3:
4171
142
    case ZEND_DECLARE_ATTRIBUTED_CONST:
4172
142
      zend_jit_set_last_valid_opline(jit, opline + 2);
4173
142
      break;
4174
9.27k
    default:
4175
9.27k
      zend_jit_set_last_valid_opline(jit, opline + 1);
4176
9.27k
      break;
4177
9.41k
  }
4178
9.41k
  return 1;
4179
9.41k
}
4180
4181
static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
4182
7.26k
{
4183
7.26k
  ir_ref ref;
4184
7.26k
  zend_basic_block *bb;
4185
4186
7.26k
  zend_jit_set_ip(jit, opline);
4187
7.26k
  if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
4188
0
    if (opline->opcode == ZEND_DO_UCALL ||
4189
0
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
4190
0
        opline->opcode == ZEND_DO_FCALL ||
4191
0
        opline->opcode == ZEND_RETURN) {
4192
4193
      /* Use inlined HYBRID VM handler */
4194
0
      zend_vm_opcode_handler_t handler = opline->handler;
4195
0
      ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
4196
0
    } else {
4197
0
      zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
4198
0
      ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
4199
0
      ref = ir_LOAD_A(jit_IP(jit));
4200
0
      ir_TAILCALL(IR_VOID, ref);
4201
0
    }
4202
7.26k
  } else {
4203
7.26k
    zend_vm_opcode_handler_t handler = opline->handler;
4204
7.26k
    if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
4205
7.26k
      zend_jit_tailcall_handler(jit, ir_CONST_OPCODE_HANDLER_FUNC(handler));
4206
7.26k
    } else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
4207
0
     && (opline->opcode == ZEND_CATCH
4208
0
      || opline->opcode == ZEND_FAST_CALL
4209
0
      || opline->opcode == ZEND_FAST_RET
4210
0
      || opline->opcode == ZEND_MATCH_ERROR
4211
0
      || opline->opcode == ZEND_THROW
4212
0
      || opline->opcode == ZEND_VERIFY_NEVER_TYPE)) {
4213
0
      ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
4214
0
      zend_jit_vm_enter(jit, ip);
4215
0
    } else {
4216
0
      ir_TAILCALL_2(IR_ADDR, ir_CONST_OPCODE_HANDLER_FUNC(handler), jit_FP(jit), jit_IP(jit));
4217
0
    }
4218
7.26k
  }
4219
7.26k
  if (jit->b >= 0) {
4220
7.26k
    bb = &jit->ssa->cfg.blocks[jit->b];
4221
7.26k
    if (bb->successors_count > 0
4222
84
     && (opline->opcode == ZEND_DO_FCALL
4223
84
      || opline->opcode == ZEND_DO_UCALL
4224
84
      || opline->opcode == ZEND_DO_FCALL_BY_NAME
4225
84
      || opline->opcode == ZEND_INCLUDE_OR_EVAL
4226
16
      || opline->opcode == ZEND_GENERATOR_CREATE
4227
8
      || opline->opcode == ZEND_YIELD
4228
0
      || opline->opcode == ZEND_YIELD_FROM
4229
84
      || opline->opcode == ZEND_FAST_CALL)) {
4230
      /* Add a fake control edge from UNREACHABLE to the following ENTRY */
4231
84
      int succ;
4232
4233
84
      if (bb->successors_count == 1) {
4234
84
        succ = bb->successors[0];
4235
84
        ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
4236
84
      } else {
4237
        /* Use only the following successor of FAST_CALL */
4238
0
        ZEND_ASSERT(opline->opcode == ZEND_FAST_CALL);
4239
0
        succ = jit->b + 1;
4240
        /* we need an entry */
4241
0
        jit->ssa->cfg.blocks[succ].flags |= ZEND_BB_ENTRY;
4242
0
      }
4243
84
      ref = jit->ctx.insns_count - 1;
4244
84
      ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE || jit->ctx.ir_base[ref].op == IR_RETURN);
4245
84
      ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
4246
84
      _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
4247
84
    }
4248
7.26k
    jit->b = -1;
4249
7.26k
    zend_jit_reset_last_valid_opline(jit);
4250
7.26k
  }
4251
7.26k
  return 1;
4252
7.26k
}
4253
4254
static int zend_jit_call(zend_jit_ctx *jit, const zend_op *opline, unsigned int next_block)
4255
68
{
4256
68
  return zend_jit_tail_handler(jit, opline);
4257
68
}
4258
4259
static int zend_jit_spill_store(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type)
4260
0
{
4261
0
  ZEND_ASSERT(Z_MODE(src) == IS_REG);
4262
0
  ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4263
4264
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4265
0
    jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4266
0
    if (set_type &&
4267
0
        (Z_REG(dst) != ZREG_FP ||
4268
0
         !JIT_G(current_frame) ||
4269
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4270
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4271
0
    }
4272
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4273
0
    jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4274
0
    if (set_type &&
4275
0
        (Z_REG(dst) != ZREG_FP ||
4276
0
         !JIT_G(current_frame) ||
4277
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4278
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4279
0
    }
4280
0
  } else {
4281
0
    ZEND_UNREACHABLE();
4282
0
  }
4283
0
  return 1;
4284
0
}
4285
4286
static int zend_jit_spill_store_inv(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4287
2
{
4288
2
  ZEND_ASSERT(Z_MODE(src) == IS_REG);
4289
2
  ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL);
4290
4291
2
  if (Z_LOAD(src) || Z_STORE(src)) {
4292
    /* it's not necessary to store register if it was previously loaded or already stored */
4293
0
    return 1;
4294
0
  }
4295
4296
2
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4297
2
    jit_set_Z_LVAL(jit, dst, zend_jit_use_reg(jit, src));
4298
2
    if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4299
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4300
2
    } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG) {
4301
      /* invalidate memory type */
4302
0
      STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4303
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4304
0
    }
4305
2
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4306
0
    jit_set_Z_DVAL(jit, dst, zend_jit_use_reg(jit, src));
4307
0
    if (Z_REG(dst) != ZREG_FP || !JIT_G(current_frame)) {
4308
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4309
0
    } else if (STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE) {
4310
      /* invalidate memory type */
4311
0
      STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) = IS_UNKNOWN;
4312
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4313
0
    }
4314
0
  } else {
4315
0
    ZEND_UNREACHABLE();
4316
0
  }
4317
2
  return 1;
4318
2
}
4319
4320
static int zend_jit_load_reg(zend_jit_ctx *jit, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4321
3
{
4322
3
  ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL);
4323
3
  ZEND_ASSERT(Z_MODE(dst) == IS_REG);
4324
4325
3
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4326
3
    zend_jit_def_reg(jit, dst, jit_Z_LVAL(jit, src));
4327
3
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4328
0
    zend_jit_def_reg(jit, dst, jit_Z_DVAL(jit, src));
4329
0
  } else {
4330
0
    ZEND_UNREACHABLE();
4331
0
  }
4332
3
  return 1;
4333
3
}
4334
4335
static int zend_jit_store_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var, bool set_type)
4336
0
{
4337
0
  zend_jit_addr src = ZEND_ADDR_REG(ssa_var);
4338
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4339
4340
0
  return zend_jit_spill_store(jit, src, dst, info, set_type);
4341
0
}
4342
4343
static int zend_jit_store_ref(zend_jit_ctx *jit, uint32_t info, int var, int32_t src, bool set_type)
4344
0
{
4345
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4346
4347
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4348
0
    jit_set_Z_LVAL(jit, dst, src);
4349
0
    if (set_type &&
4350
0
        (Z_REG(dst) != ZREG_FP ||
4351
0
         !JIT_G(current_frame) ||
4352
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4353
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4354
0
    }
4355
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4356
0
    jit_set_Z_DVAL(jit, dst, src);
4357
0
    if (set_type &&
4358
0
        (Z_REG(dst) != ZREG_FP ||
4359
0
         !JIT_G(current_frame) ||
4360
0
         STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4361
0
      jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4362
0
    }
4363
0
  } else {
4364
0
    ZEND_UNREACHABLE();
4365
0
  }
4366
0
  return 1;
4367
0
}
4368
4369
static ir_ref zend_jit_deopt_rload(zend_jit_ctx *jit, ir_type type, int32_t reg)
4370
4
{
4371
4
  ir_ref ref = jit->ctx.control;
4372
4
  ir_insn *insn;
4373
4374
8
  while (1) {
4375
8
    insn = &jit->ctx.ir_base[ref];
4376
8
    if (insn->op == IR_RLOAD && insn->op2 == reg) {
4377
4
      ZEND_ASSERT(insn->type == type);
4378
4
      return ref;
4379
4
    } else if (insn->op == IR_START) {
4380
0
      break;
4381
0
    }
4382
4
    ref = insn->op1;
4383
4
  }
4384
0
  return ir_RLOAD(type, reg);
4385
4
}
4386
4387
/* Same as zend_jit_deopt_rload(), but 'reg' may be spilled on C stack */
4388
static ir_ref zend_jit_deopt_rload_spilled(zend_jit_ctx *jit, ir_type type, int8_t reg, int32_t offset)
4389
0
{
4390
0
  ZEND_ASSERT(reg >= 0);
4391
4392
0
  if (IR_REG_SPILLED(reg)) {
4393
0
    return ir_LOAD(type, ir_ADD_OFFSET(zend_jit_deopt_rload(jit, type, IR_REG_NUM(reg)), offset));
4394
0
  } else {
4395
0
    return zend_jit_deopt_rload(jit, type, reg);
4396
0
  }
4397
0
}
4398
4399
static int zend_jit_store_const_long(zend_jit_ctx *jit, int var, zend_long val)
4400
0
{
4401
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4402
0
  ir_ref src = ir_CONST_LONG(val);
4403
4404
0
  if (jit->ra && jit->ra[var].ref == IR_NULL) {
4405
0
    zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4406
0
  }
4407
0
  jit_set_Z_LVAL(jit, dst, src);
4408
0
  jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4409
0
  return 1;
4410
0
}
4411
4412
static int zend_jit_store_const_double(zend_jit_ctx *jit, int var, double val)
4413
0
{
4414
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4415
0
  ir_ref src = ir_CONST_DOUBLE(val);
4416
4417
0
  if (jit->ra && jit->ra[var].ref == IR_NULL) {
4418
0
    zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4419
0
  }
4420
0
  jit_set_Z_DVAL(jit, dst, src);
4421
0
  jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4422
0
  return 1;
4423
0
}
4424
4425
static int zend_jit_store_type(zend_jit_ctx *jit, int var, uint8_t type)
4426
28
{
4427
28
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4428
4429
28
  ZEND_ASSERT(type <= IS_DOUBLE);
4430
28
  jit_set_Z_TYPE_INFO(jit, dst, type);
4431
28
  return 1;
4432
28
}
4433
4434
static int zend_jit_store_reg(zend_jit_ctx *jit, uint32_t info, int var, int8_t reg, bool in_mem, bool set_type)
4435
4
{
4436
4
  zend_jit_addr src;
4437
4
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4438
4
  ir_type type;
4439
4440
4
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4441
4
    type = IR_LONG;
4442
4
    src = zend_jit_deopt_rload(jit, type, reg);
4443
4
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4444
4
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4445
4
    } else if (!in_mem) {
4446
0
      jit_set_Z_LVAL(jit, dst, src);
4447
0
      if (set_type &&
4448
0
          (Z_REG(dst) != ZREG_FP ||
4449
0
           !JIT_G(current_frame) ||
4450
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4451
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4452
0
      }
4453
0
    }
4454
4
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4455
0
    type = IR_DOUBLE;
4456
0
    src = zend_jit_deopt_rload(jit, type, reg);
4457
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4458
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4459
0
    } else if (!in_mem) {
4460
0
      jit_set_Z_DVAL(jit, dst, src);
4461
0
      if (set_type &&
4462
0
          (Z_REG(dst) != ZREG_FP ||
4463
0
           !JIT_G(current_frame) ||
4464
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4465
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4466
0
      }
4467
0
    }
4468
0
  } else {
4469
0
    ZEND_UNREACHABLE();
4470
0
  }
4471
4
  return 1;
4472
4
}
4473
4474
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)
4475
0
{
4476
0
  zend_jit_addr src;
4477
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4478
4479
0
  if ((info & MAY_BE_ANY) == MAY_BE_LONG) {
4480
0
    src = ir_LOAD_L(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4481
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4482
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4483
0
    } else {
4484
0
      jit_set_Z_LVAL(jit, dst, src);
4485
0
      if (set_type &&
4486
0
          (Z_REG(dst) != ZREG_FP ||
4487
0
           !JIT_G(current_frame) ||
4488
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) {
4489
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_LONG);
4490
0
      }
4491
0
    }
4492
0
  } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
4493
0
    src = ir_LOAD_D(ir_ADD_OFFSET(ir_RLOAD_A(reg), offset));
4494
0
    if (jit->ra && jit->ra[var].ref == IR_NULL) {
4495
0
      zend_jit_def_reg(jit, ZEND_ADDR_REG(var), src);
4496
0
    } else {
4497
0
      jit_set_Z_DVAL(jit, dst, src);
4498
0
      if (set_type &&
4499
0
          (Z_REG(dst) != ZREG_FP ||
4500
0
           !JIT_G(current_frame) ||
4501
0
           STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) {
4502
0
        jit_set_Z_TYPE_INFO(jit, dst, IS_DOUBLE);
4503
0
      }
4504
0
    }
4505
0
  } else {
4506
0
    ZEND_UNREACHABLE();
4507
0
  }
4508
0
  return 1;
4509
0
}
4510
4511
static int zend_jit_store_var_type(zend_jit_ctx *jit, int var, uint32_t type)
4512
0
{
4513
0
  zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4514
4515
0
  jit_set_Z_TYPE_INFO(jit, dst, type);
4516
0
  return 1;
4517
0
}
4518
4519
static int zend_jit_zval_try_addref(zend_jit_ctx *jit, zend_jit_addr var_addr)
4520
0
{
4521
0
  ir_ref if_refcounted, end1;
4522
4523
0
  if_refcounted = jit_if_REFCOUNTED(jit, var_addr);
4524
0
  ir_IF_FALSE(if_refcounted);
4525
0
  end1 = ir_END();
4526
0
  ir_IF_TRUE(if_refcounted);
4527
0
  jit_GC_ADDREF(jit, jit_Z_PTR(jit, var_addr));
4528
0
  ir_MERGE_WITH(end1);
4529
0
  return 1;
4530
0
}
4531
4532
static int zend_jit_store_var_if_necessary(zend_jit_ctx *jit, int var, zend_jit_addr src, uint32_t info)
4533
3.45k
{
4534
3.45k
  if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4535
0
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4536
0
    return zend_jit_spill_store(jit, src, dst, info, true);
4537
0
  }
4538
3.45k
  return 1;
4539
3.45k
}
4540
4541
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)
4542
52
{
4543
52
  if (Z_MODE(src) == IS_REG && Z_STORE(src)) {
4544
0
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4545
0
    bool set_type = true;
4546
4547
0
    if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) ==
4548
0
        (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) {
4549
0
      if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) {
4550
0
        if (JIT_G(current_frame)) {
4551
0
          uint32_t mem_type = STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var));
4552
4553
0
          if (mem_type != IS_UNKNOWN
4554
0
           && (info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == (1 << mem_type)) {
4555
0
            set_type = false;
4556
0
          }
4557
0
        } else {
4558
0
          set_type = false;
4559
0
        }
4560
0
      }
4561
0
    }
4562
0
    return zend_jit_spill_store(jit, src, dst, info, set_type);
4563
0
  }
4564
52
  return 1;
4565
52
}
4566
4567
static int zend_jit_load_var(zend_jit_ctx *jit, uint32_t info, int var, int ssa_var)
4568
0
{
4569
0
  zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
4570
0
  zend_jit_addr dst = ZEND_ADDR_REG(ssa_var);
4571
4572
0
  return zend_jit_load_reg(jit, src, dst, info);
4573
0
}
4574
4575
static int zend_jit_invalidate_var_if_necessary(zend_jit_ctx *jit, uint8_t op_type, zend_jit_addr addr, znode_op op)
4576
1.33k
{
4577
1.33k
  if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) {
4578
    /* Invalidate operand type to prevent incorrect destruction by exception_handler_free_op1_op2() */
4579
15
    zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var);
4580
15
    jit_set_Z_TYPE_INFO(jit, dst, IS_UNDEF);
4581
15
  }
4582
1.33k
  return 1;
4583
1.33k
}
4584
4585
static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info)
4586
3
{
4587
3
  if (!zend_jit_same_addr(src, dst)) {
4588
3
    if (Z_MODE(src) == IS_REG) {
4589
2
      if (Z_MODE(dst) == IS_REG) {
4590
2
        zend_jit_def_reg(jit, dst, zend_jit_use_reg(jit, src));
4591
2
        if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) {
4592
0
          zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4593
4594
0
          if (!zend_jit_spill_store(jit, dst, var_addr, info,
4595
0
              JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4596
0
              JIT_G(current_frame) == NULL ||
4597
0
              STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4598
0
              (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4599
0
          )) {
4600
0
            return 0;
4601
0
          }
4602
0
        }
4603
2
      } else if (Z_MODE(dst) == IS_MEM_ZVAL) {
4604
0
        if (!Z_LOAD(src) && !Z_STORE(src)) {
4605
0
          if (!zend_jit_spill_store(jit, src, dst, info,
4606
0
              JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4607
0
              JIT_G(current_frame) == NULL ||
4608
0
              STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4609
0
              (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4610
0
          )) {
4611
0
            return 0;
4612
0
          }
4613
0
        }
4614
0
      } else {
4615
0
        ZEND_UNREACHABLE();
4616
0
      }
4617
2
    } else if (Z_MODE(src) == IS_MEM_ZVAL) {
4618
1
      if (Z_MODE(dst) == IS_REG) {
4619
1
        if (!zend_jit_load_reg(jit, src, dst, info)) {
4620
0
          return 0;
4621
0
        }
4622
1
      } else {
4623
0
        ZEND_UNREACHABLE();
4624
0
      }
4625
1
    } else {
4626
0
      ZEND_UNREACHABLE();
4627
0
    }
4628
3
  } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) {
4629
0
    dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
4630
0
    if (!zend_jit_spill_store(jit, src, dst, info,
4631
0
        JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
4632
0
        JIT_G(current_frame) == NULL ||
4633
0
        STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN ||
4634
0
        (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY)
4635
0
    )) {
4636
0
      return 0;
4637
0
    }
4638
0
  }
4639
3
  return 1;
4640
3
}
4641
4642
struct jit_observer_fcall_is_unobserved_data {
4643
  ir_ref if_unobserved;
4644
  ir_ref ir_end_inputs;
4645
};
4646
4647
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) {
4648
0
  ir_ref run_time_cache;
4649
0
  struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
4650
0
  if (func) {
4651
0
    ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4652
0
  } else {
4653
    // JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
4654
0
    ZEND_ASSERT(rx != IR_UNUSED);
4655
0
    ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
4656
0
      ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4657
0
      ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4658
0
    ir_IF_TRUE(if_trampoline_or_generator);
4659
0
    ir_END_list(data.ir_end_inputs);
4660
0
    ir_IF_FALSE(if_trampoline_or_generator);
4661
0
  }
4662
0
  if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4663
    // JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
4664
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)));
4665
0
#ifndef ZTS
4666
0
  } else if (func && rx == IS_UNUSED) { // happens for internal functions only
4667
0
    ZEND_ASSERT(!ZEND_USER_CODE(func->type));
4668
0
    run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4669
0
#endif
4670
0
  } else {
4671
    // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4672
0
    if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
4673
0
      run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
4674
0
    } else {
4675
      // JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
4676
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)));
4677
0
      ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4678
0
      ir_IF_TRUE(if_odd);
4679
4680
0
      ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4681
4682
0
      ir_ref if_odd_end = ir_END();
4683
0
      ir_IF_FALSE(if_odd);
4684
4685
      // JIT: if (func->common.runtime_cache != NULL) {
4686
0
      ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4687
0
      ir_IF_TRUE(if_rt_cache);
4688
0
      ir_END_list(data.ir_end_inputs);
4689
0
      ir_IF_FALSE(if_rt_cache);
4690
4691
0
      ir_MERGE_WITH(if_odd_end);
4692
0
      run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
4693
0
    }
4694
0
  }
4695
  // JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
4696
0
  if (func) {
4697
0
    *observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
4698
0
  } else {
4699
    // JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
4700
0
    ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4701
0
    ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
4702
0
    ir_IF_TRUE(if_internal_func);
4703
4704
0
    ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
4705
4706
0
    ir_ref if_internal_func_end = ir_END();
4707
0
    ir_IF_FALSE(if_internal_func);
4708
4709
0
    ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4710
4711
0
    ir_MERGE_WITH(if_internal_func_end);
4712
0
    *observer_handler = ir_PHI_2(IR_ADDR, observer_handler_user, observer_handler_internal);
4713
0
  }
4714
4715
  // JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
4716
0
  data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
4717
0
  ir_IF_FALSE(data.if_unobserved);
4718
0
  return data;
4719
0
}
4720
4721
/* For frameless the true branch of if_unobserved is used and this function not called. */
4722
0
static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4723
0
  ir_END_list(data->ir_end_inputs);
4724
0
  ir_IF_TRUE(data->if_unobserved);
4725
0
  ir_END_list(data->ir_end_inputs);
4726
0
  ir_MERGE_list(data->ir_end_inputs);
4727
0
}
4728
4729
0
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
4730
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4731
0
}
4732
4733
0
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4734
  // JIT: if (execute_data == EG(current_observed_frame)) {
4735
0
  ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4736
0
  ir_IF_TRUE(has_end_observer);
4737
0
  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4738
0
    rx, res_ref);
4739
0
  ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4740
0
}
4741
4742
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)
4743
45
{
4744
45
  ir_ref if_long = IR_UNUSED;
4745
45
  ir_ref op1_lval_ref = IR_UNUSED;
4746
45
  ir_ref ref;
4747
45
  ir_op op;
4748
4749
45
  if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) {
4750
25
    if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
4751
25
    ir_IF_TRUE(if_long);
4752
25
  }
4753
45
  if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
4754
12
    op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4755
12
    jit_set_Z_LVAL(jit, res_addr, op1_lval_ref);
4756
12
    if (Z_MODE(res_addr) != IS_REG) {
4757
10
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4758
10
    }
4759
12
  }
4760
45
  if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL
4761
43
   && Z_MODE(op1_addr) == IS_REG
4762
0
   && !Z_LOAD(op1_addr)
4763
0
   && !Z_STORE(op1_addr)) {
4764
0
    jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_LONG);
4765
0
  }
4766
45
  if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4767
30
    op = may_overflow ? IR_ADD_OV : IR_ADD;
4768
30
  } else {
4769
15
    op = may_overflow ? IR_SUB_OV : IR_SUB;
4770
15
  }
4771
45
  if (!op1_lval_ref) {
4772
33
    op1_lval_ref = jit_Z_LVAL(jit, op1_addr);
4773
33
  }
4774
45
  ref = ir_BINARY_OP_L(op, op1_lval_ref, ir_CONST_LONG(1));
4775
45
  if (op1_def_info & MAY_BE_LONG) {
4776
45
    jit_set_Z_LVAL(jit, op1_def_addr, ref);
4777
45
  }
4778
45
  if (may_overflow &&
4779
45
      (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)) ||
4780
43
       ((opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD))))) {
4781
12
    int32_t exit_point;
4782
12
    const void *exit_addr;
4783
12
    zend_jit_trace_stack *stack;
4784
12
    uint32_t old_op1_info, old_res_info = 0;
4785
4786
12
    stack = JIT_G(current_frame)->stack;
4787
12
    old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4788
12
    SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0);
4789
12
    if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4790
12
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4791
12
    } else {
4792
0
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4793
0
    }
4794
12
    if (opline->result_type != IS_UNUSED) {
4795
12
      old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4796
12
      if (opline->opcode == ZEND_PRE_INC) {
4797
10
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4798
10
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MAX + 1.0));
4799
10
      } else if (opline->opcode == ZEND_PRE_DEC) {
4800
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
4801
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
4802
2
      } else if (opline->opcode == ZEND_POST_INC) {
4803
2
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4804
2
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MAX));
4805
2
      } else if (opline->opcode == ZEND_POST_DEC) {
4806
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4807
0
        SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_LONG(ZEND_LONG_MIN));
4808
0
      }
4809
12
    }
4810
4811
12
    exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4812
12
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4813
12
    if (!exit_addr) {
4814
0
      return 0;
4815
0
    }
4816
12
    ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
4817
4818
12
    if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4819
10
        opline->result_type != IS_UNUSED) {
4820
10
      jit_set_Z_LVAL(jit, res_addr, ref);
4821
10
      if (Z_MODE(res_addr) != IS_REG) {
4822
10
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4823
10
      }
4824
10
    }
4825
4826
12
    SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
4827
12
    if (opline->result_type != IS_UNUSED) {
4828
12
      SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
4829
12
    }
4830
33
  } else if (may_overflow) {
4831
33
    ir_ref if_overflow;
4832
33
    ir_ref merge_inputs = IR_UNUSED;
4833
4834
33
    if (((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4835
33
     || (opline->result_type != IS_UNUSED && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) ==  (MAY_BE_DOUBLE|MAY_BE_GUARD))) {
4836
0
      int32_t exit_point;
4837
0
      const void *exit_addr;
4838
0
      zend_jit_trace_stack *stack;
4839
0
      uint32_t old_res_info = 0, old_op1_info = 0;
4840
4841
0
      stack = JIT_G(current_frame)->stack;
4842
0
      if (opline->result_type != IS_UNUSED) {
4843
0
        old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
4844
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0);
4845
0
        if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) {
4846
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ref);
4847
0
        } else {
4848
0
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), op1_lval_ref);
4849
0
        }
4850
0
      }
4851
0
      old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
4852
0
      SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_LONG, 0);
4853
0
      SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var), ref);
4854
4855
0
      exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
4856
0
      exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4857
0
      if (!exit_addr) {
4858
0
        return 0;
4859
0
      }
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
33
    } else {
4867
33
      if_overflow = ir_IF(ir_OVERFLOW(ref));
4868
33
      ir_IF_FALSE(if_overflow);
4869
33
      if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4870
23
          opline->result_type != IS_UNUSED) {
4871
6
        jit_set_Z_LVAL(jit, res_addr, ref);
4872
6
        if (Z_MODE(res_addr) != IS_REG) {
4873
6
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
4874
6
        }
4875
6
      }
4876
33
      ir_END_list(merge_inputs);
4877
4878
      /* overflow => cold path */
4879
33
      ir_IF_TRUE_cold(if_overflow);
4880
33
    }
4881
4882
33
    if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
4883
18
      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
18
      } 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
18
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0x43e0000000000000));
4891
18
#endif
4892
18
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4893
18
      }
4894
18
    } else {
4895
15
      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
15
      } 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
15
        jit_set_Z_LVAL(jit, op1_def_addr, ir_CONST_LONG(0xc3e0000000000000));
4903
15
#endif
4904
15
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_DOUBLE);
4905
15
      }
4906
15
    }
4907
33
    if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) &&
4908
23
        opline->result_type != IS_UNUSED) {
4909
6
      if (opline->opcode == ZEND_PRE_INC) {
4910
6
        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
6
        } 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
6
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
4918
6
#endif
4919
6
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
4920
6
        }
4921
6
      } 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
6
    }
4935
4936
33
    if (merge_inputs) {
4937
33
      ir_END_list(merge_inputs);
4938
33
      ir_MERGE_list(merge_inputs);
4939
33
    }
4940
33
  } 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
45
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
4950
25
    ir_ref merge_inputs = ir_END();
4951
4952
    /* !is_long => cold path */
4953
25
    ir_IF_FALSE_cold(if_long);
4954
25
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
4955
25
      jit_SET_EX_OPLINE(jit, opline);
4956
25
      if (op1_info & MAY_BE_UNDEF) {
4957
25
        ir_ref if_def;
4958
4959
25
        if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
4960
25
        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
25
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
4964
4965
25
        jit_set_Z_TYPE_INFO(jit, op1_def_addr, IS_NULL);
4966
25
        ir_MERGE_WITH_EMPTY_TRUE(if_def);
4967
4968
25
        op1_info |= MAY_BE_NULL;
4969
25
      }
4970
4971
25
      ref = jit_ZVAL_ADDR(jit, op1_addr);
4972
4973
25
      if (op1_info & MAY_BE_REF) {
4974
25
        ir_ref if_ref, if_typed, func, ref2, arg2;
4975
4976
25
        if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
4977
25
        ir_IF_TRUE(if_ref);
4978
25
        ref2 = jit_Z_PTR_ref(jit, ref);
4979
4980
25
        if_typed = jit_if_TYPED_REF(jit, ref2);
4981
25
        ir_IF_TRUE(if_typed);
4982
4983
25
        if (RETURN_VALUE_USED(opline)) {
4984
14
          ZEND_ASSERT(Z_MODE(res_addr) != IS_REG);
4985
14
          arg2 = jit_ZVAL_ADDR(jit, res_addr);
4986
14
        } else {
4987
11
          arg2 = IR_NULL;
4988
11
        }
4989
25
        if (opline->opcode == ZEND_PRE_INC) {
4990
8
          func = ir_CONST_FC_FUNC(zend_jit_pre_inc_typed_ref);
4991
17
        } else if (opline->opcode == ZEND_PRE_DEC) {
4992
7
          func = ir_CONST_FC_FUNC(zend_jit_pre_dec_typed_ref);
4993
10
        } else if (opline->opcode == ZEND_POST_INC) {
4994
2
          func = ir_CONST_FC_FUNC(zend_jit_post_inc_typed_ref);
4995
8
        } else if (opline->opcode == ZEND_POST_DEC) {
4996
8
          func = ir_CONST_FC_FUNC(zend_jit_post_dec_typed_ref);
4997
8
        } else {
4998
0
          ZEND_UNREACHABLE();
4999
0
        }
5000
5001
25
        ir_CALL_2(IR_VOID, func, ref2, arg2);
5002
25
        zend_jit_check_exception(jit);
5003
25
        ir_END_list(merge_inputs);
5004
5005
25
        ir_IF_FALSE(if_typed);
5006
25
        ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
5007
25
        ir_MERGE_WITH_EMPTY_FALSE(if_ref);
5008
25
        ref = ir_PHI_2(IR_ADDR, ref2, ref);
5009
25
      }
5010
5011
25
      if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) {
5012
10
        jit_ZVAL_COPY(jit,
5013
10
          res_addr,
5014
10
          res_use_info,
5015
10
          ZEND_ADDR_REF_ZVAL(ref), op1_info, true);
5016
10
      }
5017
25
      if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) {
5018
10
        if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) {
5019
4
          ir_ref arg2 = jit_ZVAL_ADDR(jit, res_addr);
5020
4
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc), ref, arg2);
5021
6
        } else {
5022
6
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function), ref);
5023
6
        }
5024
15
      } else {
5025
15
        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
15
        } else {
5029
15
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function), ref);
5030
15
        }
5031
15
      }
5032
25
      if (may_throw) {
5033
25
        zend_jit_check_exception(jit);
5034
25
      }
5035
25
    } 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
25
    ir_END_list(merge_inputs);
5055
25
    ir_MERGE_list(merge_inputs);
5056
25
  }
5057
45
  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
45
  if (opline->result_type != IS_UNUSED) {
5061
28
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5062
0
      return 0;
5063
0
    }
5064
28
  }
5065
45
  return 1;
5066
45
}
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
291
{
5078
291
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5079
291
  ir_op op;
5080
291
  ir_ref op1, op2, ref, if_overflow = IR_UNUSED;
5081
5082
291
  if (opcode == ZEND_ADD) {
5083
66
    op = may_overflow ? IR_ADD_OV : IR_ADD;
5084
225
  } else if (opcode == ZEND_SUB) {
5085
134
    op = may_overflow ? IR_SUB_OV : IR_SUB;
5086
134
  } else if (opcode == ZEND_MUL) {
5087
91
    op = may_overflow ? IR_MUL_OV : IR_MUL;
5088
91
  } else {
5089
0
    ZEND_UNREACHABLE();
5090
0
  }
5091
291
  op1 = jit_Z_LVAL(jit, op1_addr);
5092
291
  op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5093
291
  ref = ir_BINARY_OP_L(op, op1, op2);
5094
5095
291
  if (may_overflow) {
5096
285
    if (res_info & MAY_BE_GUARD) {
5097
183
      if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) {
5098
182
        zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
5099
182
        uint32_t old_res_info;
5100
182
        int32_t exit_point;
5101
182
        const void *exit_addr;
5102
5103
182
        if (opline->opcode == ZEND_ADD
5104
34
         && 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
182
        } else if (opline->opcode == ZEND_SUB
5111
103
         && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5112
13
          old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5113
13
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
5114
13
          SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), ir_CONST_DOUBLE((double)ZEND_LONG_MIN - 1.0));
5115
13
          exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
5116
13
          SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
5117
169
        } else {
5118
169
          exit_point = zend_jit_trace_get_exit_point(opline, 0);
5119
169
        }
5120
5121
182
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5122
182
        if (!exit_addr) {
5123
0
          return 0;
5124
0
        }
5125
182
        ir_GUARD_NOT(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5126
182
        may_overflow = 0;
5127
182
      } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
5128
1
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
5129
1
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5130
5131
1
        if (!exit_addr) {
5132
0
          return 0;
5133
0
        }
5134
1
        ir_GUARD(ir_OVERFLOW(ref), ir_CONST_ADDR(exit_addr));
5135
1
      } else {
5136
0
        ZEND_UNREACHABLE();
5137
0
      }
5138
183
    } else {
5139
102
      if_overflow = ir_IF(ir_OVERFLOW(ref));
5140
102
      ir_IF_FALSE(if_overflow);
5141
102
    }
5142
285
  }
5143
5144
291
  if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5145
290
    jit_set_Z_LVAL(jit, res_addr, ref);
5146
5147
290
    if (Z_MODE(res_addr) != IS_REG) {
5148
176
      if (!zend_jit_same_addr(op1_addr, res_addr)) {
5149
129
        if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5150
65
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5151
65
        }
5152
129
      }
5153
176
    }
5154
290
  }
5155
5156
291
  if (may_overflow) {
5157
103
    ir_ref fast_path = IR_UNUSED;
5158
5159
103
    if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5160
102
      fast_path = ir_END();
5161
102
      ir_IF_TRUE_cold(if_overflow);
5162
102
    }
5163
103
    if (opcode == ZEND_ADD) {
5164
28
      if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1) {
5165
4
        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
4
        } 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
4
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
5173
4
#endif
5174
4
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5175
4
        }
5176
4
        if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5177
4
          ir_MERGE_WITH(fast_path);
5178
4
        }
5179
4
        return 1;
5180
4
      }
5181
24
      op = IR_ADD;
5182
75
    } else if (opcode == ZEND_SUB) {
5183
29
      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
29
      op = IR_SUB;
5201
46
    } else if (opcode == ZEND_MUL) {
5202
46
      op = IR_MUL;
5203
46
    } else {
5204
0
      ZEND_UNREACHABLE();
5205
0
    }
5206
99
#if 1
5207
    /* reload */
5208
99
    op1 = jit_Z_LVAL(jit, op1_addr);
5209
99
    op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5210
99
#endif
5211
99
#if 1
5212
    /* disable CSE */
5213
99
    ir_ref old_cse_limit = jit->ctx.fold_cse_limit;
5214
99
    jit->ctx.fold_cse_limit = 0x7fffffff;
5215
99
#endif
5216
99
    op1 = ir_INT2D(op1);
5217
99
    op2 = ir_INT2D(op2);
5218
99
#if 1
5219
99
    jit->ctx.fold_cse_limit = old_cse_limit;
5220
99
#endif
5221
99
    ref = ir_BINARY_OP_D(op, op1, op2);
5222
99
    jit_set_Z_DVAL(jit, res_addr, ref);
5223
99
    if (Z_MODE(res_addr) != IS_REG) {
5224
99
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5225
99
    }
5226
99
    if ((res_info & MAY_BE_ANY) != MAY_BE_DOUBLE) {
5227
98
      ir_MERGE_WITH(fast_path);
5228
98
    }
5229
99
  }
5230
5231
287
  return 1;
5232
291
}
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
46
{
5241
46
  ir_op op;
5242
46
  ir_ref op1, op2, ref;
5243
5244
46
  if (opcode == ZEND_ADD) {
5245
7
    op = IR_ADD;
5246
39
  } else if (opcode == ZEND_SUB) {
5247
17
    op = IR_SUB;
5248
22
  } else if (opcode == ZEND_MUL) {
5249
22
    op = IR_MUL;
5250
22
  } else if (opcode == ZEND_DIV) {
5251
0
    op = IR_DIV;
5252
0
  } else {
5253
0
    ZEND_UNREACHABLE();
5254
0
  }
5255
46
  op1 = jit_Z_LVAL(jit, op1_addr);
5256
46
  op2 = jit_Z_DVAL(jit, op2_addr);
5257
46
  ref = ir_BINARY_OP_D(op, ir_INT2D(op1), op2);
5258
46
  jit_set_Z_DVAL(jit, res_addr, ref);
5259
5260
46
  if (Z_MODE(res_addr) != IS_REG) {
5261
31
    if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5262
28
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5263
28
    }
5264
31
  }
5265
46
  return 1;
5266
46
}
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
83
{
5275
83
  ir_op op;
5276
83
  ir_ref op1, op2, ref;
5277
5278
83
  if (opcode == ZEND_ADD) {
5279
24
    op = IR_ADD;
5280
59
  } else if (opcode == ZEND_SUB) {
5281
16
    op = IR_SUB;
5282
43
  } else if (opcode == ZEND_MUL) {
5283
43
    op = IR_MUL;
5284
43
  } else if (opcode == ZEND_DIV) {
5285
0
    op = IR_DIV;
5286
0
  } else {
5287
0
    ZEND_UNREACHABLE();
5288
0
  }
5289
83
  op1 = jit_Z_DVAL(jit, op1_addr);
5290
83
  op2 = jit_Z_LVAL(jit, op2_addr);
5291
83
  ref = ir_BINARY_OP_D(op, op1, ir_INT2D(op2));
5292
83
  jit_set_Z_DVAL(jit, res_addr, ref);
5293
5294
83
  if (Z_MODE(res_addr) != IS_REG) {
5295
70
    if (!zend_jit_same_addr(op1_addr, res_addr)) {
5296
26
      if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5297
20
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5298
20
      }
5299
26
    }
5300
70
  }
5301
83
  return 1;
5302
83
}
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
22
{
5311
22
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5312
22
  ir_op op;
5313
22
  ir_ref op1, op2, ref;
5314
5315
22
  if (opcode == ZEND_ADD) {
5316
6
    op = IR_ADD;
5317
16
  } else if (opcode == ZEND_SUB) {
5318
10
    op = IR_SUB;
5319
10
  } else if (opcode == ZEND_MUL) {
5320
6
    op = IR_MUL;
5321
6
  } else if (opcode == ZEND_DIV) {
5322
0
    op = IR_DIV;
5323
0
  } else {
5324
0
    ZEND_UNREACHABLE();
5325
0
  }
5326
22
  op1 = jit_Z_DVAL(jit, op1_addr);
5327
22
  op2 = (same_ops) ? op1 : jit_Z_DVAL(jit, op2_addr);
5328
22
  ref = ir_BINARY_OP_D(op, op1, op2);
5329
22
  jit_set_Z_DVAL(jit, res_addr, ref);
5330
5331
22
  if (Z_MODE(res_addr) != IS_REG) {
5332
19
    if (!zend_jit_same_addr(op1_addr, res_addr)) {
5333
18
      if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) {
5334
18
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
5335
18
      }
5336
18
    }
5337
19
  }
5338
22
  return 1;
5339
22
}
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
448
{
5359
448
  ir_ref if_op1_long = IR_UNUSED;
5360
448
  ir_ref if_op1_double = IR_UNUSED;
5361
448
  ir_ref if_op2_double = IR_UNUSED;
5362
448
  ir_ref if_op1_long_op2_long = IR_UNUSED;
5363
448
  ir_ref if_op1_long_op2_double = IR_UNUSED;
5364
448
  ir_ref if_op1_double_op2_double = IR_UNUSED;
5365
448
  ir_ref if_op1_double_op2_long = IR_UNUSED;
5366
448
  ir_ref slow_inputs = IR_UNUSED;
5367
448
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5368
448
  ir_refs *end_inputs;
5369
448
  ir_refs *res_inputs;
5370
5371
448
  ir_refs_init(end_inputs, 6);
5372
448
  ir_refs_init(res_inputs, 6);
5373
5374
448
  if (Z_MODE(op1_addr) == IS_REG) {
5375
135
    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
313
  } else if (Z_MODE(op2_addr) == IS_REG) {
5380
33
    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
33
  }
5385
5386
448
  if (Z_MODE(res_addr) == IS_REG) {
5387
145
    jit->delay_var = Z_SSA_VAR(res_addr);
5388
145
    jit->delay_refs = res_inputs;
5389
145
  }
5390
5391
448
  if ((res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG) && (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
5392
183
    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
183
    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
183
    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
183
    ir_refs_add(end_inputs, ir_END());
5404
183
    if (if_op1_long) {
5405
0
      ir_IF_FALSE_cold(if_op1_long);
5406
0
      ir_END_list(slow_inputs);
5407
0
    }
5408
183
    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
265
  } else if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
5413
108
    if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) {
5414
57
      if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5415
57
      ir_IF_TRUE(if_op1_long);
5416
57
    }
5417
108
    if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) {
5418
15
      if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5419
15
      ir_IF_FALSE_cold(if_op1_long_op2_long);
5420
15
      if (op2_info & MAY_BE_DOUBLE) {
5421
12
        if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5422
12
          if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5423
12
          ir_IF_FALSE_cold(if_op1_long_op2_double);
5424
12
          ir_END_list(slow_inputs);
5425
12
          ir_IF_TRUE(if_op1_long_op2_double);
5426
12
        }
5427
12
        if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5428
0
          return 0;
5429
0
        }
5430
12
        ir_refs_add(end_inputs, ir_END());
5431
12
      } else {
5432
3
        ir_END_list(slow_inputs);
5433
3
      }
5434
15
      ir_IF_TRUE(if_op1_long_op2_long);
5435
15
    }
5436
108
    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
108
    ir_refs_add(end_inputs, ir_END());
5440
5441
108
    if (if_op1_long) {
5442
57
      ir_IF_FALSE_cold(if_op1_long);
5443
57
    }
5444
5445
108
    if (op1_info & MAY_BE_DOUBLE) {
5446
55
      if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5447
53
        if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
5448
53
        ir_IF_FALSE_cold(if_op1_double);
5449
53
        ir_END_list(slow_inputs);
5450
53
        ir_IF_TRUE(if_op1_double);
5451
53
      }
5452
55
      if (op2_info & MAY_BE_DOUBLE) {
5453
9
        if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5454
9
          if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5455
9
          ir_IF_TRUE(if_op1_double_op2_double);
5456
9
        }
5457
9
        if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5458
0
          return 0;
5459
0
        }
5460
9
        ir_refs_add(end_inputs, ir_END());
5461
9
        if (if_op1_double_op2_double) {
5462
9
          ir_IF_FALSE_cold(if_op1_double_op2_double);
5463
9
        }
5464
9
      }
5465
55
      if (!same_ops) {
5466
55
        if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
5467
9
          if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5468
9
          ir_IF_FALSE_cold(if_op1_double_op2_long);
5469
9
          ir_END_list(slow_inputs);
5470
9
          ir_IF_TRUE(if_op1_double_op2_long);
5471
9
        }
5472
55
        if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5473
0
          return 0;
5474
0
        }
5475
55
        ir_refs_add(end_inputs, ir_END());
5476
55
      } else if (if_op1_double_op2_double) {
5477
0
        ir_END_list(slow_inputs);
5478
0
      }
5479
55
    } else if (if_op1_long) {
5480
2
      ir_END_list(slow_inputs);
5481
2
    }
5482
157
  } else if ((op1_info & MAY_BE_DOUBLE) &&
5483
40
             !(op1_info & MAY_BE_LONG) &&
5484
40
             (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5485
40
             (res_info & MAY_BE_DOUBLE)) {
5486
40
    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
40
    if (op2_info & MAY_BE_DOUBLE) {
5493
13
      if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) {
5494
1
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
5495
1
        ir_IF_TRUE(if_op1_double_op2_double);
5496
1
      }
5497
13
      if (!zend_jit_math_double_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5498
0
        return 0;
5499
0
      }
5500
13
      ir_refs_add(end_inputs, ir_END());
5501
13
      if (if_op1_double_op2_double) {
5502
1
        ir_IF_FALSE_cold(if_op1_double_op2_double);
5503
1
      }
5504
13
    }
5505
40
    if (!same_ops && (op2_info & MAY_BE_LONG)) {
5506
28
      if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
5507
1
        if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5508
1
        ir_IF_FALSE_cold(if_op1_double_op2_long);
5509
1
        ir_END_list(slow_inputs);
5510
1
        ir_IF_TRUE(if_op1_double_op2_long);
5511
1
      }
5512
28
      if (!zend_jit_math_double_long(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5513
0
        return 0;
5514
0
      }
5515
28
      ir_refs_add(end_inputs, ir_END());
5516
28
    } else if (if_op1_double_op2_double) {
5517
0
      ir_END_list(slow_inputs);
5518
0
    }
5519
117
  } else if ((op2_info & MAY_BE_DOUBLE) &&
5520
35
             !(op2_info & MAY_BE_LONG) &&
5521
35
             (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
5522
34
             (res_info & MAY_BE_DOUBLE)) {
5523
34
    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
34
    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
34
    if (!same_ops && (op1_info & MAY_BE_LONG)) {
5543
34
      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
34
      if (!zend_jit_math_long_double(jit, opcode, op1_addr, op2_addr, res_addr, res_use_info)) {
5550
0
        return 0;
5551
0
      }
5552
34
      ir_refs_add(end_inputs, ir_END());
5553
34
    } else if (if_op1_double_op2_double) {
5554
0
      ir_END_list(slow_inputs);
5555
0
    }
5556
34
  }
5557
5558
448
  if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
5559
310
    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
5560
145
    ir_ref func, arg1, arg2, arg3;
5561
5562
145
    if (slow_inputs) {
5563
62
      ir_MERGE_list(slow_inputs);
5564
62
    }
5565
5566
145
    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
145
    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
145
    if (Z_MODE(res_addr) == IS_REG) {
5581
0
      arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5582
145
    } else {
5583
145
      arg1 = jit_ZVAL_ADDR(jit, res_addr);
5584
145
    }
5585
145
    arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5586
145
    arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5587
145
    jit_SET_EX_OPLINE(jit, opline);
5588
145
    if (opcode == ZEND_ADD) {
5589
28
      func = ir_CONST_FC_FUNC(add_function);
5590
117
    } else if (opcode == ZEND_SUB) {
5591
5
      func = ir_CONST_FC_FUNC(sub_function);
5592
112
    } else if (opcode == ZEND_MUL) {
5593
112
      func = ir_CONST_FC_FUNC(mul_function);
5594
112
    } else if (opcode == ZEND_DIV) {
5595
0
      func = ir_CONST_FC_FUNC(div_function);
5596
0
    } else {
5597
0
      ZEND_UNREACHABLE();
5598
0
    }
5599
145
    ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5600
5601
145
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5602
145
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5603
5604
145
    if (may_throw) {
5605
145
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5606
57
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5607
57
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5608
88
      } 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
88
      } else {
5611
88
        zend_jit_check_exception(jit);
5612
88
      }
5613
145
    }
5614
145
    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
145
    ir_refs_add(end_inputs, ir_END());
5621
145
  }
5622
5623
448
  if (end_inputs->count) {
5624
448
    ir_MERGE_N(end_inputs->count, end_inputs->refs);
5625
448
  }
5626
5627
448
  if (Z_MODE(res_addr) == IS_REG) {
5628
145
    ZEND_ASSERT(jit->delay_refs == res_inputs);
5629
145
    ZEND_ASSERT(end_inputs->count == res_inputs->count);
5630
145
    jit->delay_var = -1;
5631
145
    jit->delay_refs = NULL;
5632
145
    if (res_inputs->count == 1) {
5633
145
      zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
5634
145
    } 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
145
  }
5639
5640
448
  return 1;
5641
448
}
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
318
{
5645
318
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
5646
5647
318
  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
318
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
5651
0
    return 0;
5652
0
  }
5653
318
  return 1;
5654
318
}
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
3
{
5658
3
  ir_ref ref;
5659
3
  ir_ref arg1 = jit_Z_PTR(jit, op1_addr);
5660
3
  ir_ref arg2 = jit_Z_PTR(jit, op2_addr);
5661
5662
3
  ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_add_arrays_helper), arg1, arg2);
5663
3
  jit_set_Z_PTR(jit, res_addr, ref);
5664
3
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_ARRAY_EX);
5665
3
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
5666
3
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
5667
3
  return 1;
5668
3
}
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
2.76k
{
5689
2.76k
  ir_ref ref = IR_UNUSED;
5690
2.76k
  ir_ref if_long1 = IR_UNUSED;
5691
2.76k
  ir_ref if_long2 = IR_UNUSED;
5692
2.76k
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
5693
2.76k
  ir_refs *res_inputs;
5694
5695
2.76k
  ir_refs_init(res_inputs, 2);
5696
5697
2.76k
  if (Z_MODE(op1_addr) == IS_REG
5698
107
   && 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
2.76k
  if (Z_MODE(op2_addr) == IS_REG
5704
9
   && 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
2.76k
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
5711
2.17k
    if_long1 = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
5712
2.17k
    ir_IF_TRUE(if_long1);
5713
2.17k
  }
5714
2.76k
  if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5715
891
    if_long2 = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
5716
891
    ir_IF_TRUE(if_long2);
5717
891
  }
5718
5719
2.76k
  if (opcode == ZEND_SL) {
5720
242
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5721
154
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5722
5723
154
      if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5724
116
        if (EXPECTED(op2_lval > 0)) {
5725
30
          ref = ir_CONST_LONG(0);
5726
86
        } else {
5727
86
          zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5728
86
          zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5729
86
          jit_SET_EX_OPLINE(jit, opline);
5730
86
          ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5731
86
          if (Z_MODE(res_addr) == IS_REG) {
5732
0
            ref = ir_CONST_LONG(0); // dead code
5733
0
          }
5734
86
        }
5735
116
      } else {
5736
38
        ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5737
38
      }
5738
154
    } else {
5739
88
      ref = jit_Z_LVAL(jit, op2_addr);
5740
88
      if (!op2_range ||
5741
0
           op2_range->min < 0 ||
5742
88
           op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5743
5744
88
        ir_ref if_wrong, cold_path, ref2, if_ok;
5745
88
        ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5746
5747
88
        if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5748
88
        ir_IF_TRUE_cold(if_wrong);
5749
88
        if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5750
88
        ir_IF_FALSE(if_ok);
5751
88
        jit_SET_EX_OPLINE(jit, opline);
5752
88
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5753
88
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5754
88
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5755
88
        ir_IF_TRUE(if_ok);
5756
88
        ref2 = ir_CONST_LONG(0);
5757
88
        cold_path = ir_END();
5758
88
        ir_IF_FALSE(if_wrong);
5759
88
        ref = ir_SHL_L(op1_ref, ref);
5760
88
        ir_MERGE_WITH(cold_path);
5761
88
        ref = ir_PHI_2(IR_LONG, ref, ref2);
5762
88
      } else {
5763
0
        ref = ir_SHL_L(jit_Z_LVAL(jit, op1_addr), ref);
5764
0
      }
5765
88
    }
5766
2.52k
  } else if (opcode == ZEND_SR) {
5767
73
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5768
28
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5769
5770
28
      if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
5771
20
        if (EXPECTED(op2_lval > 0)) {
5772
7
          ref = ir_SAR_L(
5773
7
            jit_Z_LVAL(jit, op1_addr),
5774
7
            ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1));
5775
13
        } else {
5776
13
          zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5777
13
          zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5778
13
          jit_SET_EX_OPLINE(jit, opline);
5779
13
          ir_GUARD(IR_FALSE, jit_STUB_ADDR(jit, jit_stub_negative_shift));
5780
13
          if (Z_MODE(res_addr) == IS_REG) {
5781
0
            ref = ir_CONST_LONG(0); // dead code
5782
0
          }
5783
13
        }
5784
20
      } else {
5785
8
        ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5786
8
      }
5787
45
    } else {
5788
45
      ref = jit_Z_LVAL(jit, op2_addr);
5789
45
      if (!op2_range ||
5790
0
           op2_range->min < 0 ||
5791
45
           op2_range->max >= SIZEOF_ZEND_LONG * 8) {
5792
5793
45
        ir_ref if_wrong, cold_path, ref2, if_ok;
5794
5795
45
        if_wrong = ir_IF(ir_UGT(ref, ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1)));
5796
45
        ir_IF_TRUE_cold(if_wrong);
5797
45
        if_ok = ir_IF(ir_GE(ref, ir_CONST_LONG(0)));
5798
45
        ir_IF_FALSE(if_ok);
5799
45
        jit_SET_EX_OPLINE(jit, opline);
5800
45
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5801
45
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5802
45
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_negative_shift));
5803
45
        ir_IF_TRUE(if_ok);
5804
45
        ref2 = ir_CONST_LONG((SIZEOF_ZEND_LONG * 8) - 1);
5805
45
        cold_path = ir_END();
5806
45
        ir_IF_FALSE(if_wrong);
5807
45
        ir_MERGE_WITH(cold_path);
5808
45
        ref = ir_PHI_2(IR_LONG, ref, ref2);
5809
45
      }
5810
45
      ref = ir_SAR_L(jit_Z_LVAL(jit, op1_addr), ref);
5811
45
    }
5812
2.45k
  } else if (opcode == ZEND_MOD) {
5813
1.30k
    if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
5814
934
      zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr));
5815
5816
934
      if (op2_lval == 0) {
5817
64
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5818
64
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5819
64
        jit_SET_EX_OPLINE(jit, opline);
5820
64
        ir_GUARD(IR_FALSE,  jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5821
64
        if (Z_MODE(res_addr) == IS_REG) {
5822
2
          ref = ir_CONST_LONG(0); // dead code
5823
2
        }
5824
870
      } else if (op2_lval == -1) {
5825
        /* Prevent overflow error/crash if op1 == LONG_MIN */
5826
22
        ref = ir_CONST_LONG(0);
5827
848
      } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) {
5828
0
        ref = ir_AND_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval - 1));
5829
848
      } else {
5830
848
        ref = ir_MOD_L(jit_Z_LVAL(jit, op1_addr), ir_CONST_LONG(op2_lval));
5831
848
      }
5832
934
    } else {
5833
370
      ir_ref zero_path = 0;
5834
370
      ir_ref op1_ref = jit_Z_LVAL(jit, op1_addr);
5835
5836
370
      ref = jit_Z_LVAL(jit, op2_addr);
5837
370
      if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) {
5838
370
        ir_ref if_ok = ir_IF(ref);
5839
370
        ir_IF_FALSE(if_ok);
5840
370
        jit_SET_EX_OPLINE(jit, opline);
5841
370
        zend_jit_invalidate_var_if_necessary(jit, op1_type, op1_addr, op1);
5842
370
        zend_jit_invalidate_var_if_necessary(jit, op2_type, op2_addr, op2);
5843
370
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_mod_by_zero));
5844
370
        ir_IF_TRUE(if_ok);
5845
370
      }
5846
5847
      /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */
5848
370
      if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) {
5849
370
        ir_ref if_minus_one = ir_IF(ir_EQ(ref, ir_CONST_LONG(-1)));
5850
370
        ir_IF_TRUE_cold(if_minus_one);
5851
370
        zero_path = ir_END();
5852
370
        ir_IF_FALSE(if_minus_one);
5853
370
      }
5854
370
      ref = ir_MOD_L(op1_ref, ref);
5855
5856
370
      if (zero_path) {
5857
370
        ir_MERGE_WITH(zero_path);
5858
370
        ref = ir_PHI_2(IR_LONG, ref, ir_CONST_LONG(0));
5859
370
      }
5860
370
    }
5861
1.30k
  } else {
5862
1.14k
    ir_op op;
5863
1.14k
    ir_ref op1, op2;
5864
5865
1.14k
    if (opcode == ZEND_BW_OR) {
5866
393
      op = IR_OR;
5867
754
    } else if (opcode == ZEND_BW_AND) {
5868
701
      op = IR_AND;
5869
701
    } else if (opcode == ZEND_BW_XOR) {
5870
53
      op = IR_XOR;
5871
53
    } else {
5872
0
      ZEND_UNREACHABLE();
5873
0
    }
5874
1.14k
    op1 = jit_Z_LVAL(jit, op1_addr);
5875
1.14k
    op2 = (same_ops) ? op1 : jit_Z_LVAL(jit, op2_addr);
5876
1.14k
    ref = ir_BINARY_OP_L(op, op1, op2);
5877
1.14k
  }
5878
5879
2.76k
  if (ref) {
5880
2.60k
    if (Z_MODE(res_addr) == IS_REG
5881
155
     && ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))
5882
153
      || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
5883
2
      jit->delay_var = Z_SSA_VAR(res_addr);
5884
2
      jit->delay_refs = res_inputs;
5885
2
    }
5886
2.60k
    jit_set_Z_LVAL(jit, res_addr, ref);
5887
2.60k
    if (Z_MODE(res_addr) != IS_REG) {
5888
2.45k
      if (!zend_jit_same_addr(op1_addr, res_addr)) {
5889
2.43k
        if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) {
5890
2.40k
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
5891
2.40k
        }
5892
2.43k
      }
5893
2.45k
    }
5894
2.60k
  }
5895
5896
2.76k
  if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) ||
5897
2.35k
    (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
5898
2.35k
    ir_ref fast_path = ir_END();
5899
2.35k
    ir_ref func, arg1, arg2, arg3;
5900
5901
2.35k
    if (if_long2 && if_long1) {
5902
706
      ir_ref ref;
5903
706
      ir_IF_FALSE_cold(if_long2);
5904
706
      ref = ir_END();
5905
706
      ir_IF_FALSE_cold(if_long1);
5906
706
      ir_MERGE_2(ref, ir_END());
5907
1.65k
    } else if (if_long1) {
5908
1.46k
      ir_IF_FALSE_cold(if_long1);
5909
1.46k
    } else if (if_long2) {
5910
185
      ir_IF_FALSE_cold(if_long2);
5911
185
    }
5912
5913
2.35k
    if (op1_info & MAY_BE_UNDEF) {
5914
2.15k
      ir_ref if_def, ref, ref2;
5915
5916
2.15k
      ref = jit_ZVAL_ADDR(jit, op1_addr);
5917
2.15k
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
5918
2.15k
      ir_IF_FALSE_cold(if_def);
5919
5920
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
5921
2.15k
      jit_SET_EX_OPLINE(jit, opline);
5922
2.15k
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
5923
5924
2.15k
      ref2 = jit_EG(uninitialized_zval);
5925
2.15k
      ir_MERGE_WITH_EMPTY_TRUE(if_def);
5926
2.15k
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
5927
2.15k
      op1_addr = ZEND_ADDR_REF_ZVAL(ref);
5928
2.15k
    }
5929
5930
2.35k
    if (op2_info & MAY_BE_UNDEF) {
5931
885
      ir_ref if_def, ref, ref2;
5932
5933
885
      ref = jit_ZVAL_ADDR(jit, op2_addr);
5934
885
      if_def = jit_if_not_Z_TYPE(jit, op2_addr, IS_UNDEF);
5935
885
      ir_IF_FALSE_cold(if_def);
5936
5937
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op2.var)));
5938
885
      jit_SET_EX_OPLINE(jit, opline);
5939
885
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
5940
5941
885
      ref2 = jit_EG(uninitialized_zval);
5942
885
      ir_MERGE_WITH_EMPTY_TRUE(if_def);
5943
885
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
5944
885
      op2_addr = ZEND_ADDR_REF_ZVAL(ref);
5945
885
    }
5946
5947
2.35k
    if (Z_MODE(op1_addr) == IS_REG) {
5948
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var);
5949
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
5950
0
        return 0;
5951
0
      }
5952
0
      op1_addr = real_addr;
5953
0
    }
5954
2.35k
    if (Z_MODE(op2_addr) == IS_REG) {
5955
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var);
5956
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
5957
0
        return 0;
5958
0
      }
5959
0
      op2_addr = real_addr;
5960
0
    }
5961
2.35k
    if (Z_MODE(res_addr) == IS_REG) {
5962
2
      arg1 = jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var));
5963
2.35k
    } else {
5964
2.35k
      arg1 = jit_ZVAL_ADDR(jit, res_addr);
5965
2.35k
    }
5966
2.35k
    arg2 = jit_ZVAL_ADDR(jit, op1_addr);
5967
2.35k
    arg3 = jit_ZVAL_ADDR(jit, op2_addr);
5968
2.35k
    jit_SET_EX_OPLINE(jit, opline);
5969
2.35k
    if (opcode == ZEND_BW_OR) {
5970
373
      func = ir_CONST_FC_FUNC(bitwise_or_function);
5971
1.98k
    } else if (opcode == ZEND_BW_AND) {
5972
620
      func = ir_CONST_FC_FUNC(bitwise_and_function);
5973
1.36k
    } else if (opcode == ZEND_BW_XOR) {
5974
51
      func = ir_CONST_FC_FUNC(bitwise_xor_function);
5975
1.31k
    } else if (opcode == ZEND_SL) {
5976
161
      func = ir_CONST_FC_FUNC(shift_left_function);
5977
1.15k
    } else if (opcode == ZEND_SR) {
5978
61
      func = ir_CONST_FC_FUNC(shift_right_function);
5979
1.09k
    } else if (opcode == ZEND_MOD) {
5980
1.09k
      func = ir_CONST_FC_FUNC(mod_function);
5981
1.09k
    } else {
5982
0
      ZEND_UNREACHABLE();
5983
0
    }
5984
2.35k
    ir_CALL_3(IR_VOID, func, arg1, arg2, arg3);
5985
5986
2.35k
    if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) {
5987
      /* compound assignment may decrement "op2" refcount */
5988
0
      op2_info |= MAY_BE_RC1;
5989
0
    }
5990
5991
2.35k
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
5992
2.35k
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
5993
5994
2.35k
    if (may_throw) {
5995
2.35k
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
5996
2
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
5997
2
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
5998
2.35k
      } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
5999
4
        zend_jit_check_exception_undef_result(jit, opline);
6000
2.35k
      } else {
6001
2.35k
        zend_jit_check_exception(jit);
6002
2.35k
      }
6003
2.35k
    }
6004
6005
2.35k
    if (Z_MODE(res_addr) == IS_REG) {
6006
2
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var);
6007
2
      if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
6008
0
        return 0;
6009
0
      }
6010
2
    }
6011
6012
2.35k
    ir_MERGE_2(fast_path, ir_END());
6013
6014
2.35k
    if (Z_MODE(res_addr) == IS_REG) {
6015
2
      ZEND_ASSERT(jit->delay_refs == res_inputs);
6016
2
      ZEND_ASSERT(res_inputs->count == 2);
6017
2
      jit->delay_var = -1;
6018
2
      jit->delay_refs = NULL;
6019
2
      if (res_inputs->count == 1) {
6020
0
        zend_jit_def_reg(jit, res_addr, res_inputs->refs[0]);
6021
2
      } else {
6022
2
        ir_ref phi = ir_PHI_N(IR_LONG, res_inputs->count, res_inputs->refs);
6023
2
        zend_jit_def_reg(jit, res_addr, phi);
6024
2
      }
6025
2
    }
6026
2.35k
  }
6027
6028
2.76k
  return 1;
6029
2.76k
}
6030
6031
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)
6032
2.75k
{
6033
2.75k
  ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG));
6034
6035
2.75k
  if (!zend_jit_long_math_helper(jit, opline, opline->opcode,
6036
2.75k
      opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6037
2.75k
      opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6038
2.75k
      opline->result.var, res_addr, res_info, res_use_info, may_throw)) {
6039
0
    return 0;
6040
0
  }
6041
2.75k
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6042
0
    return 0;
6043
0
  }
6044
2.75k
  return 1;
6045
2.75k
}
6046
6047
static int zend_jit_concat_helper(zend_jit_ctx   *jit,
6048
                                  const zend_op  *opline,
6049
                                  uint8_t         op1_type,
6050
                                  znode_op        op1,
6051
                                  zend_jit_addr   op1_addr,
6052
                                  uint32_t        op1_info,
6053
                                  uint8_t         op2_type,
6054
                                  znode_op        op2,
6055
                                  zend_jit_addr   op2_addr,
6056
                                  uint32_t        op2_info,
6057
                                  zend_jit_addr   res_addr,
6058
                                  int             may_throw)
6059
30
{
6060
30
  ir_ref if_op1_string = IR_UNUSED;
6061
30
  ir_ref if_op2_string = IR_UNUSED;
6062
30
  ir_ref fast_path = IR_UNUSED;
6063
6064
30
  if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6065
15
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6066
0
      if_op1_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
6067
0
      ir_IF_TRUE(if_op1_string);
6068
0
    }
6069
15
    if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) {
6070
8
      if_op2_string = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
6071
8
      ir_IF_TRUE(if_op2_string);
6072
8
    }
6073
15
    if (zend_jit_same_addr(op1_addr, res_addr)) {
6074
1
      ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6075
1
      ir_ref arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6076
6077
1
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_assign_concat_helper), arg1, arg2);
6078
      /* concatenation with itself may reduce refcount */
6079
1
      op2_info |= MAY_BE_RC1;
6080
14
    } else {
6081
14
      ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6082
14
      ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6083
14
      ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6084
6085
14
      if (op1_type == IS_CV || op1_type == IS_CONST) {
6086
11
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_helper), arg1, arg2, arg3);
6087
11
      } else {
6088
3
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fast_concat_tmp_helper), arg1, arg2, arg3);
6089
3
      }
6090
14
    }
6091
    /* concatenation with empty string may increase refcount */
6092
15
    op2_info |= MAY_BE_RCN;
6093
15
    jit_FREE_OP(jit, op2_type, op2, op2_info, opline);
6094
15
    if (if_op1_string || if_op2_string) {
6095
8
      fast_path = ir_END();
6096
8
    }
6097
15
  }
6098
30
  if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) ||
6099
23
      (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) {
6100
23
    if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6101
8
      if (if_op1_string && if_op2_string) {
6102
0
        ir_IF_FALSE(if_op1_string);
6103
0
        ir_MERGE_WITH_EMPTY_FALSE(if_op2_string);
6104
8
      } else if (if_op1_string) {
6105
0
        ir_IF_FALSE_cold(if_op1_string);
6106
8
      } else if (if_op2_string) {
6107
8
        ir_IF_FALSE_cold(if_op2_string);
6108
8
      }
6109
8
    }
6110
23
    ir_ref arg1 = jit_ZVAL_ADDR(jit, res_addr);
6111
23
    ir_ref arg2 = jit_ZVAL_ADDR(jit, op1_addr);
6112
23
    ir_ref arg3 = jit_ZVAL_ADDR(jit, op2_addr);
6113
6114
23
    jit_SET_EX_OPLINE(jit, opline);
6115
23
    ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(concat_function), arg1, arg2, arg3);
6116
    /* concatenation with empty string may increase refcount */
6117
23
    op1_info |= MAY_BE_RCN;
6118
23
    op2_info |= MAY_BE_RCN;
6119
23
    jit_FREE_OP(jit, op1_type, op1, op1_info, NULL);
6120
23
    jit_FREE_OP(jit, op2_type, op2, op2_info, NULL);
6121
23
    if (may_throw) {
6122
20
      if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) {
6123
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
6124
0
          jit_STUB_ADDR(jit, jit_stub_exception_handler_free_op2));
6125
20
      } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) {
6126
0
        zend_jit_check_exception_undef_result(jit, opline);
6127
20
      } else {
6128
20
        zend_jit_check_exception(jit);
6129
20
      }
6130
20
    }
6131
23
    if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) {
6132
8
      ir_MERGE_WITH(fast_path);
6133
8
    }
6134
23
  }
6135
30
  return 1;
6136
30
}
6137
6138
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)
6139
14
{
6140
14
  zend_jit_addr op1_addr, op2_addr;
6141
6142
14
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6143
14
  ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING));
6144
6145
14
  op1_addr = OP1_ADDR();
6146
14
  op2_addr = OP2_ADDR();
6147
6148
14
  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);
6149
14
}
6150
6151
static int zend_jit_assign_op(zend_jit_ctx   *jit,
6152
                              const zend_op  *opline,
6153
                              uint32_t        op1_info,
6154
                              zend_jit_addr   op1_addr,
6155
                              zend_ssa_range *op1_range,
6156
                              uint32_t        op1_def_info,
6157
                              zend_jit_addr   op1_def_addr,
6158
                              uint32_t        op1_mem_info,
6159
                              uint32_t        op2_info,
6160
                              zend_jit_addr   op2_addr,
6161
                              zend_ssa_range *op2_range,
6162
                              int             may_overflow,
6163
                              int             may_throw)
6164
7
{
6165
7
  int result = 1;
6166
7
  ir_ref slow_path = IR_UNUSED;
6167
6168
7
  ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED);
6169
7
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF));
6170
6171
7
  if (op1_info & MAY_BE_REF) {
6172
0
    ir_ref ref, ref2, arg2, op1_noref_path;
6173
0
    ir_ref if_op1_ref = IR_UNUSED;
6174
0
    ir_ref if_op1_typed = IR_UNUSED;
6175
0
    binary_op_type binary_op = get_binary_op(opline->extended_value);
6176
6177
0
    if (Z_MODE(op2_addr) == IS_REG
6178
0
     && Z_LOAD(op2_addr)
6179
0
     && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
6180
      /* Force load, so that the register is defined on all paths */
6181
0
      zend_jit_use_reg(jit, op2_addr);
6182
0
    }
6183
6184
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
6185
0
    if_op1_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6186
0
    ir_IF_FALSE(if_op1_ref);
6187
0
    op1_noref_path = ir_END();
6188
0
    ir_IF_TRUE(if_op1_ref);
6189
0
    ref2 = jit_Z_PTR_ref(jit, ref);
6190
6191
0
    if_op1_typed = jit_if_TYPED_REF(jit, ref2);
6192
0
    ir_IF_TRUE_cold(if_op1_typed);
6193
6194
0
    if (Z_MODE(op2_addr) == IS_REG) {
6195
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6196
0
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
6197
0
        return 0;
6198
0
      }
6199
0
      arg2 = jit_ZVAL_ADDR(jit, real_addr);
6200
0
    } else {
6201
0
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
6202
0
    }
6203
0
    jit_SET_EX_OPLINE(jit, opline);
6204
0
    if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
6205
0
     && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6206
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref_tmp),
6207
0
        ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6208
0
    } else {
6209
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
6210
0
        ref2, arg2, ir_CONST_FC_FUNC(binary_op));
6211
0
    }
6212
0
    zend_jit_check_exception(jit);
6213
0
    slow_path = ir_END();
6214
6215
0
    ir_IF_FALSE(if_op1_typed);
6216
0
    ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6217
6218
0
    ir_MERGE_WITH(op1_noref_path);
6219
0
    ref = ir_PHI_2(IR_ADDR, ref2, ref);
6220
0
    ZEND_ASSERT(op1_addr == op1_def_addr);
6221
0
    op1_def_addr = op1_addr = ZEND_ADDR_REF_ZVAL(ref);
6222
0
  }
6223
6224
7
  switch (opline->extended_value) {
6225
0
    case ZEND_ADD:
6226
0
    case ZEND_SUB:
6227
0
    case ZEND_MUL:
6228
0
    case ZEND_DIV:
6229
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);
6230
0
      break;
6231
0
    case ZEND_BW_OR:
6232
6
    case ZEND_BW_AND:
6233
6
    case ZEND_BW_XOR:
6234
6
    case ZEND_SL:
6235
6
    case ZEND_SR:
6236
6
    case ZEND_MOD:
6237
6
      result = zend_jit_long_math_helper(jit, opline, opline->extended_value,
6238
6
        opline->op1_type, opline->op1, op1_addr, op1_info, op1_range,
6239
6
        opline->op2_type, opline->op2, op2_addr, op2_info, op2_range,
6240
6
        opline->op1.var, op1_def_addr, op1_def_info, op1_mem_info, may_throw);
6241
6
      break;
6242
1
    case ZEND_CONCAT:
6243
1
      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);
6244
1
      break;
6245
0
    default:
6246
0
      ZEND_UNREACHABLE();
6247
7
  }
6248
6249
7
  if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) {
6250
0
    return 0;
6251
0
  }
6252
6253
7
  if (op1_info & MAY_BE_REF) {
6254
0
    ir_MERGE_WITH(slow_path);
6255
0
  }
6256
6257
7
  return result;
6258
7
}
6259
6260
static ir_ref jit_ZVAL_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6261
695
{
6262
695
  ir_ref if_ref, ref2;
6263
6264
695
  if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_REFERENCE)));
6265
695
  ir_IF_TRUE(if_ref);
6266
695
  ref2 = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
6267
695
  ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6268
695
  return ir_PHI_2(IR_ADDR, ref2, ref);
6269
695
}
6270
6271
static zend_jit_addr jit_ZVAL_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6272
229
{
6273
229
  ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6274
229
  ref = jit_ZVAL_DEREF_ref(jit, ref);
6275
229
  return ZEND_ADDR_REF_ZVAL(ref);
6276
229
}
6277
6278
static ir_ref jit_ZVAL_INDIRECT_DEREF_ref(zend_jit_ctx *jit, ir_ref ref)
6279
38
{
6280
38
  ir_ref if_ref, ref2;
6281
6282
38
  if_ref = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_INDIRECT)));
6283
38
  ir_IF_TRUE(if_ref);
6284
38
  ref2 = jit_Z_PTR_ref(jit, ref);
6285
38
  ir_MERGE_WITH_EMPTY_FALSE(if_ref);
6286
38
  return ir_PHI_2(IR_ADDR, ref2, ref);
6287
38
}
6288
6289
static zend_jit_addr jit_ZVAL_INDIRECT_DEREF(zend_jit_ctx *jit, zend_jit_addr addr)
6290
38
{
6291
38
  ir_ref ref = jit_ZVAL_ADDR(jit, addr);
6292
38
  ref = jit_ZVAL_INDIRECT_DEREF_ref(jit, ref);
6293
38
  return ZEND_ADDR_REF_ZVAL(ref);
6294
38
}
6295
6296
static int zend_jit_simple_assign(zend_jit_ctx   *jit,
6297
                                  const zend_op  *opline,
6298
                                  zend_jit_addr   var_addr,
6299
                                  uint32_t        var_info,
6300
                                  uint32_t        var_def_info,
6301
                                  uint8_t         val_type,
6302
                                  zend_jit_addr   val_addr,
6303
                                  uint32_t        val_info,
6304
                                  zend_jit_addr   res_addr,
6305
                                  bool            check_exception)
6306
1.26k
{
6307
1.26k
  ir_ref end_inputs = IR_UNUSED;
6308
6309
1.26k
  if (Z_MODE(val_addr) == IS_CONST_ZVAL) {
6310
358
    zval *zv = Z_ZV(val_addr);
6311
6312
358
    if (!res_addr) {
6313
266
      jit_ZVAL_COPY_CONST(jit,
6314
266
        var_addr,
6315
266
        var_info, var_def_info,
6316
266
        zv, true);
6317
266
    } else {
6318
92
      jit_ZVAL_COPY_CONST(jit,
6319
92
        var_addr,
6320
92
        var_info, var_def_info,
6321
92
        zv, true);
6322
92
      jit_ZVAL_COPY_CONST(jit,
6323
92
        res_addr,
6324
92
        -1, var_def_info,
6325
92
        zv, true);
6326
92
    }
6327
906
  } else {
6328
906
    if (val_info & MAY_BE_UNDEF) {
6329
671
      ir_ref if_def, ret;
6330
6331
671
      if_def = jit_if_not_Z_TYPE(jit, val_addr, IS_UNDEF);
6332
671
      ir_IF_FALSE_cold(if_def);
6333
6334
671
      jit_set_Z_TYPE_INFO(jit, var_addr, IS_NULL);
6335
671
      if (res_addr) {
6336
145
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
6337
145
      }
6338
671
      jit_SET_EX_OPLINE(jit, opline);
6339
6340
671
      ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL);
6341
      // zend_error_unchecked(E_WARNING, "Undefined variable $%S", CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)));
6342
671
      ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6343
6344
671
      if (check_exception) {
6345
376
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
6346
376
      }
6347
6348
671
      ir_END_list(end_inputs);
6349
671
      ir_IF_TRUE(if_def);
6350
671
    }
6351
906
    if (val_info & MAY_BE_REF) {
6352
663
      if (val_type == IS_CV) {
6353
102
        ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
6354
102
        ref = jit_ZVAL_DEREF_ref(jit, ref);
6355
102
        val_addr = ZEND_ADDR_REF_ZVAL(ref);
6356
561
      } else {
6357
561
        ir_ref ref, type, if_ref, ref2, refcount, if_not_zero;
6358
6359
561
        ref = jit_ZVAL_ADDR(jit, val_addr);
6360
561
        type = jit_Z_TYPE_ref(jit, ref);
6361
561
        if_ref = ir_IF(ir_EQ(type, ir_CONST_U8(IS_REFERENCE)));
6362
6363
561
        ir_IF_TRUE_cold(if_ref);
6364
561
        ref = jit_Z_PTR_ref(jit, ref);
6365
561
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
6366
561
        if (!res_addr) {
6367
463
          jit_ZVAL_COPY(jit,
6368
463
            var_addr,
6369
463
            var_info,
6370
463
            ZEND_ADDR_REF_ZVAL(ref2), val_info, true);
6371
463
        } else {
6372
98
          jit_ZVAL_COPY_2(jit,
6373
98
            res_addr,
6374
98
            var_addr,
6375
98
            var_info,
6376
98
            ZEND_ADDR_REF_ZVAL(ref2), val_info, 2);
6377
98
        }
6378
6379
561
        refcount = jit_GC_DELREF(jit, ref);
6380
561
        if_not_zero = ir_IF(refcount);
6381
561
        ir_IF_FALSE(if_not_zero);
6382
        // TODO: instead of dtor() call and ADDREF above, we may call efree() and move addref at "true" path ???
6383
        // This is related to GH-10168 (keep this before GH-10168 is completely closed)
6384
        // jit_EFREE(jit, ref, sizeof(zend_reference), NULL, NULL);
6385
561
        jit_ZVAL_DTOR(jit, ref, val_info, opline);
6386
561
        ir_END_list(end_inputs);
6387
561
        ir_IF_TRUE(if_not_zero);
6388
561
        ir_END_list(end_inputs);
6389
6390
561
        ir_IF_FALSE(if_ref);
6391
561
      }
6392
663
    }
6393
6394
906
    if (!res_addr) {
6395
700
      jit_ZVAL_COPY(jit,
6396
700
        var_addr,
6397
700
        var_info,
6398
700
        val_addr, val_info, val_type == IS_CV);
6399
700
    } else {
6400
206
      jit_ZVAL_COPY_2(jit,
6401
206
        res_addr,
6402
206
        var_addr,
6403
206
        var_info,
6404
206
        val_addr, val_info, val_type == IS_CV ? 2 : 1);
6405
206
    }
6406
906
  }
6407
6408
1.26k
  if (end_inputs) {
6409
709
    ir_END_list(end_inputs);
6410
709
    ir_MERGE_list(end_inputs);
6411
709
  }
6412
6413
1.26k
  return 1;
6414
1.26k
}
6415
6416
static int zend_jit_assign_to_variable_call(zend_jit_ctx   *jit,
6417
                                            const zend_op  *opline,
6418
                                            zend_jit_addr   __var_use_addr,
6419
                                            zend_jit_addr   var_addr,
6420
                                            uint32_t        __var_info,
6421
                                            uint32_t        __var_def_info,
6422
                                            uint8_t         val_type,
6423
                                            zend_jit_addr   val_addr,
6424
                                            uint32_t        val_info,
6425
                                            zend_jit_addr   __res_addr,
6426
                                            bool       __check_exception)
6427
7
{
6428
7
  jit_stub_id func;
6429
7
  ir_ref undef_path = IR_UNUSED;
6430
6431
7
  if (val_info & MAY_BE_UNDEF) {
6432
1
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
6433
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
6434
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6435
6436
0
      if (!exit_addr) {
6437
0
        return 0;
6438
0
      }
6439
6440
0
      jit_guard_not_Z_TYPE(jit, val_addr, IS_UNDEF, exit_addr);
6441
1
    } else {
6442
1
      ir_ref if_def;
6443
6444
1
      ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP);
6445
1
      if_def = ir_IF(jit_Z_TYPE(jit, val_addr));
6446
1
      ir_IF_FALSE_cold(if_def);
6447
1
      jit_SET_EX_OPLINE(jit, opline);
6448
1
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(Z_OFFSET(val_addr)));
6449
6450
1
      ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_assign_const, IR_FASTCALL_FUNC),
6451
1
        jit_ZVAL_ADDR(jit, var_addr),
6452
1
        jit_EG(uninitialized_zval));
6453
6454
1
      undef_path = ir_END();
6455
1
      ir_IF_TRUE(if_def);
6456
1
    }
6457
1
  }
6458
6459
7
  if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) {
6460
4
    func = jit_stub_assign_tmp;
6461
4
  } else if (val_type == IS_CONST) {
6462
0
    func = jit_stub_assign_const;
6463
3
  } else if (val_type == IS_TMP_VAR) {
6464
2
    func = jit_stub_assign_tmp;
6465
2
  } else if (val_type == IS_VAR) {
6466
0
    if (!(val_info & MAY_BE_REF)) {
6467
0
      func = jit_stub_assign_tmp;
6468
0
    } else {
6469
0
      func = jit_stub_assign_var;
6470
0
    }
6471
1
  } else if (val_type == IS_CV) {
6472
1
    if (!(val_info & MAY_BE_REF)) {
6473
0
      func = jit_stub_assign_cv_noref;
6474
1
    } else {
6475
1
      func = jit_stub_assign_cv;
6476
1
    }
6477
1
  } else {
6478
0
    ZEND_UNREACHABLE();
6479
0
  }
6480
6481
7
  if (opline) {
6482
7
    jit_SET_EX_OPLINE(jit, opline);
6483
7
  }
6484
6485
7
  ir_CALL_2(IR_VOID, jit_STUB_FUNC_ADDR(jit, func, IR_FASTCALL_FUNC),
6486
7
    jit_ZVAL_ADDR(jit, var_addr),
6487
7
    jit_ZVAL_ADDR(jit, val_addr));
6488
6489
7
  if (undef_path) {
6490
1
    ir_MERGE_WITH(undef_path);
6491
1
  }
6492
6493
7
  return 1;
6494
7
}
6495
6496
static int zend_jit_assign_to_variable(zend_jit_ctx   *jit,
6497
                                       const zend_op  *opline,
6498
                                       zend_jit_addr   var_use_addr,
6499
                                       zend_jit_addr   var_addr,
6500
                                       uint32_t        var_info,
6501
                                       uint32_t        var_def_info,
6502
                                       uint8_t         val_type,
6503
                                       zend_jit_addr   val_addr,
6504
                                       uint32_t        val_info,
6505
                                       zend_jit_addr   res_addr,
6506
                                       zend_jit_addr   ref_addr,
6507
                                       bool       check_exception)
6508
601
{
6509
601
  ir_ref if_refcounted = IR_UNUSED;
6510
601
  ir_ref simple_inputs = IR_UNUSED;
6511
601
  bool done = false;
6512
601
  zend_jit_addr real_res_addr = 0;
6513
601
  ir_refs *end_inputs;
6514
601
  ir_refs *res_inputs;
6515
6516
601
  ir_refs_init(end_inputs, 6);
6517
601
  ir_refs_init(res_inputs, 6);
6518
6519
601
  if (Z_MODE(val_addr) == IS_REG && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
6520
    /* Force load */
6521
0
    zend_jit_use_reg(jit, val_addr);
6522
0
  }
6523
6524
601
  if (Z_MODE(var_addr) == IS_REG) {
6525
4
    jit->delay_var = Z_SSA_VAR(var_addr);
6526
4
    jit->delay_refs = res_inputs;
6527
4
    if (Z_MODE(res_addr) == IS_REG) {
6528
4
      real_res_addr = res_addr;
6529
4
      res_addr = 0;
6530
4
    }
6531
597
  } else if (Z_MODE(res_addr) == IS_REG) {
6532
0
    jit->delay_var = Z_SSA_VAR(res_addr);
6533
0
    jit->delay_refs = res_inputs;
6534
0
  }
6535
6536
601
  if ((var_info & MAY_BE_REF) || ref_addr) {
6537
380
    ir_ref ref = 0, if_ref = 0, ref2, arg2, if_typed, non_ref_path;
6538
380
    uintptr_t func;
6539
6540
380
    if (!ref_addr) {
6541
377
      ref = jit_ZVAL_ADDR(jit, var_use_addr);
6542
377
      if_ref = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_REFERENCE));
6543
377
      ir_IF_TRUE(if_ref);
6544
377
      ref2 = jit_Z_PTR_ref(jit, ref);
6545
377
    } else {
6546
3
      ref2 = jit_ZVAL_ADDR(jit, ref_addr);
6547
3
    }
6548
380
    if_typed = jit_if_TYPED_REF(jit, ref2);
6549
380
    ir_IF_TRUE_cold(if_typed);
6550
380
    jit_SET_EX_OPLINE(jit, opline);
6551
380
    if (Z_MODE(val_addr) == IS_REG) {
6552
0
      zend_jit_addr real_addr;
6553
6554
0
      if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
6555
0
        real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
6556
0
      } else {
6557
0
        ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
6558
0
        real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
6559
0
      }
6560
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
6561
0
        return 0;
6562
0
      }
6563
0
      arg2 = jit_ZVAL_ADDR(jit, real_addr);
6564
380
    } else {
6565
380
      arg2 = jit_ZVAL_ADDR(jit, val_addr);
6566
380
    }
6567
380
    if (!res_addr) {
6568
287
      if (val_type == IS_CONST) {
6569
75
        func = (uintptr_t)zend_jit_assign_const_to_typed_ref;
6570
212
      } else if (val_type == IS_TMP_VAR) {
6571
191
        func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref;
6572
191
      } else if (val_type == IS_VAR) {
6573
4
        func = (uintptr_t)zend_jit_assign_var_to_typed_ref;
6574
17
      } else if (val_type == IS_CV) {
6575
17
        func = (uintptr_t)zend_jit_assign_cv_to_typed_ref;
6576
17
      } else {
6577
0
        ZEND_UNREACHABLE();
6578
0
      }
6579
287
      ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2);
6580
287
    } else {
6581
93
      if (val_type == IS_CONST) {
6582
30
        func = (uintptr_t)zend_jit_assign_const_to_typed_ref2;
6583
63
      } else if (val_type == IS_TMP_VAR) {
6584
49
        func = (uintptr_t)zend_jit_assign_tmp_to_typed_ref2;
6585
49
      } else if (val_type == IS_VAR) {
6586
0
        func = (uintptr_t)zend_jit_assign_var_to_typed_ref2;
6587
14
      } else if (val_type == IS_CV) {
6588
14
        func = (uintptr_t)zend_jit_assign_cv_to_typed_ref2;
6589
14
      } else {
6590
0
        ZEND_UNREACHABLE();
6591
0
      }
6592
93
      ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(func), ref2, arg2, jit_ZVAL_ADDR(jit, res_addr));
6593
93
    }
6594
380
    if (check_exception) {
6595
290
      zend_jit_check_exception(jit);
6596
290
    }
6597
380
    ir_refs_add(end_inputs, ir_END());
6598
6599
380
    if (!ref_addr) {
6600
377
      ir_IF_FALSE(if_ref);
6601
377
      non_ref_path = ir_END();
6602
377
      ir_IF_FALSE(if_typed);
6603
377
      ref2 = ir_ADD_OFFSET(ref2, offsetof(zend_reference, val));
6604
377
      ir_MERGE_WITH(non_ref_path);
6605
377
      ref = ir_PHI_2(IR_ADDR, ref2, ref);
6606
377
      var_addr = var_use_addr = ZEND_ADDR_REF_ZVAL(ref);
6607
377
    } else {
6608
3
      ir_IF_FALSE(if_typed);
6609
3
    }
6610
380
  }
6611
6612
601
  if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
6613
387
    ir_ref ref, counter, if_not_zero;
6614
6615
387
    if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
6616
387
      if_refcounted = jit_if_REFCOUNTED(jit, var_use_addr);
6617
387
      ir_IF_FALSE(if_refcounted);
6618
387
      ir_END_list(simple_inputs);
6619
387
      ir_IF_TRUE_cold(if_refcounted);
6620
387
    } else if (RC_MAY_BE_1(var_info)) {
6621
0
      done = true;
6622
0
    }
6623
387
    ref = jit_Z_PTR(jit, var_use_addr);
6624
387
    if (RC_MAY_BE_1(var_info)) {
6625
387
      if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, false)) {
6626
0
        return 0;
6627
0
      }
6628
387
      counter = jit_GC_DELREF(jit, ref);
6629
6630
387
      if_not_zero = ir_IF(counter);
6631
387
      ir_IF_FALSE(if_not_zero);
6632
387
      jit_ZVAL_DTOR(jit, ref, var_info, opline);
6633
387
      if (check_exception) {
6634
297
        zend_jit_check_exception(jit);
6635
297
      }
6636
387
      ir_refs_add(end_inputs, ir_END());
6637
387
      ir_IF_TRUE(if_not_zero);
6638
387
      if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) {
6639
387
        ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6640
387
        ir_IF_FALSE(if_may_leak);
6641
387
        if (opline) {
6642
367
          jit_SET_EX_OPLINE(jit, opline);
6643
367
        }
6644
387
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6645
6646
387
        if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6647
0
          ZEND_ASSERT(jit->delay_refs == res_inputs);
6648
0
          ZEND_ASSERT(res_inputs->count > 0);
6649
0
          ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6650
0
        }
6651
387
        if (check_exception && (val_info & MAY_BE_UNDEF)) {
6652
217
          zend_jit_check_exception(jit);
6653
217
        }
6654
387
        ir_refs_add(end_inputs, ir_END());
6655
387
        ir_IF_TRUE(if_may_leak);
6656
387
      }
6657
387
      if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6658
0
        ZEND_ASSERT(jit->delay_refs == res_inputs);
6659
0
        ZEND_ASSERT(res_inputs->count > 0);
6660
0
        ir_refs_add(res_inputs, res_inputs->refs[res_inputs->count - 1]);
6661
0
      }
6662
387
      if (check_exception && (val_info & MAY_BE_UNDEF)) {
6663
217
        zend_jit_check_exception(jit);
6664
217
      }
6665
387
      ir_refs_add(end_inputs, ir_END());
6666
387
    } else /* if (RC_MAY_BE_N(var_info)) */ {
6667
0
      jit_GC_DELREF(jit, ref);
6668
0
      if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) {
6669
0
        ir_ref if_may_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref);
6670
0
        ir_IF_FALSE(if_may_leak);
6671
0
        if (opline) {
6672
0
          jit_SET_EX_OPLINE(jit, opline);
6673
0
        }
6674
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref);
6675
0
        ir_END_list(simple_inputs);
6676
0
        ir_IF_TRUE(if_may_leak);
6677
0
      }
6678
0
      ir_END_list(simple_inputs);
6679
0
    }
6680
387
  }
6681
6682
601
  if (simple_inputs) {
6683
387
    ir_MERGE_list(simple_inputs);
6684
387
  }
6685
6686
601
  if (!done) {
6687
601
    if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, check_exception)) {
6688
0
      return 0;
6689
0
    }
6690
601
    if (end_inputs->count) {
6691
387
      ir_refs_add(end_inputs, ir_END());
6692
387
    }
6693
601
  }
6694
6695
601
  if (end_inputs->count) {
6696
387
    ir_MERGE_N(end_inputs->count, end_inputs->refs);
6697
387
  }
6698
6699
601
  if (Z_MODE(var_addr) == IS_REG || Z_MODE(res_addr) == IS_REG) {
6700
4
    ir_ref phi;
6701
6702
4
    ZEND_ASSERT(jit->delay_refs == res_inputs);
6703
4
    ZEND_ASSERT(end_inputs->count == res_inputs->count || (end_inputs->count == 0 && res_inputs->count == 1));
6704
4
    jit->delay_var = -1;
6705
4
    jit->delay_refs = NULL;
6706
4
    if (res_inputs->count == 1) {
6707
4
      phi = res_inputs->refs[0];
6708
4
    } else {
6709
0
      phi = ir_PHI_N((var_def_info & MAY_BE_LONG & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
6710
0
        res_inputs->count, res_inputs->refs);
6711
0
    }
6712
4
    if (Z_MODE(var_addr) == IS_REG) {
6713
4
      if ((var_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || ref_addr) {
6714
0
        phi = ir_emit2(&jit->ctx, IR_OPT(IR_COPY, jit->ctx.ir_base[phi].type), phi, 1);
6715
0
      }
6716
4
      zend_jit_def_reg(jit, var_addr, phi);
6717
4
      if (real_res_addr) {
6718
4
        if (var_def_info & MAY_BE_LONG) {
6719
4
          jit_set_Z_LVAL(jit, real_res_addr, jit_Z_LVAL(jit, var_addr));
6720
4
        } else {
6721
0
          jit_set_Z_DVAL(jit, real_res_addr, jit_Z_DVAL(jit, var_addr));
6722
0
        }
6723
4
      }
6724
4
    } else {
6725
0
      zend_jit_def_reg(jit, res_addr, phi);
6726
0
    }
6727
4
  }
6728
6729
601
  return 1;
6730
601
}
6731
6732
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)
6733
231
{
6734
231
  if (op1_addr != op1_def_addr) {
6735
0
    if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
6736
0
      return 0;
6737
0
    }
6738
0
    if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
6739
0
      op1_addr = op1_def_addr;
6740
0
    }
6741
0
  }
6742
6743
231
  if (!zend_jit_simple_assign(jit, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, true)) {
6744
0
    return 0;
6745
0
  }
6746
231
  if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6747
0
    return 0;
6748
0
  }
6749
231
  return 1;
6750
231
}
6751
6752
static int zend_jit_assign(zend_jit_ctx  *jit,
6753
                           const zend_op *opline,
6754
                           uint32_t       op1_info,
6755
                           zend_jit_addr  op1_use_addr,
6756
                           uint32_t       op1_def_info,
6757
                           zend_jit_addr  op1_addr,
6758
                           uint32_t       op2_info,
6759
                           zend_jit_addr  op2_addr,
6760
                           zend_jit_addr  op2_def_addr,
6761
                           uint32_t       res_info,
6762
                           zend_jit_addr  res_addr,
6763
                           zend_jit_addr  ref_addr,
6764
                           int            may_throw)
6765
461
{
6766
461
  ZEND_ASSERT(opline->op1_type == IS_CV);
6767
6768
461
  if (op2_addr != op2_def_addr) {
6769
3
    if (!zend_jit_update_regs(jit, opline->op2.var, op2_addr, op2_def_addr, op2_info)) {
6770
0
      return 0;
6771
0
    }
6772
3
    if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) {
6773
1
      op2_addr = op2_def_addr;
6774
1
    }
6775
3
  }
6776
6777
461
  if (Z_MODE(op1_addr) != IS_REG
6778
457
   && Z_MODE(op1_use_addr) == IS_REG
6779
0
   && !Z_LOAD(op1_use_addr)
6780
0
   && !Z_STORE(op1_use_addr)) {
6781
    /* Force type update */
6782
0
    op1_info |= MAY_BE_UNDEF;
6783
0
  }
6784
461
  if (!zend_jit_assign_to_variable(jit, opline, op1_use_addr, op1_addr, op1_info, op1_def_info,
6785
461
      opline->op2_type, op2_addr, op2_info, res_addr, ref_addr, may_throw)) {
6786
0
    return 0;
6787
0
  }
6788
461
  if (Z_MODE(op1_addr) == IS_REG) {
6789
4
    if (Z_STORE(op1_addr)) {
6790
0
      if (!zend_jit_store_var_if_necessary_ex(jit, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) {
6791
0
        return 0;
6792
0
      }
6793
4
    } else if ((op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
6794
0
      && Z_MODE(op1_use_addr) == IS_MEM_ZVAL
6795
0
      && Z_REG(op1_use_addr) == ZREG_FP
6796
0
      && EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)) < jit->current_op_array->last_var) {
6797
      /* We have to update type of CV because it may be captured by exception backtrace or released on RETURN */
6798
0
      if ((op1_def_info & MAY_BE_ANY) == MAY_BE_LONG) {
6799
0
        jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_LONG);
6800
0
        if (JIT_G(current_frame)) {
6801
0
          SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_LONG, 1);
6802
0
        }
6803
0
      } else if ((op1_def_info & MAY_BE_ANY) == MAY_BE_DOUBLE) {
6804
0
        jit_set_Z_TYPE_INFO(jit, op1_use_addr, IS_DOUBLE);
6805
0
        if (JIT_G(current_frame)) {
6806
0
          SET_STACK_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(op1_use_addr)), IS_DOUBLE, 1);
6807
0
        }
6808
0
      } else {
6809
0
        ZEND_UNREACHABLE();
6810
0
      }
6811
0
    }
6812
4
  }
6813
461
  if (opline->result_type != IS_UNUSED) {
6814
120
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
6815
0
      return 0;
6816
0
    }
6817
120
  }
6818
6819
461
  return 1;
6820
461
}
6821
6822
static ir_op zend_jit_cmp_op(const zend_op *opline)
6823
2.28k
{
6824
2.28k
  ir_op op;
6825
6826
2.28k
  switch (opline->opcode) {
6827
102
    case ZEND_IS_EQUAL:
6828
102
    case ZEND_IS_IDENTICAL:
6829
102
    case ZEND_CASE:
6830
102
    case ZEND_CASE_STRICT:
6831
102
      op = IR_EQ;
6832
102
      break;
6833
123
    case ZEND_IS_NOT_EQUAL:
6834
123
    case ZEND_IS_NOT_IDENTICAL:
6835
123
      op = IR_NE;
6836
123
      break;
6837
1.91k
    case ZEND_IS_SMALLER:
6838
1.91k
      op = IR_LT;
6839
1.91k
      break;
6840
148
    case ZEND_IS_SMALLER_OR_EQUAL:
6841
148
      op = IR_LE;
6842
148
      break;
6843
0
    default:
6844
0
      ZEND_UNREACHABLE();
6845
2.28k
  }
6846
2.28k
  return op;
6847
2.28k
}
6848
6849
static ir_ref zend_jit_cmp_long_long(zend_jit_ctx   *jit,
6850
                                     const zend_op  *opline,
6851
                                     zend_ssa_range *op1_range,
6852
                                     zend_jit_addr   op1_addr,
6853
                                     zend_ssa_range *op2_range,
6854
                                     zend_jit_addr   op2_addr,
6855
                                     zend_jit_addr   res_addr,
6856
                                     uint8_t         smart_branch_opcode,
6857
                                     uint32_t        target_label,
6858
                                     uint32_t        target_label2,
6859
                                     const void     *exit_addr,
6860
                                     bool       skip_comparison)
6861
532
{
6862
532
  ir_ref ref;
6863
532
  bool result;
6864
6865
532
  if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) {
6866
7
    if (!smart_branch_opcode ||
6867
4
        smart_branch_opcode == ZEND_JMPZ_EX ||
6868
4
        smart_branch_opcode == ZEND_JMPNZ_EX) {
6869
3
      jit_set_Z_TYPE_INFO(jit, res_addr, result ? IS_TRUE : IS_FALSE);
6870
3
    }
6871
7
    if (smart_branch_opcode && !exit_addr) {
6872
4
      if (smart_branch_opcode == ZEND_JMPZ ||
6873
4
          smart_branch_opcode == ZEND_JMPZ_EX) {
6874
4
        return jit_IF_ex(jit, IR_FALSE, result ? target_label : target_label2);
6875
4
      } else if (smart_branch_opcode == ZEND_JMPNZ ||
6876
0
                 smart_branch_opcode == ZEND_JMPNZ_EX) {
6877
0
        return jit_IF_ex(jit, IR_TRUE, result ? target_label : target_label2);
6878
0
      } else {
6879
0
        ZEND_UNREACHABLE();
6880
0
      }
6881
4
    }
6882
3
    if (opline->opcode != ZEND_IS_IDENTICAL
6883
3
     && opline->opcode != ZEND_IS_NOT_IDENTICAL
6884
3
     && opline->opcode != ZEND_CASE_STRICT) {
6885
3
      return ir_END();
6886
3
    } else {
6887
0
      return IR_NULL; /* success */
6888
0
    }
6889
3
  }
6890
6891
525
  ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_LVAL(jit, op1_addr), jit_Z_LVAL(jit, op2_addr));
6892
6893
525
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6894
440
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6895
440
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6896
440
  }
6897
525
  if (exit_addr) {
6898
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6899
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6900
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6901
0
      } else {
6902
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6903
0
      }
6904
0
    } else {
6905
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6906
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6907
0
      } else {
6908
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6909
0
      }
6910
0
    }
6911
525
  } else if (smart_branch_opcode) {
6912
85
    return jit_IF_ex(jit, ref,
6913
85
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6914
85
  }
6915
6916
440
  if (opline->opcode != ZEND_IS_IDENTICAL
6917
440
   && opline->opcode != ZEND_IS_NOT_IDENTICAL
6918
440
   && opline->opcode != ZEND_CASE_STRICT) {
6919
440
    return ir_END();
6920
440
  } else {
6921
0
    return IR_NULL; /* success */
6922
0
  }
6923
440
}
6924
6925
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)
6926
399
{
6927
399
  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));
6928
6929
399
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6930
334
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6931
334
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6932
334
  }
6933
399
  if (exit_addr) {
6934
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6935
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6936
0
    } else {
6937
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6938
0
    }
6939
399
  } else if (smart_branch_opcode) {
6940
65
    return jit_IF_ex(jit, ref,
6941
65
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6942
65
  }
6943
334
  return ir_END();
6944
399
}
6945
6946
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)
6947
399
{
6948
399
  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)));
6949
6950
399
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6951
360
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6952
360
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6953
360
  }
6954
399
  if (exit_addr) {
6955
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6956
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6957
0
    } else {
6958
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6959
0
    }
6960
399
  } else if (smart_branch_opcode) {
6961
39
    return jit_IF_ex(jit, ref,
6962
39
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6963
39
  }
6964
360
  return ir_END();
6965
399
}
6966
6967
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)
6968
309
{
6969
309
  ir_ref ref = ir_CMP_OP(zend_jit_cmp_op(opline), jit_Z_DVAL(jit, op1_addr), jit_Z_DVAL(jit, op2_addr));
6970
6971
309
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
6972
288
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
6973
288
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
6974
288
  }
6975
309
  if (exit_addr) {
6976
0
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
6977
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6978
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6979
0
      } else {
6980
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6981
0
      }
6982
0
    } else {
6983
0
      if (opline->opcode != ZEND_IS_NOT_IDENTICAL) {
6984
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
6985
0
      } else {
6986
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
6987
0
      }
6988
0
    }
6989
309
  } else if (smart_branch_opcode) {
6990
21
    return jit_IF_ex(jit, ref,
6991
21
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
6992
21
  }
6993
288
  if (opline->opcode != ZEND_IS_IDENTICAL
6994
288
   && opline->opcode != ZEND_IS_NOT_IDENTICAL
6995
288
   && opline->opcode != ZEND_CASE_STRICT) {
6996
288
    return ir_END();
6997
288
  } else {
6998
0
    return IR_NULL; /* success */
6999
0
  }
7000
288
}
7001
7002
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)
7003
653
{
7004
653
  ref = ir_CMP_OP(zend_jit_cmp_op(opline), ref, ir_CONST_I32(0));
7005
7006
653
  if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7007
562
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7008
562
      ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7009
562
  }
7010
653
  if (exit_addr) {
7011
3
    if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7012
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7013
3
    } else {
7014
3
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7015
3
    }
7016
650
  } else if (smart_branch_opcode) {
7017
88
    return jit_IF_ex(jit, ref,
7018
88
      (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7019
88
  }
7020
7021
565
  return ir_END();
7022
653
}
7023
7024
static int zend_jit_cmp(zend_jit_ctx   *jit,
7025
                        const zend_op  *opline,
7026
                        uint32_t        op1_info,
7027
                        zend_ssa_range *op1_range,
7028
                        zend_jit_addr   op1_addr,
7029
                        uint32_t        op2_info,
7030
                        zend_ssa_range *op2_range,
7031
                        zend_jit_addr   op2_addr,
7032
                        zend_jit_addr   res_addr,
7033
                        int             may_throw,
7034
                        uint8_t         smart_branch_opcode,
7035
                        uint32_t        target_label,
7036
                        uint32_t        target_label2,
7037
                        const void     *exit_addr,
7038
                        bool       skip_comparison)
7039
700
{
7040
700
  ir_ref ref = IR_UNUSED;
7041
700
  ir_ref if_op1_long = IR_UNUSED;
7042
700
  ir_ref if_op1_double = IR_UNUSED;
7043
700
  ir_ref if_op2_double = IR_UNUSED;
7044
700
  ir_ref if_op1_long_op2_long = IR_UNUSED;
7045
700
  ir_ref if_op1_long_op2_double = IR_UNUSED;
7046
700
  ir_ref if_op1_double_op2_double = IR_UNUSED;
7047
700
  ir_ref if_op1_double_op2_long = IR_UNUSED;
7048
700
  ir_ref slow_inputs = IR_UNUSED;
7049
700
  bool same_ops = zend_jit_same_addr(op1_addr, op2_addr);
7050
700
  bool has_slow =
7051
700
    (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7052
596
    (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) &&
7053
563
    ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7054
164
     (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))));
7055
700
  ir_refs *end_inputs;
7056
7057
700
  ir_refs_init(end_inputs, 8);
7058
7059
700
  if (Z_MODE(op1_addr) == IS_REG) {
7060
7
    if (!has_concrete_type(op2_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op1_addr)].ref == IR_NULL) {
7061
      /* Force load */
7062
0
      zend_jit_use_reg(jit, op1_addr);
7063
0
    }
7064
693
  } else if (Z_MODE(op2_addr) == IS_REG) {
7065
10
    if (!has_concrete_type(op1_info & MAY_BE_ANY) && jit->ra[Z_SSA_VAR(op2_addr)].ref == IR_NULL) {
7066
      /* Force load */
7067
0
      zend_jit_use_reg(jit, op2_addr);
7068
0
    }
7069
10
  }
7070
7071
700
  if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) {
7072
532
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
7073
387
      if_op1_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7074
387
      ir_IF_TRUE(if_op1_long);
7075
387
    }
7076
532
    if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) {
7077
385
      if_op1_long_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7078
385
      ir_IF_FALSE_cold(if_op1_long_op2_long);
7079
385
      if (op2_info & MAY_BE_DOUBLE) {
7080
385
        if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7081
385
          if_op1_long_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7082
385
          ir_IF_FALSE_cold(if_op1_long_op2_double);
7083
385
          ir_END_list(slow_inputs);
7084
385
          ir_IF_TRUE(if_op1_long_op2_double);
7085
385
        }
7086
385
        ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7087
385
        if (!ref) {
7088
0
          return 0;
7089
0
        }
7090
385
        ir_refs_add(end_inputs, ref);
7091
385
      } else {
7092
0
        ir_END_list(slow_inputs);
7093
0
      }
7094
385
      ir_IF_TRUE(if_op1_long_op2_long);
7095
385
    }
7096
532
    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);
7097
532
    if (!ref) {
7098
0
      return 0;
7099
0
    }
7100
532
    ir_refs_add(end_inputs, ref);
7101
7102
532
    if (if_op1_long) {
7103
387
      ir_IF_FALSE_cold(if_op1_long);
7104
387
    }
7105
532
    if (op1_info & MAY_BE_DOUBLE) {
7106
387
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7107
387
        if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7108
387
        ir_IF_FALSE_cold(if_op1_double);
7109
387
        ir_END_list(slow_inputs);
7110
387
        ir_IF_TRUE(if_op1_double);
7111
387
      }
7112
387
      if (op2_info & MAY_BE_DOUBLE) {
7113
282
        if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7114
280
          if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7115
280
          ir_IF_TRUE(if_op1_double_op2_double);
7116
280
        }
7117
282
        ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7118
282
        if (!ref) {
7119
0
          return 0;
7120
0
        }
7121
282
        ir_refs_add(end_inputs, ref);
7122
282
        if (if_op1_double_op2_double) {
7123
280
          ir_IF_FALSE_cold(if_op1_double_op2_double);
7124
280
        }
7125
282
      }
7126
387
      if (!same_ops) {
7127
385
        if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) {
7128
280
          if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7129
280
          ir_IF_FALSE_cold(if_op1_double_op2_long);
7130
280
          ir_END_list(slow_inputs);
7131
280
          ir_IF_TRUE(if_op1_double_op2_long);
7132
280
        }
7133
385
        ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7134
385
        if (!ref) {
7135
0
          return 0;
7136
0
        }
7137
385
        ir_refs_add(end_inputs, ref);
7138
385
      } else if (if_op1_double_op2_double) {
7139
0
        ir_END_list(slow_inputs);
7140
0
      }
7141
387
    } else if (if_op1_long) {
7142
0
      ir_END_list(slow_inputs);
7143
0
    }
7144
532
  } else if ((op1_info & MAY_BE_DOUBLE) &&
7145
53
             !(op1_info & MAY_BE_LONG) &&
7146
17
             (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7147
17
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7148
0
      if_op1_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7149
0
      ir_IF_FALSE_cold(if_op1_double);
7150
0
      ir_END_list(slow_inputs);
7151
0
      ir_IF_TRUE(if_op1_double);
7152
0
    }
7153
17
    if (op2_info & MAY_BE_DOUBLE) {
7154
15
      if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7155
12
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7156
12
        ir_IF_TRUE(if_op1_double_op2_double);
7157
12
      }
7158
15
      ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7159
15
      if (!ref) {
7160
0
        return 0;
7161
0
      }
7162
15
      ir_refs_add(end_inputs, ref);
7163
15
      if (if_op1_double_op2_double) {
7164
12
        ir_IF_FALSE_cold(if_op1_double_op2_double);
7165
12
      }
7166
15
    }
7167
17
    if (!same_ops && (op2_info & MAY_BE_LONG)) {
7168
14
      if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7169
12
        if_op1_double_op2_long = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
7170
12
        ir_IF_FALSE_cold(if_op1_double_op2_long);
7171
12
        ir_END_list(slow_inputs);
7172
12
        ir_IF_TRUE(if_op1_double_op2_long);
7173
12
      }
7174
14
      ref = zend_jit_cmp_double_long(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7175
14
      if (!ref) {
7176
0
        return 0;
7177
0
      }
7178
14
      ir_refs_add(end_inputs, ref);
7179
14
    } else if (if_op1_double_op2_double) {
7180
0
      ir_END_list(slow_inputs);
7181
0
    }
7182
151
  } else if ((op2_info & MAY_BE_DOUBLE) &&
7183
29
             !(op2_info & MAY_BE_LONG) &&
7184
17
             (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
7185
14
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) {
7186
0
      if_op2_double = jit_if_Z_TYPE(jit, op2_addr, IS_DOUBLE);
7187
0
      ir_IF_FALSE_cold(if_op2_double);
7188
0
      ir_END_list(slow_inputs);
7189
0
      ir_IF_TRUE(if_op2_double);
7190
0
    }
7191
14
    if (op1_info & MAY_BE_DOUBLE) {
7192
12
      if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) {
7193
12
        if_op1_double_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_DOUBLE);
7194
12
        ir_IF_TRUE(if_op1_double_op2_double);
7195
12
      }
7196
12
      ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7197
12
      if (!ref) {
7198
0
        return 0;
7199
0
      }
7200
12
      ir_refs_add(end_inputs, ref);
7201
12
      if (if_op1_double_op2_double) {
7202
12
        ir_IF_FALSE_cold(if_op1_double_op2_double);
7203
12
      }
7204
12
    }
7205
14
    if (!same_ops && (op1_info & MAY_BE_LONG)) {
7206
14
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) {
7207
12
        if_op1_long_op2_double = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
7208
12
        ir_IF_FALSE_cold(if_op1_long_op2_double);
7209
12
        ir_END_list(slow_inputs);
7210
12
        ir_IF_TRUE(if_op1_long_op2_double);
7211
12
      }
7212
14
      ref = zend_jit_cmp_long_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7213
14
      if (!ref) {
7214
0
        return 0;
7215
0
      }
7216
14
      ir_refs_add(end_inputs, ref);
7217
14
    } else if (if_op1_double_op2_double) {
7218
0
      ir_END_list(slow_inputs);
7219
0
    }
7220
14
  }
7221
7222
700
  if (has_slow ||
7223
184
      (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) ||
7224
653
      (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) {
7225
653
      ir_ref op1, op2, ref;
7226
7227
653
    if (slow_inputs) {
7228
516
      ir_MERGE_list(slow_inputs);
7229
516
    }
7230
653
    jit_SET_EX_OPLINE(jit, opline);
7231
7232
653
    if (Z_MODE(op1_addr) == IS_REG) {
7233
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7234
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7235
0
        return 0;
7236
0
      }
7237
0
      op1_addr = real_addr;
7238
0
    }
7239
653
    if (Z_MODE(op2_addr) == IS_REG) {
7240
2
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7241
2
      if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7242
0
        return 0;
7243
0
      }
7244
2
      op2_addr = real_addr;
7245
2
    }
7246
7247
653
    op1 = jit_ZVAL_ADDR(jit, op1_addr);
7248
653
    if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7249
152
      op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, NULL, false);
7250
152
    }
7251
653
    op2 = jit_ZVAL_ADDR(jit, op2_addr);
7252
653
    if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7253
95
      op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, NULL, false);
7254
95
    }
7255
653
    ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_compare), op1, op2);
7256
653
    if (opline->opcode != ZEND_CASE) {
7257
653
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7258
653
    }
7259
653
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7260
653
    if (may_throw) {
7261
626
      zend_jit_check_exception_undef_result(jit, opline);
7262
626
    }
7263
7264
653
    ref = zend_jit_cmp_slow(jit, ref, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7265
653
    if (!ref) {
7266
0
      return 0;
7267
0
    }
7268
653
    ir_refs_add(end_inputs, ref);
7269
653
  }
7270
7271
700
  if (end_inputs->count) {
7272
700
    uint32_t n = end_inputs->count;
7273
7274
700
    if (smart_branch_opcode && !exit_addr) {
7275
92
      zend_basic_block *bb;
7276
92
      ir_ref ref;
7277
92
      uint32_t label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7278
77
        target_label2 : target_label;
7279
92
      uint32_t label2 = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7280
77
        target_label : target_label2;
7281
7282
92
      ZEND_ASSERT(jit->b >= 0);
7283
92
      bb = &jit->ssa->cfg.blocks[jit->b];
7284
92
      ZEND_ASSERT(bb->successors_count == 2);
7285
7286
92
      if (UNEXPECTED(bb->successors[0] == bb->successors[1])) {
7287
0
        ir_ref merge_inputs = IR_UNUSED;
7288
7289
0
        while (n) {
7290
0
          n--;
7291
0
          ir_IF_TRUE(end_inputs->refs[n]);
7292
0
          ir_END_list(merge_inputs);
7293
0
          ir_IF_FALSE(end_inputs->refs[n]);
7294
0
          ir_END_list(merge_inputs);
7295
0
        }
7296
0
        ir_MERGE_list(merge_inputs);
7297
0
        _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7298
92
      } else if (n == 1) {
7299
4
        ref = end_inputs->refs[0];
7300
4
        _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7301
4
        _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7302
88
      } else {
7303
88
        ir_ref true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7304
7305
386
        while (n) {
7306
298
          n--;
7307
298
          jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label);
7308
298
          ir_END_list(true_inputs);
7309
298
          jit_IF_TRUE_FALSE_ex(jit, end_inputs->refs[n], label2);
7310
298
          ir_END_list(false_inputs);
7311
298
        }
7312
88
        ir_MERGE_list(true_inputs);
7313
88
        _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7314
88
        ir_MERGE_list(false_inputs);
7315
88
        _zend_jit_add_predecessor_ref(jit, label2, jit->b, ir_END());
7316
88
      }
7317
92
      jit->b = -1;
7318
608
    } else {
7319
608
      ir_MERGE_N(n, end_inputs->refs);
7320
608
    }
7321
700
  } else if (smart_branch_opcode && !exit_addr) {
7322
    /* dead code */
7323
0
    _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
7324
0
    jit->b = -1;
7325
0
  }
7326
7327
700
  return 1;
7328
700
}
7329
7330
static bool zend_jit_is_const_empty_array(zend_jit_addr addr)
7331
118
{
7332
118
  return Z_MODE(addr) == IS_CONST_ZVAL
7333
21
    && Z_TYPE_P(Z_ZV(addr)) == IS_ARRAY
7334
2
    && zend_hash_num_elements(Z_ARRVAL_P(Z_ZV(addr))) == 0;
7335
118
}
7336
7337
static int zend_jit_identical(zend_jit_ctx   *jit,
7338
                              const zend_op  *opline,
7339
                              uint32_t        op1_info,
7340
                              zend_ssa_range *op1_range,
7341
                              zend_jit_addr   op1_addr,
7342
                              uint32_t        op2_info,
7343
                              zend_ssa_range *op2_range,
7344
                              zend_jit_addr   op2_addr,
7345
                              zend_jit_addr   res_addr,
7346
                              int             may_throw,
7347
                              uint8_t         smart_branch_opcode,
7348
                              uint32_t        target_label,
7349
                              uint32_t        target_label2,
7350
                              const void     *exit_addr,
7351
                              bool       skip_comparison)
7352
62
{
7353
62
  bool always_false = false, always_true = false;
7354
62
  ir_ref ref = IR_UNUSED;
7355
7356
62
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
7357
9
    ir_ref op1 = jit_ZVAL_ADDR(jit, op1_addr);
7358
9
    op1 = zend_jit_zval_check_undef(jit, op1, opline->op1.var, opline, false);
7359
9
    op1_info |= MAY_BE_NULL;
7360
9
    op1_addr = ZEND_ADDR_REF_ZVAL(op1);
7361
9
  }
7362
62
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
7363
4
    ir_ref op2 = jit_ZVAL_ADDR(jit, op2_addr);
7364
4
    op2 = zend_jit_zval_check_undef(jit, op2, opline->op2.var, opline, false);
7365
4
    op2_info |= MAY_BE_NULL;
7366
4
    op2_addr = ZEND_ADDR_REF_ZVAL(op2);
7367
4
  }
7368
7369
62
  if ((op1_info & op2_info & MAY_BE_ANY) == 0) {
7370
1
    always_false = true;
7371
61
  } else if (has_concrete_type(op1_info)
7372
1
   && has_concrete_type(op2_info)
7373
0
   && concrete_type(op1_info) == concrete_type(op2_info)
7374
0
   && concrete_type(op1_info) <= IS_TRUE) {
7375
0
    always_true = true;
7376
61
  } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) {
7377
0
    if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) {
7378
0
      always_true = true;
7379
0
    } else {
7380
0
      always_false = true;
7381
0
    }
7382
0
  }
7383
7384
62
  if (always_true) {
7385
0
    if (opline->opcode != ZEND_CASE_STRICT) {
7386
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7387
0
    }
7388
0
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7389
0
    if (!smart_branch_opcode
7390
0
     || smart_branch_opcode == ZEND_JMPZ_EX
7391
0
     || smart_branch_opcode == ZEND_JMPNZ_EX) {
7392
0
      jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE);
7393
0
    }
7394
0
    if (may_throw) {
7395
0
      zend_jit_check_exception(jit);
7396
0
    }
7397
0
    if (exit_addr) {
7398
0
      if (smart_branch_opcode == ZEND_JMPNZ || smart_branch_opcode == ZEND_JMPNZ_EX) {
7399
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7400
0
      }
7401
0
    } else if (smart_branch_opcode) {
7402
0
      uint32_t label;
7403
7404
0
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7405
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7406
0
          target_label : target_label2;
7407
0
      } else {
7408
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7409
0
          target_label2 : target_label;
7410
0
      }
7411
0
      _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7412
0
      jit->b = -1;
7413
0
    }
7414
0
    return 1;
7415
62
  } else if (always_false) {
7416
1
    if (opline->opcode != ZEND_CASE_STRICT) {
7417
1
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7418
1
    }
7419
1
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
7420
1
    if (!smart_branch_opcode
7421
1
     || smart_branch_opcode == ZEND_JMPZ_EX
7422
1
     || smart_branch_opcode == ZEND_JMPNZ_EX) {
7423
0
      jit_set_Z_TYPE_INFO(jit, res_addr, opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE);
7424
0
    }
7425
1
    if (may_throw) {
7426
1
      zend_jit_check_exception(jit);
7427
1
    }
7428
1
    if (exit_addr) {
7429
0
      if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7430
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7431
0
      }
7432
1
    } else if (smart_branch_opcode) {
7433
1
      uint32_t label;
7434
7435
1
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7436
0
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7437
0
          target_label2 : target_label;
7438
1
      } else {
7439
1
        label = (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ?
7440
1
          target_label : target_label2;
7441
1
      }
7442
1
      _zend_jit_add_predecessor_ref(jit, label, jit->b, ir_END());
7443
1
      jit->b = -1;
7444
1
    }
7445
1
    return 1;
7446
1
  }
7447
7448
61
  if ((opline->op1_type & (IS_CV|IS_VAR)) && (op1_info & MAY_BE_REF)) {
7449
4
    ref = jit_ZVAL_ADDR(jit, op1_addr);
7450
4
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7451
4
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7452
4
  }
7453
61
  if ((opline->op2_type & (IS_CV|IS_VAR)) && (op2_info & MAY_BE_REF)) {
7454
1
    ref = jit_ZVAL_ADDR(jit, op2_addr);
7455
1
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7456
1
    op2_addr = ZEND_ADDR_REF_ZVAL(ref);
7457
1
  }
7458
7459
61
  if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG &&
7460
0
      (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) {
7461
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);
7462
0
    if (!ref) {
7463
0
      return 0;
7464
0
    }
7465
61
  } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE &&
7466
0
             (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
7467
0
    ref = zend_jit_cmp_double_double(jit, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr);
7468
0
    if (!ref) {
7469
0
      return 0;
7470
0
    }
7471
61
  } else {
7472
61
    if (opline->op1_type != IS_CONST) {
7473
61
      if (Z_MODE(op1_addr) == IS_REG) {
7474
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7475
0
        if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7476
0
          return 0;
7477
0
        }
7478
0
        op1_addr = real_addr;
7479
0
      }
7480
61
    }
7481
61
    if (opline->op2_type != IS_CONST) {
7482
38
      if (Z_MODE(op2_addr) == IS_REG) {
7483
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7484
0
        if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7485
0
          return 0;
7486
0
        }
7487
0
      }
7488
38
    }
7489
7490
61
    if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) {
7491
0
      zval *val = Z_ZV(op1_addr);
7492
7493
0
      ref = ir_EQ(jit_Z_TYPE(jit, op2_addr), ir_CONST_U8(Z_TYPE_P(val)));
7494
61
    } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) {
7495
2
      zval *val = Z_ZV(op2_addr);
7496
7497
2
      ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(Z_TYPE_P(val)));
7498
59
    } else if (zend_jit_is_const_empty_array(op1_addr) && (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
7499
      // JIT: zend_hash_num_elements(Z_ARRVAL_P(op2)) == 0
7500
0
      ref = ir_EQ(ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, op2_addr), offsetof(HashTable, nNumOfElements))),
7501
0
        ir_CONST_U32(0));
7502
59
    } else if (zend_jit_is_const_empty_array(op2_addr) && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
7503
      // JIT: zend_hash_num_elements(Z_ARRVAL_P(op1)) == 0
7504
0
      ref = ir_EQ(ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(HashTable, nNumOfElements))),
7505
0
        ir_CONST_U32(0));
7506
59
    } else {
7507
59
      if (Z_MODE(op1_addr) == IS_REG) {
7508
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
7509
0
        if (!zend_jit_spill_store_inv(jit, op1_addr, real_addr, op1_info)) {
7510
0
          return 0;
7511
0
        }
7512
0
        op1_addr = real_addr;
7513
0
      }
7514
59
      if (Z_MODE(op2_addr) == IS_REG) {
7515
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
7516
0
        if (!zend_jit_spill_store_inv(jit, op2_addr, real_addr, op2_info)) {
7517
0
          return 0;
7518
0
        }
7519
0
        op2_addr = real_addr;
7520
0
      }
7521
59
      if (may_throw) {
7522
45
        jit_SET_EX_OPLINE(jit, opline);
7523
45
      }
7524
7525
59
      ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_is_identical),
7526
59
        jit_ZVAL_ADDR(jit, op1_addr),
7527
59
        jit_ZVAL_ADDR(jit, op2_addr));
7528
59
    }
7529
7530
61
    if (!smart_branch_opcode || smart_branch_opcode == ZEND_JMPNZ_EX || smart_branch_opcode == ZEND_JMPZ_EX) {
7531
13
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7532
5
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7533
5
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7534
8
      } else {
7535
8
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7536
8
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7537
8
      }
7538
13
    }
7539
61
    if (opline->opcode != ZEND_CASE_STRICT) {
7540
19
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7541
19
    }
7542
61
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
7543
61
    if (may_throw) {
7544
45
      zend_jit_check_exception_undef_result(jit, opline);
7545
45
    }
7546
61
    if (exit_addr) {
7547
0
      if (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) {
7548
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7549
0
      } else {
7550
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7551
0
      }
7552
61
    } else if (smart_branch_opcode) {
7553
48
      if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
7554
        /* swap labels */
7555
0
        uint32_t tmp = target_label;
7556
0
        target_label = target_label2;
7557
0
        target_label2 = tmp;
7558
0
      }
7559
48
      ref = jit_IF_ex(jit, ref,
7560
48
        (smart_branch_opcode == ZEND_JMPZ || smart_branch_opcode == ZEND_JMPZ_EX) ? target_label2 : target_label);
7561
48
    }
7562
61
  }
7563
7564
61
  if (smart_branch_opcode && !exit_addr) {
7565
48
    zend_basic_block *bb;
7566
7567
48
    ZEND_ASSERT(jit->b >= 0);
7568
48
    bb = &jit->ssa->cfg.blocks[jit->b];
7569
48
    ZEND_ASSERT(bb->successors_count == 2);
7570
7571
48
    if (bb->successors_count == 2 && bb->successors[0] == bb->successors[1]) {
7572
0
      ir_IF_TRUE(ref);
7573
0
      ir_MERGE_WITH_EMPTY_FALSE(ref);
7574
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
7575
48
    } else {
7576
48
      ZEND_ASSERT(bb->successors_count == 2);
7577
48
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
7578
48
      _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
7579
48
    }
7580
48
    jit->b = -1;
7581
48
  }
7582
7583
61
  return 1;
7584
61
}
7585
7586
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, bool warn_undef)
7587
433
{
7588
433
  uint32_t true_label = -1;
7589
433
  uint32_t false_label = -1;
7590
433
  bool set_bool = false;
7591
433
  bool set_bool_not = false;
7592
433
  bool always_true = false, always_false = false;
7593
433
  ir_ref ref, end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7594
433
  ir_type type = IR_UNUSED;
7595
7596
433
  if (branch_opcode == ZEND_BOOL) {
7597
32
    set_bool = true;
7598
401
  } else if (branch_opcode == ZEND_BOOL_NOT) {
7599
190
    set_bool = true;
7600
190
    set_bool_not = true;
7601
211
  } else if (branch_opcode == ZEND_JMPZ) {
7602
70
    true_label = target_label2;
7603
70
    false_label = target_label;
7604
141
  } else if (branch_opcode == ZEND_JMPNZ) {
7605
85
    true_label = target_label;
7606
85
    false_label = target_label2;
7607
85
  } else if (branch_opcode == ZEND_JMPZ_EX) {
7608
48
    set_bool = true;
7609
48
    true_label = target_label2;
7610
48
    false_label = target_label;
7611
48
  } else if (branch_opcode == ZEND_JMPNZ_EX) {
7612
8
    set_bool = true;
7613
8
    true_label = target_label;
7614
8
    false_label = target_label2;
7615
8
  } else {
7616
0
    ZEND_UNREACHABLE();
7617
0
  }
7618
7619
433
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) {
7620
47
    ref = jit_ZVAL_ADDR(jit, op1_addr);
7621
47
    ref = jit_ZVAL_DEREF_ref(jit, ref);
7622
47
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
7623
47
  }
7624
7625
433
  if (Z_MODE(op1_addr) == IS_CONST_ZVAL
7626
    /* NAN Value must cause a warning to be emitted */
7627
47
    && (Z_TYPE_P(Z_ZV(op1_addr)) != IS_DOUBLE || !zend_isnan(Z_DVAL_P(Z_ZV(op1_addr))))) {
7628
45
    if (zend_is_true(Z_ZV(op1_addr))) {
7629
37
      always_true = true;
7630
37
    } else {
7631
8
      always_false = true;
7632
8
    }
7633
388
  } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7634
352
    if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) {
7635
2
      always_true = true;
7636
350
    } else if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) {
7637
30
      if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF) && warn_undef) {
7638
22
        ref = jit_ZVAL_ADDR(jit, op1_addr);
7639
22
        zend_jit_zval_check_undef(jit, ref, opline->op1.var, opline, false);
7640
22
      }
7641
30
      always_false = true;
7642
30
    }
7643
352
  }
7644
7645
433
  if (always_true) {
7646
39
    if (set_bool) {
7647
39
      jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7648
39
    }
7649
39
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7650
39
    if (may_throw) {
7651
37
      zend_jit_check_exception(jit);
7652
37
    }
7653
39
    if (true_label != (uint32_t)-1) {
7654
0
      ZEND_ASSERT(exit_addr == NULL);
7655
0
      _zend_jit_add_predecessor_ref(jit, true_label, jit->b, ir_END());
7656
0
      jit->b = -1;
7657
0
    }
7658
39
    return 1;
7659
394
  } else if (always_false) {
7660
38
    if (set_bool) {
7661
27
      jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7662
27
    }
7663
38
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
7664
38
    if (may_throw) {
7665
29
      zend_jit_check_exception(jit);
7666
29
    }
7667
38
    if (false_label != (uint32_t)-1) {
7668
3
      ZEND_ASSERT(exit_addr == NULL);
7669
3
      _zend_jit_add_predecessor_ref(jit, false_label, jit->b, ir_END());
7670
3
      jit->b = -1;
7671
3
    }
7672
38
    return 1;
7673
38
  }
7674
7675
356
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) {
7676
320
    type = jit_Z_TYPE(jit, op1_addr);
7677
320
    if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) {
7678
320
      ir_ref if_type = ir_IF(ir_LT(type, ir_CONST_U8(IS_TRUE)));
7679
7680
320
      ir_IF_TRUE_cold(if_type);
7681
7682
320
      if ((op1_info & MAY_BE_UNDEF) && warn_undef) {
7683
318
        zend_jit_type_check_undef(jit,
7684
318
          type,
7685
318
          opline->op1.var,
7686
318
          opline, true, false, true);
7687
318
      }
7688
320
      if (set_bool) {
7689
190
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7690
190
      }
7691
320
      if (exit_addr) {
7692
0
        if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_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
320
      } else if (false_label != (uint32_t)-1) {
7698
180
        ir_END_list(false_inputs);
7699
180
      } else {
7700
140
        ir_END_list(end_inputs);
7701
140
      }
7702
320
      ir_IF_FALSE(if_type);
7703
320
    }
7704
7705
320
    if (op1_info & MAY_BE_TRUE) {
7706
320
      ir_ref if_type = IR_UNUSED;
7707
7708
320
      if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) {
7709
320
        if_type = ir_IF(ir_EQ(type, ir_CONST_U8(IS_TRUE)));
7710
7711
320
        ir_IF_TRUE(if_type);
7712
320
      }
7713
320
      if (set_bool) {
7714
190
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7715
190
      }
7716
320
      if (exit_addr) {
7717
0
        if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7718
0
          ir_END_list(end_inputs);
7719
0
        } else {
7720
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7721
0
        }
7722
320
      } else if (true_label != (uint32_t)-1) {
7723
180
        ir_END_list(true_inputs);
7724
180
      } else {
7725
140
        ir_END_list(end_inputs);
7726
140
      }
7727
320
      if (if_type) {
7728
320
        ir_IF_FALSE(if_type);
7729
320
      }
7730
320
    }
7731
320
  }
7732
7733
356
  if (op1_info & MAY_BE_LONG) {
7734
344
    ir_ref if_long = IR_UNUSED;
7735
344
    ir_ref ref;
7736
7737
344
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) {
7738
320
      if (!type) {
7739
0
        type = jit_Z_TYPE(jit, op1_addr);
7740
0
      }
7741
320
      if_long = ir_IF(ir_EQ(type, ir_CONST_U8(IS_LONG)));
7742
320
      ir_IF_TRUE(if_long);
7743
320
    }
7744
344
    ref = jit_Z_LVAL(jit, op1_addr);
7745
344
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7746
151
      ref = ir_NE(ref, ir_CONST_LONG(0));
7747
151
      if (set_bool_not) {
7748
123
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7749
123
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7750
123
      } else {
7751
28
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7752
28
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7753
28
      }
7754
151
      ir_END_list(end_inputs);
7755
193
    } else if (exit_addr) {
7756
13
      if (set_bool) {
7757
2
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7758
2
          ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, ir_CONST_LONG(0))), ir_CONST_U32(IS_FALSE)));
7759
2
      }
7760
13
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7761
2
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7762
11
      } else {
7763
11
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7764
11
      }
7765
13
      ir_END_list(end_inputs);
7766
180
    } else {
7767
180
      ir_ref if_val = ir_IF(ref);
7768
180
      ir_IF_TRUE(if_val);
7769
180
      if (set_bool) {
7770
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7771
50
      }
7772
180
      ir_END_list(true_inputs);
7773
180
      ir_IF_FALSE(if_val);
7774
180
      if (set_bool) {
7775
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7776
50
      }
7777
180
      ir_END_list(false_inputs);
7778
180
    }
7779
344
    if (if_long) {
7780
320
      ir_IF_FALSE(if_long);
7781
320
    }
7782
344
  }
7783
7784
356
  if (op1_info & MAY_BE_DOUBLE) {
7785
322
    ir_ref if_double = IR_UNUSED;
7786
322
    ir_ref ref;
7787
7788
322
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7789
320
      if (!type) {
7790
0
        type = jit_Z_TYPE(jit, op1_addr);
7791
0
      }
7792
320
      if_double = ir_IF(ir_EQ(type, ir_CONST_U8(IS_DOUBLE)));
7793
320
      ir_IF_TRUE(if_double);
7794
320
    }
7795
7796
322
    ir_ref dval = jit_Z_DVAL(jit, op1_addr);
7797
322
    ir_ref is_nan = ir_NE(dval, dval);
7798
322
    ir_ref if_val = ir_IF(is_nan);
7799
322
    ir_IF_TRUE_cold(if_val);
7800
322
    jit_SET_EX_OPLINE(jit, opline);
7801
322
    ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_nan_coerced_to_type_warning));
7802
    /* The warning may be turned into an exception by an error handler */
7803
322
    zend_jit_check_exception_undef_result(jit, opline);
7804
322
    ir_MERGE_WITH_EMPTY_FALSE(if_val);
7805
7806
322
    ref = ir_NE(dval, ir_CONST_DOUBLE(0.0));
7807
322
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7808
142
      if (set_bool_not) {
7809
115
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7810
115
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7811
115
      } else {
7812
27
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7813
27
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7814
27
      }
7815
142
      ir_END_list(end_inputs);
7816
180
    } else if (exit_addr) {
7817
0
        if (set_bool) {
7818
0
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7819
0
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7820
0
        }
7821
0
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7822
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7823
0
      } else {
7824
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7825
0
      }
7826
0
      ir_END_list(end_inputs);
7827
180
    } else {
7828
180
      ir_ref if_val = ir_IF(ref);
7829
180
      ir_IF_TRUE(if_val);
7830
180
      if (set_bool) {
7831
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7832
50
      }
7833
180
      ir_END_list(true_inputs);
7834
180
      ir_IF_FALSE(if_val);
7835
180
      if (set_bool) {
7836
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7837
50
      }
7838
180
      ir_END_list(false_inputs);
7839
180
    }
7840
322
    if (if_double) {
7841
320
      ir_IF_FALSE(if_double);
7842
320
    }
7843
322
  }
7844
7845
356
  if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) {
7846
328
    if ((op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))) == MAY_BE_ARRAY) {
7847
      /* CV deref handled above. These opcodes only take CONST|TMP|CV operands, and TMPs never hold references. */
7848
3
      ZEND_ASSERT(opline->op1_type == IS_CV || !(op1_info & MAY_BE_REF));
7849
      // JIT: zend_hash_num_elements(Z_ARRVAL_P(op1)) != 0
7850
3
      ref = ir_NE(ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(HashTable, nNumOfElements))),
7851
3
        ir_CONST_U32(0));
7852
3
      if (opline->op1_type == IS_CV) {
7853
        /* The check above can't throw, and a CV isn't freed. */
7854
0
        may_throw = 0;
7855
0
      }
7856
325
    } else {
7857
325
      jit_SET_EX_OPLINE(jit, opline);
7858
325
      ref = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_is_true), jit_ZVAL_ADDR(jit, op1_addr));
7859
325
    }
7860
328
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
7861
328
    if (may_throw) {
7862
322
      zend_jit_check_exception_undef_result(jit, opline);
7863
322
    }
7864
328
    if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT) {
7865
146
      if (set_bool_not) {
7866
121
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7867
121
          ir_SUB_U32(ir_CONST_U32(IS_TRUE), ir_ZEXT_U32(ref)));
7868
121
      } else {
7869
25
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7870
25
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7871
25
      }
7872
146
      if (end_inputs) {
7873
140
        ir_END_list(end_inputs);
7874
140
      }
7875
182
    } else if (exit_addr) {
7876
2
      if (set_bool) {
7877
1
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
7878
1
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
7879
1
      }
7880
2
      if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) {
7881
1
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
7882
1
      } else {
7883
1
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
7884
1
      }
7885
2
      if (end_inputs) {
7886
0
        ir_END_list(end_inputs);
7887
0
      }
7888
180
    } else {
7889
180
      ir_ref if_val = ir_IF(ref);
7890
180
      ir_IF_TRUE(if_val);
7891
180
      if (set_bool) {
7892
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_FALSE : IS_TRUE);
7893
50
      }
7894
180
      ir_END_list(true_inputs);
7895
180
      ir_IF_FALSE(if_val);
7896
180
      if (set_bool) {
7897
50
        jit_set_Z_TYPE_INFO(jit, res_addr, set_bool_not ? IS_TRUE : IS_FALSE);
7898
50
      }
7899
180
      ir_END_list(false_inputs);
7900
180
    }
7901
328
  }
7902
7903
356
  if (branch_opcode == ZEND_BOOL || branch_opcode == ZEND_BOOL_NOT || exit_addr) {
7904
174
    if (end_inputs) {
7905
166
      ir_MERGE_list(end_inputs);
7906
166
    }
7907
182
  } else {
7908
182
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
7909
182
  }
7910
7911
356
  return 1;
7912
356
}
7913
7914
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)
7915
4
{
7916
4
  uint32_t defined_label = (uint32_t)-1;
7917
4
  uint32_t undefined_label = (uint32_t)-1;
7918
4
  zval *zv = RT_CONSTANT(opline, opline->op1);
7919
4
  zend_jit_addr res_addr = 0;
7920
4
  ir_ref ref, ref2, if_set, if_zero, if_set2;
7921
4
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
7922
7923
4
  if (smart_branch_opcode && !exit_addr) {
7924
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7925
0
      defined_label = target_label2;
7926
0
      undefined_label = target_label;
7927
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
7928
0
      defined_label = target_label;
7929
0
      undefined_label = target_label2;
7930
0
    } else {
7931
0
      ZEND_UNREACHABLE();
7932
0
    }
7933
4
  } else {
7934
4
    res_addr = RES_ADDR();
7935
4
  }
7936
7937
  // if (CACHED_PTR(opline->extended_value)) {
7938
4
  ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
7939
7940
4
  if_set = ir_IF(ref);
7941
7942
4
  ir_IF_FALSE_cold(if_set);
7943
4
  if_zero = ir_END();
7944
7945
4
  ir_IF_TRUE(if_set);
7946
4
  if_set2 = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
7947
4
  ir_IF_FALSE(if_set2);
7948
7949
4
  if (exit_addr) {
7950
0
    if (smart_branch_opcode == ZEND_JMPNZ) {
7951
0
      jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7952
0
    } else {
7953
0
      ir_END_list(end_inputs);
7954
0
    }
7955
4
  } else if (smart_branch_opcode) {
7956
0
    ir_END_list(true_inputs);
7957
4
  } else {
7958
4
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
7959
4
    ir_END_list(end_inputs);
7960
4
  }
7961
7962
4
  ir_IF_TRUE_cold(if_set2);
7963
7964
4
  ref2 = jit_EG(zend_constants);
7965
4
  ref = ir_SHR_A(ref, ir_CONST_ADDR(1));
7966
4
  if (sizeof(void*) == 8) {
7967
4
    ref = ir_TRUNC_U32(ref);
7968
4
  }
7969
4
  ref2 = ir_EQ(ref, ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(ref2), offsetof(HashTable, nNumOfElements))));
7970
4
  ref2 = ir_IF(ref2);
7971
4
  ir_IF_TRUE(ref2);
7972
7973
4
  if (exit_addr) {
7974
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7975
0
      jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
7976
0
    } else {
7977
0
      ir_END_list(end_inputs);
7978
0
    }
7979
4
  } else if (smart_branch_opcode) {
7980
0
    ir_END_list(false_inputs);
7981
4
  } else {
7982
4
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
7983
4
    ir_END_list(end_inputs);
7984
4
  }
7985
7986
4
  ir_IF_FALSE(ref2);
7987
4
  ir_MERGE_2(if_zero, ir_END());
7988
7989
4
  jit_SET_EX_OPLINE(jit, opline);
7990
4
  ref2 = ir_NE(ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_check_constant), ir_CONST_ADDR(zv)), IR_NULL);
7991
4
  if (exit_addr) {
7992
0
    if (smart_branch_opcode == ZEND_JMPZ) {
7993
0
      ir_GUARD(ref2, ir_CONST_ADDR(exit_addr));
7994
0
    } else {
7995
0
      ir_GUARD_NOT(ref2, ir_CONST_ADDR(exit_addr));
7996
0
    }
7997
0
    ir_END_list(end_inputs);
7998
4
  } else if (smart_branch_opcode) {
7999
0
    ref2 = ir_IF(ref2);
8000
0
    ir_IF_TRUE(ref2);
8001
0
    ir_END_list(true_inputs);
8002
0
    ir_IF_FALSE(ref2);
8003
0
    ir_END_list(false_inputs);
8004
4
  } else {
8005
4
    jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8006
4
      ir_ADD_U32(ir_ZEXT_U32(ref2), ir_CONST_U32(IS_FALSE)));
8007
4
    ir_END_list(end_inputs);
8008
4
  }
8009
8010
4
  if (!smart_branch_opcode || exit_addr) {
8011
4
    if (end_inputs) {
8012
4
      ir_MERGE_list(end_inputs);
8013
4
    }
8014
4
  } else {
8015
0
    _zend_jit_merge_smart_branch_inputs(jit, defined_label, undefined_label, true_inputs, false_inputs);
8016
0
  }
8017
8018
4
  return 1;
8019
4
}
8020
8021
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)
8022
0
{
8023
0
  zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
8024
0
  ir_ref if_def = ir_IF(jit_Z_TYPE(jit, reg_addr));
8025
8026
0
  ir_IF_FALSE_cold(if_def);
8027
8028
0
  if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
8029
0
    if (!zend_jit_save_call_chain(jit, -1)) {
8030
0
      return 0;
8031
0
    }
8032
0
  }
8033
8034
0
  if ((opline-1)->opcode != ZEND_FETCH_CONSTANT
8035
0
   && (opline-1)->opcode != ZEND_FETCH_LIST_R
8036
0
   && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR))
8037
0
   && !(flags & ZEND_JIT_EXIT_FREE_OP1)) {
8038
0
    zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var);
8039
8040
0
    zend_jit_zval_try_addref(jit, val_addr);
8041
0
  }
8042
8043
0
  jit_LOAD_IP_ADDR(jit, opline - 1);
8044
8045
  /* We can't use trace_escape() because opcode handler may be overridden by JIT */
8046
0
  zend_jit_op_array_trace_extension *jit_extension =
8047
0
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8048
0
  size_t offset = jit_extension->offset;
8049
0
  ir_ref ref = ir_CONST_FC_FUNC(ZEND_OP_TRACE_INFO((opline - 1), offset)->orig_handler);
8050
0
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
8051
0
    ir_TAILCALL(IR_OPCODE_HANDLER_RET, ref);
8052
0
  } else {
8053
0
    ir_ref opline_ref = ir_CALL_2(IR_OPCODE_HANDLER_RET, ref, jit_FP(jit), jit_IP(jit));
8054
0
    zend_jit_vm_enter(jit, opline_ref);
8055
0
  }
8056
8057
0
  ir_IF_TRUE(if_def);
8058
8059
0
  return 1;
8060
0
}
8061
8062
static int zend_jit_restore_zval(zend_jit_ctx *jit, int var, int8_t reg)
8063
0
{
8064
0
  zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
8065
0
  zend_jit_addr reg_addr = ZEND_ADDR_REF_ZVAL(zend_jit_deopt_rload(jit, IR_ADDR, reg));
8066
8067
  // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8068
0
  jit_ZVAL_COPY(jit, var_addr, MAY_BE_ANY, reg_addr, MAY_BE_ANY, true);
8069
0
  return 1;
8070
0
}
8071
8072
static zend_jit_addr zend_jit_guard_fetch_result_type(zend_jit_ctx         *jit,
8073
                                                      const zend_op        *opline,
8074
                                                      zend_jit_addr         val_addr,
8075
                                                      uint8_t               type,
8076
                                                      bool                  deref,
8077
                                                      uint32_t              flags,
8078
                                                      bool                  op1_avoid_refcounting)
8079
6
{
8080
6
  zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
8081
6
  int32_t exit_point;
8082
6
  const void *res_exit_addr = NULL;
8083
6
  ir_ref end1 = IR_UNUSED, ref1 = IR_UNUSED;
8084
6
  ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
8085
6
  uint32_t old_op1_info = 0;
8086
6
  uint32_t old_info;
8087
6
  ir_ref old_ref;
8088
8089
8090
6
  if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8091
2
    old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
8092
2
    if (op1_avoid_refcounting
8093
2
     || ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
8094
0
      && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS))) {
8095
0
      SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
8096
0
    }
8097
2
  }
8098
6
  old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
8099
6
  old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8100
6
  CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
8101
6
  SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
8102
8103
6
  if (deref) {
8104
2
    ir_ref if_type;
8105
8106
2
    if (type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8107
0
      if_type = ir_IF(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)));
8108
2
    } else {
8109
2
      if_type = jit_if_Z_TYPE(jit, val_addr, type);
8110
2
    }
8111
2
    ir_IF_TRUE(if_type);
8112
2
    end1 = ir_END();
8113
2
    ref1 = ref;
8114
2
    ir_IF_FALSE_cold(if_type);
8115
8116
2
    SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
8117
2
    exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8118
2
    res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8119
2
    if (!res_exit_addr) {
8120
0
      return 0;
8121
0
    }
8122
8123
2
    jit_guard_Z_TYPE(jit, val_addr, IS_REFERENCE, res_exit_addr);
8124
2
    ref = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
8125
2
    val_addr = ZEND_ADDR_REF_ZVAL(ref);
8126
2
  }
8127
8128
6
  SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ref, ZREG_ZVAL_COPY);
8129
6
  exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
8130
6
  res_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8131
6
  if (!res_exit_addr) {
8132
0
    return 0;
8133
0
  }
8134
8135
6
  if (!deref && type == IS_NULL && (opline->opcode == ZEND_FETCH_DIM_IS || opline->opcode == ZEND_FETCH_OBJ_IS)) {
8136
0
    ir_GUARD(ir_ULE(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(type)), ir_CONST_ADDR(res_exit_addr));
8137
6
  } else {
8138
6
    jit_guard_Z_TYPE(jit, val_addr, type, res_exit_addr);
8139
6
  }
8140
8141
6
  if (deref) {
8142
2
    ir_MERGE_WITH(end1);
8143
2
    ref = ir_PHI_2(IR_ADDR, ref, ref1);
8144
2
  }
8145
8146
6
  val_addr = ZEND_ADDR_REF_ZVAL(ref);
8147
8148
6
  SET_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var), old_ref);
8149
6
  SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
8150
6
  if (opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) {
8151
2
    SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
8152
2
  }
8153
8154
6
  return val_addr;
8155
6
}
8156
8157
static int zend_jit_fetch_constant(zend_jit_ctx         *jit,
8158
                                   const zend_op        *opline,
8159
                                   const zend_op_array  *op_array,
8160
                                   zend_ssa             *ssa,
8161
                                   const zend_ssa_op    *ssa_op,
8162
                                   zend_jit_addr         res_addr)
8163
3.64k
{
8164
3.64k
  zval *zv = RT_CONSTANT(opline, opline->op2) + 1;
8165
3.64k
  uint32_t res_info = RES_INFO();
8166
3.64k
  ir_ref ref, ref2, if_set, if_special, not_set_path, special_path, fast_path;
8167
8168
  // JIT: c = CACHED_PTR(opline->extended_value);
8169
3.64k
  ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value));
8170
8171
  // JIT: if (c != NULL)
8172
3.64k
  if_set = ir_IF(ref);
8173
8174
3.64k
  if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) {
8175
    // JIT: if (!IS_SPECIAL_CACHE_VAL(c))
8176
3.64k
    ir_IF_FALSE_cold(if_set);
8177
3.64k
    not_set_path = ir_END();
8178
3.64k
    ir_IF_TRUE(if_set);
8179
3.64k
    if_special = ir_IF(ir_AND_A(ref, ir_CONST_ADDR(CACHE_SPECIAL)));
8180
3.64k
    ir_IF_TRUE_cold(if_special);
8181
3.64k
    special_path = ir_END();
8182
3.64k
    ir_IF_FALSE(if_special);
8183
3.64k
    fast_path = ir_END();
8184
3.64k
    ir_MERGE_2(not_set_path, special_path);
8185
3.64k
  } else {
8186
0
    ir_IF_TRUE(if_set);
8187
0
    fast_path = ir_END();
8188
0
    ir_IF_FALSE_cold(if_set);
8189
0
  }
8190
8191
  // JIT: zend_jit_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num);
8192
3.64k
  jit_SET_EX_OPLINE(jit, opline);
8193
3.64k
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_get_constant),
8194
3.64k
    ir_CONST_ADDR(zv),
8195
3.64k
    ir_CONST_U32(opline->op1.num));
8196
3.64k
  ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
8197
8198
3.64k
  ir_MERGE_WITH(fast_path);
8199
3.64k
  ref = ir_PHI_2(IR_ADDR, ref2, ref);
8200
8201
3.64k
  if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
8202
3
    uint8_t type = concrete_type(res_info);
8203
3
    zend_jit_addr const_addr = ZEND_ADDR_REF_ZVAL(ref);
8204
8205
3
    const_addr = zend_jit_guard_fetch_result_type(jit, opline, const_addr, type, false, 0, false);
8206
3
    if (!const_addr) {
8207
0
      return 0;
8208
0
    }
8209
8210
3
    res_info &= ~MAY_BE_GUARD;
8211
3
    ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
8212
8213
    // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8214
3
    jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, res_info, true);
8215
3
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
8216
0
      return 0;
8217
0
    }
8218
3.64k
  } else {
8219
3.64k
    ir_ref const_addr = ZEND_ADDR_REF_ZVAL(ref);
8220
8221
    // JIT: ZVAL_COPY_OR_DUP(EX_VAR(opline->result.var), &c->value); (no dup)
8222
3.64k
    jit_ZVAL_COPY(jit, res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, true);
8223
3.64k
  }
8224
8225
8226
3.64k
  return 1;
8227
3.64k
}
8228
8229
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)
8230
2
{
8231
2
  uint32_t  mask;
8232
2
  zend_jit_addr op1_addr = OP1_ADDR();
8233
2
  zend_jit_addr res_addr = 0;
8234
2
  uint32_t true_label = -1, false_label = -1;
8235
2
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8236
8237
  // TODO: support for is_resource() ???
8238
2
  ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE);
8239
8240
2
  if (smart_branch_opcode && !exit_addr) {
8241
0
    if (smart_branch_opcode == ZEND_JMPZ) {
8242
0
      true_label = target_label2;
8243
0
      false_label = target_label;
8244
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
8245
0
      true_label = target_label;
8246
0
      false_label = target_label2;
8247
0
    } else {
8248
0
      ZEND_UNREACHABLE();
8249
0
    }
8250
2
  } else {
8251
2
    res_addr = RES_ADDR();
8252
2
  }
8253
8254
2
  if (op1_info & MAY_BE_UNDEF) {
8255
2
    ir_ref if_def = IR_UNUSED;
8256
8257
2
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8258
2
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
8259
2
      ir_IF_FALSE_cold(if_def);
8260
2
    }
8261
8262
2
    jit_SET_EX_OPLINE(jit, opline);
8263
2
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
8264
2
    zend_jit_check_exception_undef_result(jit, opline);
8265
2
    if (opline->extended_value & MAY_BE_NULL) {
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 {
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
2
    } else {
8279
2
      if (exit_addr) {
8280
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8281
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8282
0
        } else {
8283
0
          ir_END_list(end_inputs);
8284
0
        }
8285
2
      } else if (smart_branch_opcode) {
8286
0
        ir_END_list(false_inputs);
8287
2
      } else {
8288
2
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8289
2
        if (if_def) {
8290
2
          ir_END_list(end_inputs);
8291
2
        }
8292
2
      }
8293
2
    }
8294
8295
2
    if (if_def) {
8296
2
      ir_IF_TRUE(if_def);
8297
2
      op1_info |= MAY_BE_NULL;
8298
2
    }
8299
2
  }
8300
8301
2
  if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
8302
2
    mask = opline->extended_value;
8303
2
    if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) {
8304
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8305
0
      if (exit_addr) {
8306
0
        if (smart_branch_opcode == ZEND_JMPNZ) {
8307
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8308
0
        } else if (end_inputs) {
8309
0
          ir_END_list(end_inputs);
8310
0
        }
8311
0
      } else if (smart_branch_opcode) {
8312
0
        ir_END_list(true_inputs);
8313
0
      } else {
8314
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8315
0
        ir_END_list(end_inputs);
8316
0
      }
8317
2
      } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) {
8318
0
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8319
0
      if (exit_addr) {
8320
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8321
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
8322
0
        } else if (end_inputs) {
8323
0
          ir_END_list(end_inputs);
8324
0
        }
8325
0
      } else if (smart_branch_opcode) {
8326
0
        ir_END_list(false_inputs);
8327
0
      } else {
8328
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8329
0
        ir_END_list(end_inputs);
8330
0
      }
8331
2
    } else {
8332
2
      ir_ref ref;
8333
2
      bool invert = false;
8334
2
      uint8_t type;
8335
8336
2
      switch (mask) {
8337
0
        case MAY_BE_NULL:   type = IS_NULL;   break;
8338
0
        case MAY_BE_FALSE:  type = IS_FALSE;  break;
8339
0
        case MAY_BE_TRUE:   type = IS_TRUE;   break;
8340
0
        case MAY_BE_LONG:   type = IS_LONG;   break;
8341
0
        case MAY_BE_DOUBLE: type = IS_DOUBLE; break;
8342
0
        case MAY_BE_STRING: type = IS_STRING; break;
8343
2
        case MAY_BE_ARRAY:  type = IS_ARRAY;  break;
8344
0
        case MAY_BE_OBJECT: type = IS_OBJECT; break;
8345
0
        case MAY_BE_ANY - MAY_BE_NULL:     type = IS_NULL;   invert = true; break;
8346
0
        case MAY_BE_ANY - MAY_BE_FALSE:    type = IS_FALSE;  invert = true; break;
8347
0
        case MAY_BE_ANY - MAY_BE_TRUE:     type = IS_TRUE;   invert = true; break;
8348
0
        case MAY_BE_ANY - MAY_BE_LONG:     type = IS_LONG;   invert = true; break;
8349
0
        case MAY_BE_ANY - MAY_BE_DOUBLE:   type = IS_DOUBLE; invert = true; break;
8350
0
        case MAY_BE_ANY - MAY_BE_STRING:   type = IS_STRING; invert = true; break;
8351
0
        case MAY_BE_ANY - MAY_BE_ARRAY:    type = IS_ARRAY;  invert = true; break;
8352
0
        case MAY_BE_ANY - MAY_BE_OBJECT:   type = IS_OBJECT; invert = true; break;
8353
0
        case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = true; break;
8354
0
        default:
8355
0
          type = 0;
8356
2
      }
8357
8358
2
      if (op1_info & MAY_BE_REF) {
8359
2
        ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8360
2
        ref = jit_ZVAL_DEREF_ref(jit, ref);
8361
2
        op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8362
2
      }
8363
2
      if (type == 0) {
8364
0
        ref = ir_AND_U32(ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)), ir_CONST_U32(mask));
8365
0
        if (!smart_branch_opcode) {
8366
0
          ref = ir_NE(ref, ir_CONST_U32(0));
8367
0
        }
8368
2
      } else if (invert) {
8369
0
        ref = ir_NE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8370
2
      } else {
8371
2
        ref = ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(type));
8372
2
      }
8373
8374
2
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
8375
8376
2
      if (exit_addr) {
8377
0
        if (smart_branch_opcode == ZEND_JMPZ) {
8378
0
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8379
0
        } else {
8380
0
          ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8381
0
        }
8382
0
        if (end_inputs) {
8383
0
          ir_END_list(end_inputs);
8384
0
        }
8385
2
      } else if (smart_branch_opcode) {
8386
0
        ir_ref if_val = ir_IF(ref);
8387
0
        ir_IF_TRUE(if_val);
8388
0
        ir_END_list(true_inputs);
8389
0
        ir_IF_FALSE(if_val);
8390
0
        ir_END_list(false_inputs);
8391
2
      } else {
8392
2
        jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8393
2
          ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8394
2
        ir_END_list(end_inputs);
8395
2
      }
8396
2
      }
8397
2
  }
8398
8399
2
  if (!smart_branch_opcode || exit_addr) {
8400
2
    if (end_inputs) {
8401
2
      ir_MERGE_list(end_inputs);
8402
2
    } else if (exit_addr && !jit->ctx.control) {
8403
0
      ir_BEGIN(IR_UNUSED); /* unreachable block */
8404
0
    }
8405
2
  } else {
8406
0
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8407
0
  }
8408
8409
2
  return 1;
8410
2
}
8411
8412
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)
8413
0
{
8414
0
  zend_jit_addr res_addr = RES_ADDR();
8415
0
  uint32_t true_label = -1, false_label = -1;
8416
0
  ir_ref end_inputs = IR_UNUSED, true_inputs = IR_UNUSED, false_inputs = IR_UNUSED;
8417
8418
0
  if (opline->extended_value & ZEND_ISEMPTY) {
8419
    /* empty($cv) is !$cv, except that an undefined CV doesn't emit a warning. */
8420
0
    uint8_t branch_opcode;
8421
8422
0
    if (!smart_branch_opcode) {
8423
0
      branch_opcode = ZEND_BOOL_NOT;
8424
0
    } else if (smart_branch_opcode == ZEND_JMPZ) {
8425
0
      branch_opcode = ZEND_JMPNZ;
8426
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
8427
0
      branch_opcode = ZEND_JMPZ;
8428
0
    } else {
8429
0
      ZEND_UNREACHABLE();
8430
0
    }
8431
    /* zend_is_true() may call an object's cast handler. */
8432
0
    return zend_jit_bool_jmpznz(jit, opline, op1_info, op1_addr, res_addr,
8433
0
      target_label, target_label2, (op1_info & MAY_BE_OBJECT) != 0, branch_opcode, exit_addr, false);
8434
0
  }
8435
8436
0
  if (smart_branch_opcode && !exit_addr) {
8437
0
    if (smart_branch_opcode == ZEND_JMPZ) {
8438
0
      true_label = target_label2;
8439
0
      false_label = target_label;
8440
0
    } else if (smart_branch_opcode == ZEND_JMPNZ) {
8441
0
      true_label = target_label;
8442
0
      false_label = target_label2;
8443
0
    } else {
8444
0
      ZEND_UNREACHABLE();
8445
0
    }
8446
0
  } else {
8447
0
    res_addr = RES_ADDR();
8448
0
  }
8449
8450
0
  if (op1_info & MAY_BE_REF) {
8451
0
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
8452
0
    ref = jit_ZVAL_DEREF_ref(jit, ref);
8453
0
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
8454
0
  }
8455
8456
0
  if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
8457
0
    if (exit_addr) {
8458
0
      ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ);
8459
0
    } else if (smart_branch_opcode) {
8460
0
      ir_END_list(true_inputs);
8461
0
    } else {
8462
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
8463
0
      ir_END_list(end_inputs);
8464
0
    }
8465
0
  } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) {
8466
0
    if (exit_addr) {
8467
0
      ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ);
8468
0
    } else if (smart_branch_opcode) {
8469
0
      ir_END_list(false_inputs);
8470
0
    } else {
8471
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
8472
0
      ir_END_list(end_inputs);
8473
0
    }
8474
0
  } else {
8475
0
    ir_ref ref = ir_GT(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL));
8476
0
    if (exit_addr) {
8477
0
      if (smart_branch_opcode == ZEND_JMPNZ) {
8478
0
        ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
8479
0
      } else {
8480
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8481
0
      }
8482
0
    } else if (smart_branch_opcode) {
8483
0
      ir_ref if_val = ir_IF(ref);
8484
0
      ir_IF_TRUE(if_val);
8485
0
      ir_END_list(true_inputs);
8486
0
      ir_IF_FALSE(if_val);
8487
0
      ir_END_list(false_inputs);
8488
0
    } else {
8489
0
      jit_set_Z_TYPE_INFO_ref(jit, jit_ZVAL_ADDR(jit, res_addr),
8490
0
        ir_ADD_U32(ir_ZEXT_U32(ref), ir_CONST_U32(IS_FALSE)));
8491
0
      ir_END_list(end_inputs);
8492
0
    }
8493
0
  }
8494
8495
0
  if (!smart_branch_opcode || exit_addr) {
8496
0
    if (end_inputs) {
8497
0
      ir_MERGE_list(end_inputs);
8498
0
    }
8499
0
  } else {
8500
0
    _zend_jit_merge_smart_branch_inputs(jit, true_label, false_label, true_inputs, false_inputs);
8501
0
  }
8502
8503
0
  return 1;
8504
0
}
8505
8506
/* copy of hidden zend_closure */
8507
typedef struct _zend_closure {
8508
  zend_object       std;
8509
  zend_function     func;
8510
  zend_object      *this_ptr;
8511
  zend_class_entry *called_scope;
8512
  zif_handler       orig_internal_handler;
8513
} zend_closure;
8514
8515
static int zend_jit_stack_check(zend_jit_ctx *jit, const zend_op *opline, uint32_t used_stack)
8516
0
{
8517
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8518
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8519
8520
0
  if (!exit_addr) {
8521
0
    return 0;
8522
0
  }
8523
8524
  // JIT: if (EG(vm_stack_end) - EG(vm_stack_top) < used_stack)
8525
0
  ir_GUARD(
8526
0
    ir_UGE(
8527
0
      ir_SUB_A(ir_LOAD_A(jit_EG(vm_stack_end)), ir_LOAD_A(jit_EG(vm_stack_top))),
8528
0
      ir_CONST_ADDR(used_stack)),
8529
0
    ir_CONST_ADDR(exit_addr));
8530
8531
0
  return 1;
8532
0
}
8533
8534
static int zend_jit_free_trampoline(zend_jit_ctx *jit, ir_ref func)
8535
0
{
8536
  // JIT: if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
8537
0
  ir_ref if_trampoline = ir_IF(ir_AND_U32(
8538
0
    ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, common.fn_flags))),
8539
0
    ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE)));
8540
8541
0
  ir_IF_TRUE(if_trampoline);
8542
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_trampoline_helper), func);
8543
0
  ir_MERGE_WITH_EMPTY_FALSE(if_trampoline);
8544
8545
0
  return 1;
8546
0
}
8547
8548
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)
8549
960
{
8550
960
  uint32_t used_stack;
8551
960
  ir_ref used_stack_ref = IR_UNUSED;
8552
960
  bool stack_check = true;
8553
960
  ir_ref rx, ref, top, if_enough_stack, cold_path = IR_UNUSED;
8554
8555
960
  ZEND_ASSERT(func_ref != IR_NULL);
8556
960
  if (func) {
8557
636
    used_stack = zend_vm_calc_used_stack(opline->extended_value, func);
8558
636
    if ((int)used_stack <= checked_stack) {
8559
0
      stack_check = false;
8560
0
    }
8561
636
    used_stack_ref = ir_CONST_ADDR(used_stack);
8562
636
  } else {
8563
324
    ir_ref num_args_ref;
8564
324
    ir_ref if_internal_func = IR_UNUSED;
8565
324
    const size_t func_type_offset = is_closure ? offsetof(zend_closure, func.type) : offsetof(zend_function, type);
8566
8567
324
    used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval);
8568
324
    used_stack_ref = ir_CONST_ADDR(used_stack);
8569
324
    used_stack_ref = ir_HARD_COPY_A(used_stack_ref); /* load constant once */
8570
8571
    // JIT: if (EXPECTED(ZEND_USER_CODE(func->type))) {
8572
324
    ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, func_type_offset));
8573
324
    if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
8574
324
    ir_IF_FALSE(if_internal_func);
8575
8576
    // JIT: used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval);
8577
324
    num_args_ref = ir_CONST_U32(opline->extended_value);
8578
324
    if (!is_closure) {
8579
324
      ref = ir_SUB_U32(
8580
324
        ir_SUB_U32(
8581
324
          ir_MIN_U32(
8582
324
            num_args_ref,
8583
324
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.num_args)))),
8584
324
          ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.last_var)))),
8585
324
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, op_array.T))));
8586
324
    } else {
8587
0
      ref = ir_SUB_U32(
8588
0
        ir_SUB_U32(
8589
0
          ir_MIN_U32(
8590
0
            num_args_ref,
8591
0
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.num_args)))),
8592
0
          ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.last_var)))),
8593
0
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.op_array.T))));
8594
0
    }
8595
324
    ref = ir_MUL_U32(ref, ir_CONST_U32(sizeof(zval)));
8596
324
    if (sizeof(void*) == 8) {
8597
324
      ref = ir_SEXT_A(ref);
8598
324
    }
8599
324
    ref = ir_SUB_A(used_stack_ref, ref);
8600
8601
324
    ir_MERGE_WITH_EMPTY_TRUE(if_internal_func);
8602
324
    used_stack_ref = ir_PHI_2(IR_ADDR, ref, used_stack_ref);
8603
324
  }
8604
8605
960
  zend_jit_start_reuse_ip(jit);
8606
8607
  // JIT: if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) {
8608
960
  jit_STORE_IP(jit, ir_LOAD_A(jit_EG(vm_stack_top)));
8609
8610
960
  if (stack_check) {
8611
    // JIT: Check Stack Overflow
8612
960
    ref = ir_UGE(
8613
960
      ir_SUB_A(
8614
960
        ir_LOAD_A(jit_EG(vm_stack_end)),
8615
960
        jit_IP(jit)),
8616
960
      used_stack_ref);
8617
8618
960
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8619
210
      bool may_be_trampoline = !func && (opline->opcode == ZEND_INIT_METHOD_CALL);
8620
210
      int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8621
210
        may_be_trampoline ?
8622
210
          (ZEND_JIT_EXIT_TO_VM | ZEND_JIT_EXIT_METHOD_CALL) : ZEND_JIT_EXIT_TO_VM);
8623
210
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8624
8625
210
      if (!exit_addr) {
8626
0
        return 0;
8627
0
      }
8628
8629
210
      if (may_be_trampoline) {
8630
2
        jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
8631
2
        jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
8632
2
      }
8633
8634
210
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8635
750
    } else {
8636
750
      if_enough_stack = ir_IF(ref);
8637
750
      ir_IF_FALSE_cold(if_enough_stack);
8638
8639
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
8640
      if (0) {
8641
#else
8642
750
      if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8643
393
#endif
8644
393
        jit_SET_EX_OPLINE(jit, opline);
8645
393
        ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_int_extend_stack_helper), used_stack_ref);
8646
393
      } else {
8647
357
        if (!is_closure) {
8648
357
          ref = func_ref;
8649
357
        } else {
8650
0
          ref = ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func));
8651
0
        }
8652
357
        jit_SET_EX_OPLINE(jit, opline);
8653
357
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_extend_stack_helper),
8654
357
          used_stack_ref, ref);
8655
357
      }
8656
750
      jit_STORE_IP(jit, ref);
8657
8658
750
      cold_path = ir_END();
8659
750
      ir_IF_TRUE(if_enough_stack);
8660
750
    }
8661
960
  }
8662
8663
960
  ref = jit_EG(vm_stack_top);
8664
960
  rx = jit_IP(jit);
8665
960
#if !OPTIMIZE_FOR_SIZE
8666
  /* JIT: EG(vm_stack_top) = (zval*)((char*)call + used_stack);
8667
   * This version is longer but faster
8668
   *    mov EG(vm_stack_top), %CALL
8669
   *    lea size(%call), %tmp
8670
   *    mov %tmp, EG(vm_stack_top)
8671
   */
8672
960
  top = rx;
8673
#else
8674
  /* JIT: EG(vm_stack_top) += used_stack;
8675
   * Use ir_emit() because ir_LOAD() makes load forwarding and doesn't allow load/store fusion
8676
   *    mov EG(vm_stack_top), %CALL
8677
   *    add $size, EG(vm_stack_top)
8678
   */
8679
  top = jit->ctx.control = ir_emit2(&jit->ctx, IR_OPT(IR_LOAD, IR_ADDR), jit->ctx.control, ref);
8680
#endif
8681
960
  ir_STORE(ref, ir_ADD_A(top, used_stack_ref));
8682
8683
  // JIT: zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object);
8684
960
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) {
8685
    // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8686
958
    ir_STORE(jit_CALL(rx, This.u1.type_info), ir_CONST_U32(IS_UNDEF | ZEND_CALL_NESTED_FUNCTION));
8687
958
  }
8688
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
8689
  if (0) {
8690
#else
8691
960
  if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) {
8692
582
#endif
8693
582
    if (cold_path) {
8694
393
      ir_MERGE_WITH(cold_path);
8695
393
      rx = jit_IP(jit);
8696
393
    }
8697
8698
    // JIT: call->func = func;
8699
582
    ir_STORE(jit_CALL(rx, func), func_ref);
8700
582
  } else {
8701
378
    if (!is_closure) {
8702
      // JIT: call->func = func;
8703
377
      ir_STORE(jit_CALL(rx, func), func_ref);
8704
377
    } else {
8705
      // JIT: call->func = &closure->func;
8706
1
      ir_STORE(jit_CALL(rx, func), ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8707
1
    }
8708
378
    if (cold_path) {
8709
357
      ir_MERGE_WITH(cold_path);
8710
357
      rx = jit_IP(jit);
8711
357
    }
8712
378
  }
8713
960
  if (opline->opcode == ZEND_INIT_METHOD_CALL) {
8714
    // JIT: Z_PTR(call->This) = obj;
8715
13
    ZEND_ASSERT(this_ref != IR_NULL);
8716
13
    ir_STORE(jit_CALL(rx, This.value.ptr), this_ref);
8717
13
      if (opline->op1_type == IS_UNUSED || delayed_fetch_this) {
8718
      // JIT: call->call_info |= ZEND_CALL_HAS_THIS;
8719
0
      ref = jit_CALL(rx, This.u1.type_info);
8720
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8721
0
        ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS));
8722
0
      } else {
8723
0
        ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_HAS_THIS)));
8724
0
      }
8725
13
      } else {
8726
13
      if (opline->op1_type == IS_CV) {
8727
        // JIT: GC_ADDREF(obj);
8728
4
        jit_GC_ADDREF(jit, this_ref);
8729
4
      }
8730
8731
      // JIT: call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS;
8732
13
      ref = jit_CALL(rx, This.u1.type_info);
8733
13
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8734
2
        ir_STORE(ref, ir_CONST_U32( ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS));
8735
11
      } else {
8736
11
        ir_STORE(ref,
8737
11
          ir_OR_U32(ir_LOAD_U32(ref),
8738
11
            ir_CONST_U32(ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS)));
8739
11
      }
8740
13
      }
8741
947
  } else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL) {
8742
    // JIT: Z_CE(call->This) = called_scope;
8743
10
    ir_STORE(jit_CALL(rx, This), this_ref);
8744
937
  } else if (!is_closure) {
8745
    // JIT: Z_CE(call->This) = called_scope;
8746
936
    ir_STORE(jit_CALL(rx, This), IR_NULL);
8747
936
  } else {
8748
1
    ir_ref object_or_called_scope, call_info, call_info2, object, if_cond;
8749
1
    ir_ref if_cond_user = IR_UNUSED;
8750
8751
1
    if (opline->op2_type == IS_CV) {
8752
      // JIT: GC_ADDREF(closure);
8753
0
      jit_GC_ADDREF(jit, func_ref);
8754
0
    }
8755
8756
    // JIT: RX(object_or_called_scope) = closure->called_scope;
8757
1
    object_or_called_scope = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, called_scope)));
8758
8759
    // JIT: call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE |
8760
    //      (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE);
8761
1
    call_info = ir_OR_U32(
8762
1
      ir_AND_U32(
8763
1
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.common.fn_flags))),
8764
1
        ir_CONST_U32(ZEND_ACC_FAKE_CLOSURE)),
8765
1
        ir_CONST_U32(ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE));
8766
8767
    // JIT: object_or_called_scope = closure->this_ptr;
8768
1
    object = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, this_ptr)));
8769
    // JIT: if (closure->this_ptr != NULL) {
8770
1
    if_cond = ir_IF(object);
8771
1
    ir_IF_TRUE(if_cond);
8772
8773
    // JIT: call_info |= ZEND_CALL_HAS_THIS;
8774
1
    call_info2 = ir_OR_U32(call_info, ir_CONST_U32(ZEND_CALL_HAS_THIS));
8775
8776
1
    ir_MERGE_WITH_EMPTY_FALSE(if_cond);
8777
1
    call_info = ir_PHI_2(IR_U32, call_info2, call_info);
8778
1
    object_or_called_scope = ir_PHI_2(IR_ADDR, object, object_or_called_scope);
8779
8780
    // JIT: ZEND_SET_CALL_INFO(call, 0, call_info);
8781
1
    ref = jit_CALL(rx, This.u1.type_info);
8782
1
    ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), call_info));
8783
8784
    // JIT: Z_PTR(call->This) = object_or_called_scope;
8785
1
    ir_STORE(jit_CALL(rx, This.value.ptr), object_or_called_scope);
8786
8787
1
    if (!func) {
8788
      // JIT: if (closure->func.common.type & ZEND_USER_FUNCTION)
8789
0
      ir_ref type = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func.type)));
8790
0
      if_cond_user = ir_IF(ir_AND_U8(type, ir_CONST_U8(ZEND_USER_FUNCTION)));
8791
0
      ir_IF_TRUE(if_cond_user);
8792
0
    }
8793
8794
1
    if (!func || func->common.type == ZEND_USER_FUNCTION) {
8795
      // JIT: zend_jit_init_func_run_time_cache_helper(closure->func);
8796
1
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper),
8797
1
        ir_ADD_OFFSET(func_ref, offsetof(zend_closure, func)));
8798
1
    }
8799
8800
1
    if (!func) {
8801
0
      ir_MERGE_WITH_EMPTY_FALSE(if_cond_user);
8802
0
    }
8803
1
  }
8804
8805
  // JIT: ZEND_CALL_NUM_ARGS(call) = num_args;
8806
960
  ir_STORE(jit_CALL(rx, This.u2.num_args), ir_CONST_U32(opline->extended_value));
8807
8808
960
  return 1;
8809
960
}
8810
8811
static int zend_jit_func_guard(zend_jit_ctx *jit, ir_ref func_ref, const zend_function *func, const void *exit_addr)
8812
2
{
8813
2
  if (func->type == ZEND_USER_FUNCTION &&
8814
0
      (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) ||
8815
0
       (func->common.fn_flags & ZEND_ACC_CLOSURE) ||
8816
0
       !func->common.function_name)) {
8817
0
    const zend_op *opcodes = func->op_array.opcodes;
8818
8819
    // JIT: if (call->func.op_array.opcodes != opcodes) goto exit_addr;
8820
0
    ir_GUARD(
8821
0
      ir_EQ(
8822
0
        ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes))),
8823
0
        ir_CONST_ADDR(opcodes)),
8824
0
      ir_CONST_ADDR(exit_addr));
8825
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
8826
  } else if (func->type == ZEND_INTERNAL_FUNCTION) {
8827
    // ASLR may cause different addresses in different workers. Check for the internal function handler.
8828
    // JIT: if (call->func.internal_function.handler != handler) goto exit_addr;
8829
    ir_GUARD(
8830
      ir_EQ(
8831
        ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler))),
8832
        ir_CONST_FC_FUNC(func->internal_function.handler)),
8833
      ir_CONST_ADDR(exit_addr));
8834
#endif
8835
2
  } else {
8836
    // JIT: if (call->func != func) goto exit_addr;
8837
2
    ir_GUARD(ir_EQ(func_ref, ir_CONST_ADDR(func)), ir_CONST_ADDR(exit_addr));
8838
2
  }
8839
8840
2
  return 1;
8841
2
}
8842
8843
static int zend_jit_init_fcall_guard(zend_jit_ctx *jit, uint32_t level, const zend_function *func, const zend_op *to_opline)
8844
2
{
8845
2
  int32_t exit_point;
8846
2
  const void *exit_addr;
8847
2
  ir_ref call;
8848
8849
2
  if (func->type == ZEND_USER_FUNCTION
8850
0
   && !zend_accel_in_shm(func->op_array.opcodes)) {
8851
    /* op_array and op_array->opcodes are not persistent. We can't link. */
8852
0
    return 0;
8853
0
  }
8854
8855
2
  exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM);
8856
2
  exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8857
2
  if (!exit_addr) {
8858
0
    return 0;
8859
0
  }
8860
8861
  // call = EX(call);
8862
2
  call = ir_LOAD_A(jit_EX(call));
8863
2
  while (level > 0) {
8864
    // call = call->prev_execute_data
8865
0
    call = ir_LOAD_A(jit_CALL(call, prev_execute_data));
8866
0
    level--;
8867
0
  }
8868
8869
2
  return zend_jit_func_guard(jit, ir_LOAD_A(jit_CALL(call, func)), func, exit_addr);
8870
2
}
8871
8872
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)
8873
936
{
8874
936
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
8875
936
  zend_call_info *call_info = NULL;
8876
936
  zend_function *func = NULL;
8877
936
  ir_ref func_ref = IR_UNUSED;
8878
8879
936
  if (jit->delayed_call_level) {
8880
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
8881
0
      return 0;
8882
0
    }
8883
0
  }
8884
8885
936
  if (info) {
8886
936
    call_info = info->callee_info;
8887
1.00k
    while (call_info && call_info->caller_init_opline != opline) {
8888
70
      call_info = call_info->next_callee;
8889
70
    }
8890
936
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
8891
633
      func = call_info->callee_func;
8892
633
    }
8893
936
  }
8894
8895
936
  if (!func
8896
303
   && trace
8897
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL) {
8898
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
8899
    /* ASLR */
8900
    if (trace->func->type != ZEND_INTERNAL_FUNCTION) {
8901
      func = (zend_function*)trace->func;
8902
    }
8903
#else
8904
0
    func = (zend_function*)trace->func;
8905
0
#endif
8906
0
  }
8907
8908
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
8909
  if (0) {
8910
#else
8911
936
  if (opline->opcode == ZEND_INIT_FCALL
8912
633
   && func
8913
633
   && func->type == ZEND_INTERNAL_FUNCTION) {
8914
582
#endif
8915
    /* load constant address later */
8916
582
    func_ref = ir_CONST_ADDR(func);
8917
582
  } else if (func && op_array == &func->op_array) {
8918
    /* recursive call */
8919
3
    if (!(func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)
8920
3
     || zend_jit_prefer_const_addr_load(jit, (uintptr_t)func)) {
8921
3
      func_ref = ir_LOAD_A(jit_EX(func));
8922
3
    } else {
8923
0
      func_ref = ir_CONST_ADDR(func);
8924
0
    }
8925
351
  } else {
8926
351
    ir_ref if_func, cache_slot_ref, ref;
8927
8928
    // JIT: if (CACHED_PTR(opline->result.num))
8929
351
    cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num);
8930
351
    func_ref = ir_LOAD_A(cache_slot_ref);
8931
351
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
8932
18
     && func
8933
18
     && (func->common.fn_flags & ZEND_ACC_IMMUTABLE)
8934
18
     && opline->opcode != ZEND_INIT_FCALL) {
8935
      /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */
8936
0
      if_func = ir_IF(ir_EQ(func_ref, ir_CONST_ADDR(func)));
8937
351
    } else {
8938
351
      if_func = ir_IF(func_ref);
8939
351
    }
8940
351
    ir_IF_FALSE_cold(if_func);
8941
351
    if (opline->opcode == ZEND_INIT_FCALL
8942
48
     && func
8943
48
     && func->type == ZEND_USER_FUNCTION
8944
48
     && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) {
8945
48
      ref = ir_HARD_COPY_A(ir_CONST_ADDR(func)); /* load constant once */
8946
48
        ir_STORE(cache_slot_ref, ref);
8947
48
      ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_init_func_run_time_cache_helper), ref);
8948
303
    } else {
8949
303
      zval *zv = RT_CONSTANT(opline, opline->op2);
8950
8951
303
      if (opline->opcode == ZEND_INIT_FCALL) {
8952
0
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8953
0
          ir_CONST_ADDR(Z_STR_P(zv)),
8954
0
          cache_slot_ref);
8955
303
      } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) {
8956
293
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_func_helper),
8957
293
          ir_CONST_ADDR(Z_STR_P(zv + 1)),
8958
293
          cache_slot_ref);
8959
293
      } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) {
8960
10
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_ns_func_helper),
8961
10
          ir_CONST_ADDR(zv),
8962
10
          cache_slot_ref);
8963
10
      } else {
8964
0
        ZEND_UNREACHABLE();
8965
0
      }
8966
303
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8967
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8968
0
          func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0);
8969
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
8970
8971
0
        if (!exit_addr) {
8972
0
          return 0;
8973
0
        }
8974
0
        if (!func || opline->opcode == ZEND_INIT_FCALL) {
8975
0
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
8976
0
        } else if (!zend_jit_func_guard(jit, ref, func, exit_addr)) {
8977
0
          return 0;
8978
0
        }
8979
303
      } else {
8980
303
jit_SET_EX_OPLINE(jit, opline);
8981
303
        ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_undefined_function));
8982
303
      }
8983
303
    }
8984
351
    ir_MERGE_WITH_EMPTY_TRUE(if_func);
8985
351
    func_ref = ir_PHI_2(IR_ADDR, ref, func_ref);
8986
351
  }
8987
8988
936
  if (!zend_jit_push_call_frame(jit, opline, op_array, func, false, false, checked_stack, func_ref, IR_UNUSED)) {
8989
0
    return 0;
8990
0
  }
8991
8992
936
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
8993
357
    if (!zend_jit_save_call_chain(jit, call_level)) {
8994
0
      return 0;
8995
0
    }
8996
579
  } else {
8997
579
    ZEND_ASSERT(call_level > 0);
8998
579
    jit->delayed_call_level = call_level;
8999
579
    delayed_call_chain = true;
9000
579
  }
9001
9002
936
  if (trace
9003
207
   && trace->op == ZEND_JIT_TRACE_END
9004
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9005
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9006
0
      return 0;
9007
0
    }
9008
0
  }
9009
9010
936
  return 1;
9011
936
}
9012
9013
static int zend_jit_init_method_call(zend_jit_ctx         *jit,
9014
                                     const zend_op        *opline,
9015
                                     uint32_t              b,
9016
                                     const zend_op_array  *op_array,
9017
                                     zend_ssa             *ssa,
9018
                                     const zend_ssa_op    *ssa_op,
9019
                                     int                   call_level,
9020
                                     uint32_t              op1_info,
9021
                                     zend_jit_addr         op1_addr,
9022
                                     zend_class_entry     *ce,
9023
                                     bool                  ce_is_instanceof,
9024
                                     bool                  on_this,
9025
                                     bool                  delayed_fetch_this,
9026
                                     zend_class_entry     *trace_ce,
9027
                                     zend_jit_trace_rec   *trace,
9028
                                     int                   checked_stack,
9029
                                     ir_ref                func_ref,
9030
                                     ir_ref                this_ref,
9031
                                     bool                  polymorphic_side_trace)
9032
13
{
9033
13
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
9034
13
  zend_call_info *call_info = NULL;
9035
13
  zend_function *func = NULL;
9036
13
  zval *function_name;
9037
13
  ir_ref if_static = IR_UNUSED, cold_path;
9038
9039
13
  ZEND_ASSERT(opline->op2_type == IS_CONST);
9040
13
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
9041
9042
13
  function_name = RT_CONSTANT(opline, opline->op2);
9043
9044
13
  if (info) {
9045
13
    call_info = info->callee_info;
9046
13
    while (call_info && call_info->caller_init_opline != opline) {
9047
0
      call_info = call_info->next_callee;
9048
0
    }
9049
13
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
9050
0
      func = call_info->callee_func;
9051
0
    }
9052
13
  }
9053
9054
13
  if (polymorphic_side_trace) {
9055
    /* function is passed from parent snapshot */
9056
0
    ZEND_ASSERT(func_ref != IR_UNUSED && this_ref != IR_UNUSED);
9057
13
  } else {
9058
13
    ir_ref ref, ref2, if_found, fast_path, run_time_cache, this_ref2;
9059
9060
13
    if (on_this) {
9061
0
      zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
9062
0
      this_ref = jit_Z_PTR(jit, this_addr);
9063
13
    } else {
9064
13
        if (op1_info & MAY_BE_REF) {
9065
11
        if (opline->op1_type == IS_CV) {
9066
          // JIT: ZVAL_DEREF(op1)
9067
2
          ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
9068
2
          ref = jit_ZVAL_DEREF_ref(jit, ref);
9069
2
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9070
9
        } else {
9071
9
          ir_ref if_ref;
9072
9073
          /* Hack: Convert reference to regular value to simplify JIT code */
9074
9
          ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP);
9075
9076
9
          if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9077
9
          ir_IF_TRUE(if_ref);
9078
9
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper), jit_ZVAL_ADDR(jit, op1_addr));
9079
9080
9
          ir_MERGE_WITH_EMPTY_FALSE(if_ref);
9081
9
        }
9082
11
      }
9083
13
      if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
9084
11
        if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9085
0
          int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9086
0
          const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9087
9088
0
          if (!exit_addr) {
9089
0
            return 0;
9090
0
          }
9091
0
          ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_OBJECT)),
9092
0
            ir_CONST_ADDR(exit_addr));
9093
11
        } else {
9094
11
          ir_ref if_object = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
9095
9096
11
          ir_IF_FALSE_cold(if_object);
9097
9098
11
          jit_SET_EX_OPLINE(jit, opline);
9099
11
          if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9100
9
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call_tmp),
9101
9
              jit_ZVAL_ADDR(jit, op1_addr));
9102
9
          } else {
9103
2
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_method_call),
9104
2
              jit_ZVAL_ADDR(jit, op1_addr));
9105
2
          }
9106
11
          ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
9107
11
          ir_IF_TRUE(if_object);
9108
11
        }
9109
11
      }
9110
9111
13
      this_ref = jit_Z_PTR(jit, op1_addr);
9112
13
    }
9113
9114
13
    if (jit->delayed_call_level) {
9115
0
      if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9116
0
        return 0;
9117
0
      }
9118
0
    }
9119
9120
13
    if (func) {
9121
      // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9122
0
      ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9123
9124
0
      if_found = ir_IF(ref);
9125
0
      ir_IF_TRUE(if_found);
9126
0
      fast_path = ir_END();
9127
13
    } else {
9128
      // JIT: if (CACHED_PTR(opline->result.num) == obj->ce)) {
9129
13
      run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
9130
13
      ref = ir_EQ(
9131
13
        ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num)),
9132
13
        ir_LOAD_A(ir_ADD_OFFSET(this_ref, offsetof(zend_object, ce))));
9133
13
      if_found = ir_IF(ref);
9134
13
      ir_IF_TRUE(if_found);
9135
9136
      // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9137
13
      ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->result.num + sizeof(void*)));
9138
13
      fast_path = ir_END();
9139
9140
13
    }
9141
9142
13
    ir_IF_FALSE_cold(if_found);
9143
13
    jit_SET_EX_OPLINE(jit, opline);
9144
9145
13
    if (!jit->ctx.fixed_call_stack_size) {
9146
      // JIT: alloca(sizeof(void*));
9147
0
      this_ref2 = ir_ALLOCA(ir_CONST_ADDR(0x10));
9148
13
    } else {
9149
#ifdef _WIN64
9150
      this_ref2 = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9151
#else
9152
13
      this_ref2 = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
9153
13
#endif
9154
13
    }
9155
13
    ir_STORE(this_ref2, this_ref);
9156
9157
13
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9158
9
      ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_tmp_helper),
9159
9
          this_ref,
9160
9
          ir_CONST_ADDR(function_name),
9161
9
          this_ref2);
9162
9
    } else {
9163
4
      ref2 = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_method_helper),
9164
4
          this_ref,
9165
4
          ir_CONST_ADDR(function_name),
9166
4
          this_ref2);
9167
4
    }
9168
9169
9170
13
    if (!jit->ctx.fixed_call_stack_size) {
9171
0
      this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9172
      // JIT: revert alloca
9173
0
      ir_AFREE(ir_CONST_ADDR(0x10));
9174
13
    } else {
9175
#ifdef _WIN64
9176
      this_ref2 = ir_LOAD_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
9177
#else
9178
13
      this_ref2 = ir_LOAD_A(ir_RLOAD_A(IR_REG_SP));
9179
13
#endif
9180
13
    }
9181
9182
13
    ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9183
9184
13
    ir_MERGE_WITH(fast_path);
9185
13
    func_ref = ir_PHI_2(IR_ADDR, ref2, ref);
9186
13
    this_ref = ir_PHI_2(IR_ADDR, this_ref2, this_ref);
9187
13
  }
9188
9189
13
  if ((!func || zend_jit_may_be_modified(func, op_array))
9190
13
   && trace
9191
2
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9192
2
   && trace->func) {
9193
0
    int32_t exit_point;
9194
0
    const void *exit_addr;
9195
9196
0
    exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL);
9197
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9198
0
    if (!exit_addr) {
9199
0
      return 0;
9200
0
    }
9201
9202
0
    jit->trace->exit_info[exit_point].poly_func.ref = func_ref;
9203
0
    jit->trace->exit_info[exit_point].poly_this.ref = this_ref;
9204
9205
0
    func = (zend_function*)trace->func;
9206
9207
0
    if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9208
0
      return 0;
9209
0
    }
9210
0
  }
9211
9212
13
  if (!func) {
9213
    // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9214
13
    if_static = ir_IF(ir_AND_U32(
9215
13
      ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9216
13
      ir_CONST_U32(ZEND_ACC_STATIC)));
9217
13
    ir_IF_TRUE_cold(if_static);
9218
13
  }
9219
9220
13
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) {
9221
13
    ir_ref ret;
9222
9223
13
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) {
9224
9
      ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame_tmp),
9225
9
          this_ref,
9226
9
          func_ref,
9227
9
          ir_CONST_U32(opline->extended_value));
9228
9
    } else {
9229
4
      ret = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_static_method_call_frame),
9230
4
          this_ref,
9231
4
          func_ref,
9232
4
          ir_CONST_U32(opline->extended_value));
9233
4
    }
9234
9235
13
    if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) {
9236
9
      ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9237
9
    }
9238
13
    jit_STORE_IP(jit, ret);
9239
13
  }
9240
9241
13
  if (!func) {
9242
13
    cold_path = ir_END();
9243
13
    ir_IF_FALSE(if_static);
9244
13
  }
9245
9246
13
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) {
9247
13
    if (!zend_jit_push_call_frame(jit, opline, NULL, func, false, delayed_fetch_this, checked_stack, func_ref, this_ref)) {
9248
0
      return 0;
9249
0
    }
9250
13
  }
9251
9252
13
  if (!func) {
9253
13
    ir_MERGE_WITH(cold_path);
9254
13
  }
9255
13
  zend_jit_start_reuse_ip(jit);
9256
9257
13
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9258
7
    if (!zend_jit_save_call_chain(jit, call_level)) {
9259
0
      return 0;
9260
0
    }
9261
7
  } else {
9262
6
    ZEND_ASSERT(call_level > 0);
9263
6
    delayed_call_chain = true;
9264
6
    jit->delayed_call_level = call_level;
9265
6
  }
9266
9267
13
  if (trace
9268
2
   && trace->op == ZEND_JIT_TRACE_END
9269
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9270
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9271
0
      return 0;
9272
0
    }
9273
0
  }
9274
9275
13
  return 1;
9276
13
}
9277
9278
static int zend_jit_init_static_method_call(zend_jit_ctx         *jit,
9279
                                            const zend_op        *opline,
9280
                                            uint32_t              b,
9281
                                            const zend_op_array  *op_array,
9282
                                            zend_ssa             *ssa,
9283
                                            const zend_ssa_op    *ssa_op,
9284
                                            int                   call_level,
9285
                                            zend_jit_trace_rec   *trace,
9286
                                            int                   checked_stack)
9287
10
{
9288
10
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
9289
10
  zend_call_info *call_info = NULL;
9290
10
  zend_class_entry *ce;
9291
10
  zend_function *func = NULL;
9292
10
  ir_ref func_ref, func_ref2, scope_ref, scope_ref2, if_cached, cold_path, ref;
9293
10
  ir_ref if_static = IR_UNUSED;
9294
9295
10
  if (info) {
9296
10
    call_info = info->callee_info;
9297
13
    while (call_info && call_info->caller_init_opline != opline) {
9298
3
      call_info = call_info->next_callee;
9299
3
    }
9300
10
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
9301
2
      func = call_info->callee_func;
9302
2
    }
9303
10
  }
9304
9305
10
  ce = zend_get_known_class(op_array, opline, opline->op1_type, opline->op1);
9306
10
  if (!func && ce && (opline->op1_type == IS_CONST || !(ce->ce_flags & ZEND_ACC_TRAIT))) {
9307
0
    zval *zv = RT_CONSTANT(opline, opline->op2);
9308
0
    zend_string *method_name;
9309
9310
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
9311
0
    method_name = Z_STR_P(zv);
9312
0
    zv = zend_hash_find(&ce->function_table, method_name);
9313
0
    if (zv) {
9314
0
      zend_function *fn = Z_PTR_P(zv);
9315
9316
0
      if (fn->common.scope == op_array->scope
9317
0
       || (fn->common.fn_flags & ZEND_ACC_PUBLIC)
9318
0
       || ((fn->common.fn_flags & ZEND_ACC_PROTECTED)
9319
0
        && op_array->scope
9320
0
        && instanceof_function_slow(op_array->scope, fn->common.scope))) {
9321
0
        func = fn;
9322
0
      }
9323
0
    }
9324
0
  }
9325
9326
10
  if (jit->delayed_call_level) {
9327
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9328
0
      return 0;
9329
0
    }
9330
0
  }
9331
9332
  // JIT: fbc = CACHED_PTR(opline->result.num + sizeof(void*));
9333
10
  func_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num + sizeof(void*)));
9334
9335
  // JIT: if (fbc)
9336
10
  if_cached = ir_IF(func_ref);
9337
10
  ir_IF_FALSE_cold(if_cached);
9338
9339
10
  jit_SET_EX_OPLINE(jit, opline);
9340
10
  scope_ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_class_helper), jit_FP(jit));
9341
10
  ir_GUARD(scope_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9342
9343
10
  func_ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_find_static_method_helper), jit_FP(jit), scope_ref2);
9344
10
  ir_GUARD(func_ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9345
9346
10
  cold_path = ir_END();
9347
9348
10
  ir_IF_TRUE(if_cached);
9349
10
  if (ce && (ce->ce_flags & ZEND_ACC_IMMUTABLE) && (ce->ce_flags & ZEND_ACC_LINKED)) {
9350
0
    scope_ref = ir_CONST_ADDR(ce);
9351
10
  } else {
9352
10
    scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->result.num));
9353
10
  }
9354
9355
10
  ir_MERGE_2(cold_path, ir_END());
9356
10
  func_ref = ir_PHI_2(IR_ADDR, func_ref2, func_ref);
9357
10
  scope_ref = ir_PHI_2(IR_ADDR, scope_ref2, scope_ref);
9358
9359
10
  if ((!func || zend_jit_may_be_modified(func, op_array))
9360
8
   && trace
9361
0
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9362
0
   && trace->func) {
9363
0
    int32_t exit_point;
9364
0
    const void *exit_addr;
9365
9366
0
    exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : 0);
9367
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9368
0
    if (!exit_addr) {
9369
0
      return 0;
9370
0
    }
9371
9372
//    jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
9373
//    jit->trace->exit_info[exit_point].poly_this_ref = scope_ref;
9374
9375
0
    func = (zend_function*)trace->func;
9376
9377
0
    if (!zend_jit_func_guard(jit, func_ref, func, exit_addr)) {
9378
0
      return 0;
9379
0
    }
9380
0
  }
9381
9382
10
  if (!func || !(func->common.fn_flags & ZEND_ACC_STATIC)) {
9383
8
    if (!func) {
9384
      // JIT: if (fbc->common.fn_flags & ZEND_ACC_STATIC) {
9385
8
      if_static = ir_IF(ir_AND_U32(
9386
8
        ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
9387
8
        ir_CONST_U32(ZEND_ACC_STATIC)));
9388
8
      ir_IF_FALSE_cold(if_static);
9389
8
    }
9390
9391
8
    jit_SET_EX_OPLINE(jit, opline);
9392
8
    ref = ir_CALL_3(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_push_this_method_call_frame),
9393
8
        scope_ref,
9394
8
        func_ref,
9395
8
        ir_CONST_U32(opline->extended_value));
9396
8
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9397
8
    jit_STORE_IP(jit, ref);
9398
9399
8
    if (!func) {
9400
8
      cold_path = ir_END();
9401
8
      ir_IF_TRUE(if_static);
9402
8
    }
9403
8
  }
9404
9405
10
  if (!func || (func->common.fn_flags & ZEND_ACC_STATIC)) {
9406
10
    if (opline->op1_type == IS_UNUSED
9407
1
     && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT ||
9408
1
         (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF)) {
9409
1
      if (op_array->fn_flags & ZEND_ACC_STATIC) {
9410
0
        scope_ref = ir_LOAD_A(jit_EX(This.value.ref));
9411
1
      } else if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
9412
0
        ir_ref if_object, values = IR_UNUSED;
9413
9414
0
        if_object = ir_IF(ir_EQ(jit_Z_TYPE_ref(jit, jit_EX(This)), ir_CONST_U8(IS_OBJECT)));
9415
0
        ir_IF_TRUE(if_object);
9416
0
        ir_END_PHI_list(values,
9417
0
          ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce))));
9418
0
        ir_IF_FALSE(if_object);
9419
0
        ir_END_PHI_list(values, ir_LOAD_A(jit_EX(This.value.ref)));
9420
0
        scope_ref = ir_PHI_list(values);
9421
1
      } else {
9422
1
        scope_ref = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(This.value.ref)), offsetof(zend_object, ce)));
9423
1
      }
9424
1
    }
9425
10
    if (!zend_jit_push_call_frame(jit, opline, op_array, func, false, false, checked_stack, func_ref, scope_ref)) {
9426
0
      return 0;
9427
0
    }
9428
9429
10
    if (!func) {
9430
8
      ir_MERGE_2(cold_path, ir_END());
9431
8
    }
9432
10
  }
9433
9434
10
  zend_jit_start_reuse_ip(jit);
9435
10
  if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9436
5
    if (!zend_jit_save_call_chain(jit, call_level)) {
9437
0
      return 0;
9438
0
    }
9439
5
  } else {
9440
5
    ZEND_ASSERT(call_level > 0);
9441
5
    jit->delayed_call_level = call_level;
9442
5
    delayed_call_chain = true;
9443
5
  }
9444
9445
10
  if (trace
9446
0
   && trace->op == ZEND_JIT_TRACE_END
9447
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9448
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9449
0
      return 0;
9450
0
    }
9451
0
  }
9452
9453
10
  return 1;
9454
10
}
9455
9456
static int zend_jit_init_closure_call(zend_jit_ctx         *jit,
9457
                                      const zend_op        *opline,
9458
                                      uint32_t              b,
9459
                                      const zend_op_array  *op_array,
9460
                                      zend_ssa             *ssa,
9461
                                      const zend_ssa_op    *ssa_op,
9462
                                      int                   call_level,
9463
                                      zend_jit_trace_rec   *trace,
9464
                                      int                   checked_stack)
9465
1
{
9466
1
  zend_function *func = NULL;
9467
1
  zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
9468
1
  ir_ref ref;
9469
9470
1
  ref = jit_Z_PTR(jit, op2_addr);
9471
9472
1
  if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure
9473
0
   && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) {
9474
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9475
0
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9476
9477
0
    if (!exit_addr) {
9478
0
      return 0;
9479
0
    }
9480
9481
0
    ir_GUARD(
9482
0
      ir_EQ(
9483
0
        ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_object, ce))),
9484
0
        ir_CONST_ADDR(zend_ce_closure)),
9485
0
      ir_CONST_ADDR(exit_addr));
9486
9487
0
    if (ssa->var_info && ssa_op->op2_use >= 0) {
9488
0
      ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD;
9489
0
      ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure;
9490
0
      ssa->var_info[ssa_op->op2_use].is_instanceof = 0;
9491
0
    }
9492
0
  }
9493
9494
1
  if (trace
9495
1
   && trace->op == ZEND_JIT_TRACE_INIT_CALL
9496
1
   && trace->func
9497
1
   && trace->func->type == ZEND_USER_FUNCTION) {
9498
1
    const zend_op *opcodes;
9499
1
    int32_t exit_point;
9500
1
    const void *exit_addr;
9501
9502
1
    func = (zend_function*)trace->func;
9503
1
    opcodes = func->op_array.opcodes;
9504
1
    exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL);
9505
1
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9506
1
    if (!exit_addr) {
9507
0
      return 0;
9508
0
    }
9509
9510
1
    ir_GUARD(
9511
1
      ir_EQ(
9512
1
        ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_closure, func.op_array.opcodes))),
9513
1
        ir_CONST_ADDR(opcodes)),
9514
1
      ir_CONST_ADDR(exit_addr));
9515
1
  }
9516
9517
1
  if (jit->delayed_call_level) {
9518
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
9519
0
      return 0;
9520
0
    }
9521
0
  }
9522
9523
1
  if (!zend_jit_push_call_frame(jit, opline, NULL, func, true, false, checked_stack, ref, IR_UNUSED)) {
9524
0
    return 0;
9525
0
  }
9526
9527
1
  if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) {
9528
0
    if (!zend_jit_save_call_chain(jit, call_level)) {
9529
0
      return 0;
9530
0
    }
9531
1
  } else {
9532
1
    ZEND_ASSERT(call_level > 0);
9533
1
    delayed_call_chain = true;
9534
1
    jit->delayed_call_level = call_level;
9535
1
  }
9536
9537
1
  if (trace
9538
1
   && trace->op == ZEND_JIT_TRACE_END
9539
0
   && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9540
0
    if (!zend_jit_set_ip(jit, opline + 1)) {
9541
0
      return 0;
9542
0
    }
9543
0
  }
9544
9545
1
  return 1;
9546
1
}
9547
9548
static int zend_jit_send_val(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr)
9549
3.54k
{
9550
3.54k
  uint32_t arg_num = opline->op2.num;
9551
3.54k
  zend_jit_addr arg_addr;
9552
9553
3.54k
  ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM);
9554
9555
3.54k
  if (!zend_jit_reuse_ip(jit)) {
9556
0
    return 0;
9557
0
  }
9558
9559
3.54k
  if (opline->opcode == ZEND_SEND_VAL_EX) {
9560
284
    uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2);
9561
9562
284
    ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM);
9563
9564
284
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9565
0
     && JIT_G(current_frame)
9566
0
     && JIT_G(current_frame)->call
9567
0
     && JIT_G(current_frame)->call->func) {
9568
0
      if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9569
        /* Don't generate code that always throws exception */
9570
0
        return 0;
9571
0
      }
9572
284
    } else {
9573
284
      ir_ref cond = ir_AND_U32(
9574
284
        ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9575
284
        ir_CONST_U32(mask));
9576
9577
284
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9578
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9579
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9580
0
        if (!exit_addr) {
9581
0
          return 0;
9582
0
        }
9583
0
        ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
9584
284
      } else {
9585
284
        ir_ref if_pass_by_ref;
9586
9587
284
        if_pass_by_ref = ir_IF(cond);
9588
9589
284
        ir_IF_TRUE_cold(if_pass_by_ref);
9590
284
        if (Z_MODE(op1_addr) == IS_REG) {
9591
          /* set type to avoid zval_ptr_dtor() on uninitialized value */
9592
2
          zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
9593
2
          jit_set_Z_TYPE_INFO(jit, addr, IS_UNDEF);
9594
2
        }
9595
284
        jit_SET_EX_OPLINE(jit, opline);
9596
284
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_throw_cannot_pass_by_ref));
9597
9598
284
        ir_IF_FALSE(if_pass_by_ref);
9599
284
      }
9600
284
    }
9601
284
  }
9602
9603
3.54k
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9604
9605
3.54k
  if (opline->op1_type == IS_CONST) {
9606
3.25k
    zval *zv = RT_CONSTANT(opline, opline->op1);
9607
9608
3.25k
    jit_ZVAL_COPY_CONST(jit,
9609
3.25k
      arg_addr,
9610
3.25k
      MAY_BE_ANY, MAY_BE_ANY,
9611
3.25k
      zv, true);
9612
3.25k
  } else {
9613
289
    jit_ZVAL_COPY(jit,
9614
289
      arg_addr,
9615
289
      MAY_BE_ANY,
9616
289
      op1_addr, op1_info, false);
9617
289
  }
9618
9619
3.54k
  return 1;
9620
3.54k
}
9621
9622
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)
9623
49
{
9624
49
  zend_jit_addr op1_addr, arg_addr, ref_addr;
9625
49
  ir_ref ref_path = IR_UNUSED;
9626
9627
49
  op1_addr = OP1_ADDR();
9628
49
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9629
9630
49
  if (!zend_jit_reuse_ip(jit)) {
9631
0
    return 0;
9632
0
  }
9633
9634
49
  if (opline->op1_type == IS_VAR) {
9635
25
    if (op1_info & MAY_BE_INDIRECT) {
9636
25
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
9637
25
    }
9638
25
  } else if (opline->op1_type == IS_CV) {
9639
24
    if (op1_info & MAY_BE_UNDEF) {
9640
24
      if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9641
        // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9642
24
        ir_ref if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9643
24
        ir_IF_FALSE(if_def);
9644
        // JIT: ZVAL_NULL(op1)
9645
24
        jit_set_Z_TYPE_INFO(jit,op1_addr, IS_NULL);
9646
24
        ir_MERGE_WITH_EMPTY_TRUE(if_def);
9647
24
      }
9648
24
      op1_info &= ~MAY_BE_UNDEF;
9649
24
      op1_info |= MAY_BE_NULL;
9650
24
    }
9651
24
  } else {
9652
0
    ZEND_UNREACHABLE();
9653
0
  }
9654
9655
49
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) {
9656
49
    ir_ref ref, ref2;
9657
9658
49
    if (op1_info & MAY_BE_REF) {
9659
49
      ir_ref if_ref;
9660
9661
      // JIT: if (Z_TYPE_P(op1) == IS_UNDEF)
9662
49
      if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9663
49
      ir_IF_TRUE(if_ref);
9664
      // JIT: ref = Z_PTR_P(op1)
9665
49
      ref = jit_Z_PTR(jit, op1_addr);
9666
      // JIT: GC_ADDREF(ref)
9667
49
      jit_GC_ADDREF(jit, ref);
9668
      // JIT: ZVAL_REFERENCE(arg, ref)
9669
49
      jit_set_Z_PTR(jit, arg_addr, ref);
9670
49
      jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9671
49
      ref_path = ir_END();
9672
49
      ir_IF_FALSE(if_ref);
9673
49
    }
9674
9675
    // JIT: ZVAL_NEW_REF(arg, varptr);
9676
    // JIT: ref = emalloc(sizeof(zend_reference));
9677
49
    ref = jit_EMALLOC(jit, sizeof(zend_reference), op_array, opline);
9678
    // JIT: GC_REFCOUNT(ref) = 2
9679
49
    jit_set_GC_REFCOUNT(jit, ref, 2);
9680
    // JIT: GC_TYPE(ref) = GC_REFERENCE
9681
49
    ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, gc.u.type_info)), ir_CONST_U32(GC_REFERENCE));
9682
49
    ir_STORE(ir_ADD_OFFSET(ref, offsetof(zend_reference, sources.ptr)), IR_NULL);
9683
49
    ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9684
49
    ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9685
9686
        // JIT: ZVAL_COPY_VALUE(&ref->val, op1)
9687
49
    jit_ZVAL_COPY(jit,
9688
49
      ref_addr,
9689
49
      MAY_BE_ANY,
9690
49
      op1_addr, op1_info, false);
9691
9692
    // JIT: ZVAL_REFERENCE(arg, ref)
9693
49
    jit_set_Z_PTR(jit, op1_addr, ref);
9694
49
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
9695
9696
    // JIT: ZVAL_REFERENCE(arg, ref)
9697
49
    jit_set_Z_PTR(jit, arg_addr, ref);
9698
49
    jit_set_Z_TYPE_INFO(jit, arg_addr, IS_REFERENCE_EX);
9699
49
  }
9700
9701
49
  if (ref_path) {
9702
49
    ir_MERGE_WITH(ref_path);
9703
49
  }
9704
9705
49
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
9706
9707
49
  return 1;
9708
49
}
9709
9710
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)
9711
120
{
9712
120
  uint32_t arg_num = opline->op2.num;
9713
120
  zend_jit_addr arg_addr;
9714
120
  ir_ref end_inputs = IR_UNUSED;
9715
9716
120
  ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX &&
9717
120
       opline->opcode != ZEND_SEND_VAR_NO_REF_EX) ||
9718
120
      arg_num <= MAX_ARG_FLAG_NUM);
9719
9720
120
  arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var);
9721
9722
120
  if (!zend_jit_reuse_ip(jit)) {
9723
0
    return 0;
9724
0
  }
9725
9726
120
  if (opline->opcode == ZEND_SEND_VAR_EX) {
9727
25
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9728
0
     && JIT_G(current_frame)
9729
0
     && JIT_G(current_frame)->call
9730
0
     && JIT_G(current_frame)->call->func) {
9731
0
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9732
0
        if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9733
0
          return 0;
9734
0
        }
9735
0
        return 1;
9736
0
      }
9737
25
    } else {
9738
25
      uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9739
9740
      // JIT: if (RX->func->quick_arg_flags & mask)
9741
25
      ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9742
25
        ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_RX(func)), offsetof(zend_function, quick_arg_flags))),
9743
25
        ir_CONST_U32(mask)));
9744
25
      ir_IF_TRUE_cold(if_send_by_ref);
9745
9746
25
      if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9747
0
        return 0;
9748
0
      }
9749
9750
25
      ir_END_list(end_inputs);
9751
25
      ir_IF_FALSE(if_send_by_ref);
9752
25
    }
9753
95
  } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) {
9754
32
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9755
0
     && JIT_G(current_frame)
9756
0
     && JIT_G(current_frame)->call
9757
0
     && JIT_G(current_frame)->call->func) {
9758
0
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9759
9760
            // JIT: ZVAL_COPY_VALUE(arg, op1)
9761
0
        jit_ZVAL_COPY(jit,
9762
0
          arg_addr,
9763
0
          MAY_BE_ANY,
9764
0
          op1_addr, op1_info, false);
9765
9766
0
        if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9767
0
          if (!(op1_info & MAY_BE_REF)) {
9768
            /* Don't generate code that always throws exception */
9769
0
            return 0;
9770
0
          } else {
9771
0
            int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9772
0
            const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9773
0
            if (!exit_addr) {
9774
0
              return 0;
9775
0
            }
9776
9777
            // JIT: if (Z_TYPE_P(op1) != IS_REFERENCE)
9778
0
            ir_GUARD(ir_EQ(jit_Z_TYPE(jit, op1_addr), ir_CONST_U32(IS_REFERENCE)),
9779
0
              ir_CONST_ADDR(exit_addr));
9780
0
          }
9781
0
        }
9782
0
        return 1;
9783
0
      }
9784
32
    } else {
9785
32
      uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
9786
32
      ir_ref func, if_send_by_ref, if_prefer_ref;
9787
9788
      // JIT: if (RX->func->quick_arg_flags & mask)
9789
32
      func = ir_LOAD_A(jit_RX(func));
9790
32
      if_send_by_ref = ir_IF(ir_AND_U32(
9791
32
        ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9792
32
        ir_CONST_U32(mask)));
9793
32
      ir_IF_TRUE_cold(if_send_by_ref);
9794
9795
32
      mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2);
9796
9797
          // JIT: ZVAL_COPY_VALUE(arg, op1)
9798
32
      jit_ZVAL_COPY(jit,
9799
32
        arg_addr,
9800
32
        MAY_BE_ANY,
9801
32
        op1_addr, op1_info, false);
9802
9803
32
      if (op1_info & MAY_BE_REF) {
9804
32
        ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9805
32
        ir_IF_TRUE(if_ref);
9806
32
        ir_END_list(end_inputs);
9807
32
        ir_IF_FALSE(if_ref);
9808
32
      }
9809
9810
      // JIT: if (RX->func->quick_arg_flags & mask)
9811
32
      if_prefer_ref = ir_IF(ir_AND_U32(
9812
32
        ir_LOAD_U32(ir_ADD_OFFSET(func, offsetof(zend_function, quick_arg_flags))),
9813
32
        ir_CONST_U32(mask)));
9814
32
      ir_IF_TRUE(if_prefer_ref);
9815
32
      ir_END_list(end_inputs);
9816
32
      ir_IF_FALSE(if_prefer_ref);
9817
9818
32
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9819
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9820
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9821
0
        if (!exit_addr) {
9822
0
          return 0;
9823
0
        }
9824
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
9825
32
      } else {
9826
32
        jit_SET_EX_OPLINE(jit, opline);
9827
32
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9828
32
          jit_ZVAL_ADDR(jit, arg_addr));
9829
32
        zend_jit_check_exception(jit);
9830
32
        ir_END_list(end_inputs);
9831
32
      }
9832
9833
32
      ir_IF_FALSE(if_send_by_ref);
9834
32
    }
9835
63
  } else if (opline->opcode == ZEND_SEND_FUNC_ARG) {
9836
26
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
9837
2
     && JIT_G(current_frame)
9838
2
     && JIT_G(current_frame)->call
9839
2
     && JIT_G(current_frame)->call->func) {
9840
2
      if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
9841
0
        if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 0)) {
9842
0
          return 0;
9843
0
        }
9844
0
        return 1;
9845
0
      }
9846
24
    } else {
9847
      // JIT: if (RX->This.u1.type_info & ZEND_CALL_SEND_ARG_BY_REF)
9848
24
      ir_ref if_send_by_ref = ir_IF(ir_AND_U32(
9849
24
        ir_LOAD_U32(jit_RX(This.u1.type_info)),
9850
24
        ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
9851
24
      ir_IF_TRUE_cold(if_send_by_ref);
9852
9853
24
      if (!zend_jit_send_ref(jit, opline, op_array, op1_info, 1)) {
9854
0
        return 0;
9855
0
      }
9856
9857
24
      ir_END_list(end_inputs);
9858
24
      ir_IF_FALSE(if_send_by_ref);
9859
24
    }
9860
26
  }
9861
9862
120
  if (op1_info & MAY_BE_UNDEF) {
9863
99
    ir_ref ref, if_def = IR_UNUSED;
9864
9865
99
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9866
93
      if_def = jit_if_not_Z_TYPE(jit, op1_addr, IS_UNDEF);
9867
93
      ir_IF_FALSE_cold(if_def);
9868
93
    }
9869
9870
    // JIT: zend_jit_undefined_op_helper(opline->op1.var)
9871
99
    jit_SET_EX_OPLINE(jit, opline);
9872
99
    ref = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
9873
99
      ir_CONST_U32(opline->op1.var));
9874
9875
    // JIT: ZVAL_NULL(arg)
9876
99
    jit_set_Z_TYPE_INFO(jit, arg_addr, IS_NULL);
9877
9878
    // JIT: check_exception
9879
99
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
9880
9881
99
    if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) {
9882
93
      ir_END_list(end_inputs);
9883
93
      ir_IF_TRUE(if_def);
9884
93
    } else {
9885
6
      if (end_inputs) {
9886
0
        ir_END_list(end_inputs);
9887
0
        ir_MERGE_list(end_inputs);
9888
0
      }
9889
6
      return 1;
9890
6
    }
9891
99
  }
9892
9893
114
  if (opline->opcode == ZEND_SEND_VAR_NO_REF) {
9894
        // JIT: ZVAL_COPY_VALUE(arg, op1)
9895
0
    jit_ZVAL_COPY(jit,
9896
0
      arg_addr,
9897
0
      MAY_BE_ANY,
9898
0
      op1_addr, op1_info, false);
9899
0
    if (op1_info & MAY_BE_REF) {
9900
        // JIT: if (Z_TYPE_P(arg) == IS_REFERENCE)
9901
0
        ir_ref if_ref = jit_if_Z_TYPE(jit, arg_addr, IS_REFERENCE);
9902
0
        ir_IF_TRUE(if_ref);
9903
0
        ir_END_list(end_inputs);
9904
0
        ir_IF_FALSE(if_ref);
9905
0
    }
9906
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
9907
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
9908
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
9909
0
      if (!exit_addr) {
9910
0
        return 0;
9911
0
      }
9912
0
      ir_GUARD(IR_FALSE, ir_CONST_ADDR(exit_addr));
9913
0
    } else {
9914
0
      jit_SET_EX_OPLINE(jit, opline);
9915
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_only_vars_by_reference),
9916
0
        jit_ZVAL_ADDR(jit, arg_addr));
9917
0
      zend_jit_check_exception(jit);
9918
0
    }
9919
114
  } else {
9920
114
    if (op1_info & MAY_BE_REF) {
9921
95
      if (opline->op1_type == IS_CV) {
9922
37
        ir_ref ref;
9923
9924
        // JIT: ZVAL_DEREF(op1)
9925
37
        ref = jit_ZVAL_ADDR(jit, op1_addr);
9926
37
        ref = jit_ZVAL_DEREF_ref(jit, ref);
9927
37
        op1_addr = ZEND_ADDR_REF_ZVAL(ref);
9928
9929
            // JIT: ZVAL_COPY(arg, op1)
9930
37
        jit_ZVAL_COPY(jit,
9931
37
          arg_addr,
9932
37
          MAY_BE_ANY,
9933
37
          op1_addr, op1_info, true);
9934
58
      } else {
9935
58
        ir_ref if_ref, ref, ref2, refcount, if_not_zero, if_refcounted;
9936
58
        zend_jit_addr ref_addr;
9937
9938
        // JIT: if (Z_TYPE_P(op1) == IS_REFERENCE)
9939
58
        if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
9940
58
        ir_IF_TRUE_cold(if_ref);
9941
9942
        // JIT: ref = Z_COUNTED_P(op1);
9943
58
        ref = jit_Z_PTR(jit, op1_addr);
9944
58
        ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
9945
58
        ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
9946
9947
        // JIT: ZVAL_COPY_VALUE(arg, op1);
9948
58
        jit_ZVAL_COPY(jit,
9949
58
          arg_addr,
9950
58
          MAY_BE_ANY,
9951
58
          ref_addr, op1_info, false);
9952
9953
        // JIT: if (GC_DELREF(ref) != 0)
9954
58
        refcount = jit_GC_DELREF(jit, ref);
9955
58
        if_not_zero = ir_IF(refcount);
9956
58
        ir_IF_TRUE(if_not_zero);
9957
9958
                // JIT: if (Z_REFCOUNTED_P(arg)
9959
58
        if_refcounted = jit_if_REFCOUNTED(jit, arg_addr);
9960
58
        ir_IF_TRUE(if_refcounted);
9961
        // JIT: Z_ADDREF_P(arg)
9962
58
        jit_GC_ADDREF(jit, jit_Z_PTR(jit, arg_addr));
9963
58
        ir_END_list(end_inputs);
9964
58
        ir_IF_FALSE(if_refcounted);
9965
58
        ir_END_list(end_inputs);
9966
9967
58
        ir_IF_FALSE(if_not_zero);
9968
9969
        // JIT: efree(ref)
9970
58
        jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
9971
58
        ir_END_list(end_inputs);
9972
9973
58
        ir_IF_FALSE(if_ref);
9974
9975
        // JIT: ZVAL_COPY_VALUE(arg, op1);
9976
58
        jit_ZVAL_COPY(jit,
9977
58
          arg_addr,
9978
58
          MAY_BE_ANY,
9979
58
          op1_addr, op1_info, false);
9980
58
      }
9981
95
    } else {
9982
19
      if (op1_addr != op1_def_addr) {
9983
0
        if (!zend_jit_update_regs(jit, opline->op1.var, op1_addr, op1_def_addr, op1_info)) {
9984
0
          return 0;
9985
0
        }
9986
0
        if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) {
9987
0
          op1_addr = op1_def_addr;
9988
0
        }
9989
0
      }
9990
9991
          // JIT: ZVAL_COPY_VALUE(arg, op1)
9992
19
      jit_ZVAL_COPY(jit,
9993
19
        arg_addr,
9994
19
        MAY_BE_ANY,
9995
19
        op1_addr, op1_info, opline->op1_type == IS_CV);
9996
19
    }
9997
114
  }
9998
9999
114
  if (end_inputs) {
10000
95
    ir_END_list(end_inputs);
10001
95
    ir_MERGE_list(end_inputs);
10002
95
  }
10003
10004
114
  return 1;
10005
114
}
10006
10007
static int zend_jit_check_func_arg(zend_jit_ctx *jit, const zend_op *opline)
10008
26
{
10009
26
  uint32_t arg_num = opline->op2.num;
10010
26
  ir_ref ref;
10011
10012
26
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10013
2
   && JIT_G(current_frame)
10014
2
   && JIT_G(current_frame)->call
10015
2
   && JIT_G(current_frame)->call->func) {
10016
2
    if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) {
10017
0
      if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
10018
0
        TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call);
10019
        // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10020
0
        if (jit->reuse_ip) {
10021
0
          ref = jit_IP(jit);
10022
0
        } else {
10023
0
          ref = ir_LOAD_A(jit_EX(call));
10024
0
        }
10025
0
        ref = jit_CALL(ref, This.u1.type_info);
10026
0
        ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
10027
0
      }
10028
2
    } else {
10029
2
      if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
10030
0
        TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call);
10031
        // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10032
0
        if (jit->reuse_ip) {
10033
0
          ref = jit_IP(jit);
10034
0
        } else {
10035
0
          ref = ir_LOAD_A(jit_EX(call));
10036
0
        }
10037
0
        ref = jit_CALL(ref, This.u1.type_info);
10038
0
        ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
10039
0
      }
10040
2
    }
10041
24
  } else {
10042
    // JIT: if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
10043
24
    uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2);
10044
24
    ir_ref rx, if_ref, cold_path;
10045
10046
24
    if (!zend_jit_reuse_ip(jit)) {
10047
0
      return 0;
10048
0
    }
10049
10050
24
    rx = jit_IP(jit);
10051
10052
24
    ref = ir_AND_U32(
10053
24
      ir_LOAD_U32(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_function, quick_arg_flags))),
10054
24
      ir_CONST_U32(mask));
10055
24
    if_ref = ir_IF(ref);
10056
24
    ir_IF_TRUE_cold(if_ref);
10057
10058
    // JIT: ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10059
24
    ref = jit_CALL(rx, This.u1.type_info);
10060
24
    ir_STORE(ref, ir_OR_U32(ir_LOAD_U32(ref), ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
10061
10062
24
    cold_path = ir_END();
10063
24
    ir_IF_FALSE(if_ref);
10064
10065
    // JIT: ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF);
10066
24
    ref = jit_CALL(rx, This.u1.type_info);
10067
24
    ir_STORE(ref, ir_AND_U32(ir_LOAD_U32(ref), ir_CONST_U32(~ZEND_CALL_SEND_ARG_BY_REF)));
10068
10069
24
    ir_MERGE_WITH(cold_path);
10070
24
  }
10071
10072
26
  return 1;
10073
26
}
10074
10075
static int zend_jit_check_undef_args(zend_jit_ctx *jit, const zend_op *opline)
10076
29
{
10077
29
  ir_ref call, if_may_have_undef, ret;
10078
10079
29
  if (jit->reuse_ip) {
10080
0
    call = jit_IP(jit);
10081
29
  } else {
10082
29
    call = ir_LOAD_A(jit_EX(call));
10083
29
  }
10084
10085
29
  if_may_have_undef = ir_IF(ir_AND_U8(
10086
29
    ir_LOAD_U8(ir_ADD_OFFSET(call, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10087
29
    ir_CONST_U8(ZEND_CALL_MAY_HAVE_UNDEF >> 24)));
10088
10089
29
  ir_IF_TRUE_cold(if_may_have_undef);
10090
29
  jit_SET_EX_OPLINE(jit, opline);
10091
29
  ret = ir_CALL_1(IR_I32, ir_CONST_FC_FUNC(zend_handle_undef_args), call);
10092
29
  ir_GUARD_NOT(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10093
29
  ir_MERGE_WITH_EMPTY_FALSE(if_may_have_undef);
10094
10095
29
  return 1;
10096
29
}
10097
10098
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)
10099
3.63k
{
10100
3.63k
  zend_func_info *info = ZEND_FUNC_INFO(op_array);
10101
3.63k
  zend_call_info *call_info = NULL;
10102
3.63k
  const zend_function *func = NULL;
10103
3.63k
  uint32_t i;
10104
3.63k
  uint32_t call_num_args = 0;
10105
3.63k
  bool unknown_num_args = false;
10106
3.63k
  const void *exit_addr = NULL;
10107
3.63k
  const zend_op *prev_opline;
10108
3.63k
  ir_ref rx, func_ref = IR_UNUSED, if_user = IR_UNUSED, user_path = IR_UNUSED;
10109
10110
3.63k
  prev_opline = opline - 1;
10111
3.63k
  while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
10112
0
    prev_opline--;
10113
0
  }
10114
3.63k
  if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY ||
10115
3.63k
      prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10116
29
    unknown_num_args = true;
10117
29
  }
10118
10119
3.63k
  if (info) {
10120
3.63k
    call_info = info->callee_info;
10121
3.72k
    while (call_info && call_info->caller_call_opline != opline) {
10122
84
      call_info = call_info->next_callee;
10123
84
    }
10124
3.63k
    if (call_info && call_info->callee_func && !call_info->is_prototype) {
10125
614
      func = call_info->callee_func;
10126
614
    }
10127
3.63k
    if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)
10128
0
     && (!JIT_G(current_frame)
10129
0
      || !JIT_G(current_frame)->call
10130
0
      || !JIT_G(current_frame)->call->func)) {
10131
0
      call_info = NULL; func = NULL; /* megamorphic call from trait */
10132
0
    }
10133
3.63k
  }
10134
3.63k
  if (!func) {
10135
    /* resolve function at run time */
10136
3.02k
  } else if (func->type == ZEND_USER_FUNCTION) {
10137
43
    ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL);
10138
43
    call_num_args = call_info->num_args;
10139
571
  } else if (func->type == ZEND_INTERNAL_FUNCTION) {
10140
571
    ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL);
10141
571
    call_num_args = call_info->num_args;
10142
571
  } else {
10143
0
    ZEND_UNREACHABLE();
10144
0
  }
10145
10146
3.63k
  if (trace && !func) {
10147
7
    if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
10148
6
      ZEND_ASSERT(!trace->func || trace->func->type == ZEND_INTERNAL_FUNCTION);
10149
6
#ifndef ZEND_OPCACHE_SHM_REATTACHMENT
10150
      // TODO: ASLR may cause different addresses in different workers ???
10151
6
      func = trace->func;
10152
6
      if (JIT_G(current_frame) &&
10153
6
          JIT_G(current_frame)->call &&
10154
6
          TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10155
6
        call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10156
6
      } else {
10157
0
        unknown_num_args = true;
10158
0
      }
10159
6
#endif
10160
6
    } else if (trace->op == ZEND_JIT_TRACE_ENTER) {
10161
1
      ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION);
10162
1
      if (zend_accel_in_shm(trace->func->op_array.opcodes)) {
10163
1
        func = trace->func;
10164
1
        if (JIT_G(current_frame) &&
10165
1
            JIT_G(current_frame)->call &&
10166
1
            TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) {
10167
1
          call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call);
10168
1
        } else {
10169
0
          unknown_num_args = true;
10170
0
        }
10171
1
      }
10172
1
    }
10173
7
  }
10174
10175
3.63k
  bool may_have_extra_named_params =
10176
3.63k
    (opline->extended_value & ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS) &&
10177
21
    (!func || func->common.fn_flags & ZEND_ACC_VARIADIC);
10178
10179
3.63k
  if (!jit->reuse_ip) {
10180
133
    zend_jit_start_reuse_ip(jit);
10181
    // JIT: call = EX(call);
10182
133
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(call)));
10183
133
  }
10184
3.63k
  rx = jit_IP(jit);
10185
3.63k
  zend_jit_stop_reuse_ip(jit);
10186
10187
3.63k
  jit_SET_EX_OPLINE(jit, opline);
10188
10189
3.63k
  if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10190
3.59k
    if (!func) {
10191
3.02k
      if (trace) {
10192
2
        uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10193
10194
2
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10195
2
        if (!exit_addr) {
10196
0
          return 0;
10197
0
        }
10198
10199
2
        func_ref = ir_LOAD_A(jit_CALL(rx, func));
10200
2
        ir_GUARD_NOT(
10201
2
          ir_AND_U32(
10202
2
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10203
2
            ir_CONST_U32(ZEND_ACC_DEPRECATED|ZEND_ACC_NODISCARD)),
10204
2
          ir_CONST_ADDR(exit_addr));
10205
2
      }
10206
3.02k
    }
10207
3.59k
  }
10208
10209
3.63k
  if (!jit->delayed_call_level) {
10210
    // JIT: EX(call) = call->prev_execute_data;
10211
3.12k
    ir_STORE(jit_EX(call),
10212
3.12k
      (call_level == 1) ? IR_NULL : ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
10213
3.12k
  }
10214
3.63k
  delayed_call_chain = false;
10215
3.63k
  jit->delayed_call_level = 0;
10216
10217
  // JIT: call->prev_execute_data = execute_data;
10218
3.63k
  ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
10219
10220
3.63k
  if (!func) {
10221
3.02k
    if (!func_ref) {
10222
3.01k
      func_ref = ir_LOAD_A(jit_CALL(rx, func));
10223
3.01k
    }
10224
3.02k
  }
10225
10226
3.63k
  if (opline->opcode == ZEND_DO_FCALL || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
10227
3.59k
    if (!func) {
10228
3.02k
      if (!trace) {
10229
3.01k
        ir_ref if_deprecated_nodiscard, ret;
10230
10231
3.01k
        uint32_t no_discard = RETURN_VALUE_USED(opline) ? 0 : ZEND_ACC_NODISCARD;
10232
10233
3.01k
        if_deprecated_nodiscard = ir_IF(ir_AND_U32(
10234
3.01k
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10235
3.01k
            ir_CONST_U32(ZEND_ACC_DEPRECATED|no_discard)));
10236
3.01k
        ir_IF_TRUE_cold(if_deprecated_nodiscard);
10237
10238
3.01k
        ir_ref helper = ir_CONST_FC_FUNC(no_discard ? zend_jit_deprecated_nodiscard_helper : zend_jit_deprecated_helper);
10239
3.01k
        if (GCC_GLOBAL_REGS) {
10240
0
          ret = ir_CALL(IR_BOOL, helper);
10241
3.01k
        } else {
10242
3.01k
          ret = ir_CALL_1(IR_BOOL, helper, rx);
10243
3.01k
        }
10244
3.01k
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10245
3.01k
        ir_MERGE_WITH_EMPTY_FALSE(if_deprecated_nodiscard);
10246
3.01k
      }
10247
3.02k
    } else {
10248
576
      if (func->common.fn_flags & ZEND_ACC_DEPRECATED) {
10249
0
        ir_ref ret;
10250
10251
0
        if (GCC_GLOBAL_REGS) {
10252
0
          ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper));
10253
0
        } else {
10254
0
          ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_deprecated_helper), rx);
10255
0
        }
10256
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10257
0
      }
10258
10259
576
      if ((func->common.fn_flags & ZEND_ACC_NODISCARD) && !RETURN_VALUE_USED(opline)) {
10260
0
        ir_ref ret;
10261
10262
0
        if (GCC_GLOBAL_REGS) {
10263
0
          ret = ir_CALL(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper));
10264
0
        } else {
10265
0
          ret = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_nodiscard_helper), rx);
10266
0
        }
10267
0
        ir_GUARD(ret, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10268
0
      }
10269
576
    }
10270
3.59k
  }
10271
10272
3.63k
  if (!func
10273
3.02k
   && opline->opcode != ZEND_DO_UCALL
10274
3.02k
   && opline->opcode != ZEND_DO_ICALL) {
10275
3.02k
    ir_ref type_ref = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
10276
3.02k
    if_user = ir_IF(ir_EQ(type_ref, ir_CONST_U8(ZEND_USER_FUNCTION)));
10277
3.02k
    ir_IF_TRUE(if_user);
10278
3.02k
  }
10279
10280
3.63k
  if ((!func || func->type == ZEND_USER_FUNCTION)
10281
3.06k
   && opline->opcode != ZEND_DO_ICALL) {
10282
3.06k
    bool recursive_call_through_jmp = false;
10283
3.06k
    uint32_t num_args = 0;
10284
10285
    // JIT: EX(call) = NULL;
10286
3.06k
    ir_STORE(jit_CALL(rx, call), IR_NULL);
10287
10288
    // JIT: EX(return_value) = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : 0;
10289
3.06k
    ir_STORE(jit_CALL(rx, return_value),
10290
3.06k
      RETURN_VALUE_USED(opline) ?
10291
3.06k
        jit_ZVAL_ADDR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var)) :
10292
3.06k
        IR_NULL);
10293
10294
    // JIT: EX_LOAD_RUN_TIME_CACHE(op_array);
10295
3.06k
    if (!func || func->op_array.cache_size) {
10296
3.06k
      ir_ref run_time_cache;
10297
10298
3.06k
      if (func && op_array == &func->op_array) {
10299
        /* recursive call */
10300
3
        run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
10301
3.06k
      } else if (func
10302
41
       && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE)
10303
40
       && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) {
10304
40
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)),
10305
40
          (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache)));
10306
3.02k
      } else if (func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
10307
        /* Closures always use direct pointers */
10308
1
        ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10309
10310
1
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10311
3.02k
      } else {
10312
3.02k
        ir_ref if_odd, run_time_cache2;
10313
3.02k
        ir_ref local_func_ref = func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func));
10314
10315
3.02k
        run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(local_func_ref, offsetof(zend_op_array, run_time_cache__ptr)));
10316
3.02k
        if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
10317
3.02k
        ir_IF_TRUE(if_odd);
10318
10319
3.02k
        run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
10320
10321
3.02k
        ir_MERGE_WITH_EMPTY_FALSE(if_odd);
10322
3.02k
        run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
10323
3.02k
      }
10324
10325
3.06k
      ir_STORE(jit_CALL(rx, run_time_cache), run_time_cache);
10326
3.06k
    }
10327
10328
    // JIT: EG(current_execute_data) = execute_data = call;
10329
3.06k
    ir_STORE(jit_EG(current_execute_data), rx);
10330
3.06k
    jit_STORE_FP(jit, rx);
10331
10332
    // JIT: opline = op_array->opcodes;
10333
3.06k
    if (func && !unknown_num_args) {
10334
10335
111
      for (i = call_num_args; i < func->op_array.last_var; i++) {
10336
69
        uint32_t n = EX_NUM_TO_VAR(i);
10337
69
        zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, n);
10338
10339
69
        jit_set_Z_TYPE_INFO_ex(jit, var_addr, ir_CONST_U32(IS_UNDEF));
10340
69
      }
10341
10342
42
      if (call_num_args <= func->op_array.num_args) {
10343
37
        if (!trace || (trace->op == ZEND_JIT_TRACE_END
10344
21
         && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10345
21
          if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
10346
0
            if (trace) {
10347
0
              num_args = 0;
10348
0
            } else if (call_info) {
10349
0
              num_args = skip_valid_arguments(op_array, ssa, call_info);
10350
0
            } else {
10351
0
              num_args = call_num_args;
10352
0
            }
10353
21
          } else {
10354
21
            num_args = call_num_args;
10355
21
          }
10356
21
          if (zend_accel_in_shm(func->op_array.opcodes)) {
10357
21
            jit_LOAD_IP_ADDR(jit, func->op_array.opcodes + num_args);
10358
21
          } else {
10359
0
            if (!func_ref) {
10360
0
              func_ref = ir_LOAD_A(jit_CALL(rx, func));
10361
0
            }
10362
0
            ir_ref ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10363
0
            if (num_args) {
10364
0
              ip = ir_ADD_OFFSET(ip, num_args * sizeof(zend_op));
10365
0
            }
10366
0
            jit_STORE_IP(jit, ip);
10367
0
          }
10368
10369
21
          if (!trace && op_array == &func->op_array && call_num_args >= op_array->required_num_args) {
10370
            /* recursive call */
10371
0
            recursive_call_through_jmp = true;
10372
0
          }
10373
21
        }
10374
37
      } else {
10375
5
        ir_ref helper;
10376
5
        if (!trace || (trace->op == ZEND_JIT_TRACE_END
10377
4
         && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10378
4
          ir_ref ip;
10379
10380
4
          if (zend_accel_in_shm(func->op_array.opcodes)) {
10381
4
            ip = ir_CONST_ADDR(func->op_array.opcodes);
10382
4
          } else {
10383
0
            if (!func_ref) {
10384
0
              func_ref = ir_LOAD_A(jit_CALL(rx, func));
10385
0
            }
10386
0
            ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10387
0
          }
10388
4
          jit_STORE_IP(jit, ip);
10389
4
          helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper);
10390
4
        } else {
10391
1
          helper = ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper_no_skip_recv);
10392
1
        }
10393
5
        if (GCC_GLOBAL_REGS) {
10394
0
          ir_CALL(IR_VOID, helper);
10395
5
        } else if (ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
10396
5
          ir_CALL_2(IR_ADDR, helper, jit_FP(jit), jit_IP(jit));
10397
5
        } else {
10398
0
          ir_ref ref = ir_CALL_2(IR_ADDR, helper, jit_FP(jit), jit_IP(jit));
10399
0
          jit_STORE_IP(jit, ref);
10400
0
        }
10401
5
      }
10402
3.02k
    } else {
10403
3.02k
      ir_ref ip;
10404
3.02k
      ir_ref merge_inputs = IR_UNUSED;
10405
10406
      // JIT: opline = op_array->opcodes
10407
3.02k
      if (func && zend_accel_in_shm(func->op_array.opcodes)) {
10408
2
        ip = ir_CONST_ADDR(func->op_array.opcodes);
10409
3.02k
      } else {
10410
3.02k
        if (!func_ref) {
10411
0
          func_ref = ir_LOAD_A(jit_CALL(rx, func));
10412
0
        }
10413
3.02k
        ip = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, opcodes)));
10414
3.02k
      }
10415
3.02k
      jit_STORE_IP(jit, ip);
10416
10417
      // JIT: num_args = EX_NUM_ARGS();
10418
3.02k
      ir_ref num_args, first_extra_arg;
10419
10420
3.02k
      num_args = ir_LOAD_U32(jit_EX(This.u2.num_args));
10421
3.02k
      if (func) {
10422
2
        first_extra_arg = ir_CONST_U32(func->op_array.num_args);
10423
3.02k
      } else {
10424
        // JIT: first_extra_arg = op_array->num_args;
10425
3.02k
        ZEND_ASSERT(func_ref);
10426
3.02k
        first_extra_arg = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, num_args)));
10427
3.02k
      }
10428
10429
      // JIT: if (UNEXPECTED(num_args > first_extra_arg))
10430
3.02k
      ir_ref if_extra_args = ir_IF(ir_GT(num_args, first_extra_arg));
10431
3.02k
      ir_IF_TRUE_cold(if_extra_args);
10432
3.02k
      if (GCC_GLOBAL_REGS) {
10433
0
        ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper));
10434
3.02k
      } else {
10435
3.02k
        ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_copy_extra_args_helper), jit_FP(jit), jit_IP(jit));
10436
3.02k
        jit_STORE_IP(jit, ref);
10437
3.02k
      }
10438
3.02k
      ir_END_list(merge_inputs);
10439
3.02k
      ir_IF_FALSE(if_extra_args);
10440
3.02k
      if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) {
10441
3.02k
        if (!func) {
10442
          // JIT: if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0))
10443
3.02k
          ir_ref if_has_type_hints = ir_IF(ir_AND_U32(
10444
3.02k
            ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, fn_flags))),
10445
3.02k
            ir_CONST_U32(ZEND_ACC_HAS_TYPE_HINTS)));
10446
3.02k
          ir_IF_TRUE(if_has_type_hints);
10447
3.02k
          ir_END_list(merge_inputs);
10448
3.02k
          ir_IF_FALSE(if_has_type_hints);
10449
3.02k
        }
10450
        // JIT: opline += num_args;
10451
10452
3.02k
        ir_ref ref = ir_MUL_U32(num_args, ir_CONST_U32(sizeof(zend_op)));
10453
10454
3.02k
        if (sizeof(void*) == 8) {
10455
3.02k
          ref = ir_ZEXT_A(ref);
10456
3.02k
        }
10457
10458
3.02k
        jit_STORE_IP(jit, ir_ADD_A(jit_IP(jit), ref));
10459
3.02k
      }
10460
10461
3.02k
      ir_END_list(merge_inputs);
10462
3.02k
      ir_MERGE_list(merge_inputs);
10463
10464
      // JIT: if (EXPECTED((int)num_args < op_array->last_var)) {
10465
3.02k
      ir_ref last_var;
10466
10467
3.02k
      if (func) {
10468
2
        last_var = ir_CONST_U32(func->op_array.last_var);
10469
3.02k
      } else {
10470
3.02k
        ZEND_ASSERT(func_ref);
10471
3.02k
        last_var = ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_op_array, last_var)));
10472
3.02k
      }
10473
10474
3.02k
      ir_ref idx = ir_SUB_U32(last_var, num_args);
10475
3.02k
      ir_ref if_need = ir_IF(ir_GT(idx, ir_CONST_U32(0)));
10476
3.02k
      ir_IF_TRUE(if_need);
10477
10478
      // JIT: zval *var = EX_VAR_NUM(num_args);
10479
3.02k
      if (sizeof(void*) == 8) {
10480
3.02k
        num_args = ir_ZEXT_A(num_args);
10481
3.02k
      }
10482
3.02k
      ir_ref var_ref = ir_ADD_OFFSET(
10483
3.02k
        ir_ADD_A(jit_FP(jit), ir_MUL_A(num_args, ir_CONST_ADDR(sizeof(zval)))),
10484
3.02k
        (ZEND_CALL_FRAME_SLOT * sizeof(zval)) + offsetof(zval, u1.type_info));
10485
10486
3.02k
      ir_ref loop = ir_LOOP_BEGIN(ir_END());
10487
3.02k
      var_ref = ir_PHI_2(IR_ADDR, var_ref, IR_UNUSED);
10488
3.02k
      idx = ir_PHI_2(IR_U32, idx, IR_UNUSED);
10489
3.02k
      ir_STORE(var_ref, ir_CONST_I32(IS_UNDEF));
10490
3.02k
      ir_PHI_SET_OP(var_ref, 2, ir_ADD_OFFSET(var_ref, sizeof(zval)));
10491
3.02k
      ir_ref idx2 = ir_SUB_U32(idx, ir_CONST_U32(1));
10492
3.02k
      ir_PHI_SET_OP(idx, 2, idx2);
10493
3.02k
      ir_ref if_not_zero = ir_IF(idx2);
10494
3.02k
      ir_IF_TRUE(if_not_zero);
10495
3.02k
      ir_MERGE_SET_OP(loop, 2, ir_LOOP_END());
10496
3.02k
      ir_IF_FALSE(if_not_zero);
10497
3.02k
      ir_MERGE_WITH_EMPTY_FALSE(if_need);
10498
3.02k
    }
10499
10500
3.06k
    if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
10501
0
      ir_ref observer_handler;
10502
0
      ir_ref rx = jit_FP(jit);
10503
0
      const zend_op *observer_opline = NULL;
10504
0
      struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10505
0
      if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10506
0
        ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10507
0
        observer_opline = trace[1].opline;
10508
0
        jit_SET_EX_OPLINE(jit, observer_opline);
10509
0
      } else {
10510
        // EX(opline) = opline
10511
0
        ir_STORE(jit_EX(opline), jit_IP(jit));
10512
0
      }
10513
0
      jit_observer_fcall_begin(jit, rx, observer_handler);
10514
10515
0
      zend_jit_check_timeout(jit, observer_opline, NULL);
10516
10517
0
      jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10518
0
    }
10519
10520
3.06k
    if (trace) {
10521
19
      if (!func && (opline->opcode != ZEND_DO_UCALL)) {
10522
2
        user_path = ir_END();
10523
2
      }
10524
3.04k
    } else {
10525
3.04k
      zend_basic_block *bb;
10526
10527
3.04k
      do {
10528
3.04k
        if (recursive_call_through_jmp) {
10529
0
          ir_ref begin, end;
10530
0
          ir_insn *insn;
10531
10532
          /* attempt to convert direct recursive call into loop */
10533
0
          begin = jit->bb_start_ref[num_args];
10534
0
          ZEND_ASSERT(begin != IR_UNUSED);
10535
0
          insn = &jit->ctx.ir_base[begin];
10536
0
          if (insn->op == IR_BEGIN) {
10537
0
            end = ir_LOOP_END();
10538
0
            insn = &jit->ctx.ir_base[begin];
10539
0
            insn->op = IR_LOOP_BEGIN;
10540
0
            insn->inputs_count = 2;
10541
0
            insn->op2 = end;
10542
0
            break;
10543
0
          } else if ((insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN)
10544
0
              && insn->inputs_count == 2) {
10545
0
            end = ir_LOOP_END();
10546
0
            insn = &jit->ctx.ir_base[begin];
10547
0
            insn->op = IR_LOOP_BEGIN;
10548
0
            insn->inputs_count = 3;
10549
0
            insn->op3 = end;
10550
0
            break;
10551
0
          }
10552
0
        }
10553
        /* fallback to indirect JMP or RETURN */
10554
3.04k
        if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
10555
3.04k
          zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
10556
3.04k
        } else {
10557
0
          zend_jit_vm_enter(jit, jit_IP(jit));
10558
0
        }
10559
3.04k
      } while (0);
10560
10561
3.04k
      bb = &jit->ssa->cfg.blocks[jit->b];
10562
3.04k
      if (bb->successors_count > 0) {
10563
3.04k
        int succ;
10564
3.04k
        ir_ref ref;
10565
10566
3.04k
        ZEND_ASSERT(bb->successors_count == 1);
10567
3.04k
        succ = bb->successors[0];
10568
        /* Add a fake control edge from UNREACHABLE/RETURN to the following ENTRY */
10569
3.04k
        ref = jit->ctx.insns_count - 1;
10570
3.04k
        ZEND_ASSERT(jit->ctx.ir_base[ref].op == IR_UNREACHABLE
10571
3.04k
          || jit->ctx.ir_base[ref].op == IR_RETURN
10572
3.04k
          || jit->ctx.ir_base[ref].op == IR_LOOP_END);
10573
3.04k
        ZEND_ASSERT(jit->ssa->cfg.blocks[succ].flags & ZEND_BB_ENTRY);
10574
3.04k
        ref = zend_jit_continue_entry(jit, ref, jit->ssa->cfg.blocks[succ].start);
10575
3.04k
        if (func || (opline->opcode == ZEND_DO_UCALL)) {
10576
27
          _zend_jit_add_predecessor_ref(jit, succ, jit->b, ref);
10577
27
          jit->b = -1;
10578
3.01k
        } else {
10579
3.01k
          user_path = ref;
10580
3.01k
        }
10581
3.04k
      }
10582
3.04k
    }
10583
3.06k
  }
10584
10585
3.63k
  if ((!func || func->type == ZEND_INTERNAL_FUNCTION)
10586
3.59k
   && (opline->opcode != ZEND_DO_UCALL)) {
10587
3.59k
    if (!func && (opline->opcode != ZEND_DO_ICALL)) {
10588
3.02k
      ir_IF_FALSE(if_user);
10589
3.02k
    }
10590
10591
    // JIT: EG(current_execute_data) = execute_data;
10592
3.59k
    ir_STORE(jit_EG(current_execute_data), rx);
10593
10594
3.59k
    bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10595
3.59k
    if (may_have_observer) {
10596
0
      ir_ref observer_handler;
10597
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)));
10598
0
      jit_observer_fcall_begin(jit, rx, observer_handler);
10599
0
      jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
10600
0
    }
10601
10602
    // JIT: ZVAL_NULL(EX_VAR(opline->result.var));
10603
3.59k
    ir_ref res_addr = IR_UNUSED, func_ptr;
10604
10605
3.59k
    if (RETURN_VALUE_USED(opline)) {
10606
299
      res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10607
3.29k
    } else {
10608
      /* CPU stack allocated temporary zval */
10609
3.29k
      ir_ref ptr;
10610
10611
3.29k
      if (!jit->ctx.fixed_call_stack_size) {
10612
        // JIT: alloca(sizeof(void*));
10613
0
        ptr = ir_ALLOCA(ir_CONST_ADDR(sizeof(zval)));
10614
3.29k
      } else {
10615
#ifdef _WIN64
10616
        ptr = ir_HARD_COPY_A(jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS));
10617
#else
10618
3.29k
        ptr = ir_HARD_COPY_A(ir_RLOAD_A(IR_REG_SP));
10619
3.29k
#endif
10620
3.29k
      }
10621
3.29k
      res_addr = ZEND_ADDR_REF_ZVAL(ptr);
10622
3.29k
    }
10623
10624
3.59k
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
10625
10626
3.59k
    zend_jit_reset_last_valid_opline(jit);
10627
10628
    // JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10629
3.59k
    ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10630
3.59k
    if (zend_execute_internal) {
10631
3.59k
      ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
10632
3.59k
    } else {
10633
0
      if (func) {
10634
0
        func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
10635
0
      } else {
10636
0
        func_ptr = ir_LOAD_A(ir_ADD_OFFSET(func_ref, offsetof(zend_internal_function, handler)));
10637
#if defined(IR_TARGET_X86)
10638
        func_ptr = ir_CAST_FC_FUNC(func_ptr);
10639
#endif
10640
0
      }
10641
0
      ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
10642
0
    }
10643
10644
3.59k
    if (may_have_observer) {
10645
0
      jit_observer_fcall_end(jit, rx, res_ref);
10646
0
    }
10647
10648
    /* When zend_interrupt_function is set, it gets called while
10649
     * the frame is still on top. This is less efficient than
10650
     * doing it later once it's popped off. There is code further
10651
     * down that handles when there isn't an interrupt function.
10652
     */
10653
3.59k
    if (zend_interrupt_function) {
10654
      // JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
10655
0
      ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
10656
0
      ir_IF_TRUE_cold(if_interrupt);
10657
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
10658
0
      ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
10659
0
    }
10660
10661
    // JIT: EG(current_execute_data) = execute_data;
10662
3.59k
    ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
10663
10664
    // JIT: zend_vm_stack_free_args(call);
10665
3.59k
    if (func && !unknown_num_args) {
10666
1.34k
      for (i = 0; i < call_num_args; i++ ) {
10667
775
        if (zend_jit_needs_arg_dtor(func, i, call_info)) {
10668
291
          uint32_t offset = EX_NUM_TO_VAR(i);
10669
291
          zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
10670
10671
291
          jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, false,
10672
291
                opline);
10673
291
        }
10674
775
      }
10675
3.02k
    } else {
10676
3.02k
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_vm_stack_free_args_helper), rx);
10677
3.02k
    }
10678
10679
3.59k
    if (may_have_extra_named_params) {
10680
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS))
10681
21
      ir_ref if_has_named = ir_IF(ir_AND_U8(
10682
21
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 3)),
10683
21
        ir_CONST_U8(ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24)));
10684
21
      ir_IF_TRUE_cold(if_has_named);
10685
10686
21
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_extra_named_params),
10687
21
        ir_LOAD_A(jit_CALL(rx, extra_named_params)));
10688
10689
21
      ir_MERGE_WITH_EMPTY_FALSE(if_has_named);
10690
21
    }
10691
10692
3.59k
    if (opline->opcode == ZEND_DO_FCALL) {
10693
      // TODO: optimize ???
10694
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS))
10695
3.59k
      ir_ref if_release_this = ir_IF(ir_AND_U8(
10696
3.59k
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10697
3.59k
        ir_CONST_U8(ZEND_CALL_RELEASE_THIS >> 16)));
10698
3.59k
      ir_IF_TRUE_cold(if_release_this);
10699
10700
      // JIT: OBJ_RELEASE(Z_OBJ(RX->This));
10701
3.59k
      jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_CALL(rx, This.value.obj)));
10702
10703
3.59k
      ir_MERGE_WITH_EMPTY_FALSE(if_release_this);
10704
3.59k
    }
10705
10706
10707
3.59k
    ir_ref allocated_path = IR_UNUSED;
10708
10709
3.59k
    if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
10710
186
        !JIT_G(current_frame) ||
10711
186
        !JIT_G(current_frame)->call ||
10712
186
        !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) ||
10713
182
        prev_opline->opcode == ZEND_SEND_UNPACK ||
10714
182
        prev_opline->opcode == ZEND_SEND_ARRAY ||
10715
3.41k
      prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) {
10716
10717
      // JIT: zend_vm_stack_free_call_frame(call);
10718
      // JIT: if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_ALLOCATED))
10719
3.41k
      ir_ref if_allocated = ir_IF(ir_AND_U8(
10720
3.41k
        ir_LOAD_U8(ir_ADD_OFFSET(rx, offsetof(zend_execute_data, This.u1.type_info) + 2)),
10721
3.41k
        ir_CONST_U8(ZEND_CALL_ALLOCATED >> 16)));
10722
3.41k
      ir_IF_TRUE_cold(if_allocated);
10723
10724
3.41k
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_free_call_frame), rx);
10725
10726
3.41k
      allocated_path = ir_END();
10727
3.41k
      ir_IF_FALSE(if_allocated);
10728
3.41k
    }
10729
10730
3.59k
    ir_STORE(jit_EG(vm_stack_top), rx);
10731
10732
3.59k
    if (allocated_path) {
10733
3.41k
      ir_MERGE_WITH(allocated_path);
10734
3.41k
    }
10735
10736
3.59k
    if (!RETURN_VALUE_USED(opline)) {
10737
3.29k
      zend_class_entry *ce;
10738
3.29k
      bool ce_is_instanceof;
10739
3.29k
      uint32_t func_info = call_info ?
10740
478
        zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) :
10741
3.29k
        (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN);
10742
10743
      /* If an exception is thrown, the return_value may stay at the
10744
       * original value of null. */
10745
3.29k
      func_info |= MAY_BE_NULL;
10746
10747
3.29k
      if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
10748
3.05k
        ir_ref sp;
10749
3.05k
        if (!jit->ctx.fixed_call_stack_size) {
10750
0
          sp = ir_RLOAD_A(IR_REG_SP);
10751
3.05k
        } else {
10752
#ifdef _WIN64
10753
          sp = jit_ADD_OFFSET(jit, ir_RLOAD_A(IR_REG_SP), IR_SHADOW_ARGS);
10754
#else
10755
3.05k
          sp = ir_RLOAD_A(IR_REG_SP);
10756
3.05k
#endif
10757
3.05k
        }
10758
3.05k
        res_addr = ZEND_ADDR_REF_ZVAL(sp);
10759
3.05k
        jit_ZVAL_PTR_DTOR(jit, res_addr, func_info, true, opline);
10760
3.05k
      }
10761
3.29k
      if (!jit->ctx.fixed_call_stack_size) {
10762
        // JIT: revert alloca
10763
0
        ir_AFREE(ir_CONST_ADDR(sizeof(zval)));
10764
0
      }
10765
3.29k
    }
10766
10767
    // JIT: if (UNEXPECTED(EG(exception) != NULL)) {
10768
3.59k
    ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
10769
3.59k
      jit_STUB_ADDR(jit, jit_stub_icall_throw));
10770
10771
    /* If there isn't a zend_interrupt_function, the timeout is
10772
     * handled here because it's more efficient.
10773
     */
10774
3.59k
    if (!zend_interrupt_function) {
10775
      // TODO: Can we avoid checking for interrupts after each call ???
10776
3.59k
      if (trace && jit->last_valid_opline != opline) {
10777
186
        int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
10778
10779
186
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10780
186
        if (!exit_addr) {
10781
0
          return 0;
10782
0
        }
10783
3.40k
      } else {
10784
3.40k
        exit_addr = NULL;
10785
3.40k
      }
10786
10787
3.59k
      zend_jit_check_timeout(jit, opline + 1, exit_addr);
10788
3.59k
    }
10789
10790
3.59k
    if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
10791
3.41k
      jit_LOAD_IP_ADDR(jit, opline + 1);
10792
3.41k
    } else if (trace
10793
184
     && trace->op == ZEND_JIT_TRACE_END
10794
0
     && trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
10795
0
      jit_LOAD_IP_ADDR(jit, opline + 1);
10796
0
    }
10797
3.59k
  }
10798
10799
3.63k
  if (user_path) {
10800
3.02k
    ir_MERGE_WITH(user_path);
10801
3.02k
  }
10802
10803
3.63k
  return 1;
10804
3.63k
}
10805
10806
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)
10807
86
{
10808
86
  ir_ref if_skip_constructor = jit_IF_ex(jit, jit_CMP_IP(jit, IR_NE, opline), next_block);
10809
10810
86
  ir_IF_FALSE(if_skip_constructor);
10811
10812
86
  if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
10813
0
    if (!zend_jit_tail_handler(jit, opline)) {
10814
0
      return 0;
10815
0
    }
10816
86
  } else {
10817
86
    if (!zend_jit_do_fcall(jit, opline, op_array, ssa, call_level, next_block, NULL)) {
10818
0
      return 0;
10819
0
    }
10820
86
  }
10821
10822
  /* override predecessors of the next block */
10823
86
  ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
10824
86
  if (!jit->ctx.control) {
10825
0
    ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
10826
0
    ir_IF_TRUE(if_skip_constructor);
10827
0
    ir_MERGE_2(jit->bb_edges[jit->bb_predecessors[next_block]], ir_END());
10828
0
    jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10829
86
  } else {
10830
86
    ZEND_ASSERT(!jit->bb_edges[jit->bb_predecessors[next_block]]);
10831
    /* merge current control path with the true branch of constructor skip condition */
10832
86
    ir_MERGE_WITH_EMPTY_TRUE(if_skip_constructor);
10833
86
    jit->bb_edges[jit->bb_predecessors[next_block]] = ir_END();
10834
10835
86
    jit->b = -1;
10836
86
  }
10837
10838
86
  return 1;
10839
86
}
10840
10841
static bool zend_jit_class_is_persistent(const zend_class_entry *ce)
10842
0
{
10843
0
  if (ce->type == ZEND_INTERNAL_CLASS) {
10844
#ifdef ZEND_OPCACHE_SHM_REATTACHMENT
10845
    /* ASLR, see zend_jit_may_be_modified() */
10846
    return false;
10847
#else
10848
0
    return true;
10849
0
#endif
10850
0
  }
10851
0
  return (ce->ce_flags & ZEND_ACC_IMMUTABLE) != 0;
10852
0
}
10853
10854
/* Checks whether a class "ce" always satisfies the type "type".
10855
 * This must take into account different requests.
10856
 * Checks against names of parents and interfaces. */
10857
static bool zend_jit_class_satisfies_type(const zend_class_entry *ce, zend_type type)
10858
13
{
10859
13
  const zend_type *single_type;
10860
10861
  /* Simplification: skip intersection types */
10862
13
  if (!ce || !zend_jit_class_is_persistent(ce) || ZEND_TYPE_IS_INTERSECTION(type)) {
10863
13
    return false;
10864
13
  }
10865
10866
0
  ZEND_TYPE_FOREACH(type, single_type) {
10867
    /* Intersection members of DNF types are not handled */
10868
0
    if (ZEND_TYPE_HAS_NAME(*single_type)) {
10869
0
      const zend_string *name = ZEND_TYPE_NAME(*single_type);
10870
10871
0
      for (const zend_class_entry *parent = ce; parent; parent = parent->parent) {
10872
0
        if (zend_string_equals_ci(parent->name, name)) {
10873
0
          return true;
10874
0
        }
10875
0
      }
10876
0
      for (uint32_t i = 0; i < ce->num_interfaces; i++) {
10877
0
        if (zend_string_equals_ci(ce->interfaces[i]->name, name)) {
10878
0
          return true;
10879
0
        }
10880
0
      }
10881
0
    }
10882
0
  } ZEND_TYPE_FOREACH_END();
10883
10884
0
  return false;
10885
0
}
10886
10887
/* Emit a fast path for an object of the known class "ce".
10888
 * Leaves the control flow in the "no match" path, and adds the matching path to "end_inputs". */
10889
static void zend_jit_known_class_type_fast_path(zend_jit_ctx *jit, ir_ref ref, bool is_object, const zend_class_entry *ce, ir_ref *end_inputs)
10890
0
{
10891
0
  ir_ref not_object = IR_UNUSED, if_ce;
10892
10893
0
  if (!is_object) {
10894
    // JIT: Z_TYPE_P(ref) == IS_OBJECT
10895
0
    ir_ref if_object = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(IS_OBJECT));
10896
0
    ir_IF_FALSE(if_object);
10897
0
    not_object = ir_END();
10898
0
    ir_IF_TRUE(if_object);
10899
0
  }
10900
10901
  // JIT: Z_OBJ_P(ref)->ce == ce
10902
0
  if_ce = ir_IF(ir_EQ(
10903
0
    ir_LOAD_A(ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_object, ce))),
10904
0
    ir_CONST_ADDR(ce)));
10905
0
  ir_IF_TRUE(if_ce);
10906
0
  ir_END_list(*end_inputs);
10907
10908
0
  ir_IF_FALSE(if_ce);
10909
0
  if (not_object) {
10910
0
    ir_MERGE_WITH(not_object);
10911
0
  }
10912
0
}
10913
10914
static int zend_jit_verify_arg_type(zend_jit_ctx *jit, const zend_op *opline, zend_arg_info *arg_info, bool check_exception, const zend_class_entry *known_ce)
10915
14
{
10916
14
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
10917
14
  uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
10918
14
  ir_ref ref, fast_path = IR_UNUSED, end_inputs = IR_UNUSED;
10919
14
  uint8_t type = IS_UNKNOWN;
10920
10921
14
  ref = jit_ZVAL_ADDR(jit, res_addr);
10922
14
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
10923
0
   && JIT_G(current_frame)
10924
0
   && JIT_G(current_frame)->prev) {
10925
0
    zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
10926
10927
0
    type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
10928
0
    if (type != IS_UNKNOWN && (type_mask & (1u << type))) {
10929
0
      return 1;
10930
0
    }
10931
0
  }
10932
10933
14
  if (!ZEND_ARG_SEND_MODE(arg_info)
10934
13
   && zend_jit_class_satisfies_type(known_ce, arg_info->type)) {
10935
0
    zend_jit_known_class_type_fast_path(jit, ref, type == IS_OBJECT, known_ce, &end_inputs);
10936
0
  }
10937
10938
14
  if (ZEND_ARG_SEND_MODE(arg_info)) {
10939
1
    if (opline->opcode == ZEND_RECV_INIT) {
10940
0
      ref = jit_ZVAL_DEREF_ref(jit, ref);
10941
1
    } else {
10942
1
      ref = jit_Z_PTR_ref(jit, ref);
10943
1
      ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
10944
1
    }
10945
1
  }
10946
10947
  /* A known type is not in type_mask here (see above), so the mask check would always fail */
10948
14
  if (type_mask != 0 && type == IS_UNKNOWN) {
10949
4
    if (is_power_of_two(type_mask)) {
10950
2
      uint32_t type_code = concrete_type(type_mask);
10951
2
      ir_ref if_ok = jit_if_Z_TYPE_ref(jit, ref, ir_CONST_U8(type_code));
10952
2
      ir_IF_TRUE(if_ok);
10953
2
      fast_path = ir_END();
10954
2
      ir_IF_FALSE_cold(if_ok);
10955
2
    } else {
10956
2
      ir_ref if_ok = ir_IF(ir_AND_U32(
10957
2
        ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE_ref(jit, ref)),
10958
2
        ir_CONST_U32(type_mask)));
10959
2
      ir_IF_TRUE(if_ok);
10960
2
      fast_path = ir_END();
10961
2
      ir_IF_FALSE_cold(if_ok);
10962
2
    }
10963
4
  }
10964
10965
14
  jit_SET_EX_OPLINE(jit, opline);
10966
14
  ref = ir_CALL_2(IR_BOOL, ir_CONST_FC_FUNC(zend_jit_verify_arg_slow),
10967
14
    ref, ir_CONST_ADDR(arg_info));
10968
10969
14
  if (check_exception) {
10970
14
    ir_GUARD(ref, jit_STUB_ADDR(jit, jit_stub_exception_handler));
10971
14
  }
10972
10973
14
  if (fast_path) {
10974
4
    ir_MERGE_WITH(fast_path);
10975
4
  }
10976
10977
14
  if (end_inputs) {
10978
0
    ir_END_list(end_inputs);
10979
0
    ir_MERGE_list(end_inputs);
10980
0
  }
10981
10982
14
  return 1;
10983
14
}
10984
10985
static int zend_jit_recv(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, const zend_class_entry *known_ce)
10986
14
{
10987
14
  uint32_t arg_num = opline->op1.num;
10988
14
  zend_arg_info *arg_info = NULL;
10989
10990
14
  if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
10991
14
    if (EXPECTED(arg_num <= op_array->num_args)) {
10992
14
      arg_info = &op_array->arg_info[arg_num-1];
10993
14
    } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) {
10994
0
      arg_info = &op_array->arg_info[op_array->num_args];
10995
0
    }
10996
14
    if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) {
10997
1
      arg_info = NULL;
10998
1
    }
10999
14
  }
11000
11001
14
  if (arg_info || (opline+1)->opcode != ZEND_RECV) {
11002
13
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11003
0
      if (!JIT_G(current_frame) ||
11004
0
          TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 ||
11005
0
          arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
11006
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
11007
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
11008
11009
0
        if (!exit_addr) {
11010
0
          return 0;
11011
0
        }
11012
0
        ir_GUARD(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)),
11013
0
          ir_CONST_ADDR(exit_addr));
11014
0
      }
11015
13
    } else {
11016
13
      ir_ref if_ok =ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
11017
13
      ir_IF_FALSE_cold(if_ok);
11018
11019
13
      jit_SET_EX_OPLINE(jit, opline);
11020
13
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_missing_arg_error), jit_FP(jit));
11021
13
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
11022
13
      ir_IF_TRUE(if_ok);
11023
13
    }
11024
13
  }
11025
11026
14
  if (arg_info) {
11027
13
    if (!zend_jit_verify_arg_type(jit, opline, arg_info, true, known_ce)) {
11028
0
      return 0;
11029
0
    }
11030
13
  }
11031
11032
14
  return 1;
11033
14
}
11034
11035
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)
11036
21
{
11037
21
  uint32_t arg_num = opline->op1.num;
11038
21
  zval *zv = RT_CONSTANT(opline, opline->op2);
11039
21
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11040
21
  ir_ref ref, if_fail, skip_path = IR_UNUSED;
11041
11042
21
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
11043
2
   && JIT_G(current_frame)
11044
2
   && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) {
11045
2
    if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) {
11046
2
      jit_ZVAL_COPY_CONST(jit,
11047
2
        res_addr,
11048
2
        -1, -1,
11049
2
        zv, true);
11050
2
    }
11051
19
  } else {
11052
19
    if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11053
19
        (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
11054
19
      ir_ref if_skip = ir_IF(ir_GE(ir_LOAD_U32(jit_EX(This.u2.num_args)), ir_CONST_U32(arg_num)));
11055
19
      ir_IF_TRUE(if_skip);
11056
19
      skip_path = ir_END();
11057
19
      ir_IF_FALSE(if_skip);
11058
19
    }
11059
19
    jit_ZVAL_COPY_CONST(jit,
11060
19
      res_addr,
11061
19
      -1, -1,
11062
19
      zv, true);
11063
19
  }
11064
11065
21
  if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
11066
18
    jit_SET_EX_OPLINE(jit, opline);
11067
18
    ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zval_update_constant_ex),
11068
18
      jit_ZVAL_ADDR(jit, res_addr),
11069
18
      ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), offsetof(zend_op_array, scope))));
11070
11071
18
    if_fail = ir_IF(ref);
11072
18
    ir_IF_TRUE_cold(if_fail);
11073
18
    jit_ZVAL_PTR_DTOR(jit, res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, true, opline);
11074
18
    ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
11075
18
    ir_IF_FALSE(if_fail);
11076
18
  }
11077
11078
21
  if (skip_path) {
11079
19
    ir_MERGE_WITH(skip_path);
11080
19
  }
11081
11082
21
  if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
11083
3
    do {
11084
3
      zend_arg_info *arg_info;
11085
11086
3
      if (arg_num <= op_array->num_args) {
11087
3
        arg_info = &op_array->arg_info[arg_num-1];
11088
3
      } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) {
11089
0
        arg_info = &op_array->arg_info[op_array->num_args];
11090
0
      } else {
11091
0
        break;
11092
0
      }
11093
3
      if (!ZEND_TYPE_IS_SET(arg_info->type)) {
11094
2
        break;
11095
2
      }
11096
1
      if (!zend_jit_verify_arg_type(jit, opline, arg_info, may_throw, NULL)) {
11097
0
        return 0;
11098
0
      }
11099
1
    } while (0);
11100
3
  }
11101
11102
21
  return 1;
11103
21
}
11104
11105
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, const zend_class_entry *known_ce)
11106
0
{
11107
0
  zend_arg_info *arg_info = &op_array->arg_info[-1];
11108
0
  ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type));
11109
0
  zend_jit_addr op1_addr = OP1_ADDR();
11110
0
  bool needs_slow_check = true;
11111
0
  uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY;
11112
0
  ir_ref fast_path = IR_UNUSED, end_inputs = IR_UNUSED;
11113
11114
0
  if ((op1_info & MAY_BE_OBJECT)
11115
0
   && !(type_mask & MAY_BE_OBJECT)
11116
0
   && Z_MODE(op1_addr) == IS_MEM_ZVAL
11117
0
   && zend_jit_class_satisfies_type(known_ce, arg_info->type)) {
11118
0
    zend_jit_known_class_type_fast_path(jit, jit_ZVAL_ADDR(jit, op1_addr),
11119
0
      (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT, known_ce, &end_inputs);
11120
0
  }
11121
11122
0
  if (type_mask != 0) {
11123
0
    if (((op1_info & MAY_BE_ANY) & type_mask) == 0) {
11124
      /* pass */
11125
0
    } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) {
11126
0
      needs_slow_check = false;
11127
0
    } else if (is_power_of_two(type_mask)) {
11128
0
      uint32_t type_code = concrete_type(type_mask);
11129
0
      ir_ref if_ok = jit_if_Z_TYPE(jit, op1_addr, type_code);
11130
11131
0
      ir_IF_TRUE(if_ok);
11132
0
      fast_path = ir_END();
11133
0
      ir_IF_FALSE_cold(if_ok);
11134
0
    } else {
11135
0
      ir_ref if_ok = ir_IF(ir_AND_U32(
11136
0
        ir_SHL_U32(ir_CONST_U32(1), jit_Z_TYPE(jit, op1_addr)),
11137
0
        ir_CONST_U32(type_mask)));
11138
11139
0
      ir_IF_TRUE(if_ok);
11140
0
      fast_path = ir_END();
11141
0
      ir_IF_FALSE_cold(if_ok);
11142
0
    }
11143
0
  }
11144
0
  if (needs_slow_check) {
11145
0
    ir_ref ref;
11146
11147
0
    jit_SET_EX_OPLINE(jit, opline);
11148
0
    ref = jit_ZVAL_ADDR(jit, op1_addr);
11149
0
    if (op1_info & MAY_BE_UNDEF) {
11150
0
      ref = zend_jit_zval_check_undef(jit, ref, opline->op1.var, NULL, true);
11151
0
    }
11152
11153
0
    ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_verify_return_slow),
11154
0
      ref,
11155
0
      ir_LOAD_A(jit_EX(func)),
11156
0
      ir_CONST_ADDR(arg_info));
11157
11158
0
    zend_jit_check_exception(jit);
11159
11160
0
    if (fast_path) {
11161
0
      ir_MERGE_WITH(fast_path);
11162
0
    }
11163
0
  }
11164
11165
0
  if (end_inputs) {
11166
0
    ir_END_list(end_inputs);
11167
0
    ir_MERGE_list(end_inputs);
11168
0
  }
11169
11170
0
  return true;
11171
0
}
11172
11173
static int zend_jit_leave_frame(zend_jit_ctx *jit)
11174
131
{
11175
  // JIT: EG(current_execute_data) = EX(prev_execute_data);
11176
131
  ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
11177
131
  return 1;
11178
131
}
11179
11180
static int zend_jit_free_cvs(zend_jit_ctx *jit)
11181
0
{
11182
  // JIT: EG(current_execute_data) = EX(prev_execute_data);
11183
0
  ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_EX(prev_execute_data)));
11184
11185
  // JIT: zend_free_compiled_variables(execute_data);
11186
0
  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_free_compiled_variables), jit_FP(jit));
11187
0
  return 1;
11188
0
}
11189
11190
static int zend_jit_free_cv(zend_jit_ctx *jit, uint32_t info, uint32_t var)
11191
91
{
11192
91
  if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11193
91
    zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var));
11194
11195
91
    jit_ZVAL_PTR_DTOR(jit, var_addr, info, true, NULL);
11196
91
  }
11197
91
  return 1;
11198
91
}
11199
11200
static int zend_jit_free_op(zend_jit_ctx *jit, const zend_op *opline, uint32_t info, uint32_t var_offset)
11201
0
{
11202
0
  if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11203
0
    jit_ZVAL_PTR_DTOR(jit, ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset), info, false, opline);
11204
0
  }
11205
0
  return 1;
11206
0
}
11207
11208
static int zend_jit_leave_func(zend_jit_ctx         *jit,
11209
                               const zend_op_array  *op_array,
11210
                               const zend_op        *opline,
11211
                               uint32_t              op1_info,
11212
                               bool             left_frame,
11213
                               zend_jit_trace_rec   *trace,
11214
                               zend_jit_trace_info  *trace_info,
11215
                               int                   indirect_var_access,
11216
                               int                   may_throw)
11217
143
{
11218
143
  bool may_be_top_frame =
11219
143
    JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11220
16
    !JIT_G(current_frame) ||
11221
16
    !TRACE_FRAME_IS_NESTED(JIT_G(current_frame));
11222
143
  bool may_need_call_helper =
11223
143
    indirect_var_access || /* may have symbol table */
11224
140
    !op_array->function_name || /* may have symbol table */
11225
140
    may_be_top_frame ||
11226
15
    (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */
11227
15
    JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11228
15
    !JIT_G(current_frame) ||
11229
15
    TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */
11230
15
    (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */
11231
143
  bool may_need_release_this =
11232
143
    !(op_array->fn_flags & ZEND_ACC_CLOSURE) &&
11233
105
    op_array->scope &&
11234
0
    !(op_array->fn_flags & ZEND_ACC_STATIC) &&
11235
0
    (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11236
0
     !JIT_G(current_frame) ||
11237
0
     !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame)));
11238
143
  ir_ref call_info = IR_UNUSED, ref, cold_path = IR_UNUSED;
11239
11240
143
  if (may_need_call_helper) {
11241
129
    if (!left_frame) {
11242
70
      left_frame = true;
11243
70
        if (!zend_jit_leave_frame(jit)) {
11244
0
        return 0;
11245
0
        }
11246
70
    }
11247
    /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */
11248
129
    call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11249
129
    ref = ir_AND_U32(call_info,
11250
129
      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));
11251
129
    if (trace && trace->op != ZEND_JIT_TRACE_END) {
11252
2
      ir_ref if_slow = ir_IF(ref);
11253
11254
2
      ir_IF_TRUE_cold(if_slow);
11255
2
      if (!GCC_GLOBAL_REGS) {
11256
2
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_leave_func_helper), jit_FP(jit), jit_IP(jit));
11257
2
      } else {
11258
0
        ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_leave_func_helper));
11259
0
      }
11260
11261
2
      if (may_be_top_frame) {
11262
        // TODO: try to avoid this check ???
11263
0
        if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
11264
#if 0
11265
          /* this check should be handled by the following OPLINE guard */
11266
          | cmp IP, zend_jit_halt_op
11267
          | je ->trace_halt
11268
#endif
11269
0
        } else if (GCC_GLOBAL_REGS) {
11270
0
          ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
11271
0
        } else {
11272
0
          ir_GUARD(ir_NE(ref, ir_CONST_ADDR(ZEND_VM_ENTER_BIT)), jit_STUB_ADDR(jit, jit_stub_trace_halt));
11273
0
          jit_STORE_IP(jit, ref);
11274
0
        }
11275
0
      }
11276
11277
2
      if (!GCC_GLOBAL_REGS) {
11278
        // execute_data = EG(current_execute_data)
11279
2
        jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data)));
11280
2
      }
11281
2
      cold_path = ir_END();
11282
2
      ir_IF_FALSE(if_slow);
11283
127
    } else {
11284
127
      ir_GUARD_NOT(ref, jit_STUB_ADDR(jit, jit_stub_leave_function_handler));
11285
127
    }
11286
129
  }
11287
11288
143
  if ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
11289
38
    if (!left_frame) {
11290
0
      left_frame = true;
11291
0
        if (!zend_jit_leave_frame(jit)) {
11292
0
        return 0;
11293
0
        }
11294
0
    }
11295
    // JIT: OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func)));
11296
38
    jit_OBJ_RELEASE(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(func)), -sizeof(zend_object)));
11297
105
  } else if (may_need_release_this) {
11298
0
    ir_ref if_release, fast_path = IR_UNUSED;
11299
11300
0
    if (!left_frame) {
11301
0
      left_frame = true;
11302
0
        if (!zend_jit_leave_frame(jit)) {
11303
0
        return 0;
11304
0
        }
11305
0
    }
11306
0
    if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) {
11307
      // JIT: if (call_info & ZEND_CALL_RELEASE_THIS)
11308
0
      if (!call_info) {
11309
0
        call_info = ir_LOAD_U32(jit_EX(This.u1.type_info));
11310
0
      }
11311
0
      if_release = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_RELEASE_THIS)));
11312
0
      ir_IF_FALSE(if_release);
11313
0
      fast_path = ir_END();
11314
0
      ir_IF_TRUE(if_release);
11315
0
    }
11316
    // JIT: OBJ_RELEASE(execute_data->This))
11317
0
    jit_OBJ_RELEASE(jit, ir_LOAD_A(jit_EX(This.value.obj)));
11318
0
    if (fast_path) {
11319
0
      ir_MERGE_WITH(fast_path);
11320
0
    }
11321
    // TODO: avoid EG(exception) check for $this->foo() calls
11322
0
    may_throw = 1;
11323
0
  }
11324
11325
  // JIT: EG(vm_stack_top) = (zval*)execute_data
11326
143
  ir_STORE(jit_EG(vm_stack_top), jit_FP(jit));
11327
11328
  // JIT: execute_data = EX(prev_execute_data)
11329
143
  jit_STORE_FP(jit, ir_LOAD_A(jit_EX(prev_execute_data)));
11330
11331
143
  if (!left_frame) {
11332
    // JIT: EG(current_execute_data) = execute_data
11333
12
    ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
11334
12
  }
11335
11336
143
  if (trace) {
11337
16
    if (trace->op != ZEND_JIT_TRACE_END
11338
16
     && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11339
16
      zend_jit_reset_last_valid_opline(jit);
11340
16
    } else {
11341
      /* We add extra RLOAD and RSTORE to make fusion for persistent register
11342
       *     mov (%FP), %IP
11343
       *     add $0x1c, %IP
11344
       * The naive (commented) code leads to extra register allocation and move.
11345
       *     mov (%FP), %tmp
11346
       *     add $0x1c, %tmp
11347
       *     mov %tmp, %FP
11348
       */
11349
#if 0
11350
      jit_STORE_IP(jit, ir_ADD_OFFSET(ir_LOAD_A(jit_EX(opline)), sizeof(zend_op)));
11351
#else
11352
0
      jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11353
0
      jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11354
0
#endif
11355
0
    }
11356
11357
16
    if (cold_path) {
11358
2
      ir_MERGE_WITH(cold_path);
11359
2
    }
11360
11361
16
    if (trace->op == ZEND_JIT_TRACE_BACK
11362
16
     && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) {
11363
0
      const zend_op *next_opline = trace->opline;
11364
11365
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11366
0
       && (op1_info & MAY_BE_RC1)
11367
0
       && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
11368
        /* exception might be thrown during destruction of unused return value */
11369
        // JIT: if (EG(exception))
11370
0
        ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11371
0
      }
11372
0
      do {
11373
0
        trace++;
11374
0
      } while (trace->op == ZEND_JIT_TRACE_INIT_CALL);
11375
0
      ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
11376
0
      next_opline = trace->opline;
11377
0
      ZEND_ASSERT(next_opline != NULL);
11378
11379
0
      if (trace->op == ZEND_JIT_TRACE_END
11380
0
       && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
11381
0
        trace_info->flags |= ZEND_JIT_TRACE_LOOP;
11382
11383
0
        ir_ref if_eq = ir_IF(jit_CMP_IP(jit, IR_EQ, next_opline));
11384
11385
0
        ir_IF_TRUE(if_eq);
11386
0
        ZEND_ASSERT(jit->trace_loop_ref);
11387
0
        ZEND_ASSERT(jit->ctx.ir_base[jit->trace_loop_ref].op2 == IR_UNUSED);
11388
0
        ir_MERGE_SET_OP(jit->trace_loop_ref, 2, ir_END());
11389
0
        ir_IF_FALSE(if_eq);
11390
11391
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
11392
        ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
11393
#else
11394
0
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_escape));
11395
0
#endif
11396
0
      } else {
11397
0
        ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), jit_STUB_ADDR(jit, jit_stub_trace_escape));
11398
0
      }
11399
11400
0
      zend_jit_set_last_valid_opline(jit, trace->opline);
11401
11402
0
      return 1;
11403
16
    } else if (may_throw ||
11404
13
        (((opline->op1_type & (IS_VAR|IS_TMP_VAR))
11405
0
          && (op1_info & MAY_BE_RC1)
11406
0
          && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
11407
3
         && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) {
11408
      // JIT: if (EG(exception))
11409
3
      ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11410
3
    }
11411
11412
16
    return 1;
11413
127
  } else {
11414
    // JIT: if (EG(exception))
11415
127
    ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw));
11416
    // JIT: opline = EX(opline) + 1
11417
127
    jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline)));
11418
127
    jit_STORE_IP(jit, ir_ADD_OFFSET(jit_IP(jit), sizeof(zend_op)));
11419
127
  }
11420
11421
127
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
11422
127
    zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
11423
127
  } else {
11424
0
    zend_jit_vm_leave(jit, jit_IP(jit));
11425
0
  }
11426
11427
127
  jit->b = -1;
11428
11429
127
  return 1;
11430
143
}
11431
11432
static void zend_jit_common_return(zend_jit_ctx *jit)
11433
127
{
11434
127
  ZEND_ASSERT(jit->return_inputs);
11435
127
  ir_MERGE_list(jit->return_inputs);
11436
127
}
11437
11438
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)
11439
143
{
11440
143
  zend_jit_addr ret_addr;
11441
143
  int8_t return_value_used = -1;
11442
143
  ir_ref return_value = IR_UNUSED, ref, refcount, if_return_value_used = IR_UNUSED;
11443
11444
143
  ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name);
11445
143
  ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF));
11446
11447
143
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11448
16
    jit->return_inputs = IR_UNUSED;
11449
16
    if (JIT_G(current_frame)) {
11450
16
      if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
11451
0
        return_value_used = 1;
11452
16
      } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) {
11453
16
        return_value_used = 0;
11454
16
      } else {
11455
0
        return_value_used = -1;
11456
0
      }
11457
16
    }
11458
16
  }
11459
11460
143
  if (ZEND_OBSERVER_ENABLED) {
11461
0
    if (Z_MODE(op1_addr) == IS_REG) {
11462
0
      zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
11463
11464
0
      if (!zend_jit_spill_store_inv(jit, op1_addr, dst, op1_info)) {
11465
0
        return 0;
11466
0
      }
11467
0
      op1_addr = dst;
11468
0
    }
11469
0
    jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
11470
0
  }
11471
11472
  // JIT: if (!EX(return_value))
11473
143
  return_value = ir_LOAD_A(jit_EX(return_value));
11474
143
  ret_addr = ZEND_ADDR_REF_ZVAL(return_value);
11475
143
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) &&
11476
8
      (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11477
6
    if (return_value_used == -1) {
11478
6
      if_return_value_used = ir_IF(return_value);
11479
6
      ir_IF_FALSE_cold(if_return_value_used);
11480
6
    }
11481
6
    if (return_value_used != 1) {
11482
6
      if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11483
6
        ir_ref if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11484
6
        ir_IF_FALSE(if_refcounted);
11485
6
        ir_END_list(jit->return_inputs);
11486
6
        ir_IF_TRUE(if_refcounted);
11487
6
      }
11488
6
      ref = jit_Z_PTR(jit, op1_addr);
11489
6
      refcount = jit_GC_DELREF(jit, ref);
11490
11491
6
      if (RC_MAY_BE_1(op1_info)) {
11492
6
        if (RC_MAY_BE_N(op1_info)) {
11493
2
          ir_ref if_non_zero = ir_IF(refcount);
11494
2
          ir_IF_TRUE(if_non_zero);
11495
2
          ir_END_list(jit->return_inputs);
11496
2
          ir_IF_FALSE(if_non_zero);
11497
2
        }
11498
6
        jit_ZVAL_DTOR(jit, ref, op1_info, opline);
11499
6
      }
11500
6
      if (return_value_used == -1) {
11501
6
        ir_END_list(jit->return_inputs);
11502
6
      }
11503
6
    }
11504
137
  } else if (return_value_used == -1) {
11505
121
    if_return_value_used = ir_IF(return_value);
11506
121
    ir_IF_FALSE_cold(if_return_value_used);
11507
121
    ir_END_list(jit->return_inputs);
11508
121
  }
11509
11510
143
  if (if_return_value_used) {
11511
127
    ir_IF_TRUE(if_return_value_used);
11512
127
  }
11513
11514
143
  if (return_value_used == 0) {
11515
16
    if (jit->return_inputs) {
11516
0
      ZEND_ASSERT(JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE);
11517
0
      ir_END_list(jit->return_inputs);
11518
0
      ir_MERGE_list(jit->return_inputs);
11519
0
      jit->return_inputs = IR_UNUSED;
11520
0
    }
11521
16
    return 1;
11522
16
  }
11523
11524
127
  if (opline->op1_type == IS_CONST) {
11525
119
    zval *zv = RT_CONSTANT(opline, opline->op1);
11526
11527
119
    jit_ZVAL_COPY_CONST(jit, ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, true);
11528
119
  } else if (opline->op1_type == IS_TMP_VAR) {
11529
8
    jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11530
8
  } else if (opline->op1_type == IS_CV) {
11531
0
    if (op1_info & MAY_BE_REF) {
11532
0
      ref = jit_ZVAL_ADDR(jit, op1_addr);
11533
0
      ref = jit_ZVAL_DEREF_ref(jit, ref);
11534
0
      op1_addr = ZEND_ADDR_REF_ZVAL(ref);
11535
0
    }
11536
11537
0
    if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
11538
0
      if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE ||
11539
0
          (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) ||
11540
0
          !op_array->function_name) {
11541
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, true);
11542
0
      } else if (return_value_used != 1) {
11543
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11544
        // JIT: if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr);
11545
0
        jit_set_Z_TYPE_INFO(jit, op1_addr, IS_NULL);
11546
0
      } else {
11547
0
        jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11548
0
      }
11549
0
    } else {
11550
0
      jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11551
0
    }
11552
0
  } else {
11553
0
    if (op1_info & MAY_BE_REF) {
11554
0
      ir_ref if_ref, ref2, if_non_zero;
11555
0
      zend_jit_addr ref_addr;
11556
11557
0
      if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
11558
0
      ir_IF_TRUE_cold(if_ref);
11559
11560
      // JIT: zend_refcounted *ref = Z_COUNTED_P(retval_ptr)
11561
0
      ref = jit_Z_PTR(jit, op1_addr);
11562
11563
      // JIT: ZVAL_COPY_VALUE(return_value, &ref->value)
11564
0
      ref2 = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
11565
0
      ref_addr = ZEND_ADDR_REF_ZVAL(ref2);
11566
0
      jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, ref_addr, op1_info, false);
11567
0
      ref2 = jit_GC_DELREF(jit, ref);
11568
0
      if_non_zero = ir_IF(ref2);
11569
0
      ir_IF_TRUE(if_non_zero);
11570
11571
      // JIT: if (IS_REFCOUNTED())
11572
0
      ir_ref if_refcounted = jit_if_REFCOUNTED(jit, ret_addr);
11573
0
      ir_IF_FALSE(if_refcounted);
11574
0
      ir_END_list(jit->return_inputs);
11575
0
      ir_IF_TRUE(if_refcounted);
11576
11577
      // JIT: ADDREF
11578
0
      ref2 = jit_Z_PTR(jit, ret_addr);
11579
0
      jit_GC_ADDREF(jit, ref2);
11580
0
      ir_END_list(jit->return_inputs);
11581
11582
0
      ir_IF_FALSE(if_non_zero);
11583
11584
0
      jit_EFREE(jit, ref, sizeof(zend_reference), op_array, opline);
11585
0
      ir_END_list(jit->return_inputs);
11586
11587
0
      ir_IF_FALSE(if_ref);
11588
0
    }
11589
0
    jit_ZVAL_COPY(jit, ret_addr, MAY_BE_ANY, op1_addr, op1_info, false);
11590
0
  }
11591
11592
127
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
11593
0
    if (jit->return_inputs) {
11594
0
      ir_END_list(jit->return_inputs);
11595
0
      ir_MERGE_list(jit->return_inputs);
11596
0
      jit->return_inputs = IR_UNUSED;
11597
0
    }
11598
127
  } else {
11599
127
    ir_END_list(jit->return_inputs);
11600
127
    jit->b = -1;
11601
127
  }
11602
11603
127
  return 1;
11604
143
}
11605
11606
static int zend_jit_bind_global(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11607
4
{
11608
4
  zend_jit_addr op1_addr = OP1_ADDR();
11609
4
  zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2));
11610
4
  ir_ref cache_slot_ref, idx_ref, num_used_ref, bucket_ref, ref, ref2;
11611
4
  ir_ref if_fit, if_reference, if_same_key, fast_path;
11612
4
  ir_ref slow_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
11613
11614
  // JIT: idx = (uintptr_t)CACHED_PTR(opline->extended_value) - 1;
11615
4
  cache_slot_ref = ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), opline->extended_value);
11616
4
  idx_ref = ir_SUB_A(ir_LOAD_A(cache_slot_ref), ir_CONST_ADDR(1));
11617
11618
  // JIT: if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket)))
11619
4
  num_used_ref = ir_MUL_U32(ir_LOAD_U32(jit_EG(symbol_table.nNumUsed)),
11620
4
    ir_CONST_U32(sizeof(Bucket)));
11621
4
  if (sizeof(void*) == 8) {
11622
4
    num_used_ref = ir_ZEXT_A(num_used_ref);
11623
4
  }
11624
4
  if_fit = ir_IF(ir_ULT(idx_ref, num_used_ref));
11625
4
  ir_IF_FALSE_cold(if_fit);
11626
4
  ir_END_list(slow_inputs);
11627
4
  ir_IF_TRUE(if_fit);
11628
11629
  // JIT: Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx);
11630
4
  bucket_ref = ir_ADD_A(ir_LOAD_A(jit_EG(symbol_table.arData)), idx_ref);
11631
4
  if_reference = jit_if_Z_TYPE_ref(jit, bucket_ref, ir_CONST_U8(IS_REFERENCE));
11632
4
  ir_IF_FALSE_cold(if_reference);
11633
4
  ir_END_list(slow_inputs);
11634
4
  ir_IF_TRUE(if_reference);
11635
11636
  // JIT: (EXPECTED(p->key == varname))
11637
4
  if_same_key = ir_IF(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(bucket_ref, offsetof(Bucket, key))), ir_CONST_ADDR(varname)));
11638
4
  ir_IF_FALSE_cold(if_same_key);
11639
4
  ir_END_list(slow_inputs);
11640
4
  ir_IF_TRUE(if_same_key);
11641
11642
  // JIT: GC_ADDREF(Z_PTR(p->val))
11643
4
  ref = jit_Z_PTR_ref(jit, bucket_ref);
11644
4
  jit_GC_ADDREF(jit, ref);
11645
11646
4
  fast_path = ir_END();
11647
4
  ir_MERGE_list(slow_inputs);
11648
11649
4
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_global_helper),
11650
4
    ir_CONST_ADDR(varname),
11651
4
    cache_slot_ref);
11652
11653
4
  ir_MERGE_WITH(fast_path);
11654
4
  ref = ir_PHI_2(IR_ADDR, ref2, ref);
11655
11656
4
  if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11657
4
    ir_ref if_refcounted = IR_UNUSED, refcount, if_non_zero, if_may_not_leak;
11658
11659
4
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11660
      // JIT: if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr)))
11661
4
      if_refcounted = jit_if_REFCOUNTED(jit, op1_addr);
11662
4
      ir_IF_TRUE_cold(if_refcounted);
11663
4
    }
11664
11665
    // JIT:zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
11666
4
    ref2 = jit_Z_PTR(jit, op1_addr);
11667
11668
    // JIT: ZVAL_REF(variable_ptr, ref)
11669
4
    jit_set_Z_PTR(jit, op1_addr, ref);
11670
4
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11671
11672
    // JIT: if (GC_DELREF(garbage) == 0)
11673
4
    refcount = jit_GC_DELREF(jit, ref2);
11674
4
    if_non_zero = ir_IF(refcount);
11675
4
    if (!(op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
11676
2
      ir_IF_TRUE(if_non_zero);
11677
2
      ir_END_list(end_inputs);
11678
2
    }
11679
4
    ir_IF_FALSE(if_non_zero);
11680
11681
4
    jit_ZVAL_DTOR(jit, ref2, op1_info, opline);
11682
4
    if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) {
11683
2
      ir_END_list(end_inputs);
11684
2
      ir_IF_TRUE(if_non_zero);
11685
11686
      // JIT: GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr)
11687
2
      if_may_not_leak = jit_if_GC_MAY_NOT_LEAK(jit, ref2);
11688
2
      ir_IF_TRUE(if_may_not_leak);
11689
2
      ir_END_list(end_inputs);
11690
2
      ir_IF_FALSE(if_may_not_leak);
11691
2
      if (opline) {
11692
2
        jit_SET_EX_OPLINE(jit, opline);
11693
2
      }
11694
2
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(gc_possible_root), ref2);
11695
2
    }
11696
4
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11697
4
      ir_END_list(end_inputs);
11698
4
      ir_IF_FALSE(if_refcounted);
11699
4
    }
11700
4
  }
11701
11702
4
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
11703
    // JIT: ZVAL_REF(variable_ptr, ref)
11704
4
    jit_set_Z_PTR(jit, op1_addr, ref);
11705
4
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_REFERENCE_EX);
11706
4
  }
11707
11708
4
  if (end_inputs) {
11709
4
    ir_END_list(end_inputs);
11710
4
    ir_MERGE_list(end_inputs);
11711
4
  }
11712
11713
4
  return 1;
11714
4
}
11715
11716
static int zend_jit_free(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, int may_throw)
11717
5.33k
{
11718
5.33k
  zend_jit_addr op1_addr = OP1_ADDR();
11719
11720
5.33k
  if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
11721
5.22k
    if (may_throw) {
11722
5.17k
      jit_SET_EX_OPLINE(jit, opline);
11723
5.17k
    }
11724
5.22k
    if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) {
11725
2
      ir_ref ref, if_array, if_exists, end_inputs = IR_UNUSED;
11726
11727
2
      if (op1_info & MAY_BE_ARRAY) {
11728
2
        if_array = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
11729
2
        ir_IF_TRUE(if_array);
11730
2
        ir_END_list(end_inputs);
11731
2
        ir_IF_FALSE(if_array);
11732
2
      }
11733
2
      ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_iter_idx)));
11734
2
      if_exists = ir_IF(ir_EQ(ref, ir_CONST_U32(-1)));
11735
2
      ir_IF_TRUE(if_exists);
11736
2
      ir_END_list(end_inputs);
11737
2
      ir_IF_FALSE(if_exists);
11738
11739
2
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_hash_iterator_del), ref);
11740
11741
2
      ir_END_list(end_inputs);
11742
2
      ir_MERGE_list(end_inputs);
11743
2
    }
11744
11745
5.22k
    jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, false, opline);
11746
11747
5.22k
    if (may_throw) {
11748
5.17k
      zend_jit_check_exception(jit);
11749
5.17k
    }
11750
5.22k
  }
11751
11752
5.33k
  return 1;
11753
5.33k
}
11754
11755
static int zend_jit_echo(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
11756
5.57k
{
11757
5.57k
  if (opline->op1_type == IS_CONST) {
11758
5.57k
    zval *zv;
11759
5.57k
    size_t len;
11760
11761
5.57k
    zv = RT_CONSTANT(opline, opline->op1);
11762
5.57k
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11763
5.57k
    len = Z_STRLEN_P(zv);
11764
11765
5.57k
    if (len > 0) {
11766
5.56k
      const char *str = Z_STRVAL_P(zv);
11767
11768
5.56k
      jit_SET_EX_OPLINE(jit, opline);
11769
5.56k
      ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11770
5.56k
        ir_CONST_ADDR(str), ir_CONST_ADDR(len));
11771
11772
5.56k
      zend_jit_check_exception(jit);
11773
5.56k
    }
11774
5.57k
  } else {
11775
3
    zend_jit_addr op1_addr = OP1_ADDR();
11776
3
    ir_ref ref;
11777
11778
3
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11779
11780
3
    jit_SET_EX_OPLINE(jit, opline);
11781
11782
3
    ref = jit_Z_PTR(jit, op1_addr);
11783
3
    ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_write),
11784
3
      ir_ADD_OFFSET(ref, offsetof(zend_string, val)),
11785
3
      ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_string, len))));
11786
11787
3
    if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
11788
3
      jit_ZVAL_PTR_DTOR(jit, op1_addr, op1_info, false, opline);
11789
3
    }
11790
11791
3
    zend_jit_check_exception(jit);
11792
3
  }
11793
5.57k
  return 1;
11794
5.57k
}
11795
11796
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)
11797
0
{
11798
0
  if (opline->op1_type == IS_CONST) {
11799
0
    zval *zv;
11800
0
    size_t len;
11801
11802
0
    zv = RT_CONSTANT(opline, opline->op1);
11803
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11804
0
    len = Z_STRLEN_P(zv);
11805
11806
0
    jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(len));
11807
0
    if (Z_MODE(res_addr) != IS_REG) {
11808
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11809
0
    } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11810
0
      return 0;
11811
0
    }
11812
0
  } else {
11813
0
    ir_ref ref;
11814
11815
0
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11816
11817
0
    ref = jit_Z_PTR(jit, op1_addr);
11818
0
    ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(zend_string, len)));
11819
0
    jit_set_Z_LVAL(jit, res_addr, ref);
11820
11821
0
    if (Z_MODE(res_addr) == IS_REG) {
11822
0
      if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11823
0
        return 0;
11824
0
      }
11825
0
    } else {
11826
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11827
0
    }
11828
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11829
0
  }
11830
0
  return 1;
11831
0
}
11832
11833
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)
11834
0
{
11835
0
  if (opline->op1_type == IS_CONST) {
11836
0
    zval *zv;
11837
0
    zend_long count;
11838
11839
0
    zv = RT_CONSTANT(opline, opline->op1);
11840
0
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY);
11841
0
    count = zend_hash_num_elements(Z_ARRVAL_P(zv));
11842
11843
0
    jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(count));
11844
0
    if (Z_MODE(res_addr) != IS_REG) {
11845
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11846
0
    } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11847
0
      return 0;
11848
0
    }
11849
0
  } else {
11850
0
    ir_ref ref;
11851
11852
0
    ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY);
11853
    // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+.
11854
11855
0
    ref = jit_Z_PTR(jit, op1_addr);
11856
0
    if (sizeof(void*) == 8) {
11857
0
      ref = ir_LOAD_U32(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11858
0
      ref = ir_ZEXT_L(ref);
11859
0
    } else {
11860
0
      ref = ir_LOAD_L(ir_ADD_OFFSET(ref, offsetof(HashTable, nNumOfElements)));
11861
0
    }
11862
0
    jit_set_Z_LVAL(jit, res_addr, ref);
11863
11864
0
    if (Z_MODE(res_addr) == IS_REG) {
11865
0
      if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, MAY_BE_LONG)) {
11866
0
        return 0;
11867
0
      }
11868
0
    } else {
11869
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
11870
0
    }
11871
0
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
11872
0
  }
11873
11874
0
  if (may_throw) {
11875
0
    zend_jit_check_exception(jit);
11876
0
  }
11877
0
  return 1;
11878
0
}
11879
11880
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)
11881
0
{
11882
0
  HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
11883
0
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
11884
0
  ir_ref ref;
11885
11886
0
  ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR);
11887
0
  ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING);
11888
11889
  // JIT: result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST);
11890
0
  if (opline->op1_type != IS_CONST) {
11891
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find),
11892
0
      ir_CONST_ADDR(ht),
11893
0
      jit_Z_PTR(jit, op1_addr));
11894
0
  } else {
11895
0
    zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1));
11896
11897
0
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash),
11898
0
      ir_CONST_ADDR(ht), ir_CONST_ADDR(str));
11899
0
  }
11900
11901
0
  if (exit_addr) {
11902
0
    if (smart_branch_opcode == ZEND_JMPZ) {
11903
0
      ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
11904
0
    } else {
11905
0
      ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
11906
0
    }
11907
0
  } else if (smart_branch_opcode) {
11908
0
    zend_basic_block *bb;
11909
11910
0
    ZEND_ASSERT(jit->b >= 0);
11911
0
    bb = &jit->ssa->cfg.blocks[jit->b];
11912
0
    ZEND_ASSERT(bb->successors_count == 2);
11913
0
    ref = jit_IF_ex(jit, ref,
11914
0
      (smart_branch_opcode == ZEND_JMPZ) ? target_label2 : target_label);
11915
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
11916
0
    _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ref);
11917
0
    jit->b = -1;
11918
0
  } else {
11919
0
    jit_set_Z_TYPE_INFO_ex(jit, res_addr,
11920
0
      ir_ADD_U32(ir_ZEXT_U32(ir_NE(ref, IR_NULL)), ir_CONST_U32(IS_FALSE)));
11921
0
  }
11922
11923
0
  return 1;
11924
0
}
11925
11926
static int zend_jit_rope(zend_jit_ctx *jit, const zend_op *opline, uint32_t op2_info)
11927
303
{
11928
303
  uint32_t offset;
11929
11930
303
  offset = (opline->opcode == ZEND_ROPE_INIT) ?
11931
105
    opline->result.var :
11932
303
    opline->op1.var + opline->extended_value * sizeof(zend_string*);
11933
11934
303
  if (opline->op2_type == IS_CONST) {
11935
303
    zval *zv = RT_CONSTANT(opline, opline->op2);
11936
303
    zend_string *str;
11937
11938
303
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
11939
303
    str = Z_STR_P(zv);
11940
11941
303
    ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ir_CONST_ADDR(str));
11942
303
  } else {
11943
0
    zend_jit_addr op2_addr = OP2_ADDR();
11944
0
    ir_ref ref;
11945
11946
0
    ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING);
11947
11948
0
    ref = jit_Z_PTR(jit, op2_addr);
11949
0
    ir_STORE(ir_ADD_OFFSET(jit_FP(jit), offset), ref);
11950
0
    if (opline->op2_type == IS_CV) {
11951
0
      ir_ref if_refcounted, long_path;
11952
11953
0
      if_refcounted = jit_if_REFCOUNTED(jit, op2_addr);
11954
0
      ir_IF_TRUE(if_refcounted);
11955
0
      jit_GC_ADDREF(jit, ref);
11956
0
      long_path = ir_END();
11957
11958
0
      ir_IF_FALSE(if_refcounted);
11959
0
      ir_MERGE_WITH(long_path);
11960
0
    }
11961
0
  }
11962
11963
303
  if (opline->opcode == ZEND_ROPE_END) {
11964
92
    zend_jit_addr res_addr = RES_ADDR();
11965
92
    ir_ref ref;
11966
11967
92
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_rope_end),
11968
92
      ir_ADD_OFFSET(jit_FP(jit), opline->op1.var),
11969
92
      ir_CONST_U32(opline->extended_value));
11970
11971
92
    jit_set_Z_PTR(jit, res_addr, ref);
11972
92
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
11973
92
  }
11974
11975
303
  return 1;
11976
303
}
11977
11978
/* If exit_addr is set, the value may also be IS_UNDEF */
11979
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, const void *exit_addr)
11980
0
{
11981
0
  ir_ref if_type, val;
11982
11983
0
  if (res_info == MAY_BE_LONG) {
11984
0
    if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_LONG)));
11985
0
  } else if (res_info == MAY_BE_DOUBLE) {
11986
0
    if_type = ir_IF(ir_EQ(type, ir_CONST_U32(IS_DOUBLE)));
11987
0
  } else {
11988
0
    ZEND_UNREACHABLE();
11989
0
  }
11990
0
  ir_IF_TRUE(if_type);
11991
0
  val = jit_ZVAL_ADDR(jit, val_addr);
11992
0
  ir_END_PHI_list(*values, val);
11993
0
  ir_IF_FALSE(if_type);
11994
0
  if (exit_addr) {
11995
0
    ir_GUARD(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)), ir_CONST_ADDR(exit_addr));
11996
0
  }
11997
0
  val = ir_ADD_OFFSET(jit_Z_PTR(jit, val_addr), offsetof(zend_reference, val));
11998
0
  ir_END_PHI_list(*values, val);
11999
0
  return 1;
12000
0
}
12001
12002
static int zend_jit_zval_copy_deref(zend_jit_ctx *jit, zend_jit_addr res_addr, zend_jit_addr val_addr, ir_ref type)
12003
473
{
12004
473
  ir_ref if_refcounted, if_reference, if_refcounted2, ptr, val2, ptr2, type2;
12005
473
  ir_refs *merge_inputs, *types, *ptrs;
12006
#if SIZEOF_ZEND_LONG == 4
12007
  ir_ref val = jit_ZVAL_ADDR(jit, val_addr);
12008
  ir_refs *values; /* we need this only for zval.w2 copy */
12009
#endif
12010
12011
473
  ir_refs_init(merge_inputs, 4);
12012
473
  ir_refs_init(types, 4);
12013
473
  ir_refs_init(ptrs, 4);
12014
#if SIZEOF_ZEND_LONG == 4
12015
  ir_refs_init(values, 4);
12016
#endif
12017
12018
  // JIT: ptr = Z_PTR_P(val);
12019
473
  ptr = jit_Z_PTR(jit, val_addr);
12020
12021
  // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
12022
473
  if_refcounted = ir_IF(ir_AND_U32(type, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
12023
473
  ir_IF_FALSE_cold(if_refcounted);
12024
473
  ir_refs_add(merge_inputs, ir_END());
12025
473
  ir_refs_add(types, type);
12026
473
  ir_refs_add(ptrs, ptr);
12027
#if SIZEOF_ZEND_LONG == 4
12028
  ir_refs_add(values, val);
12029
#endif
12030
12031
473
  ir_IF_TRUE(if_refcounted);
12032
12033
  // JIT: if (UNEXPECTED(Z_OPT_ISREF_P(val))) {
12034
473
  if_reference = ir_IF(ir_EQ(type, ir_CONST_U32(IS_REFERENCE_EX)));
12035
//  if_reference = ir_IF(ir_EQ(ir_TRUNC_U8(type), ir_CONST_U8(IS_REFERENCE))); // TODO: fix IR to avoid need for extra register ???
12036
473
  ir_IF_TRUE(if_reference);
12037
12038
  // JIT: val = Z_REFVAL_P(val);
12039
473
  val2 = ir_ADD_OFFSET(ptr, offsetof(zend_reference, val));
12040
473
  type2 = jit_Z_TYPE_INFO_ref(jit, val2);
12041
473
  ptr2 = jit_Z_PTR_ref(jit, val2);
12042
12043
  // JIT: if (Z_OPT_REFCOUNTED_P(val)) {
12044
473
  if_refcounted2 = ir_IF(ir_AND_U32(type2, ir_CONST_U32(Z_TYPE_FLAGS_MASK)));
12045
473
  ir_IF_FALSE_cold(if_refcounted2);
12046
473
  ir_refs_add(merge_inputs, ir_END());
12047
473
  ir_refs_add(types, type2);
12048
473
  ir_refs_add(ptrs, ptr2);
12049
#if SIZEOF_ZEND_LONG == 4
12050
  ir_refs_add(values, val2);
12051
#endif
12052
12053
473
  ir_IF_TRUE(if_refcounted2);
12054
473
  ir_MERGE_WITH_EMPTY_FALSE(if_reference);
12055
473
  type = ir_PHI_2(IR_U32, type2, type);
12056
473
  ptr = ir_PHI_2(IR_ADDR, ptr2, ptr);
12057
#if SIZEOF_ZEND_LONG == 4
12058
  val = ir_PHI_2(IR_ADDR, val2, val);
12059
#endif
12060
12061
  // JIT: Z_ADDREF_P(val);
12062
473
  jit_GC_ADDREF(jit, ptr);
12063
473
  ir_refs_add(merge_inputs, ir_END());
12064
473
  ir_refs_add(types, type);
12065
473
  ir_refs_add(ptrs, ptr);
12066
#if SIZEOF_ZEND_LONG == 4
12067
  ir_refs_add(values, val);
12068
#endif
12069
12070
473
  ir_MERGE_N(merge_inputs->count, merge_inputs->refs);
12071
473
  type = ir_PHI_N(IR_U32, types->count, types->refs);
12072
473
  ptr = ir_PHI_N(IR_ADDR, ptrs->count, ptrs->refs);
12073
#if SIZEOF_ZEND_LONG == 4
12074
  val = ir_PHI_N(IR_ADDR, values->count, values->refs);
12075
  val_addr = ZEND_ADDR_REF_ZVAL(val);
12076
#endif
12077
12078
  // JIT: Z_PTR_P(res) = ptr;
12079
473
  jit_set_Z_PTR(jit, res_addr, ptr);
12080
#if SIZEOF_ZEND_LONG == 4
12081
  jit_set_Z_W2(jit, res_addr, jit_Z_W2(jit, val_addr));
12082
#endif
12083
473
  jit_set_Z_TYPE_INFO_ex(jit, res_addr, type);
12084
12085
473
  return 1;
12086
473
}
12087
12088
static int zend_jit_fetch_dimension_address_inner(zend_jit_ctx  *jit,
12089
                                                  const zend_op *opline,
12090
                                                  uint32_t       type,
12091
                                                  uint32_t       op1_info,
12092
                                                  uint32_t       op2_info,
12093
                                                  zend_jit_addr  op2_addr,
12094
                                                  zend_ssa_range *op2_range,
12095
                                                  uint8_t        dim_type,
12096
                                                  const void    *found_exit_addr,
12097
                                                  const void    *not_found_exit_addr,
12098
                                                  const void    *exit_addr,
12099
                                                  bool           result_type_guard,
12100
                                                  ir_ref         ht_ref,
12101
                                                  ir_refs       *found_inputs,
12102
                                                  ir_refs       *found_vals,
12103
                                                  ir_ref        *end_inputs,
12104
                                                  ir_ref        *not_found_inputs)
12105
754
{
12106
754
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
12107
754
  ir_ref ref = IR_UNUSED, cond, if_found;
12108
754
  ir_ref if_type = IS_UNUSED;
12109
754
  ir_refs *test_zval_inputs, *test_zval_values;
12110
12111
754
  ir_refs_init(test_zval_inputs, 4);
12112
754
  ir_refs_init(test_zval_values, 4);
12113
12114
754
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12115
195
   && type == BP_VAR_R
12116
21
   && !exit_addr) {
12117
21
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12118
21
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12119
21
    if (!exit_addr) {
12120
0
      return 0;
12121
0
    }
12122
21
  }
12123
12124
754
  if (op2_info & MAY_BE_LONG) {
12125
481
    bool op2_loaded = false;
12126
481
    bool packed_loaded = false;
12127
481
    bool bad_packed_key = false;
12128
481
    ir_ref if_packed = IS_UNDEF;
12129
481
    ir_ref h = IR_UNUSED;
12130
481
    ir_ref idx_not_found_inputs = IR_UNUSED;
12131
12132
481
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
12133
      // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
12134
247
      if_type = jit_if_Z_TYPE(jit, op2_addr, IS_LONG);
12135
247
      ir_IF_TRUE(if_type);
12136
247
    }
12137
481
    if (op1_info & MAY_BE_PACKED_GUARD) {
12138
2
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
12139
2
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12140
12141
2
      if (!exit_addr) {
12142
0
        return 0;
12143
0
      }
12144
2
      cond = ir_AND_U32(
12145
2
        ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
12146
2
        ir_CONST_U32(HASH_FLAG_PACKED));
12147
2
      if (op1_info & MAY_BE_ARRAY_PACKED) {
12148
2
        ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
12149
2
      } else {
12150
0
        ir_GUARD_NOT(cond, ir_CONST_ADDR(exit_addr));
12151
0
      }
12152
2
    }
12153
481
    if (type == BP_VAR_W) {
12154
      // JIT: hval = Z_LVAL_P(dim);
12155
71
      h = jit_Z_LVAL(jit, op2_addr);
12156
71
      op2_loaded = true;
12157
71
    }
12158
481
    if (op1_info & MAY_BE_ARRAY_PACKED) {
12159
437
      zend_long val = -1;
12160
12161
437
      if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
12162
199
        val = Z_LVAL_P(Z_ZV(op2_addr));
12163
199
        if (val >= 0 && val < HT_MAX_SIZE) {
12164
128
          packed_loaded = true;
12165
128
        } else {
12166
71
          bad_packed_key = true;
12167
71
        }
12168
199
        h = ir_CONST_LONG(val);
12169
238
      } else {
12170
238
        if (!op2_loaded) {
12171
          // JIT: hval = Z_LVAL_P(dim);
12172
212
          h = jit_Z_LVAL(jit, op2_addr);
12173
212
          op2_loaded = true;
12174
212
        }
12175
238
        packed_loaded = true;
12176
238
      }
12177
12178
437
      if (dim_type == IS_UNDEF && type == BP_VAR_W && packed_loaded) {
12179
        /* don't generate "fast" code for packed array */
12180
2
        packed_loaded = false;
12181
2
      }
12182
12183
437
      if (packed_loaded) {
12184
        // JIT: ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
12185
364
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12186
356
          if_packed = ir_IF(
12187
356
            ir_AND_U32(
12188
356
              ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
12189
356
              ir_CONST_U32(HASH_FLAG_PACKED)));
12190
356
          ir_IF_TRUE(if_packed);
12191
356
        }
12192
        // JIT: if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
12193
364
        ref = ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed)));
12194
364
#if SIZEOF_ZEND_LONG == 8
12195
364
        if ((Z_MODE(op2_addr) == IS_CONST_ZVAL && val >= 0 && val <= UINT32_MAX)
12196
238
         || (op2_range && op2_range->min >= 0 && op2_range->max <= UINT32_MAX)) {
12197
          /* compare only the lower 32-bits to allow load fusion on x86_64 */
12198
126
          cond = ir_ULT(ir_TRUNC_U32(h), ref);
12199
238
        } else {
12200
238
          cond = ir_ULT(h, ir_ZEXT_L(ref));
12201
238
        }
12202
#else
12203
        cond = ir_ULT(h, ref);
12204
#endif
12205
364
        if (type == BP_JIT_IS) {
12206
1
          if (not_found_exit_addr) {
12207
0
            ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12208
1
          } else {
12209
1
            ir_ref if_fit = ir_IF(cond);
12210
1
            ir_IF_FALSE(if_fit);
12211
1
            ir_END_list(*end_inputs);
12212
1
            ir_IF_TRUE(if_fit);
12213
1
          }
12214
363
        } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12215
5
          ir_GUARD(cond, ir_CONST_ADDR(exit_addr));
12216
358
        } else if (type == BP_VAR_IS && not_found_exit_addr) {
12217
0
          ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12218
358
        } else if (type == BP_VAR_RW && not_found_exit_addr) {
12219
0
          ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12220
358
        } else if (type == BP_VAR_IS && result_type_guard) {
12221
0
          ir_ref if_fit = ir_IF(cond);
12222
0
          ir_IF_FALSE(if_fit);
12223
0
          ir_END_list(*not_found_inputs);
12224
0
          ir_IF_TRUE(if_fit);
12225
358
        } else {
12226
358
          ir_ref if_fit = ir_IF(cond);
12227
358
          ir_IF_FALSE(if_fit);
12228
358
          ir_END_list(idx_not_found_inputs);
12229
358
          ir_IF_TRUE(if_fit);
12230
358
        }
12231
        // JIT: _ret = &_ht->arPacked[h];
12232
364
        ref = ir_MUL_L(h, ir_CONST_LONG(sizeof(zval)));
12233
364
        ref = ir_BITCAST_A(ref);
12234
364
        ref = ir_ADD_A(ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))), ref);
12235
364
        if (type == BP_JIT_IS) {
12236
1
          ir_refs_add(test_zval_values, ref);
12237
1
          ir_refs_add(test_zval_inputs, ir_END());
12238
1
        }
12239
364
      }
12240
437
    }
12241
481
    switch (type) {
12242
1
      case BP_JIT_IS:
12243
1
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12244
1
          if (if_packed) {
12245
1
            ir_IF_FALSE(if_packed);
12246
1
            if_packed = IR_UNUSED;
12247
1
          }
12248
1
          if (!op2_loaded) {
12249
            // JIT: hval = Z_LVAL_P(dim);
12250
0
            h = jit_Z_LVAL(jit, op2_addr);
12251
0
            op2_loaded = true;
12252
0
          }
12253
1
          if (packed_loaded) {
12254
1
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12255
1
          } else {
12256
0
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12257
0
          }
12258
1
          if (not_found_exit_addr) {
12259
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12260
1
          } else {
12261
1
            if_found = ir_IF(ref);
12262
1
            ir_IF_FALSE(if_found);
12263
1
            ir_END_list(*end_inputs);
12264
1
            ir_IF_TRUE(if_found);
12265
1
          }
12266
1
          ir_refs_add(test_zval_values, ref);
12267
1
          ir_refs_add(test_zval_inputs, ir_END());
12268
1
        } else if (!not_found_exit_addr && !packed_loaded) {
12269
0
          ir_END_list(*end_inputs);
12270
0
        }
12271
1
        break;
12272
215
      case BP_VAR_R:
12273
268
      case BP_VAR_IS:
12274
268
      case BP_VAR_UNSET:
12275
268
        if (packed_loaded) {
12276
228
          ir_ref type_ref = jit_Z_TYPE_ref(jit, ref);
12277
12278
228
          if (result_type_guard) {
12279
            /* perform IS_UNDEF check only after result type guard (during deoptimization) */
12280
227
          } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12281
4
            ir_GUARD(type_ref, ir_CONST_ADDR(exit_addr));
12282
223
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12283
0
            ir_GUARD(type_ref, ir_CONST_ADDR(not_found_exit_addr));
12284
223
          } else {
12285
223
            ir_ref if_def = ir_IF(type_ref);
12286
223
            ir_IF_FALSE(if_def);
12287
223
            ir_END_list(idx_not_found_inputs);
12288
223
            ir_IF_TRUE(if_def);
12289
223
          }
12290
228
          ir_refs_add(found_inputs, ir_END());
12291
228
          ir_refs_add(found_vals, ref);
12292
228
        }
12293
268
        if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
12294
240
          if (if_packed) {
12295
220
            ir_IF_FALSE(if_packed);
12296
220
            if_packed = IR_UNUSED;
12297
220
          }
12298
240
          if (!op2_loaded) {
12299
            // JIT: hval = Z_LVAL_P(dim);
12300
78
            h = jit_Z_LVAL(jit, op2_addr);
12301
78
            op2_loaded = true;
12302
78
          }
12303
240
          if (packed_loaded) {
12304
220
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(_zend_hash_index_find), ht_ref, h);
12305
220
          } else {
12306
20
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_find), ht_ref, h);
12307
20
          }
12308
240
          if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12309
5
            ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12310
235
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12311
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12312
235
          } else if (type == BP_VAR_IS && result_type_guard) {
12313
0
            if_found = ir_IF(ref);
12314
0
            ir_IF_FALSE(if_found);
12315
0
            ir_END_list(*not_found_inputs);
12316
0
            ir_IF_TRUE(if_found);
12317
235
          } else {
12318
235
            if_found = ir_IF(ref);
12319
235
            ir_IF_FALSE(if_found);
12320
235
            ir_END_list(idx_not_found_inputs);
12321
235
            ir_IF_TRUE(if_found);
12322
235
          }
12323
240
          ir_refs_add(found_inputs, ir_END());
12324
240
          ir_refs_add(found_vals, ref);
12325
240
        } else if (!packed_loaded) {
12326
20
          if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12327
6
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
12328
14
          } else if (type == BP_VAR_IS && not_found_exit_addr) {
12329
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(not_found_exit_addr));
12330
14
          } else if (type == BP_VAR_IS && result_type_guard) {
12331
2
            ir_END_list(*not_found_inputs);
12332
12
          } else {
12333
12
            ir_END_list(idx_not_found_inputs);
12334
12
          }
12335
20
        }
12336
12337
268
        if (idx_not_found_inputs) {
12338
250
          ir_MERGE_list(idx_not_found_inputs);
12339
250
          switch (type) {
12340
199
            case BP_VAR_R:
12341
199
              ZEND_ASSERT(JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE);
12342
              // JIT: zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval);
12343
              // JIT: retval = &EG(uninitialized_zval);
12344
199
              jit_SET_EX_OPLINE(jit, opline);
12345
199
              if (Z_MODE(op2_addr) == IS_REG) {
12346
0
                if (!op2_loaded) {
12347
                  // JIT: hval = Z_LVAL_P(dim);
12348
0
                  h = jit_Z_LVAL(jit, op2_addr);
12349
0
                }
12350
0
                if (GCC_GLOBAL_REGS) {
12351
0
                  ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h);
12352
0
                } else {
12353
0
                  ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_long_key_ex), h, jit_FP(jit));
12354
0
                }
12355
199
              } else {
12356
199
                ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_offset, IR_FASTCALL_FUNC));
12357
199
              }
12358
199
              ir_END_list(*end_inputs);
12359
199
              break;
12360
51
            case BP_VAR_IS:
12361
51
            case BP_VAR_UNSET:
12362
51
              if (!not_found_exit_addr) {
12363
                // JIT: retval = &EG(uninitialized_zval);
12364
51
                jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12365
51
                ir_END_list(*end_inputs);
12366
51
              }
12367
51
              break;
12368
0
            default:
12369
0
              ZEND_UNREACHABLE();
12370
250
          }
12371
250
                }
12372
268
        break;
12373
268
      case BP_VAR_RW:
12374
141
        if (packed_loaded) {
12375
86
          if (not_found_exit_addr) {
12376
0
            ir_refs_add(found_inputs, ir_END());
12377
0
            ir_refs_add(found_vals, ref);
12378
86
          } else {
12379
86
            ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12380
86
            ir_IF_TRUE(if_def);
12381
86
            ir_refs_add(found_inputs, ir_END());
12382
86
            ir_refs_add(found_vals, ref);
12383
86
            ir_IF_FALSE_cold(if_def);
12384
86
            ir_END_list(idx_not_found_inputs);
12385
86
          }
12386
86
        }
12387
141
        if (!packed_loaded ||
12388
86
            !not_found_exit_addr ||
12389
141
            (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
12390
141
          if (if_packed) {
12391
86
            ir_IF_FALSE(if_packed);
12392
86
            if_packed = IR_UNUSED;
12393
86
            ir_END_list(idx_not_found_inputs);
12394
86
          } else if (!packed_loaded) {
12395
55
            ir_END_list(idx_not_found_inputs);
12396
55
          }
12397
12398
141
          ir_MERGE_list(idx_not_found_inputs);
12399
141
          if (!op2_loaded) {
12400
            // JIT: hval = Z_LVAL_P(dim);
12401
95
            h = jit_Z_LVAL(jit, op2_addr);
12402
95
          }
12403
141
          if (packed_loaded) {
12404
86
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw_no_packed),
12405
86
              ht_ref, h);
12406
86
          } else {
12407
55
            ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_index_lookup_rw), ht_ref, h);
12408
55
          }
12409
141
          if (not_found_exit_addr) {
12410
0
            ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12411
141
          } else {
12412
141
            if_found = ir_IF(ref);
12413
141
            ir_IF_FALSE(if_found);
12414
141
            ir_END_list(*end_inputs);
12415
141
            ir_IF_TRUE(if_found);
12416
141
          }
12417
141
          ir_refs_add(found_inputs, ir_END());
12418
141
          ir_refs_add(found_vals, ref);
12419
141
        }
12420
141
        break;
12421
71
      case BP_VAR_W:
12422
71
        if (packed_loaded) {
12423
49
          ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
12424
49
          ir_IF_TRUE_cold(if_def);
12425
49
          ir_refs_add(found_inputs, ir_END());
12426
49
          ir_refs_add(found_vals, ref);
12427
49
          ir_IF_FALSE(if_def);
12428
49
          ir_END_list(idx_not_found_inputs);
12429
49
        }
12430
71
        if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) {
12431
71
          if (if_packed) {
12432
49
            ir_IF_FALSE(if_packed);
12433
49
            if_packed = IR_UNUSED;
12434
49
            ir_END_list(idx_not_found_inputs);
12435
49
          } else if (!packed_loaded) {
12436
22
            ir_END_list(idx_not_found_inputs);
12437
22
          }
12438
71
          ir_MERGE_list(idx_not_found_inputs);
12439
71
          if (!op2_loaded) {
12440
            // JIT: hval = Z_LVAL_P(dim);
12441
0
            h = jit_Z_LVAL(jit, op2_addr);
12442
0
          }
12443
71
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_index_lookup), ht_ref, h);
12444
71
          ir_refs_add(found_inputs, ir_END());
12445
71
          ir_refs_add(found_vals, ref);
12446
71
        }
12447
71
        break;
12448
0
      default:
12449
0
        ZEND_UNREACHABLE();
12450
481
    }
12451
481
  }
12452
12453
754
  if (op2_info & MAY_BE_STRING) {
12454
479
    ir_ref key;
12455
12456
479
    if (if_type) {
12457
247
      ir_IF_FALSE(if_type);
12458
247
      if_type = IS_UNUSED;
12459
247
    }
12460
12461
479
    if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12462
      // JIT: if (EXPECTED(Z_TYPE_P(dim) == IS_STRING))
12463
247
      if_type = jit_if_Z_TYPE(jit, op2_addr, IS_STRING);
12464
247
      ir_IF_TRUE(if_type);
12465
247
    }
12466
12467
    // JIT: offset_key = Z_STR_P(dim);
12468
479
    key = jit_Z_PTR(jit, op2_addr);
12469
12470
    // JIT: retval = zend_hash_find(ht, offset_key);
12471
479
    switch (type) {
12472
1
      case BP_JIT_IS:
12473
1
        if (opline->op2_type != IS_CONST) {
12474
1
          ir_ref if_num, end1, ref2;
12475
12476
1
          if_num = ir_IF(
12477
1
            ir_ULE(
12478
1
              ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12479
1
              ir_CONST_CHAR('9')));
12480
1
          ir_IF_TRUE_cold(if_num);
12481
1
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12482
1
          end1 = ir_END();
12483
1
          ir_IF_FALSE(if_num);
12484
1
          ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12485
1
          ir_MERGE_WITH(end1);
12486
1
          ref = ir_PHI_2(IR_ADDR, ref2, ref);
12487
1
        } else {
12488
0
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12489
0
        }
12490
1
        if (not_found_exit_addr) {
12491
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12492
1
        } else {
12493
1
          if_found = ir_IF(ref);
12494
1
          ir_IF_FALSE(if_found);
12495
1
          ir_END_list(*end_inputs);
12496
1
          ir_IF_TRUE(if_found);
12497
1
        }
12498
1
        ir_refs_add(test_zval_values, ref);
12499
1
        ir_refs_add(test_zval_inputs, ir_END());
12500
1
        break;
12501
159
      case BP_VAR_R:
12502
198
      case BP_VAR_IS:
12503
198
      case BP_VAR_UNSET:
12504
198
        if (opline->op2_type != IS_CONST) {
12505
171
          ir_ref if_num, end1, ref2;
12506
12507
171
          if_num = ir_IF(
12508
171
            ir_ULE(
12509
171
              ir_LOAD_C(ir_ADD_OFFSET(key, offsetof(zend_string, val))),
12510
171
              ir_CONST_CHAR('9')));
12511
171
          ir_IF_TRUE_cold(if_num);
12512
171
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_find), ht_ref, key);
12513
171
          end1 = ir_END();
12514
171
          ir_IF_FALSE(if_num);
12515
171
          ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find), ht_ref, key);
12516
171
          ir_MERGE_WITH(end1);
12517
171
          ref = ir_PHI_2(IR_ADDR, ref2, ref);
12518
171
        } else {
12519
27
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_find_known_hash), ht_ref, key);
12520
27
        }
12521
198
        if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
12522
3
          ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
12523
195
        } else if (type == BP_VAR_IS && not_found_exit_addr) {
12524
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12525
195
        } else if (type == BP_VAR_IS && result_type_guard) {
12526
0
          if_found = ir_IF(ref);
12527
0
          ir_IF_FALSE(if_found);
12528
0
          ir_END_list(*not_found_inputs);
12529
0
          ir_IF_TRUE(if_found);
12530
195
        } else {
12531
195
          if_found = ir_IF(ref);
12532
195
          switch (type) {
12533
156
            case BP_VAR_R:
12534
156
              ir_IF_FALSE_cold(if_found);
12535
              // JIT: zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key));
12536
156
              jit_SET_EX_OPLINE(jit, opline);
12537
156
              ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_undefined_key, IR_FASTCALL_FUNC));
12538
156
              ir_END_list(*end_inputs);
12539
156
              break;
12540
39
            case BP_VAR_IS:
12541
39
            case BP_VAR_UNSET:
12542
39
              ir_IF_FALSE(if_found);
12543
              // JIT: retval = &EG(uninitialized_zval);
12544
39
              jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12545
39
              ir_END_list(*end_inputs);
12546
39
              break;
12547
0
            default:
12548
0
              ZEND_UNREACHABLE();
12549
195
          }
12550
195
          ir_IF_TRUE(if_found);
12551
195
        }
12552
198
        ir_refs_add(found_inputs, ir_END());
12553
198
        ir_refs_add(found_vals, ref);
12554
198
        break;
12555
161
      case BP_VAR_RW:
12556
161
        if (opline->op2_type != IS_CONST) {
12557
99
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_rw), ht_ref, key);
12558
99
        } else {
12559
62
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_hash_lookup_rw), ht_ref, key);
12560
62
        }
12561
161
        if (not_found_exit_addr) {
12562
3
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12563
158
        } else {
12564
158
          if_found = ir_IF(ref);
12565
158
          ir_IF_FALSE(if_found);
12566
158
          ir_END_list(*end_inputs);
12567
158
          ir_IF_TRUE(if_found);
12568
158
        }
12569
161
        ir_refs_add(found_inputs, ir_END());
12570
161
        ir_refs_add(found_vals, ref);
12571
161
        break;
12572
119
      case BP_VAR_W:
12573
119
        if (opline->op2_type != IS_CONST) {
12574
44
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_symtable_lookup_w), ht_ref, key);
12575
75
        } else {
12576
75
          ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_lookup), ht_ref, key);
12577
75
        }
12578
119
        ir_refs_add(found_inputs, ir_END());
12579
119
        ir_refs_add(found_vals, ref);
12580
119
        break;
12581
0
      default:
12582
0
        ZEND_UNREACHABLE();
12583
479
    }
12584
479
  }
12585
12586
754
  if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
12587
286
      if (if_type) {
12588
247
      ir_IF_FALSE_cold(if_type);
12589
247
      if_type = IS_UNDEF;
12590
247
    }
12591
286
    if (type != BP_VAR_RW) {
12592
222
      jit_SET_EX_OPLINE(jit, opline);
12593
222
    }
12594
286
    ref = jit_ZVAL_ADDR(jit, op2_addr);
12595
286
    switch (type) {
12596
153
      case BP_VAR_R:
12597
153
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_r_helper),
12598
153
          ht_ref,
12599
153
          ref,
12600
153
          jit_ZVAL_ADDR(jit, res_addr));
12601
153
        ir_END_list(*end_inputs);
12602
153
        break;
12603
1
      case BP_JIT_IS:
12604
1
        ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_fetch_dim_isset_helper), ht_ref, ref);
12605
1
        if (not_found_exit_addr) {
12606
0
          ir_GUARD(ref, ir_CONST_ADDR(not_found_exit_addr));
12607
0
          ir_refs_add(found_inputs, ir_END());
12608
1
        } else if (found_exit_addr) {
12609
0
          ir_GUARD_NOT(ref, ir_CONST_ADDR(found_exit_addr));
12610
0
          ir_END_list(*end_inputs);
12611
1
        } else {
12612
1
          if_found = ir_IF(ref);
12613
1
          ir_IF_TRUE(if_found);
12614
1
          ir_refs_add(found_inputs, ir_END());
12615
1
          ir_IF_FALSE(if_found);
12616
1
          ir_END_list(*end_inputs);
12617
1
        }
12618
1
        break;
12619
33
      case BP_VAR_IS:
12620
33
      case BP_VAR_UNSET:
12621
33
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_is_helper),
12622
33
          ht_ref,
12623
33
          ref,
12624
33
          jit_ZVAL_ADDR(jit, res_addr));
12625
33
        ir_END_list(*end_inputs);
12626
33
        break;
12627
64
      case BP_VAR_RW:
12628
64
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_rw_helper), ht_ref, ref);
12629
64
        if_found = ir_IF(ref);
12630
64
        ir_IF_TRUE(if_found);
12631
64
        ir_refs_add(found_inputs, ir_END());
12632
64
        ir_refs_add(found_vals, ref);
12633
64
        ir_IF_FALSE(if_found);
12634
64
        ir_END_list(*end_inputs);
12635
64
        break;
12636
35
      case BP_VAR_W:
12637
35
        ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_w_helper), ht_ref, ref);
12638
35
        if_found = ir_IF(ref);
12639
35
        ir_IF_TRUE(if_found);
12640
35
        ir_refs_add(found_inputs, ir_END());
12641
35
        ir_refs_add(found_vals, ref);
12642
35
        ir_IF_FALSE(if_found);
12643
35
        ir_END_list(*end_inputs);
12644
35
        break;
12645
0
      default:
12646
0
        ZEND_UNREACHABLE();
12647
286
    }
12648
286
  }
12649
12650
754
  if (type == BP_JIT_IS
12651
1
   && !(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
12652
    /* dead code */
12653
0
    ir_END_list(*end_inputs);
12654
754
  } else if (type == BP_JIT_IS
12655
1
   && (op1_info & MAY_BE_ARRAY)
12656
1
   && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
12657
1
   && test_zval_inputs->count) {
12658
12659
1
    ir_MERGE_N(test_zval_inputs->count, test_zval_inputs->refs);
12660
1
    ref = ir_PHI_N(IR_ADDR, test_zval_values->count, test_zval_values->refs);
12661
12662
1
    if (op1_info & MAY_BE_ARRAY_OF_REF) {
12663
1
      ref = jit_ZVAL_DEREF_ref(jit, ref);
12664
1
    }
12665
1
    cond = ir_GT(jit_Z_TYPE_ref(jit, ref), ir_CONST_U8(IS_NULL));
12666
1
    if (not_found_exit_addr) {
12667
0
      ir_GUARD(cond, ir_CONST_ADDR(not_found_exit_addr));
12668
0
      ir_refs_add(found_inputs, ir_END());
12669
1
    } else if (found_exit_addr) {
12670
0
      ir_GUARD_NOT(cond, ir_CONST_ADDR(found_exit_addr));
12671
0
      ir_END_list(*end_inputs);
12672
1
    } else {
12673
1
      ir_ref if_set = ir_IF(cond);
12674
1
      ir_IF_FALSE(if_set);
12675
1
      ir_END_list(*end_inputs);
12676
1
      ir_IF_TRUE(if_set);
12677
1
      ir_refs_add(found_inputs, ir_END());
12678
1
    }
12679
1
  }
12680
12681
754
  return 1;
12682
754
}
12683
12684
static int zend_jit_fetch_dim_read(zend_jit_ctx       *jit,
12685
                                   const zend_op      *opline,
12686
                                   zend_ssa           *ssa,
12687
                                   const zend_ssa_op  *ssa_op,
12688
                                   uint32_t            op1_info,
12689
                                   zend_jit_addr       op1_addr,
12690
                                   bool           op1_avoid_refcounting,
12691
                                   uint32_t            op2_info,
12692
                                   zend_jit_addr       op2_addr,
12693
                                   zend_ssa_range     *op2_range,
12694
                                   uint32_t            res_info,
12695
                                   zend_jit_addr       res_addr,
12696
                                   uint8_t             dim_type)
12697
429
{
12698
429
  zend_jit_addr orig_op1_addr;
12699
429
  const void *exit_addr = NULL;
12700
429
  const void *not_found_exit_addr = NULL;
12701
429
  bool result_type_guard = false;
12702
429
  bool result_avoid_refcounting = false;
12703
429
  uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0;
12704
429
  int may_throw = 0;
12705
429
  ir_ref if_type = IR_UNUSED;
12706
429
  ir_ref end_inputs = IR_UNUSED;
12707
429
  ir_ref not_found_inputs = IR_UNUSED;
12708
12709
429
  orig_op1_addr = OP1_ADDR();
12710
12711
429
  if (opline->opcode != ZEND_FETCH_DIM_IS
12712
344
   && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
12713
69
   && !has_concrete_type(op1_info)) {
12714
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
12715
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12716
0
    if (!exit_addr) {
12717
0
      return 0;
12718
0
    }
12719
0
  }
12720
12721
429
  if ((res_info & MAY_BE_GUARD)
12722
33
   && JIT_G(current_frame)
12723
33
   && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
12724
12725
7
    if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) {
12726
6
      result_type_guard = true;
12727
6
      res_info &= ~MAY_BE_GUARD;
12728
6
      ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
12729
6
    }
12730
12731
7
    if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
12732
7
     && (opline->opcode == ZEND_FETCH_LIST_R
12733
7
      || !(opline->op1_type & (IS_VAR|IS_TMP_VAR))
12734
2
      || op1_avoid_refcounting)
12735
5
     && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
12736
0
     && (ssa_op+1)->op1_use == ssa_op->result_def
12737
0
     && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))
12738
0
     && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
12739
0
      result_avoid_refcounting = true;
12740
0
      ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
12741
0
    }
12742
12743
7
    if (opline->opcode == ZEND_FETCH_DIM_IS
12744
2
     && !(res_info & MAY_BE_NULL)) {
12745
0
      uint32_t flags = 0;
12746
0
      uint32_t old_op1_info = 0;
12747
0
      uint32_t old_info;
12748
0
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
12749
0
      int32_t exit_point;
12750
12751
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
12752
0
       && !op1_avoid_refcounting) {
12753
0
        flags |= ZEND_JIT_EXIT_FREE_OP1;
12754
0
      }
12755
0
      if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12756
0
       && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12757
0
        flags |= ZEND_JIT_EXIT_FREE_OP2;
12758
0
      }
12759
12760
0
      if (op1_avoid_refcounting) {
12761
0
        old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
12762
0
        SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
12763
0
      }
12764
12765
0
      old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
12766
0
      SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0);
12767
0
      SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_TYPE_ONLY);
12768
0
      exit_point = zend_jit_trace_get_exit_point(opline+1, flags);
12769
0
      SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
12770
0
      not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
12771
0
      if (!not_found_exit_addr) {
12772
0
        return 0;
12773
0
      }
12774
12775
0
      if (op1_avoid_refcounting) {
12776
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info);
12777
0
      }
12778
0
    }
12779
7
  }
12780
12781
429
  if (op1_info & MAY_BE_REF) {
12782
268
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
12783
268
    ref = jit_ZVAL_DEREF_ref(jit, ref);
12784
268
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
12785
268
  }
12786
12787
429
  if (op1_info & MAY_BE_ARRAY) {
12788
314
    ir_ref ht_ref, ref;
12789
314
    zend_jit_addr val_addr;
12790
314
    ir_refs *found_inputs, *found_vals;
12791
12792
314
    ir_refs_init(found_inputs, 10);
12793
314
    ir_refs_init(found_vals, 10);
12794
12795
314
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
12796
269
      if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) {
12797
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_ARRAY, exit_addr);
12798
269
      } else {
12799
269
        if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
12800
269
        ir_IF_TRUE(if_type);
12801
269
      }
12802
269
    }
12803
12804
314
    ht_ref = jit_Z_PTR(jit, op1_addr);
12805
12806
314
    if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) ||
12807
269
        (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) {
12808
269
      may_throw = 1;
12809
269
    }
12810
12811
314
    if (!zend_jit_fetch_dimension_address_inner(jit, opline,
12812
314
        (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS,
12813
314
        op1_info, op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, exit_addr,
12814
314
        result_type_guard, ht_ref, found_inputs, found_vals,
12815
314
        &end_inputs, &not_found_inputs)) {
12816
0
      return 0;
12817
0
    }
12818
12819
314
    if (found_inputs->count) {
12820
282
      ir_MERGE_N(found_inputs->count, found_inputs->refs);
12821
282
      ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
12822
282
      val_addr = ZEND_ADDR_REF_ZVAL(ref);
12823
12824
282
      if (result_type_guard) {
12825
3
        uint8_t type = concrete_type(res_info);
12826
3
        uint32_t flags = 0;
12827
12828
3
        if (opline->opcode != ZEND_FETCH_LIST_R
12829
3
         && (opline->op1_type & (IS_VAR|IS_TMP_VAR))
12830
0
         && !op1_avoid_refcounting) {
12831
0
          flags |= ZEND_JIT_EXIT_FREE_OP1;
12832
0
        }
12833
3
        if ((opline->op2_type & (IS_VAR|IS_TMP_VAR))
12834
1
         && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
12835
1
          flags |= ZEND_JIT_EXIT_FREE_OP2;
12836
1
        }
12837
12838
3
        val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
12839
3
          (op1_info & MAY_BE_ARRAY_OF_REF) != 0, flags, op1_avoid_refcounting);
12840
3
        if (!val_addr) {
12841
0
          return 0;
12842
0
        }
12843
12844
3
        if (not_found_inputs) {
12845
0
          ir_END_list(not_found_inputs);
12846
0
          ir_MERGE_list(not_found_inputs);
12847
0
        }
12848
12849
        // ZVAL_COPY
12850
3
        jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
12851
3
        if (Z_MODE(res_addr) != IS_REG) {
12852
3
        } else if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
12853
0
          return 0;
12854
0
        }
12855
279
      } else if (op1_info & MAY_BE_ARRAY_OF_REF) {
12856
        // ZVAL_COPY_DEREF
12857
256
        ir_ref type_info = jit_Z_TYPE_INFO(jit, val_addr);
12858
256
        if (!zend_jit_zval_copy_deref(jit, res_addr, val_addr, type_info)) {
12859
0
          return 0;
12860
0
        }
12861
256
      } else  {
12862
        // ZVAL_COPY
12863
23
        jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, true);
12864
23
      }
12865
12866
282
      ir_END_list(end_inputs);
12867
282
    } else if (not_found_inputs) {
12868
2
      ir_MERGE_list(not_found_inputs);
12869
2
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
12870
2
      ir_END_list(end_inputs);
12871
30
    } else if (!end_inputs && jit->ctx.control) {
12872
0
      ir_END_list(end_inputs); /* dead code */
12873
0
    }
12874
314
  }
12875
12876
429
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
12877
384
    if (if_type) {
12878
269
      ir_IF_FALSE_cold(if_type);
12879
269
      if_type = IS_UNDEF;
12880
269
    }
12881
12882
384
    if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) {
12883
286
      ir_ref str_ref;
12884
12885
286
      may_throw = 1;
12886
286
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) {
12887
266
        if (exit_addr && !(op1_info & MAY_BE_OBJECT)) {
12888
0
          jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, exit_addr);
12889
266
        } else {
12890
266
          if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
12891
266
          ir_IF_TRUE(if_type);
12892
266
        }
12893
266
      }
12894
286
      str_ref = jit_Z_PTR(jit, op1_addr);
12895
12896
      /* Inlined offset read for integer offsets into strings. */
12897
286
      if (opline->opcode != ZEND_FETCH_DIM_IS
12898
231
       && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING
12899
19
       && (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) {
12900
8
        ir_ref offset_ref = jit_Z_LVAL(jit, op2_addr);
12901
8
        ir_ref len_ref = ir_LOAD_L(ir_ADD_OFFSET(str_ref, offsetof(zend_string, len)));
12902
8
        ir_ref real_offset_ref = offset_ref;
12903
8
        if (!op2_range || op2_range->min < 0) {
12904
          // JIT: if (offset < 0) offset += ZSTR_LEN(str);
12905
          /* Branchless way to add -1 for negative offsets to the string length. */
12906
8
          real_offset_ref = ir_ADD_L(offset_ref,
12907
8
            ir_AND_L(len_ref,
12908
8
              ir_SAR_L(offset_ref, ir_CONST_LONG(SIZEOF_ZEND_LONG * 8 - 1))));
12909
8
        }
12910
12911
        /* An offset that is still negative wraps around and fails this check as well. */
12912
8
        ir_ref if_in_range = ir_IF(ir_ULT(real_offset_ref, len_ref));
12913
12914
8
        ir_IF_TRUE(if_in_range);
12915
        // JIT: result = ZSTR_CHAR((uint8_t)ZSTR_VAL(str)[offset]);
12916
8
        ir_ref ref = ir_LOAD_A(
12917
8
          ir_ADD_A(
12918
8
            ir_CONST_ADDR(zend_one_char_string),
12919
8
            ir_MUL_A(
12920
8
              ir_ZEXT_A(
12921
8
                ir_LOAD_U8(
12922
8
                  ir_ADD_A(ir_ADD_OFFSET(str_ref, offsetof(zend_string, val)),
12923
8
                    ir_BITCAST_A(real_offset_ref)))),
12924
8
              ir_CONST_ADDR(sizeof(zend_string*)))));
12925
8
        ir_ref fast_path = ir_END();
12926
12927
8
        ir_IF_FALSE_cold(if_in_range);
12928
8
        jit_SET_EX_OPLINE(jit, opline);
12929
8
        ir_ref slow_ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_offset_r_helper),
12930
8
          str_ref, offset_ref);
12931
12932
8
        ir_MERGE_WITH(fast_path);
12933
8
        ref = ir_PHI_2(IR_ADDR, slow_ref, ref);
12934
8
        jit_set_Z_PTR(jit, res_addr, ref);
12935
8
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12936
278
      } else {
12937
278
        jit_SET_EX_OPLINE(jit, opline);
12938
278
        if (opline->opcode != ZEND_FETCH_DIM_IS) {
12939
223
          ir_ref ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_r_helper),
12940
223
            str_ref, jit_ZVAL_ADDR(jit, op2_addr));
12941
12942
223
          jit_set_Z_PTR(jit, res_addr, ref);
12943
223
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
12944
223
        } else {
12945
55
          ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_str_is_helper),
12946
55
            str_ref,
12947
55
            jit_ZVAL_ADDR(jit, op2_addr),
12948
55
            jit_ZVAL_ADDR(jit, res_addr));
12949
55
        }
12950
278
      }
12951
286
      ir_END_list(end_inputs);
12952
286
    }
12953
12954
384
    if (op1_info & MAY_BE_OBJECT) {
12955
269
      ir_ref arg2;
12956
12957
269
      if (if_type) {
12958
266
        ir_IF_FALSE_cold(if_type);
12959
266
        if_type = IS_UNDEF;
12960
266
      }
12961
12962
269
      may_throw = 1;
12963
269
      if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) {
12964
269
        if (exit_addr) {
12965
0
          jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
12966
269
        } else {
12967
269
          if_type = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
12968
269
          ir_IF_TRUE(if_type);
12969
269
        }
12970
269
      }
12971
12972
269
      jit_SET_EX_OPLINE(jit, opline);
12973
269
      if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
12974
1
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
12975
1
        arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
12976
268
      } else {
12977
268
        arg2 = jit_ZVAL_ADDR(jit, op2_addr);
12978
268
      }
12979
12980
269
      if (opline->opcode != ZEND_FETCH_DIM_IS) {
12981
215
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_r_helper),
12982
215
          jit_ZVAL_ADDR(jit, op1_addr),
12983
215
          arg2,
12984
215
          jit_ZVAL_ADDR(jit, res_addr));
12985
215
      } else {
12986
54
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_is_helper),
12987
54
          jit_ZVAL_ADDR(jit, op1_addr),
12988
54
          arg2,
12989
54
          jit_ZVAL_ADDR(jit, res_addr));
12990
54
      }
12991
12992
269
      ir_END_list(end_inputs);
12993
269
    }
12994
12995
384
    if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))
12996
364
     && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) {
12997
12998
364
      if (if_type) {
12999
269
        ir_IF_FALSE_cold(if_type);
13000
269
        if_type = IS_UNDEF;
13001
269
      }
13002
13003
364
      if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) {
13004
295
        jit_SET_EX_OPLINE(jit, opline);
13005
295
        if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) {
13006
242
          may_throw = 1;
13007
242
          zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op1_addr), opline->op1.var, NULL,
13008
242
                  false, true, false);
13009
242
        }
13010
13011
295
        if (op2_info & MAY_BE_UNDEF) {
13012
182
          may_throw = 1;
13013
182
          zend_jit_type_check_undef(jit, jit_Z_TYPE(jit, op2_addr), opline->op2.var, NULL,
13014
182
                  false, true, false);
13015
182
        }
13016
295
      }
13017
13018
364
      if (opline->opcode != ZEND_FETCH_DIM_IS) {
13019
285
        ir_ref ref;
13020
13021
285
        may_throw = 1;
13022
285
        if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
13023
262
          ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
13024
262
        } else {
13025
23
          jit_SET_EX_OPLINE(jit, opline);
13026
23
          ref = jit_ZVAL_ADDR(jit, op1_addr);
13027
23
        }
13028
285
        if (opline->opcode == ZEND_FETCH_LIST_R) {
13029
5
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_use), ref);
13030
280
        } else {
13031
280
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_array_access), ref);
13032
280
        }
13033
285
      }
13034
13035
364
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13036
364
      ir_END_list(end_inputs);
13037
364
    }
13038
384
  }
13039
13040
429
  if (end_inputs) {
13041
423
    ir_MERGE_list(end_inputs);
13042
13043
423
#ifdef ZEND_JIT_USE_RC_INFERENCE
13044
423
    if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13045
      /* Magic offsetGet() may increase refcount of the key */
13046
93
      op2_info |= MAY_BE_RCN;
13047
93
    }
13048
423
#endif
13049
13050
423
    if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
13051
125
      if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) {
13052
102
        may_throw = 1;
13053
102
      }
13054
125
      jit_FREE_OP(jit,  opline->op2_type, opline->op2, op2_info, opline);
13055
125
    }
13056
423
    if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) {
13057
418
      if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
13058
159
        if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
13059
151
          may_throw = 1;
13060
151
        }
13061
159
        jit_FREE_OP(jit,  opline->op1_type, opline->op1, op1_info, opline);
13062
159
      }
13063
418
    }
13064
13065
423
    if (may_throw) {
13066
385
      zend_jit_check_exception(jit);
13067
385
    }
13068
423
  } else if (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) {
13069
6
    ir_BEGIN(IR_UNUSED); /* unreachable tail */
13070
6
  }
13071
13072
429
  return 1;
13073
429
}
13074
13075
static zend_jit_addr zend_jit_prepare_array_update(zend_jit_ctx   *jit,
13076
                                                   const zend_op  *opline,
13077
                                                   uint32_t       *op1_info_ptr,
13078
                                                   zend_jit_addr   op1_addr,
13079
                                                   ir_ref         *if_type,
13080
                                                   ir_ref         *ht_ref,
13081
                                                   int            *may_throw)
13082
525
{
13083
525
  ir_ref ref = IR_UNUSED;
13084
525
  ir_ref array_reference_end = IR_UNUSED, array_reference_ref = IR_UNUSED;
13085
525
  ir_refs *array_inputs, *array_values;
13086
525
  uint32_t op1_info = *op1_info_ptr;
13087
13088
525
  ir_refs_init(array_inputs, 4);
13089
525
  ir_refs_init(array_values, 4);
13090
13091
525
  ref = jit_ZVAL_ADDR(jit, op1_addr);
13092
525
  if (op1_info & MAY_BE_REF) {
13093
299
    ir_ref if_reference, if_array, end1, ref2;
13094
13095
299
    *may_throw = 1;
13096
299
    if_reference = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
13097
299
    ir_IF_FALSE(if_reference);
13098
299
    end1 = ir_END();
13099
299
    ir_IF_TRUE_cold(if_reference);
13100
299
    array_reference_ref = ir_ADD_OFFSET(jit_Z_PTR_ref(jit, ref), offsetof(zend_reference, val));
13101
299
    if_array = jit_if_Z_TYPE_ref(jit, array_reference_ref, ir_CONST_U8(IS_ARRAY));
13102
299
    ir_IF_TRUE(if_array);
13103
299
    array_reference_end = ir_END();
13104
299
    ir_IF_FALSE_cold(if_array);
13105
299
    if (opline->opcode != ZEND_FETCH_DIM_RW && opline->opcode != ZEND_ASSIGN_DIM_OP) {
13106
116
      jit_SET_EX_OPLINE(jit, opline);
13107
116
    }
13108
299
    ref2 = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_prepare_assign_dim_ref), ref);
13109
299
    ir_GUARD(ref2, jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
13110
13111
299
    ir_MERGE_WITH(end1);
13112
299
    ref = ir_PHI_2(IR_ADDR, ref2, ref);
13113
299
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13114
299
  }
13115
13116
525
  if (op1_info & MAY_BE_ARRAY) {
13117
332
    ir_ref op1_ref = ref;
13118
13119
332
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13120
299
      *if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13121
299
      ir_IF_TRUE(*if_type);
13122
299
    }
13123
332
    if (array_reference_end) {
13124
299
      ir_MERGE_WITH(array_reference_end);
13125
299
      op1_ref = ir_PHI_2(IR_ADDR, ref, array_reference_ref);
13126
299
    }
13127
    // JIT: SEPARATE_ARRAY()
13128
332
    ref = jit_Z_PTR_ref(jit, op1_ref);
13129
332
    if (RC_MAY_BE_N(op1_info)) {
13130
332
      if (RC_MAY_BE_1(op1_info)) {
13131
332
        ir_ref if_refcount_1 = ir_IF(ir_EQ(jit_GC_REFCOUNT(jit, ref), ir_CONST_U32(1)));
13132
332
        ir_IF_TRUE(if_refcount_1);
13133
332
        ir_refs_add(array_inputs, ir_END());
13134
332
        ir_refs_add(array_values, ref);
13135
332
        ir_IF_FALSE(if_refcount_1);
13136
332
      }
13137
332
      ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_array_dup), op1_ref);
13138
332
    }
13139
332
    if (array_inputs->count || (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) {
13140
332
      ir_refs_add(array_inputs, ir_END());
13141
332
      ir_refs_add(array_values, ref);
13142
332
    }
13143
332
  }
13144
13145
525
  if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) {
13146
492
    if (*if_type) {
13147
299
      ir_IF_FALSE_cold(*if_type);
13148
299
      *if_type = IR_UNUSED;
13149
299
    }
13150
492
    if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) {
13151
299
      *if_type = ir_IF(ir_LE(jit_Z_TYPE(jit, op1_addr), ir_CONST_U8(IS_NULL)));
13152
299
      ir_IF_TRUE(*if_type);
13153
299
    }
13154
492
    if ((op1_info & MAY_BE_UNDEF)
13155
466
     && (opline->opcode == ZEND_FETCH_DIM_RW || opline->opcode == ZEND_ASSIGN_DIM_OP)) {
13156
266
      ir_ref end1 = IR_UNUSED;
13157
13158
266
      *may_throw = 1;
13159
266
      if (op1_info & MAY_BE_NULL) {
13160
183
        ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
13161
183
        ir_IF_TRUE(if_def);
13162
183
        end1 = ir_END();
13163
183
        ir_IF_FALSE(if_def);
13164
183
      }
13165
266
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op1.var));
13166
266
      if (end1) {
13167
183
        ir_MERGE_WITH(end1);
13168
183
      }
13169
266
    }
13170
    // JIT: ZVAL_ARR(container, zend_new_array(8));
13171
492
    ref = ir_CALL_1(IR_ADDR,
13172
492
      jit_STUB_FUNC_ADDR(jit, jit_stub_new_array, IR_FASTCALL_FUNC),
13173
492
      jit_ZVAL_ADDR(jit, op1_addr));
13174
492
    if (array_inputs->count) {
13175
299
      ir_refs_add(array_inputs, ir_END());
13176
299
      ir_refs_add(array_values, ref);
13177
299
    }
13178
492
    op1_info &= ~(MAY_BE_UNDEF | MAY_BE_NULL);
13179
492
    op1_info |= MAY_BE_ARRAY | MAY_BE_RC1;
13180
492
    *op1_info_ptr = op1_info;
13181
492
  }
13182
13183
525
  if (array_inputs->count) {
13184
332
    ir_MERGE_N(array_inputs->count, array_inputs->refs);
13185
332
    ref = ir_PHI_N(IR_ADDR, array_values->count, array_values->refs);
13186
332
  }
13187
13188
525
  *ht_ref = ref;
13189
525
  return op1_addr;
13190
525
}
13191
13192
static int zend_jit_fetch_dim(zend_jit_ctx   *jit,
13193
                              const zend_op  *opline,
13194
                              uint32_t        op1_info,
13195
                              zend_jit_addr   op1_addr,
13196
                              uint32_t        op2_info,
13197
                              zend_jit_addr   op2_addr,
13198
                              zend_ssa_range *op2_range,
13199
                              zend_jit_addr   res_addr,
13200
                              uint8_t         dim_type)
13201
213
{
13202
213
  int may_throw = 0;
13203
213
  ir_ref end_inputs = IR_UNUSED;
13204
213
  ir_ref ref, if_type = IR_UNUSED, ht_ref;
13205
13206
213
  if (opline->opcode == ZEND_FETCH_DIM_RW) {
13207
147
    jit_SET_EX_OPLINE(jit, opline);
13208
147
  }
13209
13210
213
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13211
13212
213
  if (op1_info & MAY_BE_ARRAY) {
13213
213
    ir_refs *found_inputs, *found_vals;
13214
13215
213
    ir_refs_init(found_inputs, 8);
13216
213
    ir_refs_init(found_vals, 8);
13217
13218
213
    if (opline->op2_type == IS_UNUSED) {
13219
20
      ir_ref if_ok;
13220
13221
20
      may_throw = 1;
13222
      // JIT:var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13223
20
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13224
20
        ht_ref, jit_EG(uninitialized_zval));
13225
13226
      // JIT: if (UNEXPECTED(!var_ptr)) {
13227
20
      if_ok = ir_IF(ref);
13228
20
      ir_IF_FALSE_cold(if_ok);
13229
20
      if (opline->opcode != ZEND_FETCH_DIM_RW) {
13230
17
        jit_SET_EX_OPLINE(jit, opline);
13231
17
      }
13232
20
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13233
20
      ir_END_list(end_inputs);
13234
13235
20
      ir_IF_TRUE(if_ok);
13236
20
      jit_set_Z_PTR(jit, res_addr, ref);
13237
20
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
13238
13239
20
      ir_END_list(end_inputs);
13240
193
    } else {
13241
193
      uint32_t type;
13242
13243
193
      switch (opline->opcode) {
13244
49
        case ZEND_FETCH_DIM_W:
13245
49
        case ZEND_FETCH_LIST_W:
13246
49
          type = BP_VAR_W;
13247
49
          break;
13248
144
        case ZEND_FETCH_DIM_RW:
13249
144
          may_throw = 1;
13250
144
          type = BP_VAR_RW;
13251
144
          break;
13252
0
        case ZEND_FETCH_DIM_UNSET:
13253
0
          type = BP_VAR_UNSET;
13254
0
          break;
13255
0
        default:
13256
0
          ZEND_UNREACHABLE();
13257
193
      }
13258
13259
193
      if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) {
13260
49
        may_throw = 1;
13261
49
      }
13262
193
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, type, op1_info,
13263
193
          op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13264
193
          false, ht_ref, found_inputs, found_vals, &end_inputs, NULL)) {
13265
0
        return 0;
13266
0
      }
13267
13268
193
      if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13269
149
        if (end_inputs) {
13270
149
          ir_MERGE_list(end_inputs);
13271
149
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
13272
149
          end_inputs = ir_END();
13273
149
        }
13274
149
      } else if (!(op2_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
13275
        /* impossible dead path */
13276
0
        end_inputs = ir_END();
13277
44
      } else {
13278
44
        ZEND_ASSERT(end_inputs == IR_UNUSED);
13279
44
      }
13280
13281
193
      if (found_inputs->count) {
13282
193
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13283
193
        ref = ir_PHI_N(IR_ADDR, found_vals->count, found_vals->refs);
13284
193
        jit_set_Z_PTR(jit, res_addr, ref);
13285
193
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
13286
193
        ir_END_list(end_inputs);
13287
193
      }
13288
13289
193
    }
13290
213
  }
13291
13292
213
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13293
186
    ir_ref arg2;
13294
13295
186
    may_throw = 1;
13296
13297
186
    if (if_type) {
13298
186
      ir_IF_FALSE(if_type);
13299
186
      if_type = IR_UNUSED;
13300
186
    }
13301
13302
186
    if (opline->opcode != ZEND_FETCH_DIM_RW) {
13303
48
      jit_SET_EX_OPLINE(jit, opline);
13304
48
    }
13305
13306
186
      if (opline->op2_type == IS_UNUSED) {
13307
7
      arg2 = IR_NULL;
13308
179
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13309
1
      ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13310
1
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13311
178
    } else {
13312
178
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13313
178
    }
13314
13315
186
    switch (opline->opcode) {
13316
48
      case ZEND_FETCH_DIM_W:
13317
48
      case ZEND_FETCH_LIST_W:
13318
48
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_w_helper),
13319
48
          jit_ZVAL_ADDR(jit, op1_addr),
13320
48
          arg2,
13321
48
          jit_ZVAL_ADDR(jit, res_addr));
13322
48
        break;
13323
138
      case ZEND_FETCH_DIM_RW:
13324
138
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_dim_obj_rw_helper),
13325
138
          jit_ZVAL_ADDR(jit, op1_addr),
13326
138
          arg2,
13327
138
          jit_ZVAL_ADDR(jit, res_addr));
13328
138
        break;
13329
//      case ZEND_FETCH_DIM_UNSET:
13330
//        | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, r0
13331
//        break;
13332
0
      default:
13333
0
        ZEND_UNREACHABLE();
13334
186
      }
13335
13336
186
    if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) {
13337
186
      ir_END_list(end_inputs);
13338
186
    }
13339
186
  }
13340
13341
213
#ifdef ZEND_JIT_USE_RC_INFERENCE
13342
213
  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))) {
13343
    /* ASSIGN_DIM may increase refcount of the key */
13344
23
    op2_info |= MAY_BE_RCN;
13345
23
  }
13346
213
#endif
13347
13348
213
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))
13349
23
   && (op2_info & MAY_HAVE_DTOR)
13350
22
   && (op2_info & MAY_BE_RC1)) {
13351
22
    may_throw = 1;
13352
22
  }
13353
13354
213
  if (end_inputs) {
13355
213
    ir_MERGE_list(end_inputs);
13356
213
  }
13357
13358
213
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13359
13360
213
  if (may_throw) {
13361
207
    zend_jit_check_exception(jit);
13362
207
  }
13363
13364
213
  return 1;
13365
213
}
13366
13367
static int zend_jit_isset_isempty_dim(zend_jit_ctx   *jit,
13368
                                      const zend_op  *opline,
13369
                                      uint32_t        op1_info,
13370
                                      zend_jit_addr   op1_addr,
13371
                                      bool       op1_avoid_refcounting,
13372
                                      uint32_t        op2_info,
13373
                                      zend_jit_addr   op2_addr,
13374
                                      zend_ssa_range *op2_range,
13375
                                      uint8_t         dim_type,
13376
                                      int             may_throw,
13377
                                      uint8_t         smart_branch_opcode,
13378
                                      uint32_t        target_label,
13379
                                      uint32_t        target_label2,
13380
                                      const void     *exit_addr)
13381
4
{
13382
4
  zend_jit_addr res_addr;
13383
4
  ir_ref if_type = IR_UNUSED;
13384
4
  ir_ref false_inputs = IR_UNUSED, end_inputs = IR_UNUSED;
13385
4
  ir_refs *true_inputs;
13386
13387
4
  ir_refs_init(true_inputs, 8);
13388
13389
  // TODO: support for empty() ???
13390
4
  ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY));
13391
13392
4
  res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13393
13394
4
  if (op1_info & MAY_BE_REF) {
13395
1
    ir_ref ref = jit_ZVAL_ADDR(jit, op1_addr);
13396
1
    ref = jit_ZVAL_DEREF_ref(jit, ref);
13397
1
    op1_addr = ZEND_ADDR_REF_ZVAL(ref);
13398
1
  }
13399
13400
4
  if (op1_info & MAY_BE_ARRAY) {
13401
1
    const void *found_exit_addr = NULL;
13402
1
    const void *not_found_exit_addr = NULL;
13403
1
    ir_ref ht_ref;
13404
13405
1
    if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) {
13406
1
      if_type = jit_if_Z_TYPE(jit, op1_addr, IS_ARRAY);
13407
1
      ir_IF_TRUE(if_type);
13408
1
    }
13409
13410
1
    ht_ref = jit_Z_PTR(jit, op1_addr);
13411
13412
1
    if (exit_addr
13413
0
     && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY))
13414
0
     && !may_throw
13415
0
     && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting)
13416
0
     && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) {
13417
0
      if (smart_branch_opcode == ZEND_JMPNZ) {
13418
0
        found_exit_addr = exit_addr;
13419
0
      } else {
13420
0
        not_found_exit_addr = exit_addr;
13421
0
      }
13422
0
    }
13423
1
    if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_JIT_IS, op1_info,
13424
1
        op2_info, op2_addr, op2_range, dim_type, found_exit_addr, not_found_exit_addr, NULL,
13425
1
        false, ht_ref, true_inputs, NULL, &false_inputs, NULL)) {
13426
0
      return 0;
13427
0
    }
13428
13429
1
    if (found_exit_addr) {
13430
0
      ir_MERGE_list(false_inputs);
13431
0
      return 1;
13432
1
    } else if (not_found_exit_addr) {
13433
0
      ir_MERGE_N(true_inputs->count, true_inputs->refs);
13434
0
      return 1;
13435
0
    }
13436
1
  }
13437
13438
4
  if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) {
13439
4
    if (if_type) {
13440
1
      ir_IF_FALSE(if_type);
13441
1
      if_type = IR_UNUSED;
13442
1
    }
13443
13444
4
    if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) {
13445
2
      ir_ref ref, arg1, arg2, if_true;
13446
13447
2
      jit_SET_EX_OPLINE(jit, opline);
13448
2
      arg1 = jit_ZVAL_ADDR(jit, op1_addr);
13449
2
      if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13450
0
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13451
0
        arg2 = ir_CONST_ADDR(Z_ZV(op2_addr)+1);
13452
2
      } else {
13453
2
        arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13454
2
      }
13455
2
      ref = ir_CALL_2(IR_I32, ir_CONST_FC_FUNC(zend_jit_isset_dim_helper), arg1, arg2);
13456
2
      if_true = ir_IF(ref);
13457
2
      ir_IF_TRUE(if_true);
13458
2
      ir_refs_add(true_inputs, ir_END());
13459
2
      ir_IF_FALSE(if_true);
13460
2
      ir_END_list(false_inputs);
13461
2
    } else {
13462
2
      if (op2_info & MAY_BE_UNDEF) {
13463
0
        ir_ref end1 = IR_UNUSED;
13464
13465
0
        if (op2_info & MAY_BE_ANY) {
13466
0
          ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op2_addr));
13467
0
          ir_IF_TRUE(if_def);
13468
0
          end1 = ir_END();
13469
0
          ir_IF_FALSE(if_def);
13470
0
        }
13471
0
        jit_SET_EX_OPLINE(jit, opline);
13472
0
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper), ir_CONST_U32(opline->op2.var));
13473
0
        if (end1) {
13474
0
          ir_MERGE_WITH(end1);
13475
0
        }
13476
0
      }
13477
2
      ir_END_list(false_inputs);
13478
2
    }
13479
4
  }
13480
13481
4
#ifdef ZEND_JIT_USE_RC_INFERENCE
13482
4
  if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) {
13483
    /* Magic offsetExists() may increase refcount of the key */
13484
1
    op2_info |= MAY_BE_RCN;
13485
1
  }
13486
4
#endif
13487
13488
4
  if (true_inputs->count) {
13489
2
    ir_MERGE_N(true_inputs->count, true_inputs->refs);
13490
13491
2
    jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13492
2
    if (!op1_avoid_refcounting) {
13493
2
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13494
2
    }
13495
2
    if (may_throw) {
13496
1
      zend_jit_check_exception_undef_result(jit, opline);
13497
1
    }
13498
2
    if (!(opline->extended_value & ZEND_ISEMPTY)) {
13499
2
      if (exit_addr) {
13500
0
        if (smart_branch_opcode == ZEND_JMPNZ) {
13501
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13502
0
        } else {
13503
0
          ir_END_list(end_inputs);
13504
0
        }
13505
2
      } else if (smart_branch_opcode) {
13506
0
        if (smart_branch_opcode == ZEND_JMPZ) {
13507
0
          _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13508
0
        } else if (smart_branch_opcode == ZEND_JMPNZ) {
13509
0
          _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13510
0
        } else {
13511
0
          ZEND_UNREACHABLE();
13512
0
        }
13513
2
      } else {
13514
2
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_TRUE);
13515
2
        ir_END_list(end_inputs);
13516
2
      }
13517
2
    } else {
13518
0
      ZEND_UNREACHABLE(); // TODO: support for empty()
13519
0
    }
13520
2
  }
13521
13522
4
  ir_MERGE_list(false_inputs);
13523
4
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13524
4
  if (!op1_avoid_refcounting) {
13525
4
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13526
4
  }
13527
4
  if (may_throw) {
13528
1
    zend_jit_check_exception_undef_result(jit, opline);
13529
1
  }
13530
4
  if (!(opline->extended_value & ZEND_ISEMPTY)) {
13531
4
    if (exit_addr) {
13532
0
      if (smart_branch_opcode == ZEND_JMPZ) {
13533
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
13534
0
      } else {
13535
0
        ir_END_list(end_inputs);
13536
0
      }
13537
4
    } else if (smart_branch_opcode) {
13538
0
      if (smart_branch_opcode == ZEND_JMPZ) {
13539
0
        _zend_jit_add_predecessor_ref(jit, target_label, jit->b, ir_END());
13540
0
      } else if (smart_branch_opcode == ZEND_JMPNZ) {
13541
0
        _zend_jit_add_predecessor_ref(jit, target_label2, jit->b, ir_END());
13542
0
      } else {
13543
0
        ZEND_UNREACHABLE();
13544
0
      }
13545
4
    } else {
13546
4
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_FALSE);
13547
4
      ir_END_list(end_inputs);
13548
4
    }
13549
4
  } else {
13550
0
    ZEND_UNREACHABLE(); // TODO: support for empty()
13551
0
  }
13552
13553
4
    if (!exit_addr && smart_branch_opcode) {
13554
0
    jit->b = -1;
13555
4
    } else {
13556
4
    ir_MERGE_list(end_inputs);
13557
4
    }
13558
13559
4
  return 1;
13560
4
}
13561
13562
static int zend_jit_assign_dim(zend_jit_ctx  *jit,
13563
                               const zend_op *opline,
13564
                               uint32_t       op1_info,
13565
                               zend_jit_addr  op1_addr,
13566
                               bool           op1_indirect,
13567
                               uint32_t       op2_info,
13568
                               zend_jit_addr  op2_addr,
13569
                               zend_ssa_range *op2_range,
13570
                               uint32_t       val_info,
13571
                               zend_jit_addr  op3_addr,
13572
                               zend_jit_addr  op3_def_addr,
13573
                               zend_jit_addr  res_addr,
13574
                               uint8_t        dim_type,
13575
                               int            may_throw)
13576
163
{
13577
163
  ir_ref if_type = IR_UNUSED;
13578
163
  ir_ref end_inputs = IR_UNUSED, ht_ref;
13579
13580
163
  if (op3_addr != op3_def_addr && op3_def_addr) {
13581
0
    if (!zend_jit_update_regs(jit, (opline+1)->op1.var, op3_addr, op3_def_addr, val_info)) {
13582
0
      return 0;
13583
0
    }
13584
0
    if (Z_MODE(op3_def_addr) == IS_REG && Z_MODE(op3_addr) != IS_REG) {
13585
0
      op3_addr = op3_def_addr;
13586
0
    }
13587
0
  }
13588
13589
163
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) {
13590
15
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
13591
15
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13592
13593
15
    if (!exit_addr) {
13594
0
      return 0;
13595
0
    }
13596
13597
15
    jit_guard_not_Z_TYPE(jit, op3_addr, IS_UNDEF, exit_addr);
13598
13599
15
    val_info &= ~MAY_BE_UNDEF;
13600
15
  }
13601
13602
163
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13603
13604
163
  if (op1_info & MAY_BE_ARRAY) {
13605
163
    if (opline->op2_type == IS_UNUSED) {
13606
45
      uint32_t var_info = MAY_BE_NULL;
13607
45
      ir_ref if_ok, ref;
13608
45
      zend_jit_addr var_addr;
13609
13610
      // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13611
45
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13612
45
        ht_ref, jit_EG(uninitialized_zval));
13613
13614
      // JIT: if (UNEXPECTED(!var_ptr)) {
13615
45
      if_ok = ir_IF(ref);
13616
45
      ir_IF_FALSE_cold(if_ok);
13617
13618
      // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13619
45
      jit_SET_EX_OPLINE(jit, opline);
13620
45
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13621
13622
45
      ir_END_list(end_inputs);
13623
13624
45
      ir_IF_TRUE(if_ok);
13625
45
      var_addr = ZEND_ADDR_REF_ZVAL(ref);
13626
45
      if (!zend_jit_simple_assign(jit, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, false)) {
13627
0
        return 0;
13628
0
      }
13629
118
    } else {
13630
118
      uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13631
118
      zend_jit_addr var_addr;
13632
118
      ir_ref ref;
13633
118
      ir_refs *found_inputs, *found_values;
13634
13635
118
      ir_refs_init(found_inputs, 8);
13636
118
      ir_refs_init(found_values, 8);
13637
13638
118
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_W, op1_info,
13639
118
          op2_info, op2_addr, op2_range, dim_type, NULL, NULL, NULL,
13640
118
          false, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13641
0
        return 0;
13642
0
      }
13643
13644
118
      if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13645
62
        var_info |= MAY_BE_REF;
13646
62
      }
13647
118
      if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13648
62
        var_info |= MAY_BE_RC1;
13649
62
      }
13650
13651
118
      if (found_inputs->count) {
13652
116
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13653
116
        ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13654
116
        var_addr = ZEND_ADDR_REF_ZVAL(ref);
13655
13656
        // JIT: value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE);
13657
116
        if (opline->op1_type == IS_VAR
13658
7
         && Z_MODE(op3_addr) != IS_REG
13659
7
         && opline->result_type == IS_UNUSED
13660
5
         && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)) {
13661
5
          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)) {
13662
0
            return 0;
13663
0
          }
13664
111
        } else {
13665
111
          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)) {
13666
0
            return 0;
13667
0
          }
13668
111
        }
13669
116
      }
13670
118
    }
13671
13672
163
    ir_END_list(end_inputs);
13673
163
  }
13674
13675
163
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13676
68
    ir_ref arg2, arg4;
13677
13678
68
    if (if_type) {
13679
68
      ir_IF_FALSE_cold(if_type);
13680
68
      if_type = IR_UNUSED;
13681
68
    }
13682
13683
68
    jit_SET_EX_OPLINE(jit, opline);
13684
13685
68
      if (opline->op2_type == IS_UNUSED) {
13686
14
      arg2 = IR_NULL;
13687
54
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13688
0
        ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13689
0
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13690
54
    } else {
13691
54
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13692
54
    }
13693
13694
68
    if (opline->result_type == IS_UNUSED) {
13695
32
      arg4 = IR_NULL;
13696
36
    } else {
13697
36
      arg4 = jit_ZVAL_ADDR(jit, res_addr);
13698
36
    }
13699
68
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_helper),
13700
68
      jit_ZVAL_ADDR(jit, op1_addr),
13701
68
      arg2,
13702
68
      jit_ZVAL_ADDR(jit, op3_addr),
13703
68
      arg4);
13704
13705
68
#ifdef ZEND_JIT_USE_RC_INFERENCE
13706
68
    if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) {
13707
      /* ASSIGN_DIM may increase refcount of the value */
13708
30
      val_info |= MAY_BE_RCN;
13709
30
    }
13710
68
#endif
13711
13712
68
    jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, NULL);
13713
13714
68
    ir_END_list(end_inputs);
13715
68
  }
13716
13717
163
#ifdef ZEND_JIT_USE_RC_INFERENCE
13718
163
  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))) {
13719
    /* ASSIGN_DIM may increase refcount of the key */
13720
37
    op2_info |= MAY_BE_RCN;
13721
37
  }
13722
163
#endif
13723
13724
163
  ir_MERGE_list(end_inputs);
13725
163
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline);
13726
13727
163
  if (!op1_indirect) {
13728
147
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
13729
147
  }
13730
13731
163
  if (may_throw) {
13732
117
    zend_jit_check_exception(jit);
13733
117
  }
13734
13735
163
  return 1;
13736
163
}
13737
13738
static int zend_jit_assign_dim_op(zend_jit_ctx   *jit,
13739
                                  const zend_op  *opline,
13740
                                  uint32_t        op1_info,
13741
                                  uint32_t        op1_def_info,
13742
                                  zend_jit_addr   op1_addr,
13743
                                  bool            op1_indirect,
13744
                                  uint32_t        op2_info,
13745
                                  zend_jit_addr   op2_addr,
13746
                                  zend_ssa_range *op2_range,
13747
                                  uint32_t        op1_data_info,
13748
                                  zend_jit_addr   op3_addr,
13749
                                  zend_ssa_range *op1_data_range,
13750
                                  uint8_t         dim_type,
13751
                                  int             may_throw)
13752
149
{
13753
149
  zend_jit_addr var_addr = IS_UNUSED;
13754
149
  const void *not_found_exit_addr = NULL;
13755
149
  uint32_t var_info = MAY_BE_NULL;
13756
149
  ir_ref if_type = IS_UNUSED;
13757
149
  ir_ref end_inputs = IR_UNUSED, ht_ref;
13758
149
  bool emit_fast_path = true;
13759
13760
149
  ZEND_ASSERT(opline->result_type == IS_UNUSED);
13761
13762
149
  if (may_throw) {
13763
149
    jit_SET_EX_OPLINE(jit, opline);
13764
149
  }
13765
13766
149
  op1_addr = zend_jit_prepare_array_update(jit, opline, &op1_info, op1_addr, &if_type, &ht_ref, &may_throw);
13767
13768
149
  if (Z_MODE(op3_addr) == IS_REG
13769
0
   && Z_LOAD(op3_addr)
13770
0
   && jit->ra[Z_SSA_VAR(op3_addr)].ref == IR_NULL) {
13771
    /* Force load */
13772
0
    zend_jit_use_reg(jit, op3_addr);
13773
0
  }
13774
13775
149
  if (op1_info & MAY_BE_ARRAY) {
13776
149
    uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0);
13777
13778
149
    if (opline->op2_type == IS_UNUSED) {
13779
21
      var_info = MAY_BE_NULL;
13780
21
      ir_ref if_ok, ref;
13781
13782
      // JIT: var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval));
13783
21
      ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_hash_next_index_insert),
13784
21
        ht_ref, jit_EG(uninitialized_zval));
13785
13786
      // JIT: if (UNEXPECTED(!var_ptr)) {
13787
21
      if_ok = ir_IF(ref);
13788
21
      ir_IF_FALSE_cold(if_ok);
13789
13790
      // JIT: zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied");
13791
21
      ir_CALL(IR_VOID, jit_STUB_FUNC_ADDR(jit, jit_stub_cannot_add_element, IR_FASTCALL_FUNC));
13792
13793
21
      ir_END_list(end_inputs);
13794
13795
21
      ir_IF_TRUE(if_ok);
13796
21
      var_addr = ZEND_ADDR_REF_ZVAL(ref);
13797
128
    } else {
13798
128
      ir_ref ref;
13799
128
      ir_refs *found_inputs, *found_values;
13800
13801
128
      ir_refs_init(found_inputs, 8);
13802
128
      ir_refs_init(found_values, 8);
13803
13804
128
      var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0);
13805
128
      if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) {
13806
48
        var_info |= MAY_BE_REF;
13807
48
      }
13808
128
      if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13809
48
        var_info |= MAY_BE_RC1;
13810
48
      }
13811
13812
128
      if (dim_type != IS_UNKNOWN
13813
18
       && dim_type != IS_UNDEF
13814
3
       && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
13815
3
       && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))
13816
3
       && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) {
13817
3
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
13818
3
        not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13819
3
        if (!not_found_exit_addr) {
13820
0
          return 0;
13821
0
        }
13822
3
      }
13823
13824
128
      if (!zend_jit_fetch_dimension_address_inner(jit, opline, BP_VAR_RW, op1_info,
13825
128
          op2_info, op2_addr, op2_range, dim_type, NULL, not_found_exit_addr, NULL,
13826
128
          false, ht_ref, found_inputs, found_values, &end_inputs, NULL)) {
13827
0
        return 0;
13828
0
      }
13829
13830
128
      if (found_inputs->count) {
13831
128
        ir_MERGE_N(found_inputs->count, found_inputs->refs);
13832
128
        ref = ir_PHI_N(IR_ADDR, found_values->count, found_values->refs);
13833
128
        var_addr = ZEND_ADDR_REF_ZVAL(ref);
13834
13835
128
        if (not_found_exit_addr && dim_type != IS_REFERENCE) {
13836
3
          jit_guard_Z_TYPE(jit, var_addr, dim_type, not_found_exit_addr);
13837
3
          var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
13838
3
        }
13839
128
        if (var_info & MAY_BE_REF) {
13840
45
          binary_op_type binary_op = get_binary_op(opline->extended_value);
13841
45
          ir_ref if_ref, if_typed, noref_path, ref_path, ref, reference, ref2, arg2;
13842
13843
45
          ref = jit_ZVAL_ADDR(jit, var_addr);
13844
45
          if_ref = jit_if_Z_TYPE(jit, var_addr, IS_REFERENCE);
13845
45
          ir_IF_FALSE(if_ref);
13846
45
          noref_path = ir_END();
13847
45
          ir_IF_TRUE(if_ref);
13848
13849
45
          reference = jit_Z_PTR_ref(jit, ref);
13850
45
          ref2 = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
13851
45
          if_typed = jit_if_TYPED_REF(jit, reference);
13852
45
          ir_IF_FALSE(if_typed);
13853
45
          ref_path = ir_END();
13854
45
          ir_IF_TRUE_cold(if_typed);
13855
13856
45
          if (Z_MODE(op3_addr) == IS_REG) {
13857
0
            zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
13858
0
            if (!zend_jit_spill_store_inv(jit, op3_addr, real_addr, op1_data_info)) {
13859
0
              return 0;
13860
0
            }
13861
0
            arg2 = jit_ZVAL_ADDR(jit, real_addr);
13862
45
          } else {
13863
45
            arg2 = jit_ZVAL_ADDR(jit, op3_addr);
13864
45
          }
13865
45
          ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
13866
45
            reference, arg2, ir_CONST_FC_FUNC(binary_op));
13867
13868
45
          ir_END_list(end_inputs);
13869
13870
45
          ir_MERGE_2(noref_path, ref_path);
13871
45
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
13872
45
          var_addr = ZEND_ADDR_REF_ZVAL(ref);
13873
45
        }
13874
128
      } else {
13875
0
        emit_fast_path = false;
13876
0
      }
13877
128
    }
13878
13879
149
    if (emit_fast_path) {
13880
149
      uint8_t val_op_type = (opline+1)->op1_type;
13881
13882
149
      if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
13883
        /* prevent FREE_OP in the helpers */
13884
23
        val_op_type = IS_CV;
13885
23
      }
13886
13887
149
      switch (opline->extended_value) {
13888
18
        case ZEND_ADD:
13889
19
        case ZEND_SUB:
13890
130
        case ZEND_MUL:
13891
130
        case ZEND_DIV:
13892
130
          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,
13893
130
              1 /* may overflow */, may_throw)) {
13894
0
            return 0;
13895
0
          }
13896
130
          break;
13897
130
        case ZEND_BW_OR:
13898
4
        case ZEND_BW_AND:
13899
4
        case ZEND_BW_XOR:
13900
4
        case ZEND_SL:
13901
4
        case ZEND_SR:
13902
4
        case ZEND_MOD:
13903
4
          if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
13904
4
              IS_CV, opline->op1, var_addr, var_info, NULL,
13905
4
              val_op_type, (opline+1)->op1, op3_addr, op1_data_info,
13906
4
              op1_data_range,
13907
4
              0, var_addr, var_def_info, var_info, may_throw)) {
13908
0
            return 0;
13909
0
          }
13910
4
          break;
13911
15
        case ZEND_CONCAT:
13912
15
          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,
13913
15
              may_throw)) {
13914
0
            return 0;
13915
0
          }
13916
15
          break;
13917
15
        default:
13918
0
          ZEND_UNREACHABLE();
13919
149
      }
13920
13921
149
      ir_END_list(end_inputs);
13922
149
    }
13923
149
  }
13924
13925
149
  if (op1_info & (MAY_BE_ANY-MAY_BE_ARRAY)) {
13926
45
    binary_op_type binary_op;
13927
45
    ir_ref arg2;
13928
13929
45
    if (if_type) {
13930
45
      ir_IF_FALSE_cold(if_type);
13931
45
      if_type = IS_UNUSED;
13932
45
    }
13933
13934
45
      if (opline->op2_type == IS_UNUSED) {
13935
15
      arg2 = IR_NULL;
13936
30
    } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) {
13937
1
      ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL);
13938
1
      arg2 = ir_CONST_ADDR(Z_ZV(op2_addr) + 1);
13939
29
    } else {
13940
29
      arg2 = jit_ZVAL_ADDR(jit, op2_addr);
13941
29
    }
13942
45
    binary_op = get_binary_op(opline->extended_value);
13943
45
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_dim_op_helper),
13944
45
      jit_ZVAL_ADDR(jit, op1_addr),
13945
45
      arg2,
13946
45
      jit_ZVAL_ADDR(jit, op3_addr),
13947
45
      ir_CONST_FC_FUNC(binary_op));
13948
45
    ir_END_list(end_inputs);
13949
45
  }
13950
13951
149
  if (end_inputs) {
13952
149
    ir_MERGE_list(end_inputs);
13953
149
  }
13954
13955
149
  if (op1_data_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
13956
16
    op1_data_info |= MAY_BE_RC1|MAY_BE_RCN;
13957
16
  }
13958
149
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
13959
149
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
13960
149
  if (!op1_indirect) {
13961
143
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
13962
143
  }
13963
149
  if (may_throw) {
13964
149
    zend_jit_check_exception(jit);
13965
149
  }
13966
13967
149
  return 1;
13968
149
}
13969
13970
static int zend_jit_fe_reset(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
13971
3
{
13972
3
  zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
13973
13974
  // JIT: ZVAL_COPY(res, value);
13975
3
  if (opline->op1_type == IS_CONST) {
13976
3
    zval *zv = RT_CONSTANT(opline, opline->op1);
13977
13978
3
    jit_ZVAL_COPY_CONST(jit, res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, true);
13979
3
  } else {
13980
0
    zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
13981
13982
0
    jit_ZVAL_COPY(jit, res_addr, -1, op1_addr, op1_info, opline->op1_type == IS_CV);
13983
0
  }
13984
13985
  // JIT: Z_FE_POS_P(res) = 0;
13986
3
  ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->result.var + offsetof(zval, u2.fe_pos)), ir_CONST_U32(0));
13987
13988
3
  return 1;
13989
3
}
13990
13991
static int zend_jit_packed_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint32_t op_info)
13992
2
{
13993
2
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD);
13994
2
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
13995
2
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
13996
2
  ir_ref ref;
13997
13998
2
  if (!exit_addr) {
13999
0
    return 0;
14000
0
  }
14001
14002
2
  ref = ir_AND_U32(
14003
2
    ir_LOAD_U32(ir_ADD_OFFSET(jit_Z_PTR(jit, addr), offsetof(zend_array, u.flags))),
14004
2
    ir_CONST_U32(HASH_FLAG_PACKED));
14005
2
  if (op_info & MAY_BE_ARRAY_PACKED) {
14006
2
    ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
14007
2
  } else {
14008
0
    ir_GUARD_NOT(ref, ir_CONST_ADDR(exit_addr));
14009
0
  }
14010
14011
2
  return 1;
14012
2
}
14013
14014
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)
14015
2
{
14016
2
  zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var);
14017
2
  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;
14018
2
  ir_ref if_def_hash = IR_UNUSED, if_def_packed = IR_UNUSED;
14019
2
  ir_ref exit_inputs = IR_UNUSED;
14020
14021
2
  if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) {
14022
    /* empty array */
14023
0
    if (exit_addr) {
14024
0
      if (exit_opcode == ZEND_JMP) {
14025
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
14026
0
      }
14027
0
    } else {
14028
0
      zend_basic_block *bb;
14029
14030
0
      ZEND_ASSERT(jit->b >= 0);
14031
0
      bb = &jit->ssa->cfg.blocks[jit->b];
14032
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ir_END());
14033
0
      jit->b = -1;
14034
0
    }
14035
0
    return 1;
14036
0
  }
14037
14038
  // JIT: array = EX_VAR(opline->op1.var);
14039
  // JIT: fe_ht = Z_ARRVAL_P(array);
14040
2
  ht_ref = jit_Z_PTR(jit, op1_addr);
14041
14042
2
  if (op1_info & MAY_BE_PACKED_GUARD) {
14043
0
    if (!zend_jit_packed_guard(jit, opline, opline->op1.var, op1_info)) {
14044
0
      return 0;
14045
0
    }
14046
0
  }
14047
14048
  // JIT: pos = Z_FE_POS_P(array);
14049
2
  hash_pos_ref = packed_pos_ref = ir_LOAD_U32(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)));
14050
14051
2
  if (MAY_BE_HASH(op1_info)) {
14052
0
    ir_ref loop_ref, pos2_ref, p2_ref;
14053
14054
0
    if (MAY_BE_PACKED(op1_info)) {
14055
0
      ref = ir_AND_U32(
14056
0
        ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, u.flags))),
14057
0
        ir_CONST_U32(HASH_FLAG_PACKED));
14058
0
      if_packed = ir_IF(ref);
14059
0
      ir_IF_FALSE(if_packed);
14060
0
    }
14061
14062
    // JIT: p = fe_ht->arData + pos;
14063
0
    if (sizeof(void*) == 8) {
14064
0
      ref = ir_ZEXT_A(hash_pos_ref);
14065
0
    } else {
14066
0
      ref = ir_BITCAST_A(hash_pos_ref);
14067
0
    }
14068
0
    hash_p_ref = ir_ADD_A(
14069
0
      ir_MUL_A(ref, ir_CONST_ADDR(sizeof(Bucket))),
14070
0
      ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arData))));
14071
14072
0
    loop_ref = ir_LOOP_BEGIN(ir_END());
14073
0
    hash_pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, IR_UNUSED);
14074
0
    hash_p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, IR_UNUSED);
14075
14076
    // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
14077
0
    ref = ir_ULT(hash_pos_ref,
14078
0
      ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
14079
14080
    // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
14081
    // JIT: ZEND_VM_CONTINUE();
14082
14083
0
    if (exit_addr) {
14084
0
      if (exit_opcode == ZEND_JMP) {
14085
0
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
14086
0
      } else {
14087
0
        ir_ref if_fit = ir_IF(ref);
14088
0
        ir_IF_FALSE(if_fit);
14089
0
        ir_END_list(exit_inputs);
14090
0
        ir_IF_TRUE(if_fit);
14091
0
      }
14092
0
    } else {
14093
0
      ir_ref if_fit = ir_IF(ref);
14094
0
      ir_IF_FALSE(if_fit);
14095
0
      ir_END_list(exit_inputs);
14096
0
      ir_IF_TRUE(if_fit);
14097
0
    }
14098
14099
    // JIT: pos++;
14100
0
    pos2_ref = ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1));
14101
14102
    // JIT: value_type = Z_TYPE_INFO_P(value);
14103
    // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
14104
0
    if (!exit_addr || exit_opcode == ZEND_JMP) {
14105
0
      if_def_hash = ir_IF(jit_Z_TYPE_ref(jit, hash_p_ref));
14106
0
      ir_IF_FALSE(if_def_hash);
14107
0
    } else {
14108
0
      ir_GUARD_NOT(jit_Z_TYPE_ref(jit, hash_p_ref), ir_CONST_ADDR(exit_addr));
14109
0
    }
14110
14111
    // JIT: p++;
14112
0
    p2_ref = ir_ADD_OFFSET(hash_p_ref, sizeof(Bucket));
14113
14114
0
    ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
14115
0
    ir_PHI_SET_OP(hash_pos_ref, 2, pos2_ref);
14116
0
    ir_PHI_SET_OP(hash_p_ref, 2, p2_ref);
14117
14118
0
    if (MAY_BE_PACKED(op1_info)) {
14119
0
      ir_IF_TRUE(if_packed);
14120
0
    }
14121
0
  }
14122
2
  if (MAY_BE_PACKED(op1_info)) {
14123
2
    ir_ref loop_ref, pos2_ref, p2_ref;
14124
14125
    // JIT: p = fe_ht->arPacked + pos;
14126
2
    if (sizeof(void*) == 8) {
14127
2
      ref = ir_ZEXT_A(packed_pos_ref);
14128
2
    } else {
14129
0
      ref = ir_BITCAST_A(packed_pos_ref);
14130
0
    }
14131
2
    packed_p_ref = ir_ADD_A(
14132
2
      ir_MUL_A(ref, ir_CONST_ADDR(sizeof(zval))),
14133
2
      ir_LOAD_A(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, arPacked))));
14134
14135
2
    loop_ref = ir_LOOP_BEGIN(ir_END());
14136
2
    packed_pos_ref = ir_PHI_2(IR_U32, packed_pos_ref, IR_UNUSED);
14137
2
    packed_p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, IR_UNUSED);
14138
14139
    // JIT: if (UNEXPECTED(pos >= fe_ht->nNumUsed)) {
14140
2
    ref = ir_ULT(packed_pos_ref,
14141
2
      ir_LOAD_U32(ir_ADD_OFFSET(ht_ref, offsetof(zend_array, nNumUsed))));
14142
14143
    // JIT: ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
14144
    // JIT: ZEND_VM_CONTINUE();
14145
2
    if (exit_addr) {
14146
2
      if (exit_opcode == ZEND_JMP) {
14147
2
        ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
14148
2
      } else {
14149
0
        ir_ref if_fit = ir_IF(ref);
14150
0
        ir_IF_FALSE(if_fit);
14151
0
        ir_END_list(exit_inputs);
14152
0
        ir_IF_TRUE(if_fit);
14153
0
      }
14154
2
    } else {
14155
0
      ir_ref if_fit = ir_IF(ref);
14156
0
      ir_IF_FALSE(if_fit);
14157
0
      ir_END_list(exit_inputs);
14158
0
      ir_IF_TRUE(if_fit);
14159
0
    }
14160
14161
    // JIT: pos++;
14162
2
    pos2_ref = ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1));
14163
14164
    // JIT: value_type = Z_TYPE_INFO_P(value);
14165
    // JIT: if (EXPECTED(value_type != IS_UNDEF)) {
14166
2
    if (!exit_addr || exit_opcode == ZEND_JMP) {
14167
2
      if_def_packed = ir_IF(jit_Z_TYPE_ref(jit, packed_p_ref));
14168
2
      ir_IF_FALSE(if_def_packed);
14169
2
    } else {
14170
0
      ir_GUARD_NOT(jit_Z_TYPE_ref(jit, packed_p_ref), ir_CONST_ADDR(exit_addr));
14171
0
    }
14172
14173
    // JIT: p++;
14174
2
    p2_ref = ir_ADD_OFFSET(packed_p_ref, sizeof(zval));
14175
14176
2
    ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
14177
2
    ir_PHI_SET_OP(packed_pos_ref, 2, pos2_ref);
14178
2
    ir_PHI_SET_OP(packed_p_ref, 2, p2_ref);
14179
2
  }
14180
14181
2
  if (!exit_addr || exit_opcode == ZEND_JMP) {
14182
2
    zend_jit_addr val_addr;
14183
2
    zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var);
14184
2
    uint32_t val_info;
14185
2
    ir_ref p_ref = IR_UNUSED, hash_path = IR_UNUSED;
14186
14187
2
    if (RETURN_VALUE_USED(opline)) {
14188
0
      zend_jit_addr res_addr = RES_ADDR();
14189
14190
0
      if (MAY_BE_HASH(op1_info)) {
14191
0
        ir_ref key_ref = IR_UNUSED, if_key = IR_UNUSED, key_path = IR_UNUSED;
14192
14193
0
        ZEND_ASSERT(if_def_hash);
14194
0
        ir_IF_TRUE(if_def_hash);
14195
14196
        // JIT: Z_FE_POS_P(array) = pos + 1;
14197
0
        ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14198
0
          ir_ADD_U32(hash_pos_ref, ir_CONST_U32(1)));
14199
14200
0
        if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14201
0
          key_ref = ir_LOAD_A(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, key)));
14202
0
        }
14203
0
        if ((op1_info & MAY_BE_ARRAY_KEY_LONG)
14204
0
         && (op1_info & MAY_BE_ARRAY_KEY_STRING)) {
14205
          // JIT: if (!p->key) {
14206
0
          if_key = ir_IF(key_ref);
14207
0
          ir_IF_TRUE(if_key);
14208
0
        }
14209
0
        if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14210
0
          ir_ref if_interned, interned_path;
14211
14212
          // JIT: ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key);
14213
0
          jit_set_Z_PTR(jit, res_addr, key_ref);
14214
0
          ref = ir_AND_U32(
14215
0
            ir_LOAD_U32(ir_ADD_OFFSET(key_ref, offsetof(zend_refcounted, gc.u.type_info))),
14216
0
            ir_CONST_U32(IS_STR_INTERNED));
14217
0
          if_interned = ir_IF(ref);
14218
0
          ir_IF_TRUE(if_interned);
14219
14220
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING);
14221
14222
0
          interned_path = ir_END();
14223
0
          ir_IF_FALSE(if_interned);
14224
14225
0
          jit_GC_ADDREF(jit, key_ref);
14226
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_STRING_EX);
14227
14228
0
          ir_MERGE_WITH(interned_path);
14229
14230
0
          if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
14231
0
            key_path = ir_END();
14232
0
          }
14233
0
        }
14234
0
        if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
14235
0
          if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14236
0
            ir_IF_FALSE(if_key);
14237
0
          }
14238
          // JIT: ZVAL_LONG(EX_VAR(opline->result.var), p->h);
14239
0
          ref = ir_LOAD_L(ir_ADD_OFFSET(hash_p_ref, offsetof(Bucket, h)));
14240
0
          jit_set_Z_LVAL(jit, res_addr, ref);
14241
0
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
14242
14243
0
          if (op1_info & MAY_BE_ARRAY_KEY_STRING) {
14244
0
            ir_MERGE_WITH(key_path);
14245
0
          }
14246
0
        }
14247
0
        if (MAY_BE_PACKED(op1_info)) {
14248
0
          hash_path = ir_END();
14249
0
        } else {
14250
0
          p_ref = hash_p_ref;
14251
0
        }
14252
0
      }
14253
0
      if (MAY_BE_PACKED(op1_info)) {
14254
0
        ZEND_ASSERT(if_def_packed);
14255
0
        ir_IF_TRUE(if_def_packed);
14256
14257
        // JIT: Z_FE_POS_P(array) = pos + 1;
14258
0
        ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14259
0
          ir_ADD_U32(packed_pos_ref, ir_CONST_U32(1)));
14260
14261
        // JIT: ZVAL_LONG(EX_VAR(opline->result.var), pos);
14262
0
        if (sizeof(zend_long) == 8) {
14263
0
          packed_pos_ref = ir_ZEXT_L(packed_pos_ref);
14264
0
        } else {
14265
0
          packed_pos_ref = ir_BITCAST_L(packed_pos_ref);
14266
0
        }
14267
0
        jit_set_Z_LVAL(jit, res_addr, packed_pos_ref);
14268
0
        jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
14269
14270
0
        if (MAY_BE_HASH(op1_info)) {
14271
0
          ir_MERGE_WITH(hash_path);
14272
0
          p_ref = ir_PHI_2(IR_ADDR, packed_p_ref, hash_p_ref);
14273
0
        } else {
14274
0
          p_ref = packed_p_ref;
14275
0
        }
14276
0
      }
14277
2
    } else {
14278
2
      ir_ref pos_ref = IR_UNUSED;
14279
14280
2
      if (if_def_hash && if_def_packed) {
14281
0
        ir_IF_TRUE(if_def_hash);
14282
0
        ir_MERGE_WITH_EMPTY_TRUE(if_def_packed);
14283
0
        pos_ref = ir_PHI_2(IR_U32, hash_pos_ref, packed_pos_ref);
14284
0
        p_ref = ir_PHI_2(IR_ADDR, hash_p_ref, packed_p_ref);
14285
2
      } else if (if_def_hash) {
14286
0
        ir_IF_TRUE(if_def_hash);
14287
0
        pos_ref = hash_pos_ref;
14288
0
        p_ref = hash_p_ref;
14289
2
      } else if (if_def_packed) {
14290
2
        ir_IF_TRUE(if_def_packed);
14291
2
        pos_ref = packed_pos_ref;
14292
2
        p_ref = packed_p_ref;
14293
2
      } else {
14294
0
        ZEND_UNREACHABLE();
14295
0
      }
14296
14297
      // JIT: Z_FE_POS_P(array) = pos + 1;
14298
2
      ir_STORE(ir_ADD_OFFSET(jit_FP(jit), opline->op1.var + offsetof(zval, u2.fe_pos)),
14299
2
        ir_ADD_U32(pos_ref, ir_CONST_U32(1)));
14300
2
    }
14301
14302
2
    val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT);
14303
2
    if (val_info & MAY_BE_ARRAY) {
14304
2
      val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
14305
2
    }
14306
2
    if (op1_info & MAY_BE_ARRAY_OF_REF) {
14307
2
      val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY |
14308
2
        MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
14309
2
    } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
14310
0
      val_info |= MAY_BE_RC1 | MAY_BE_RCN;
14311
0
    }
14312
14313
2
    val_addr = ZEND_ADDR_REF_ZVAL(p_ref);
14314
2
    if (opline->op2_type == IS_CV) {
14315
      // JIT: zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
14316
1
      if (!zend_jit_assign_to_variable(jit, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 0, true)) {
14317
0
        return 0;
14318
0
      }
14319
1
    } else {
14320
      // JIT: ZVAL_DEREF(value);
14321
1
      if (val_info & MAY_BE_REF) {
14322
1
        ir_ref ref = jit_ZVAL_ADDR(jit, val_addr);
14323
1
        ref = jit_ZVAL_DEREF_ref(jit, ref);
14324
1
        val_addr = ZEND_ADDR_REF_ZVAL(ref);
14325
1
        val_info &= ~MAY_BE_REF;
14326
1
      }
14327
      // JIT: ZVAL_COPY(res, value);
14328
1
      jit_ZVAL_COPY(jit, var_addr, -1, val_addr, val_info, true);
14329
1
    }
14330
14331
2
    if (!exit_addr) {
14332
0
      zend_basic_block *bb;
14333
14334
0
      ZEND_ASSERT(jit->b >= 0);
14335
0
      bb = &jit->ssa->cfg.blocks[jit->b];
14336
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[1], jit->b, ir_END());
14337
0
      ZEND_ASSERT(exit_inputs);
14338
0
      if (!jit->ctx.ir_base[exit_inputs].op2) {
14339
0
        ref = exit_inputs;
14340
0
      } else {
14341
0
        ir_MERGE_list(exit_inputs);
14342
0
        ref = ir_END();
14343
0
      }
14344
0
      _zend_jit_add_predecessor_ref(jit, bb->successors[0], jit->b, ref);
14345
0
      jit->b = -1;
14346
0
    }
14347
2
  } else {
14348
0
    ZEND_ASSERT(exit_inputs);
14349
0
    ir_MERGE_list(exit_inputs);
14350
0
  }
14351
14352
2
  return 1;
14353
2
}
14354
14355
static int zend_jit_load_this(zend_jit_ctx *jit, uint32_t var)
14356
3
{
14357
3
  zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14358
3
  zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
14359
3
  ir_ref ref = jit_Z_PTR(jit, this_addr);
14360
14361
3
  jit_set_Z_PTR(jit, var_addr, ref);
14362
3
  jit_set_Z_TYPE_INFO(jit, var_addr, IS_OBJECT_EX);
14363
3
  jit_GC_ADDREF(jit, ref);
14364
14365
3
  return 1;
14366
3
}
14367
14368
static int zend_jit_fetch_this(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array, bool check_only)
14369
3
{
14370
3
  if (!op_array->scope ||
14371
0
      (op_array->fn_flags & ZEND_ACC_STATIC) ||
14372
3
      ((op_array->fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_IMMUTABLE)) == ZEND_ACC_CLOSURE)) {
14373
3
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14374
0
      if (!JIT_G(current_frame) ||
14375
0
          !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) {
14376
14377
0
        zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14378
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14379
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14380
14381
0
        if (!exit_addr) {
14382
0
          return 0;
14383
0
        }
14384
14385
0
        jit_guard_Z_TYPE(jit, this_addr, IS_OBJECT, exit_addr);
14386
14387
0
        if (JIT_G(current_frame)) {
14388
0
          TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame));
14389
0
        }
14390
0
      }
14391
3
    } else {
14392
3
      zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14393
3
      ir_ref if_object = jit_if_Z_TYPE(jit, this_addr, IS_OBJECT);
14394
14395
3
      ir_IF_FALSE_cold(if_object);
14396
3
      jit_SET_EX_OPLINE(jit, opline);
14397
3
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_invalid_this));
14398
14399
3
      ir_IF_TRUE(if_object);
14400
3
    }
14401
3
  }
14402
14403
3
  if (!check_only) {
14404
3
    if (!zend_jit_load_this(jit, opline->result.var)) {
14405
0
      return 0;
14406
0
    }
14407
3
  }
14408
14409
3
  return 1;
14410
3
}
14411
14412
static int zend_jit_class_guard(zend_jit_ctx *jit, const zend_op *opline, ir_ref obj_ref, zend_class_entry *ce)
14413
0
{
14414
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
14415
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14416
14417
0
  if (!exit_addr) {
14418
0
    return 0;
14419
0
  }
14420
14421
0
  ir_GUARD(ir_EQ(ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce))), ir_CONST_ADDR(ce)),
14422
0
    ir_CONST_ADDR(exit_addr));
14423
14424
0
  return 1;
14425
0
}
14426
14427
static int zend_jit_func_arg_by_ref_guard(zend_jit_ctx *jit, const zend_op *opline)
14428
0
{
14429
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14430
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14431
0
  ir_ref rx, call_info;
14432
14433
0
  if (!exit_addr) {
14434
0
    return 0;
14435
0
  }
14436
0
  if (jit->reuse_ip) {
14437
0
    rx = jit_IP(jit);
14438
0
  } else {
14439
0
    rx = ir_LOAD_A(jit_EX(call));
14440
0
  }
14441
0
  call_info = ir_LOAD_U32(jit_CALL(rx, This.u1.type_info));
14442
0
  ir_GUARD_NOT(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)),
14443
0
    ir_CONST_ADDR(exit_addr));
14444
0
  return 1;
14445
0
}
14446
14447
static int zend_jit_fetch_obj(zend_jit_ctx         *jit,
14448
                              const zend_op        *opline,
14449
                              const zend_op_array  *op_array,
14450
                              zend_ssa             *ssa,
14451
                              const zend_ssa_op    *ssa_op,
14452
                              uint32_t              op1_info,
14453
                              zend_jit_addr         op1_addr,
14454
                              bool                  op1_indirect,
14455
                              zend_class_entry     *ce,
14456
                              bool                  ce_is_instanceof,
14457
                              bool                  on_this,
14458
                              bool                  delayed_fetch_this,
14459
                              bool                  op1_avoid_refcounting,
14460
                              zend_class_entry     *trace_ce,
14461
                              zend_jit_addr         res_addr,
14462
                              uint8_t               prop_type,
14463
                              int                   may_throw)
14464
213
{
14465
213
  zval *member;
14466
213
  zend_property_info *prop_info;
14467
213
  bool may_be_dynamic = true;
14468
213
  zend_jit_addr prop_addr;
14469
213
  uint32_t res_info = RES_INFO();
14470
213
  ir_ref prop_type_ref = IR_UNUSED;
14471
213
  ir_ref obj_ref = IR_UNUSED;
14472
213
  ir_ref prop_ref = IR_UNUSED;
14473
213
  ir_ref end_inputs = IR_UNUSED;
14474
213
  ir_ref slow_inputs = IR_UNUSED;
14475
213
  ir_ref end_values = IR_UNUSED;
14476
213
  const void *undef_exit_addr = NULL;
14477
14478
213
  ZEND_ASSERT(opline->op2_type == IS_CONST);
14479
213
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
14480
14481
213
  member = RT_CONSTANT(opline, opline->op2);
14482
213
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
14483
213
  prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename);
14484
14485
213
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_type == IS_UNDEF) {
14486
0
    prop_info = NULL;
14487
0
    trace_ce = NULL;
14488
0
  }
14489
14490
213
  if (on_this) {
14491
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
14492
0
    obj_ref = jit_Z_PTR(jit, this_addr);
14493
213
  } else {
14494
213
    if (opline->op1_type == IS_VAR
14495
2
     && opline->opcode == ZEND_FETCH_OBJ_W
14496
2
     && (op1_info & MAY_BE_INDIRECT)
14497
2
     && Z_REG(op1_addr) == ZREG_FP) {
14498
2
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
14499
2
    }
14500
213
    if (op1_info & MAY_BE_REF) {
14501
200
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
14502
200
    }
14503
213
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
14504
209
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14505
27
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14506
27
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14507
14508
27
        if (!exit_addr) {
14509
0
          return 0;
14510
0
        }
14511
27
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
14512
182
      } else {
14513
182
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
14514
14515
182
        ir_IF_FALSE_cold(if_obj);
14516
182
        if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14517
173
          ir_ref op1_ref = IR_UNUSED;
14518
14519
173
          jit_SET_EX_OPLINE(jit, opline);
14520
173
          if (opline->opcode != ZEND_FETCH_OBJ_W && (op1_info & MAY_BE_UNDEF)) {
14521
167
            zend_jit_addr orig_op1_addr = OP1_ADDR();
14522
167
            ir_ref fast_path = IR_UNUSED;
14523
14524
167
            if (op1_info & MAY_BE_ANY) {
14525
167
              ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
14526
167
              ir_IF_TRUE(if_def);
14527
167
              fast_path = ir_END();
14528
167
              ir_IF_FALSE_cold(if_def);
14529
167
            }
14530
167
            ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
14531
167
              ir_CONST_U32(opline->op1.var));
14532
167
            if (fast_path) {
14533
167
              ir_MERGE_WITH(fast_path);
14534
167
            }
14535
167
            op1_ref = jit_ZVAL_ADDR(jit, orig_op1_addr);
14536
167
          } else {
14537
6
            op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
14538
6
          }
14539
173
          if (opline->opcode == ZEND_FETCH_OBJ_W) {
14540
6
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_write),
14541
6
              op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14542
6
            jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14543
167
          } else {
14544
167
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_read),
14545
167
              op1_ref, ir_CONST_ADDR(Z_STRVAL_P(member)));
14546
167
            jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14547
167
          }
14548
173
        } else {
14549
9
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
14550
9
        }
14551
182
        ir_END_list(end_inputs);
14552
14553
182
        ir_IF_TRUE(if_obj);
14554
182
      }
14555
209
    }
14556
213
    obj_ref = jit_Z_PTR(jit, op1_addr);
14557
213
  }
14558
14559
213
  ZEND_ASSERT(obj_ref);
14560
213
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
14561
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename);
14562
0
    if (prop_info) {
14563
0
      ce = trace_ce;
14564
0
      ce_is_instanceof = false;
14565
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
14566
0
        if (on_this && JIT_G(current_frame)
14567
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
14568
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
14569
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
14570
0
          if (on_this && JIT_G(current_frame)) {
14571
0
            JIT_G(current_frame)->ce = ce;
14572
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
14573
0
          }
14574
0
        } else {
14575
0
          return 0;
14576
0
        }
14577
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
14578
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
14579
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
14580
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
14581
0
        }
14582
0
      }
14583
0
    }
14584
0
  }
14585
14586
213
  if (!prop_info) {
14587
213
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
14588
213
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
14589
213
    ir_ref if_same = ir_IF(ir_EQ(ref,
14590
213
      ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
14591
14592
213
    ir_IF_FALSE_cold(if_same);
14593
213
    ir_END_list(slow_inputs);
14594
14595
213
    ir_IF_TRUE(if_same);
14596
213
    ir_ref offset_ref = ir_LOAD_A(
14597
213
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
14598
14599
213
    may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array);
14600
213
    if (may_be_dynamic) {
14601
213
      ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
14602
213
      if (opline->opcode == ZEND_FETCH_OBJ_W) {
14603
6
        ir_IF_TRUE_cold(if_dynamic);
14604
6
        ir_END_list(slow_inputs);
14605
207
      } else {
14606
207
        ir_IF_TRUE_cold(if_dynamic);
14607
207
        jit_SET_EX_OPLINE(jit, opline);
14608
14609
207
        if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14610
197
          if (Z_MODE(res_addr) == IS_REG) {
14611
0
            ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
14612
0
              obj_ref, offset_ref);
14613
0
            ir_END_PHI_list(end_values, val_addr);
14614
197
          } else {
14615
197
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
14616
197
              obj_ref, offset_ref);
14617
197
            ir_END_list(end_inputs);
14618
197
          }
14619
197
        } else {
14620
10
          if (Z_MODE(res_addr) == IS_REG) {
14621
0
            ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
14622
0
              obj_ref, offset_ref);
14623
0
            ir_END_PHI_list(end_values, val_addr);
14624
10
          } else {
14625
10
            ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
14626
10
              obj_ref, offset_ref);
14627
10
            ir_END_list(end_inputs);
14628
10
          }
14629
10
        }
14630
207
      }
14631
213
      ir_IF_FALSE(if_dynamic);
14632
213
    }
14633
213
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
14634
213
    prop_type_ref = jit_Z_TYPE_ref(jit, prop_ref);
14635
213
    ir_ref if_def = ir_IF(prop_type_ref);
14636
213
    ir_IF_FALSE_cold(if_def);
14637
213
    ir_END_list(slow_inputs);
14638
213
    ir_IF_TRUE(if_def);
14639
213
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14640
213
    if (opline->opcode == ZEND_FETCH_OBJ_W
14641
6
     && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) {
14642
6
      uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14643
14644
6
      ir_ref allowed_inputs = IR_UNUSED;
14645
6
      ir_ref forbidden_inputs = IR_UNUSED;
14646
14647
6
      ir_ref prop_info_ref = ir_LOAD_A(
14648
6
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
14649
6
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
14650
14651
6
      ir_IF_TRUE_cold(if_has_prop_info);
14652
14653
6
      ir_ref prop_flags = ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, flags)));
14654
6
      ir_ref if_readonly_or_avis = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY|ZEND_ACC_PPP_SET_MASK)));
14655
14656
6
      ir_IF_FALSE(if_readonly_or_avis);
14657
6
      ir_END_list(allowed_inputs);
14658
14659
6
      ir_IF_TRUE_cold(if_readonly_or_avis);
14660
14661
6
      ir_ref if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14662
6
      ir_IF_TRUE(if_readonly);
14663
6
      ir_END_list(forbidden_inputs);
14664
14665
6
      ir_IF_FALSE(if_readonly);
14666
6
      ir_ref has_avis_access = ir_CALL_1(IR_BOOL, ir_CONST_FC_FUNC(zend_asymmetric_property_has_set_access), prop_info_ref);
14667
6
      ir_ref if_avis_access = ir_IF(has_avis_access);
14668
6
      ir_IF_TRUE(if_avis_access);
14669
6
      ir_END_list(allowed_inputs);
14670
14671
6
      ir_IF_FALSE(if_avis_access);
14672
6
      ir_END_list(forbidden_inputs);
14673
14674
6
      ir_MERGE_list(forbidden_inputs);
14675
14676
6
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14677
6
      ir_IF_TRUE(if_prop_obj);
14678
6
      ref = jit_Z_PTR(jit, prop_addr);
14679
6
      jit_GC_ADDREF(jit, ref);
14680
6
      jit_set_Z_PTR(jit, res_addr, ref);
14681
6
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14682
6
      ir_END_list(end_inputs);
14683
14684
6
      ir_IF_FALSE_cold(if_prop_obj);
14685
14686
6
      jit_SET_EX_OPLINE(jit, opline);
14687
6
      if_readonly = ir_IF(ir_AND_U32(prop_flags, ir_CONST_U32(ZEND_ACC_READONLY)));
14688
6
      ir_IF_TRUE(if_readonly);
14689
6
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), prop_info_ref);
14690
6
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14691
6
      ir_END_list(end_inputs);
14692
14693
6
      ir_IF_FALSE(if_readonly);
14694
6
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14695
6
        prop_info_ref, ir_CONST_ADDR("indirectly modify"));
14696
6
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14697
6
      ir_END_list(end_inputs);
14698
14699
6
      ir_MERGE_list(allowed_inputs);
14700
14701
6
      if (flags == ZEND_FETCH_DIM_WRITE) {
14702
1
        jit_SET_EX_OPLINE(jit, opline);
14703
1
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14704
1
          prop_ref, prop_info_ref);
14705
1
        ir_END_list(end_inputs);
14706
1
        ir_IF_FALSE(if_has_prop_info);
14707
5
      } else if (flags == ZEND_FETCH_REF) {
14708
4
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14709
4
          prop_ref,
14710
4
          prop_info_ref,
14711
4
          jit_ZVAL_ADDR(jit, res_addr));
14712
4
        ir_END_list(end_inputs);
14713
4
        ir_IF_FALSE(if_has_prop_info);
14714
4
      } else {
14715
1
        ZEND_ASSERT(flags == 0);
14716
1
        ir_MERGE_WITH_EMPTY_FALSE(if_has_prop_info);
14717
1
      }
14718
6
    }
14719
213
  } else {
14720
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
14721
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
14722
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
14723
0
      if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) {
14724
        /* perform IS_UNDEF check only after result type guard (during deoptimization) */
14725
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
14726
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
14727
14728
0
        if (!exit_addr) {
14729
0
          return 0;
14730
0
        }
14731
0
        if (opline->opcode != ZEND_FETCH_OBJ_W
14732
0
         && !(res_info & MAY_BE_GUARD)
14733
0
         && Z_MODE(res_addr) == IS_REG) {
14734
          /* perform IS_UNDEF check together with the dereference of the result */
14735
0
          undef_exit_addr = exit_addr;
14736
0
        } else {
14737
0
          prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14738
0
          ir_GUARD(prop_type_ref, ir_CONST_ADDR(exit_addr));
14739
0
        }
14740
0
      }
14741
0
    } else {
14742
0
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14743
0
      ir_ref if_def = ir_IF(prop_type_ref);
14744
0
      ir_IF_FALSE_cold(if_def);
14745
0
      ir_END_list(slow_inputs);
14746
0
      ir_IF_TRUE(if_def);
14747
0
    }
14748
0
    if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) {
14749
0
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14750
0
      ir_IF_TRUE(if_prop_obj);
14751
0
      ir_ref ref = jit_Z_PTR(jit, prop_addr);
14752
0
      jit_GC_ADDREF(jit, ref);
14753
0
      jit_set_Z_PTR(jit, res_addr, ref);
14754
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14755
0
      ir_END_list(end_inputs);
14756
14757
0
      ir_IF_FALSE_cold(if_prop_obj);
14758
0
      jit_SET_EX_OPLINE(jit, opline);
14759
0
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_readonly_property_indirect_modification_error), ir_CONST_ADDR(prop_info));
14760
0
      jit_set_Z_TYPE_INFO(jit, res_addr, _IS_ERROR);
14761
0
      ir_END_list(end_inputs);
14762
14763
0
      goto result_fetched;
14764
0
    } else if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_PPP_SET_MASK)) {
14765
      /* Readonly properties which are also asymmetric are never mutable indirectly, which is
14766
       * handled by the previous branch. */
14767
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));
14768
14769
0
      ir_ref if_access = ir_IF(has_access);
14770
0
      ir_IF_FALSE_cold(if_access);
14771
14772
0
      ir_ref if_prop_obj = jit_if_Z_TYPE(jit, prop_addr, IS_OBJECT);
14773
0
      ir_IF_TRUE(if_prop_obj);
14774
0
      ir_ref ref = jit_Z_PTR(jit, prop_addr);
14775
0
      jit_GC_ADDREF(jit, ref);
14776
0
      jit_set_Z_PTR(jit, res_addr, ref);
14777
0
      jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
14778
0
      ir_END_list(end_inputs);
14779
14780
0
      ir_IF_FALSE_cold(if_prop_obj);
14781
0
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_asymmetric_visibility_property_modification_error),
14782
0
        ir_CONST_ADDR(prop_info), ir_CONST_ADDR("indirectly modify"));
14783
0
      ir_END_list(end_inputs);
14784
14785
0
      ir_IF_TRUE(if_access);
14786
0
    }
14787
14788
0
    if (opline->opcode == ZEND_FETCH_OBJ_W
14789
0
     && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS)
14790
0
     && ZEND_TYPE_IS_SET(prop_info->type)) {
14791
0
      uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
14792
14793
0
      if (flags == ZEND_FETCH_DIM_WRITE) {
14794
0
        if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) {
14795
0
          if (!prop_type_ref) {
14796
0
            prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14797
0
          }
14798
0
          ir_ref if_null_or_flase = ir_IF(ir_LE(prop_type_ref, ir_CONST_U32(IR_FALSE)));
14799
0
          ir_IF_TRUE_cold(if_null_or_flase);
14800
0
          jit_SET_EX_OPLINE(jit, opline);
14801
0
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_check_array_promotion),
14802
0
            prop_ref, ir_CONST_ADDR(prop_info));
14803
0
          ir_END_list(end_inputs);
14804
0
          ir_IF_FALSE(if_null_or_flase);
14805
0
        }
14806
0
      } else if (flags == ZEND_FETCH_REF) {
14807
0
        ir_ref ref;
14808
14809
0
        if (!prop_type_ref) {
14810
0
          prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14811
0
        }
14812
14813
0
        ir_ref if_reference = ir_IF(ir_EQ(prop_type_ref, ir_CONST_U32(IS_REFERENCE_EX)));
14814
0
        ir_IF_FALSE(if_reference);
14815
0
        if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
14816
0
          ref = ir_CONST_ADDR(prop_info);
14817
0
        } else {
14818
0
          int prop_info_offset =
14819
0
            (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
14820
14821
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
14822
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
14823
0
          ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
14824
0
        }
14825
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_create_typed_ref),
14826
0
          prop_ref,
14827
0
          ref,
14828
0
          jit_ZVAL_ADDR(jit, res_addr));
14829
0
        ir_END_list(end_inputs);
14830
0
        ir_IF_TRUE(if_reference);
14831
0
      } else {
14832
0
        ZEND_UNREACHABLE();
14833
0
      }
14834
0
    }
14835
0
  }
14836
14837
213
  if (opline->opcode == ZEND_FETCH_OBJ_W) {
14838
6
    ZEND_ASSERT(prop_ref);
14839
6
    jit_set_Z_PTR(jit, res_addr, prop_ref);
14840
6
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
14841
6
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) {
14842
0
      ssa->var_info[ssa_op->result_def].indirect_reference = 1;
14843
0
    }
14844
6
    ir_END_list(end_inputs);
14845
207
  } else {
14846
207
    if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
14847
0
      ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14848
207
    } else if ((res_info & MAY_BE_GUARD) && Z_MODE(res_addr) == IS_REG) {
14849
0
      ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14850
207
    } else if (Z_MODE(res_addr) == IS_REG) {
14851
0
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14852
14853
0
      if (!zend_jit_zval_copy_deref_reg(jit, res_addr, res_info & ~MAY_BE_GUARD, prop_addr, prop_type_ref, &end_values, undef_exit_addr)) {
14854
0
        return 0;
14855
0
      }
14856
207
    } else {
14857
207
      prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14858
14859
207
      if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14860
0
        return 0;
14861
0
      }
14862
207
      ir_END_list(end_inputs);
14863
207
    }
14864
207
  }
14865
14866
213
result_fetched:
14867
213
  if (op1_avoid_refcounting) {
14868
0
    SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14869
0
  }
14870
14871
213
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14872
213
    ir_MERGE_list(slow_inputs);
14873
213
    jit_SET_EX_OPLINE(jit, opline);
14874
14875
213
    op1_info |= MAY_BE_RC1 | MAY_BE_RCN; /* object may be captured/released in magic handler */
14876
213
    if (opline->opcode == ZEND_FETCH_OBJ_W) {
14877
6
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14878
6
      ir_END_list(end_inputs);
14879
207
    } else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14880
197
      if (Z_MODE(res_addr) == IS_REG) {
14881
0
        ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14882
0
        ir_END_PHI_list(end_values, val_ref);
14883
197
      } else {
14884
197
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14885
197
        ir_END_list(end_inputs);
14886
197
      }
14887
197
    } else {
14888
10
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14889
10
      ir_END_list(end_inputs);
14890
10
    }
14891
213
  }
14892
14893
213
  if (end_values) {
14894
0
    ir_ref val_ref = ir_PHI_list(end_values);
14895
0
    zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
14896
0
    bool result_avoid_refcounting = false;
14897
14898
0
    ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14899
0
      || opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14900
0
      || opline->opcode == ZEND_FETCH_OBJ_IS);
14901
0
    ZEND_ASSERT(end_inputs == IR_UNUSED);
14902
0
    if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
14903
0
      uint8_t type = concrete_type(res_info);
14904
0
      uint32_t flags = ZEND_JIT_EXIT_CHECK_EXCEPTION;
14905
14906
0
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
14907
0
       && !delayed_fetch_this
14908
0
       && !op1_avoid_refcounting) {
14909
0
        flags |= ZEND_JIT_EXIT_FREE_OP1;
14910
0
      }
14911
14912
0
      if ((opline->result_type & (IS_VAR|IS_TMP_VAR))
14913
0
       && !(flags & ZEND_JIT_EXIT_FREE_OP1)
14914
0
       && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))
14915
0
       && (ssa_op+1)->op1_use == ssa_op->result_def
14916
0
       && zend_jit_may_avoid_refcounting(opline+1, res_info)) {
14917
0
        result_avoid_refcounting = true;
14918
0
        ssa->var_info[ssa_op->result_def].avoid_refcounting = 1;
14919
0
      }
14920
14921
0
      val_addr = zend_jit_guard_fetch_result_type(jit, opline, val_addr, type,
14922
0
        true, flags, op1_avoid_refcounting);
14923
0
      if (!val_addr) {
14924
0
        return 0;
14925
0
      }
14926
14927
0
      res_info &= ~MAY_BE_GUARD;
14928
0
      ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14929
0
    }
14930
14931
    // ZVAL_COPY
14932
0
    jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14933
14934
0
    if (!zend_jit_store_var_if_necessary(jit, opline->result.var, res_addr, res_info)) {
14935
0
      return 0;
14936
0
    }
14937
213
  } else {
14938
213
    ir_MERGE_list(end_inputs);
14939
213
  }
14940
14941
213
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
14942
213
    if (opline->op1_type == IS_VAR
14943
2
     && opline->opcode == ZEND_FETCH_OBJ_W
14944
2
     && (op1_info & MAY_BE_RC1)) {
14945
2
      zend_jit_addr orig_op1_addr = OP1_ADDR();
14946
2
      ir_ref if_refcounted, ptr, refcount, if_non_zero;
14947
2
      ir_ref merge_inputs = IR_UNUSED;
14948
14949
2
      if_refcounted = jit_if_REFCOUNTED(jit, orig_op1_addr);
14950
2
      ir_IF_FALSE( if_refcounted);
14951
2
      ir_END_list(merge_inputs);
14952
2
      ir_IF_TRUE( if_refcounted);
14953
2
      ptr = jit_Z_PTR(jit, orig_op1_addr);
14954
2
      refcount = jit_GC_DELREF(jit, ptr);
14955
2
      if_non_zero = ir_IF(refcount);
14956
2
      ir_IF_TRUE( if_non_zero);
14957
2
      ir_END_list(merge_inputs);
14958
2
      ir_IF_FALSE( if_non_zero);
14959
2
      jit_SET_EX_OPLINE(jit, opline);
14960
2
      ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_extract_helper), ptr);
14961
2
      ir_END_list(merge_inputs);
14962
2
      ir_MERGE_list(merge_inputs);
14963
211
    } else if (!op1_avoid_refcounting) {
14964
211
      if (on_this) {
14965
0
        op1_info &= ~MAY_BE_RC1;
14966
0
      }
14967
211
      jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
14968
211
    }
14969
213
  }
14970
14971
213
  if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
14972
31
   && prop_info
14973
0
   && (opline->opcode != ZEND_FETCH_OBJ_W ||
14974
0
       !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) ||
14975
0
       !ZEND_TYPE_IS_SET(prop_info->type))
14976
0
   && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) {
14977
0
    may_throw = 0;
14978
0
  }
14979
14980
213
  if (may_throw) {
14981
213
    if (Z_MODE(res_addr) == IS_REG) {
14982
0
      zend_jit_check_exception_undef_result(jit, opline);
14983
213
    } else {
14984
213
      zend_jit_check_exception(jit);
14985
213
    }
14986
213
  }
14987
14988
213
  return 1;
14989
213
}
14990
14991
static int zend_jit_fetch_obj_func_arg(zend_jit_ctx *jit, const zend_op *opline,
14992
    const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op,
14993
    uint32_t op1_info, zend_jit_addr op1_addr, zend_class_entry *ce,
14994
    bool ce_is_instanceof, bool on_this, zend_jit_addr res_addr)
14995
1
{
14996
1
  ir_ref rx, call_info, if_by_ref, end_by_ref;
14997
14998
  /* Both runtime paths must observe a consistent frame state.  The delayed
14999
   * call chain would otherwise only be flushed inside the by-ref branch (by
15000
   * zend_jit_set_ip() in zend_jit_handler()), leaving EX(call) stale on the
15001
   * by-val path and after the merge.  Flush it before branching. */
15002
1
  if (jit->delayed_call_level) {
15003
0
    if (!zend_jit_save_call_chain(jit, jit->delayed_call_level)) {
15004
0
      return 0;
15005
0
    }
15006
0
  }
15007
15008
  /* JIT: if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_SEND_ARG_BY_REF) */
15009
1
  if (jit->reuse_ip) {
15010
1
    rx = jit_IP(jit);
15011
1
  } else {
15012
0
    rx = ir_LOAD_A(jit_EX(call));
15013
0
  }
15014
1
  call_info = ir_LOAD_U32(jit_CALL(rx, This.u1.type_info));
15015
1
  if_by_ref = ir_IF(ir_AND_U32(call_info, ir_CONST_U32(ZEND_CALL_SEND_ARG_BY_REF)));
15016
15017
  /* by-ref path: the FUNC_ARG handler re-checks the flag and dispatches
15018
   * into FETCH_OBJ_W */
15019
1
  ir_IF_TRUE_cold(if_by_ref);
15020
1
  if (!zend_jit_handler(jit, opline, zend_may_throw(opline, ssa_op, op_array, ssa))) {
15021
0
    return 0;
15022
0
  }
15023
1
  end_by_ref = ir_END();
15024
15025
  /* zend_jit_handler() stored IP = opline + 1 on the by-ref path only;
15026
   * that compile-time knowledge is invalid for the by-val path and after
15027
   * the merge. */
15028
1
  zend_jit_reset_last_valid_opline(jit);
15029
15030
  /* by-val path */
15031
1
  ir_IF_FALSE(if_by_ref);
15032
1
  if (!zend_jit_fetch_obj(jit, opline, op_array, ssa, ssa_op,
15033
1
      op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
15034
1
      res_addr, IS_UNKNOWN,
15035
1
      zend_may_throw(opline, ssa_op, op_array, ssa))) {
15036
0
    return 0;
15037
0
  }
15038
1
  ir_MERGE_WITH(end_by_ref);
15039
15040
1
  return 1;
15041
1
}
15042
15043
15044
static int zend_jit_assign_obj(zend_jit_ctx         *jit,
15045
                               const zend_op        *opline,
15046
                               const zend_op_array  *op_array,
15047
                               zend_ssa             *ssa,
15048
                               const zend_ssa_op    *ssa_op,
15049
                               uint32_t              op1_info,
15050
                               zend_jit_addr         op1_addr,
15051
                               uint32_t              val_info,
15052
                               zend_jit_addr         val_addr,
15053
                               zend_jit_addr         val_def_addr,
15054
                               zend_jit_addr         res_addr,
15055
                               bool                  op1_indirect,
15056
                               zend_class_entry     *ce,
15057
                               bool                  ce_is_instanceof,
15058
                               bool                  on_this,
15059
                               bool                  delayed_fetch_this,
15060
                               zend_class_entry     *trace_ce,
15061
                               uint8_t               prop_type,
15062
                               int                   may_throw)
15063
10
{
15064
10
  zval *member;
15065
10
  zend_string *name;
15066
10
  zend_property_info *prop_info;
15067
10
  zend_jit_addr prop_addr;
15068
10
  ir_ref obj_ref = IR_UNUSED;
15069
10
  ir_ref prop_ref = IR_UNUSED;
15070
10
  ir_ref delayed_end_input = IR_UNUSED;
15071
10
  ir_ref end_inputs = IR_UNUSED;
15072
10
  ir_ref slow_inputs = IR_UNUSED;
15073
10
  uint32_t res_info = RES_INFO();
15074
15075
10
  if (Z_MODE(val_addr) == IS_REG
15076
0
   && Z_LOAD(val_addr)
15077
0
   && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
15078
    /* Force load */
15079
0
    zend_jit_use_reg(jit, val_addr);
15080
0
  }
15081
15082
10
  if (val_addr != val_def_addr && val_def_addr) {
15083
0
    if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
15084
0
      return 0;
15085
0
    }
15086
0
    if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
15087
0
      val_addr = val_def_addr;
15088
0
    }
15089
0
  }
15090
15091
10
  ZEND_ASSERT(opline->op2_type == IS_CONST);
15092
10
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15093
15094
10
  member = RT_CONSTANT(opline, opline->op2);
15095
10
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15096
10
  name = Z_STR_P(member);
15097
10
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15098
15099
10
  if (on_this) {
15100
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15101
0
    obj_ref = jit_Z_PTR(jit, this_addr);
15102
10
  } else {
15103
10
    if (opline->op1_type == IS_VAR
15104
2
     && (op1_info & MAY_BE_INDIRECT)
15105
2
     && Z_REG(op1_addr) == ZREG_FP) {
15106
2
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15107
2
    }
15108
10
    if (op1_info & MAY_BE_REF) {
15109
10
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15110
10
    }
15111
10
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15112
10
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15113
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15114
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15115
15116
0
        if (!exit_addr) {
15117
0
          return 0;
15118
0
        }
15119
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15120
10
      } else {
15121
10
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15122
10
        ir_IF_FALSE_cold(if_obj);
15123
15124
10
        jit_SET_EX_OPLINE(jit, opline);
15125
10
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15126
10
          jit_ZVAL_ADDR(jit, op1_addr),
15127
10
          ir_CONST_ADDR(ZSTR_VAL(name)));
15128
15129
10
        if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
15130
8
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
15131
8
        }
15132
15133
10
        ir_END_list(end_inputs);
15134
15135
10
        ir_IF_TRUE(if_obj);
15136
10
      }
15137
10
    }
15138
10
    obj_ref = jit_Z_PTR(jit, op1_addr);
15139
10
  }
15140
15141
10
  ZEND_ASSERT(obj_ref);
15142
10
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15143
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15144
0
    if (prop_info) {
15145
0
      ce = trace_ce;
15146
0
      ce_is_instanceof = false;
15147
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15148
0
        if (on_this && JIT_G(current_frame)
15149
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15150
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15151
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15152
0
          if (on_this && JIT_G(current_frame)) {
15153
0
            JIT_G(current_frame)->ce = ce;
15154
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15155
0
          }
15156
0
        } else {
15157
0
          return 0;
15158
0
        }
15159
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
15160
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15161
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
15162
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15163
0
        }
15164
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
15165
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15166
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
15167
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15168
0
        }
15169
0
      }
15170
0
    }
15171
0
  }
15172
15173
10
  if (!prop_info) {
15174
10
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15175
10
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15176
10
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15177
15178
10
    ir_IF_FALSE_cold(if_same);
15179
10
    ir_END_list(slow_inputs);
15180
15181
10
    ir_IF_TRUE(if_same);
15182
10
    ir_ref offset_ref = ir_LOAD_A(
15183
10
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15184
15185
10
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15186
10
    ir_IF_TRUE_cold(if_dynamic);
15187
10
    ir_END_list(slow_inputs);
15188
15189
10
    ir_IF_FALSE(if_dynamic);
15190
10
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
15191
10
    ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15192
10
    ir_IF_FALSE_cold(if_def);
15193
10
    ir_END_list(slow_inputs);
15194
15195
10
    ir_IF_TRUE(if_def);
15196
10
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15197
15198
10
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15199
10
      ir_ref arg3, arg4;
15200
10
      ir_ref prop_info_ref = ir_LOAD_A(
15201
10
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15202
10
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15203
10
      ir_IF_TRUE_cold(if_has_prop_info);
15204
15205
10
      if (Z_MODE(val_addr) == IS_REG) {
15206
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15207
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15208
0
          return 0;
15209
0
        }
15210
0
        arg3 = jit_ZVAL_ADDR(jit, real_addr);
15211
10
      } else {
15212
10
        arg3 = jit_ZVAL_ADDR(jit, val_addr);
15213
10
      }
15214
15215
10
      if (!RETURN_VALUE_USED(opline)) {
15216
2
        arg4 = IR_NULL;
15217
8
      } else if (Z_MODE(res_addr) == IS_REG) {
15218
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15219
0
        arg4 = jit_ZVAL_ADDR(jit, real_addr);
15220
8
      } else {
15221
8
        arg4 = jit_ZVAL_ADDR(jit, res_addr);
15222
8
      }
15223
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15224
10
      jit_SET_EX_OPLINE(jit, opline);
15225
10
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
15226
10
        prop_ref,
15227
10
        prop_info_ref,
15228
10
        arg3,
15229
10
        arg4);
15230
15231
10
      if ((opline+1)->op1_type == IS_CONST) {
15232
        // TODO: ???
15233
        // if (Z_TYPE_P(value) == orig_type) {
15234
        // CACHE_PTR_EX(cache_slot + 2, NULL);
15235
5
      }
15236
15237
10
      ir_END_list(end_inputs);
15238
10
      ir_IF_FALSE(if_has_prop_info);
15239
10
    }
15240
10
  } else {
15241
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15242
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15243
    /* With the exception of __clone(), readonly assignment always happens on IS_UNDEF, doding
15244
     * the fast path. Thus, the fast path is not useful. */
15245
0
    if (prop_info->flags & ZEND_ACC_READONLY) {
15246
0
      ZEND_ASSERT(slow_inputs == IR_UNUSED);
15247
0
      goto slow_path;
15248
0
    }
15249
15250
    // Undefined property with potential magic __get()/__set() or lazy object
15251
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_type != IS_UNDEF) {
15252
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15253
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15254
15255
0
      if (!exit_addr) {
15256
0
        return 0;
15257
0
      }
15258
0
      ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15259
0
    } else {
15260
0
      ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15261
0
      ir_IF_FALSE_cold(if_def);
15262
0
      ir_END_list(slow_inputs);
15263
0
      ir_IF_TRUE(if_def);
15264
0
    }
15265
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
15266
0
      ir_ref ref, arg3, arg4;
15267
15268
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15269
0
      jit_SET_EX_OPLINE(jit, opline);
15270
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15271
0
        ref = ir_CONST_ADDR(prop_info);
15272
0
      } else {
15273
0
        int prop_info_offset =
15274
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15275
15276
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15277
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15278
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15279
0
      }
15280
0
      if (Z_MODE(val_addr) == IS_REG) {
15281
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15282
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15283
0
          return 0;
15284
0
        }
15285
0
        arg3 = jit_ZVAL_ADDR(jit, real_addr);
15286
0
      } else {
15287
0
        arg3 = jit_ZVAL_ADDR(jit, val_addr);
15288
0
      }
15289
0
      if (!RETURN_VALUE_USED(opline)) {
15290
0
        arg4 = IR_NULL;
15291
0
      } else if (Z_MODE(res_addr) == IS_REG) {
15292
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15293
0
        arg4 = jit_ZVAL_ADDR(jit, real_addr);
15294
0
      } else {
15295
0
        arg4 = jit_ZVAL_ADDR(jit, res_addr);
15296
0
      }
15297
0
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
15298
0
        prop_ref,
15299
0
        ref,
15300
0
        arg3,
15301
0
        arg4);
15302
15303
0
      ir_END_list(end_inputs);
15304
0
    }
15305
0
  }
15306
15307
10
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15308
10
    if (Z_MODE(val_addr) != IS_REG
15309
10
     && (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
15310
10
     && opline->result_type == IS_UNUSED) {
15311
2
      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)) {
15312
0
        return 0;
15313
0
      }
15314
8
    } else {
15315
8
      zend_jit_addr real_res_addr;
15316
15317
8
      if (res_addr && Z_MODE(res_addr) == IS_REG) {
15318
0
        real_res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15319
8
      } else {
15320
8
        real_res_addr = res_addr;
15321
8
      }
15322
8
      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)) {
15323
0
        return 0;
15324
0
      }
15325
8
    }
15326
10
    if (end_inputs || slow_inputs) {
15327
10
      if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR))
15328
5
       && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15329
        /* skip FREE_OP_DATA() */
15330
5
        delayed_end_input = ir_END();
15331
5
      } else {
15332
5
        ir_END_list(end_inputs);
15333
5
      }
15334
10
    }
15335
10
  }
15336
15337
10
  if (slow_inputs) {
15338
10
    ir_ref arg3, arg5;
15339
15340
10
    ir_MERGE_list(slow_inputs);
15341
15342
10
slow_path:
15343
10
    jit_SET_EX_OPLINE(jit, opline);
15344
15345
10
    if (Z_MODE(val_addr) == IS_REG) {
15346
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15347
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15348
0
        return 0;
15349
0
      }
15350
0
      arg3 = jit_ZVAL_ADDR(jit, real_addr);
15351
10
    } else {
15352
10
      arg3 = jit_ZVAL_ADDR(jit, val_addr);
15353
10
    }
15354
10
    if (!RETURN_VALUE_USED(opline)) {
15355
2
      arg5 = IR_NULL;
15356
8
    } else if (Z_MODE(res_addr) == IS_REG) {
15357
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15358
0
      arg5 = jit_ZVAL_ADDR(jit, real_addr);
15359
8
    } else {
15360
8
      arg5 = jit_ZVAL_ADDR(jit, res_addr);
15361
8
    }
15362
15363
    // JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
15364
10
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15365
10
    ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
15366
10
      obj_ref,
15367
10
      ir_CONST_ADDR(name),
15368
10
      arg3,
15369
10
      ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15370
10
      arg5);
15371
15372
10
    ir_END_list(end_inputs);
15373
10
  }
15374
15375
10
  if (end_inputs) {
15376
10
    ir_MERGE_list(end_inputs);
15377
15378
10
    if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15379
5
      val_info |= MAY_BE_RC1|MAY_BE_RCN;
15380
5
    }
15381
10
    jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15382
15383
10
    if (delayed_end_input) {
15384
5
      ir_MERGE_WITH(delayed_end_input);
15385
5
    }
15386
10
  }
15387
15388
10
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15389
10
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15390
10
  }
15391
15392
10
  if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
15393
0
    zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15394
0
    if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
15395
0
      return 0;
15396
0
    }
15397
0
  }
15398
15399
10
  if (may_throw) {
15400
10
    zend_jit_check_exception(jit);
15401
10
  }
15402
15403
10
  return 1;
15404
10
}
15405
15406
static int zend_jit_assign_obj_op(zend_jit_ctx         *jit,
15407
                                  const zend_op        *opline,
15408
                                  const zend_op_array  *op_array,
15409
                                  zend_ssa             *ssa,
15410
                                  const zend_ssa_op    *ssa_op,
15411
                                  uint32_t              op1_info,
15412
                                  zend_jit_addr         op1_addr,
15413
                                  uint32_t              val_info,
15414
                                  zend_jit_addr         val_addr,
15415
                                  zend_ssa_range       *val_range,
15416
                                  bool                  op1_indirect,
15417
                                  zend_class_entry     *ce,
15418
                                  bool                  ce_is_instanceof,
15419
                                  bool                  on_this,
15420
                                  bool                  delayed_fetch_this,
15421
                                  zend_class_entry     *trace_ce,
15422
                                  uint8_t               prop_type)
15423
4
{
15424
4
  zval *member;
15425
4
  zend_string *name;
15426
4
  zend_property_info *prop_info;
15427
4
  zend_jit_addr prop_addr;
15428
4
  bool use_prop_guard = false;
15429
4
  bool may_throw = false;
15430
4
  binary_op_type binary_op = get_binary_op(opline->extended_value);
15431
4
  ir_ref obj_ref = IR_UNUSED;
15432
4
  ir_ref prop_ref = IR_UNUSED;
15433
4
  ir_ref end_inputs = IR_UNUSED;
15434
4
  ir_ref slow_inputs = IR_UNUSED;
15435
15436
4
  ZEND_ASSERT(opline->op2_type == IS_CONST);
15437
4
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15438
4
  ZEND_ASSERT(opline->result_type == IS_UNUSED);
15439
15440
4
  member = RT_CONSTANT(opline, opline->op2);
15441
4
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15442
4
  name = Z_STR_P(member);
15443
4
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15444
15445
4
  if (on_this) {
15446
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15447
0
    obj_ref = jit_Z_PTR(jit, this_addr);
15448
4
  } else {
15449
4
    if (opline->op1_type == IS_VAR
15450
1
     && (op1_info & MAY_BE_INDIRECT)
15451
1
     && Z_REG(op1_addr) == ZREG_FP) {
15452
1
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15453
1
    }
15454
4
    if (op1_info & MAY_BE_REF) {
15455
4
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15456
4
    }
15457
4
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15458
4
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15459
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15460
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15461
15462
0
        if (!exit_addr) {
15463
0
          return 0;
15464
0
        }
15465
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15466
4
      } else {
15467
4
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15468
4
        ir_IF_FALSE_cold(if_obj);
15469
15470
4
        jit_SET_EX_OPLINE(jit, opline);
15471
4
        ir_CALL_2(IR_VOID,
15472
4
          (op1_info & MAY_BE_UNDEF) ?
15473
4
            ir_CONST_FC_FUNC(zend_jit_invalid_property_assign_op) :
15474
4
            ir_CONST_FC_FUNC(zend_jit_invalid_property_assign),
15475
4
          jit_ZVAL_ADDR(jit, op1_addr),
15476
4
          ir_CONST_ADDR(ZSTR_VAL(name)));
15477
15478
4
        may_throw = true;
15479
15480
4
        ir_END_list(end_inputs);
15481
4
        ir_IF_TRUE(if_obj);
15482
4
      }
15483
4
    }
15484
4
    obj_ref = jit_Z_PTR(jit, op1_addr);
15485
4
  }
15486
15487
4
  ZEND_ASSERT(obj_ref);
15488
4
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15489
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15490
0
    if (prop_info) {
15491
0
      ce = trace_ce;
15492
0
      ce_is_instanceof = false;
15493
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15494
0
        if (on_this && JIT_G(current_frame)
15495
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15496
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15497
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15498
0
          if (on_this && JIT_G(current_frame)) {
15499
0
            JIT_G(current_frame)->ce = ce;
15500
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15501
0
          }
15502
0
        } else {
15503
0
          return 0;
15504
0
        }
15505
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
15506
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15507
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
15508
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15509
0
        }
15510
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
15511
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15512
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
15513
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15514
0
        }
15515
0
      }
15516
0
    }
15517
0
  }
15518
15519
4
  use_prop_guard = (prop_type != IS_UNKNOWN
15520
0
    && prop_type != IS_UNDEF
15521
0
    && prop_type != IS_REFERENCE
15522
0
    && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15523
15524
4
  if (Z_MODE(val_addr) == IS_REG
15525
0
   && Z_LOAD(val_addr)
15526
0
   && jit->ra[Z_SSA_VAR(val_addr)].ref == IR_NULL) {
15527
    /* Force load */
15528
0
    zend_jit_use_reg(jit, val_addr);
15529
0
  }
15530
15531
4
  if (!prop_info) {
15532
4
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15533
4
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15534
4
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15535
15536
4
    ir_IF_FALSE_cold(if_same);
15537
4
    ir_END_list(slow_inputs);
15538
15539
4
    ir_IF_TRUE(if_same);
15540
4
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15541
4
      ir_ref prop_info_ref = ir_LOAD_A(
15542
4
        ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15543
4
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15544
4
      ir_IF_TRUE_cold(if_has_prop_info);
15545
4
      ir_END_list(slow_inputs);
15546
15547
4
      ir_IF_FALSE(if_has_prop_info);
15548
4
    }
15549
4
    ir_ref offset_ref = ir_LOAD_A(
15550
4
      ir_ADD_OFFSET(run_time_cache, ((opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15551
15552
4
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15553
4
    ir_IF_TRUE_cold(if_dynamic);
15554
4
    ir_END_list(slow_inputs);
15555
15556
4
    ir_IF_FALSE(if_dynamic);
15557
15558
4
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
15559
4
    if (!use_prop_guard) {
15560
4
      ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15561
4
      ir_IF_FALSE_cold(if_def);
15562
4
      ir_END_list(slow_inputs);
15563
15564
4
      ir_IF_TRUE(if_def);
15565
4
    }
15566
4
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15567
4
  } else {
15568
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15569
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15570
15571
0
    if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15572
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15573
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15574
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15575
15576
0
        if (!exit_addr) {
15577
0
          return 0;
15578
0
        }
15579
0
        ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
15580
0
      } else {
15581
0
        ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
15582
0
        ir_IF_FALSE_cold(if_def);
15583
0
        ir_END_list(slow_inputs);
15584
0
        ir_IF_TRUE(if_def);
15585
0
      }
15586
0
    }
15587
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
15588
0
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15589
15590
0
      may_throw = true;
15591
15592
0
      jit_SET_EX_OPLINE(jit, opline);
15593
15594
0
      if (Z_MODE(val_addr) == IS_REG) {
15595
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15596
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15597
0
          return 0;
15598
0
        }
15599
0
        arg2 = jit_ZVAL_ADDR(jit, real_addr);
15600
0
      } else {
15601
0
        arg2 = jit_ZVAL_ADDR(jit, val_addr);
15602
0
      }
15603
15604
0
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15605
0
      ir_IF_FALSE(if_ref);
15606
0
      noref_path = ir_END();
15607
0
      ir_IF_TRUE(if_ref);
15608
15609
0
      reference = jit_Z_PTR(jit, prop_addr);
15610
0
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15611
0
      if_typed = jit_if_TYPED_REF(jit, reference);
15612
0
      ir_IF_FALSE(if_typed);
15613
0
      ref_path = ir_END();
15614
0
      ir_IF_TRUE_cold(if_typed);
15615
15616
0
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15617
0
        reference,
15618
0
        arg2,
15619
0
        ir_CONST_FC_FUNC(binary_op));
15620
15621
0
      ir_END_list(end_inputs);
15622
15623
0
      ir_MERGE_2(noref_path, ref_path);
15624
0
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15625
0
      prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15626
15627
      // JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
15628
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
15629
0
        ref = ir_CONST_ADDR(prop_info);
15630
0
      } else {
15631
0
        int prop_info_offset =
15632
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
15633
15634
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
15635
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
15636
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
15637
0
      }
15638
15639
0
      ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
15640
0
        prop_ref,
15641
0
        ref,
15642
0
        arg2,
15643
0
        ir_CONST_FC_FUNC(binary_op));
15644
15645
0
      ir_END_list(end_inputs);
15646
0
    }
15647
0
  }
15648
15649
4
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
15650
4
    zend_jit_addr var_addr = prop_addr;
15651
4
    uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15652
4
    uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
15653
15654
4
    if (use_prop_guard) {
15655
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
15656
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15657
0
      if (!exit_addr) {
15658
0
        return 0;
15659
0
      }
15660
15661
0
      jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
15662
0
      var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
15663
0
    }
15664
15665
4
    if (var_info & MAY_BE_REF) {
15666
4
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
15667
15668
4
      may_throw = true;
15669
15670
4
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
15671
4
      ir_IF_FALSE(if_ref);
15672
4
      noref_path = ir_END();
15673
4
      ir_IF_TRUE(if_ref);
15674
15675
4
      reference = jit_Z_PTR(jit, var_addr);
15676
4
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
15677
4
      if_typed = jit_if_TYPED_REF(jit, reference);
15678
4
      ir_IF_FALSE(if_typed);
15679
4
      ref_path = ir_END();
15680
4
      ir_IF_TRUE_cold(if_typed);
15681
15682
4
      jit_SET_EX_OPLINE(jit, opline);
15683
15684
4
      if (Z_MODE(val_addr) == IS_REG) {
15685
0
        zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15686
0
        if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15687
0
          return 0;
15688
0
        }
15689
0
        arg2 = jit_ZVAL_ADDR(jit, real_addr);
15690
4
      } else {
15691
4
        arg2 = jit_ZVAL_ADDR(jit, val_addr);
15692
4
      }
15693
4
      ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
15694
4
        reference,
15695
4
        arg2,
15696
4
        ir_CONST_FC_FUNC(binary_op));
15697
15698
4
      ir_END_list(end_inputs);
15699
15700
4
      ir_MERGE_2(noref_path, ref_path);
15701
4
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
15702
4
      var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15703
15704
4
      var_info &= ~MAY_BE_REF;
15705
4
    }
15706
15707
4
    uint8_t val_op_type = (opline+1)->op1_type;
15708
4
    if (val_op_type & (IS_TMP_VAR|IS_VAR)) {
15709
      /* prevent FREE_OP in the helpers */
15710
0
      val_op_type = IS_CV;
15711
0
    }
15712
15713
4
    switch (opline->extended_value) {
15714
0
      case ZEND_ADD:
15715
0
      case ZEND_SUB:
15716
0
      case ZEND_MUL:
15717
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15718
0
            (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15719
0
          if (opline->extended_value != ZEND_ADD ||
15720
0
              (var_info & MAY_BE_ANY) != MAY_BE_ARRAY ||
15721
0
              (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) {
15722
0
            may_throw = true;
15723
0
          }
15724
0
        }
15725
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,
15726
0
            1 /* may overflow */, 0)) {
15727
0
          return 0;
15728
0
        }
15729
0
        break;
15730
0
      case ZEND_BW_OR:
15731
0
      case ZEND_BW_AND:
15732
4
      case ZEND_BW_XOR:
15733
4
        if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15734
4
            (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15735
4
          if ((var_info & MAY_BE_ANY) != MAY_BE_STRING ||
15736
4
              (val_info & MAY_BE_ANY) != MAY_BE_STRING) {
15737
4
            may_throw = true;
15738
4
          }
15739
4
        }
15740
4
        goto long_math;
15741
0
      case ZEND_SL:
15742
0
      case ZEND_SR:
15743
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15744
0
            (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15745
0
          may_throw = true;
15746
0
        }
15747
0
        if (val_op_type != IS_CONST ||
15748
0
            Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15749
0
            Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) {
15750
0
          may_throw = true;
15751
0
        }
15752
0
        goto long_math;
15753
0
      case ZEND_MOD:
15754
0
        if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) ||
15755
0
            (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
15756
0
          may_throw = true;
15757
0
        }
15758
0
        if (val_op_type != IS_CONST ||
15759
0
            Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG ||
15760
0
            Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) {
15761
0
          may_throw = true;
15762
0
        }
15763
4
long_math:
15764
4
        if (!zend_jit_long_math_helper(jit, opline, opline->extended_value,
15765
4
            IS_CV, opline->op1, var_addr, var_info, NULL,
15766
4
            val_op_type, (opline+1)->op1, val_addr, val_info,
15767
4
            val_range,
15768
4
            0, var_addr, var_def_info, var_info, /* may throw */ 1)) {
15769
0
          return 0;
15770
0
        }
15771
4
        break;
15772
4
      case ZEND_CONCAT:
15773
0
        may_throw = true;
15774
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,
15775
0
            0)) {
15776
0
          return 0;
15777
0
        }
15778
0
        break;
15779
0
      default:
15780
0
        ZEND_UNREACHABLE();
15781
4
    }
15782
4
    if (end_inputs || slow_inputs) {
15783
4
      ir_END_list(end_inputs);
15784
4
    }
15785
4
  }
15786
15787
4
  if (slow_inputs) {
15788
4
    ir_ref arg3;
15789
15790
4
    ir_MERGE_list(slow_inputs);
15791
15792
4
    may_throw = true;
15793
15794
4
    if (Z_MODE(val_addr) == IS_REG) {
15795
0
      zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
15796
0
      if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
15797
0
        return 0;
15798
0
      }
15799
0
      arg3 = jit_ZVAL_ADDR(jit, real_addr);
15800
4
    } else {
15801
4
      arg3 = jit_ZVAL_ADDR(jit, val_addr);
15802
4
    }
15803
4
    jit_SET_EX_OPLINE(jit, opline);
15804
4
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15805
4
    ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
15806
4
      obj_ref,
15807
4
      ir_CONST_ADDR(name),
15808
4
      arg3,
15809
4
      ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
15810
4
      ir_CONST_FC_FUNC(binary_op));
15811
15812
4
    ir_END_list(end_inputs);
15813
4
  }
15814
15815
4
  if (end_inputs) {
15816
4
    ir_MERGE_list(end_inputs);
15817
4
  }
15818
15819
4
  if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
15820
0
    val_info |= MAY_BE_RC1|MAY_BE_RCN;
15821
0
  }
15822
15823
  // JIT: FREE_OP_DATA();
15824
4
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline);
15825
15826
4
  if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
15827
4
    if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
15828
4
      may_throw = true;
15829
4
    }
15830
4
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
15831
4
  }
15832
15833
4
  if (may_throw) {
15834
4
    zend_jit_check_exception(jit);
15835
4
  }
15836
15837
4
  return 1;
15838
4
}
15839
15840
static int zend_jit_incdec_obj(zend_jit_ctx         *jit,
15841
                               const zend_op        *opline,
15842
                               const zend_op_array  *op_array,
15843
                               zend_ssa             *ssa,
15844
                               const zend_ssa_op    *ssa_op,
15845
                               uint32_t              op1_info,
15846
                               zend_jit_addr         op1_addr,
15847
                               bool                  op1_indirect,
15848
                               zend_class_entry     *ce,
15849
                               bool                  ce_is_instanceof,
15850
                               bool                  on_this,
15851
                               bool                  delayed_fetch_this,
15852
                               zend_class_entry     *trace_ce,
15853
                               uint8_t               prop_type)
15854
9
{
15855
9
  zval *member;
15856
9
  zend_string *name;
15857
9
  zend_property_info *prop_info;
15858
9
  zend_jit_addr res_addr = 0;
15859
9
  zend_jit_addr prop_addr;
15860
9
  bool use_prop_guard = false;
15861
9
  bool may_throw = false;
15862
9
  uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0;
15863
9
  ir_ref obj_ref = IR_UNUSED;
15864
9
  ir_ref prop_ref = IR_UNUSED;
15865
9
  ir_ref end_inputs = IR_UNUSED;
15866
9
  ir_ref slow_inputs = IR_UNUSED;
15867
15868
9
  ZEND_ASSERT(opline->op2_type == IS_CONST);
15869
9
  ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
15870
15871
9
  if (opline->result_type != IS_UNUSED) {
15872
5
    res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
15873
5
  }
15874
15875
9
  member = RT_CONSTANT(opline, opline->op2);
15876
9
  ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0');
15877
9
  name = Z_STR_P(member);
15878
9
  prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename);
15879
15880
9
  if (on_this) {
15881
0
    zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This));
15882
0
    obj_ref = jit_Z_PTR(jit, this_addr);
15883
9
  } else {
15884
9
    if (opline->op1_type == IS_VAR
15885
8
     && (op1_info & MAY_BE_INDIRECT)
15886
8
     && Z_REG(op1_addr) == ZREG_FP) {
15887
8
      op1_addr = jit_ZVAL_INDIRECT_DEREF(jit, op1_addr);
15888
8
    }
15889
9
    if (op1_info & MAY_BE_REF) {
15890
9
      op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
15891
9
    }
15892
9
    if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) {
15893
9
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15894
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15895
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15896
15897
0
        if (!exit_addr) {
15898
0
          return 0;
15899
0
        }
15900
0
        jit_guard_Z_TYPE(jit, op1_addr, IS_OBJECT, exit_addr);
15901
9
      } else {
15902
9
        ir_ref if_obj = jit_if_Z_TYPE(jit, op1_addr, IS_OBJECT);
15903
9
        ir_IF_FALSE_cold(if_obj);
15904
15905
9
        jit_SET_EX_OPLINE(jit, opline);
15906
9
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_invalid_property_incdec),
15907
9
          jit_ZVAL_ADDR(jit, op1_addr),
15908
9
          ir_CONST_ADDR(ZSTR_VAL(name)));
15909
15910
9
        ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler));
15911
9
        ir_IF_TRUE(if_obj);
15912
9
      }
15913
9
    }
15914
9
    obj_ref = jit_Z_PTR(jit, op1_addr);
15915
9
  }
15916
15917
9
  ZEND_ASSERT(obj_ref);
15918
9
  if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
15919
0
    prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename);
15920
0
    if (prop_info) {
15921
0
      ce = trace_ce;
15922
0
      ce_is_instanceof = false;
15923
0
      if (!(op1_info & MAY_BE_CLASS_GUARD)) {
15924
0
        if (on_this && JIT_G(current_frame)
15925
0
         && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) {
15926
0
          ZEND_ASSERT(JIT_G(current_frame)->ce == ce);
15927
0
        } else if (zend_jit_class_guard(jit, opline, obj_ref, ce)) {
15928
0
          if (on_this && JIT_G(current_frame)) {
15929
0
            JIT_G(current_frame)->ce = ce;
15930
0
            TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame));
15931
0
          }
15932
0
        } else {
15933
0
          return 0;
15934
0
        }
15935
0
        if (ssa->var_info && ssa_op->op1_use >= 0) {
15936
0
          ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD;
15937
0
          ssa->var_info[ssa_op->op1_use].ce = ce;
15938
0
          ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof;
15939
0
        }
15940
0
        if (ssa->var_info && ssa_op->op1_def >= 0) {
15941
0
          ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD;
15942
0
          ssa->var_info[ssa_op->op1_def].ce = ce;
15943
0
          ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof;
15944
0
        }
15945
0
      }
15946
0
    }
15947
0
  }
15948
15949
9
  use_prop_guard = (prop_type != IS_UNKNOWN
15950
0
    && prop_type != IS_UNDEF
15951
0
    && prop_type != IS_REFERENCE
15952
0
    && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT);
15953
15954
9
  if (!prop_info) {
15955
9
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
15956
9
    ir_ref ref = ir_LOAD_A(ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS));
15957
9
    ir_ref if_same = ir_IF(ir_EQ(ref, ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)))));
15958
15959
9
    ir_IF_FALSE_cold(if_same);
15960
9
    ir_END_list(slow_inputs);
15961
15962
9
    ir_IF_TRUE(if_same);
15963
9
    if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
15964
9
      ir_ref prop_info_ref = ir_LOAD_A(
15965
9
        ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
15966
9
      ir_ref if_has_prop_info = ir_IF(prop_info_ref);
15967
9
      ir_IF_TRUE_cold(if_has_prop_info);
15968
9
      ir_END_list(slow_inputs);
15969
15970
9
      ir_IF_FALSE(if_has_prop_info);
15971
9
    }
15972
9
    ir_ref offset_ref = ir_LOAD_A(
15973
9
      ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)));
15974
15975
9
    ir_ref if_dynamic = ir_IF(ir_LT(offset_ref, ir_CONST_ADDR(ZEND_FIRST_PROPERTY_OFFSET)));
15976
9
    ir_IF_TRUE_cold(if_dynamic);
15977
9
    ir_END_list(slow_inputs);
15978
15979
9
    ir_IF_FALSE(if_dynamic);
15980
15981
9
    prop_ref = ir_ADD_A(obj_ref, offset_ref);
15982
9
    if (!use_prop_guard) {
15983
9
      ir_ref if_def = ir_IF(jit_Z_TYPE_ref(jit, prop_ref));
15984
9
      ir_IF_FALSE_cold(if_def);
15985
9
      ir_END_list(slow_inputs);
15986
15987
9
      ir_IF_TRUE(if_def);
15988
9
    }
15989
9
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15990
9
  } else {
15991
0
    prop_ref = ir_ADD_OFFSET(obj_ref, prop_info->offset);
15992
0
    prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
15993
15994
0
    if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) {
15995
0
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
15996
0
        int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
15997
0
        const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
15998
15999
0
        if (!exit_addr) {
16000
0
          return 0;
16001
0
        }
16002
0
        ir_GUARD(jit_Z_TYPE_INFO(jit, prop_addr), ir_CONST_ADDR(exit_addr));
16003
0
      } else {
16004
0
        ir_ref if_def = ir_IF(jit_Z_TYPE_INFO(jit, prop_addr));
16005
0
        ir_IF_FALSE_cold(if_def);
16006
0
        ir_END_list(slow_inputs);
16007
0
        ir_IF_TRUE(if_def);
16008
0
      }
16009
0
    }
16010
16011
0
    if (ZEND_TYPE_IS_SET(prop_info->type)) {
16012
0
      const void *func;
16013
0
      ir_ref ref;
16014
16015
0
      may_throw = true;
16016
0
      jit_SET_EX_OPLINE(jit, opline);
16017
16018
0
      if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) {
16019
0
        ref = ir_CONST_ADDR(prop_info);
16020
0
      } else {
16021
0
        int prop_info_offset =
16022
0
          (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*));
16023
16024
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_object, ce)));
16025
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
16026
0
        ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
16027
0
      }
16028
16029
0
      if (opline->result_type == IS_UNUSED) {
16030
0
        switch (opline->opcode) {
16031
0
          case ZEND_PRE_INC_OBJ:
16032
0
          case ZEND_POST_INC_OBJ:
16033
0
            func = zend_jit_inc_typed_prop;
16034
0
            break;
16035
0
          case ZEND_PRE_DEC_OBJ:
16036
0
          case ZEND_POST_DEC_OBJ:
16037
0
            func = zend_jit_dec_typed_prop;
16038
0
            break;
16039
0
          default:
16040
0
            ZEND_UNREACHABLE();
16041
0
        }
16042
16043
0
        ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func), prop_ref, ref);
16044
0
      } else {
16045
0
        switch (opline->opcode) {
16046
0
          case ZEND_PRE_INC_OBJ:
16047
0
            func = zend_jit_pre_inc_typed_prop;
16048
0
            break;
16049
0
          case ZEND_PRE_DEC_OBJ:
16050
0
            func = zend_jit_pre_dec_typed_prop;
16051
0
            break;
16052
0
          case ZEND_POST_INC_OBJ:
16053
0
            func = zend_jit_post_inc_typed_prop;
16054
0
            break;
16055
0
          case ZEND_POST_DEC_OBJ:
16056
0
            func = zend_jit_post_dec_typed_prop;
16057
0
            break;
16058
0
          default:
16059
0
            ZEND_UNREACHABLE();
16060
0
        }
16061
0
        ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(func),
16062
0
          prop_ref,
16063
0
          ref,
16064
0
          jit_ZVAL_ADDR(jit, res_addr));
16065
0
      }
16066
0
      ir_END_list(end_inputs);
16067
0
    }
16068
0
  }
16069
16070
9
  if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
16071
9
    uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
16072
9
    zend_jit_addr var_addr = prop_addr;
16073
9
    ir_ref if_long = IR_UNUSED;
16074
9
    ir_ref if_overflow = IR_UNUSED;
16075
16076
9
    if (use_prop_guard) {
16077
0
      int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
16078
0
      const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16079
0
      if (!exit_addr) {
16080
0
        return 0;
16081
0
      }
16082
16083
0
      jit_guard_Z_TYPE(jit, prop_addr, prop_type, exit_addr);
16084
0
      var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF));
16085
0
    }
16086
16087
9
    if (var_info & MAY_BE_REF) {
16088
9
      const void *func;
16089
9
      ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
16090
16091
9
      if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
16092
9
      ir_IF_FALSE(if_ref);
16093
9
      noref_path = ir_END();
16094
9
      ir_IF_TRUE(if_ref);
16095
16096
9
      reference = jit_Z_PTR(jit, var_addr);
16097
9
      ref = ir_ADD_OFFSET(reference, offsetof(zend_reference, val));
16098
9
      if_typed = jit_if_TYPED_REF(jit, reference);
16099
9
      ir_IF_FALSE(if_typed);
16100
9
      ref_path = ir_END();
16101
9
      ir_IF_TRUE_cold(if_typed);
16102
16103
9
      switch (opline->opcode) {
16104
5
        case ZEND_PRE_INC_OBJ:
16105
5
          func = zend_jit_pre_inc_typed_ref;
16106
5
          break;
16107
1
        case ZEND_PRE_DEC_OBJ:
16108
1
          func = zend_jit_pre_dec_typed_ref;
16109
1
          break;
16110
0
        case ZEND_POST_INC_OBJ:
16111
0
          func = zend_jit_post_inc_typed_ref;
16112
0
          break;
16113
3
        case ZEND_POST_DEC_OBJ:
16114
3
          func = zend_jit_post_dec_typed_ref;
16115
3
          break;
16116
0
        default:
16117
0
          ZEND_UNREACHABLE();
16118
9
      }
16119
16120
9
      may_throw = true;
16121
9
      jit_SET_EX_OPLINE(jit, opline);
16122
9
      ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(func),
16123
9
        reference,
16124
9
        (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
16125
16126
9
      ir_END_list(end_inputs);
16127
16128
9
      ir_MERGE_2(noref_path, ref_path);
16129
9
      prop_ref = ir_PHI_2(IR_ADDR, prop_ref, ref);
16130
9
      var_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
16131
16132
9
      var_info &= ~MAY_BE_REF;
16133
9
    }
16134
16135
9
    if (var_info & MAY_BE_LONG) {
16136
9
      ir_ref addr, ref;
16137
16138
9
      if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
16139
9
        if_long = jit_if_Z_TYPE(jit, var_addr, IS_LONG);
16140
9
        ir_IF_TRUE(if_long);
16141
9
      }
16142
16143
9
      addr = jit_ZVAL_ADDR(jit, var_addr);
16144
9
      ref = ir_LOAD_L(addr);
16145
9
      if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
16146
3
        if (opline->result_type != IS_UNUSED) {
16147
3
          jit_set_Z_LVAL(jit, res_addr, ref);
16148
3
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
16149
3
        }
16150
3
      }
16151
9
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
16152
5
        ref = ir_ADD_OV_L(ref, ir_CONST_LONG(1));
16153
5
      } else {
16154
4
        ref = ir_SUB_OV_L(ref, ir_CONST_LONG(1));
16155
4
      }
16156
16157
9
      ir_STORE(addr, ref);
16158
9
      if_overflow = ir_IF(ir_OVERFLOW(ref));
16159
9
      ir_IF_FALSE(if_overflow);
16160
16161
9
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) {
16162
6
        if (opline->result_type != IS_UNUSED) {
16163
2
          jit_set_Z_LVAL(jit, res_addr, ref);
16164
2
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_LONG);
16165
2
        }
16166
6
      }
16167
9
      ir_END_list(end_inputs);
16168
9
    }
16169
16170
9
    if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) {
16171
9
      if (if_long) {
16172
9
        ir_IF_FALSE_cold(if_long);
16173
9
      }
16174
9
      if (var_info & (MAY_BE_ANY - (MAY_BE_LONG|MAY_BE_DOUBLE))) {
16175
9
        may_throw = true;
16176
9
        jit_SET_EX_OPLINE(jit, opline);
16177
9
      }
16178
9
      if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) {
16179
3
        jit_ZVAL_COPY(jit, res_addr, -1, var_addr, var_info, true);
16180
3
      }
16181
9
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
16182
5
        if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
16183
1
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_inc),
16184
1
            jit_ZVAL_ADDR(jit, var_addr),
16185
1
            jit_ZVAL_ADDR(jit, res_addr));
16186
4
        } else {
16187
4
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(increment_function),
16188
4
            jit_ZVAL_ADDR(jit, var_addr));
16189
4
        }
16190
5
      } else {
16191
4
        if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
16192
1
          ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_pre_dec),
16193
1
            jit_ZVAL_ADDR(jit, var_addr),
16194
1
            jit_ZVAL_ADDR(jit, res_addr));
16195
3
        } else {
16196
3
          ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(decrement_function),
16197
3
            jit_ZVAL_ADDR(jit, var_addr));
16198
3
        }
16199
4
      }
16200
16201
9
      ir_END_list(end_inputs);
16202
9
    }
16203
9
    if (var_info & MAY_BE_LONG) {
16204
9
      ir_IF_TRUE_cold(if_overflow);
16205
9
      if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) {
16206
#if SIZEOF_ZEND_LONG == 4
16207
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0));
16208
        jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0x41e00000));
16209
#else
16210
5
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x43e0000000000000));
16211
5
#endif
16212
5
        jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
16213
5
        if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) {
16214
#if SIZEOF_ZEND_LONG == 4
16215
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0));
16216
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0x41e00000));
16217
#else
16218
1
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x43e0000000000000));
16219
1
#endif
16220
1
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
16221
1
        }
16222
5
      } else {
16223
#if SIZEOF_ZEND_LONG == 4
16224
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0x00200000));
16225
        jit_set_Z_W2(jit, var_addr, ir_CONST_U32(0xc1e00000));
16226
#else
16227
4
        jit_set_Z_LVAL(jit, var_addr, ir_CONST_LONG(0xc3e0000000000000));
16228
4
#endif
16229
4
        jit_set_Z_TYPE_INFO(jit, var_addr, IS_DOUBLE);
16230
4
        if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) {
16231
#if SIZEOF_ZEND_LONG == 4
16232
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0x00200000));
16233
          jit_set_Z_W2(jit, res_addr, ir_CONST_U32(0xc1e00000));
16234
#else
16235
1
          jit_set_Z_LVAL(jit, res_addr, ir_CONST_LONG(0xc3e0000000000000));
16236
1
#endif
16237
1
          jit_set_Z_TYPE_INFO(jit, res_addr, IS_DOUBLE);
16238
1
        }
16239
4
      }
16240
9
      if (opline->result_type != IS_UNUSED
16241
5
       && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ)
16242
2
       && prop_info
16243
0
       && !ZEND_TYPE_IS_SET(prop_info->type)
16244
0
       && (res_info & MAY_BE_GUARD)
16245
0
       && (res_info & MAY_BE_LONG)) {
16246
0
        zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
16247
0
        uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
16248
0
        int32_t exit_point;
16249
0
        const void *exit_addr;
16250
16251
0
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0);
16252
0
        exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16253
0
        exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16254
0
        if (!exit_addr) {
16255
0
          return 0;
16256
0
        }
16257
0
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
16258
0
        ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD;
16259
0
        jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16260
9
      } else {
16261
9
        ir_END_list(end_inputs);
16262
9
      }
16263
9
    }
16264
9
  }
16265
16266
9
  if (slow_inputs) {
16267
9
    const void *func;
16268
16269
9
    ir_MERGE_list(slow_inputs);
16270
16271
    // JIT: zend_jit_pre_inc_obj_helper(zobj, name, CACHE_ADDR(opline->extended_value), result);
16272
9
    switch (opline->opcode) {
16273
5
      case ZEND_PRE_INC_OBJ:
16274
5
        func = zend_jit_pre_inc_obj_helper;
16275
5
        break;
16276
1
      case ZEND_PRE_DEC_OBJ:
16277
1
        func = zend_jit_pre_dec_obj_helper;
16278
1
        break;
16279
0
      case ZEND_POST_INC_OBJ:
16280
0
        func = zend_jit_post_inc_obj_helper;
16281
0
        break;
16282
3
      case ZEND_POST_DEC_OBJ:
16283
3
        func = zend_jit_post_dec_obj_helper;
16284
3
        break;
16285
0
      default:
16286
0
        ZEND_UNREACHABLE();
16287
9
    }
16288
16289
9
    may_throw = true;
16290
9
    jit_SET_EX_OPLINE(jit, opline);
16291
9
    ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
16292
9
    ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(func),
16293
9
      obj_ref,
16294
9
      ir_CONST_ADDR(name),
16295
9
      ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
16296
9
      (opline->result_type == IS_UNUSED) ? IR_NULL : jit_ZVAL_ADDR(jit, res_addr));
16297
16298
9
    ir_END_list(end_inputs);
16299
9
  }
16300
16301
9
  if (end_inputs) {
16302
9
    ir_MERGE_list(end_inputs);
16303
9
  }
16304
16305
9
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) {
16306
8
    if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) {
16307
8
      may_throw = true;
16308
8
    }
16309
8
    jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
16310
8
  }
16311
16312
9
  if (may_throw) {
16313
9
    zend_jit_check_exception(jit);
16314
9
  }
16315
16316
9
  return 1;
16317
9
}
16318
16319
static int zend_jit_fetch_static_prop(zend_jit_ctx *jit, const zend_op *opline, const zend_op_array *op_array)
16320
12
{
16321
12
  zend_jit_addr res_addr = RES_ADDR();
16322
12
  uint32_t cache_slot = opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS;
16323
12
  uint32_t flags;
16324
12
  ir_ref ref, ref2, if_cached, fast_path, cold_path, prop_info_ref, if_typed, if_def;
16325
12
  int fetch_type;
16326
12
  zend_property_info *known_prop_info = NULL;
16327
12
  zend_class_entry *ce;
16328
16329
12
  ce = zend_get_known_class(op_array, opline, opline->op2_type, opline->op2);
16330
12
  if (ce && (opline->op2_type == IS_CONST || !(ce->ce_flags & ZEND_ACC_TRAIT))) {
16331
2
    zval *zv = RT_CONSTANT(opline, opline->op1);
16332
2
    zend_string *prop_name;
16333
16334
2
    ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING);
16335
2
    prop_name = Z_STR_P(zv);
16336
2
    zv = zend_hash_find(&ce->properties_info, prop_name);
16337
2
    if (zv) {
16338
2
      zend_property_info *prop_info = Z_PTR_P(zv);
16339
16340
2
      if (prop_info->flags & ZEND_ACC_STATIC) {
16341
2
        if (prop_info->ce == op_array->scope
16342
2
         || (prop_info->flags & ZEND_ACC_PUBLIC)
16343
0
         || ((prop_info->flags & ZEND_ACC_PROTECTED)
16344
0
          && op_array->scope
16345
2
          && instanceof_function_slow(op_array->scope, prop_info->ce))) {
16346
2
          known_prop_info = prop_info;
16347
2
        }
16348
2
      }
16349
2
    }
16350
2
  }
16351
16352
12
  switch (opline->opcode) {
16353
10
    case ZEND_FETCH_STATIC_PROP_R:
16354
10
    case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
16355
10
      fetch_type = BP_VAR_R;
16356
10
      break;
16357
0
    case ZEND_FETCH_STATIC_PROP_IS:
16358
0
      fetch_type = BP_VAR_IS;
16359
0
      break;
16360
2
    case ZEND_FETCH_STATIC_PROP_W:
16361
2
      fetch_type = BP_VAR_W;
16362
2
      break;
16363
0
    case ZEND_FETCH_STATIC_PROP_RW:
16364
0
      fetch_type = BP_VAR_RW;
16365
0
      break;
16366
0
    case ZEND_FETCH_STATIC_PROP_UNSET:
16367
0
      fetch_type = BP_VAR_UNSET;
16368
0
      break;
16369
0
    default: ZEND_UNREACHABLE();
16370
12
  }
16371
16372
  // JIT: result = CACHED_PTR(cache_slot + sizeof(void *));
16373
12
  ref = ir_LOAD_A(
16374
12
    ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*)));
16375
16376
  // JIT: if (result)
16377
12
  if_cached = ir_IF(ref);
16378
12
  ir_IF_TRUE(if_cached);
16379
16380
12
  if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_RW) {
16381
10
    if (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type)) {
16382
10
      ir_ref merge = IR_UNUSED;
16383
16384
      // JIT: if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
16385
10
      if_typed = IR_UNUSED;
16386
10
      if_def = ir_IF(jit_Z_TYPE_ref(jit, ref));
16387
10
      ir_IF_FALSE_cold(if_def);
16388
10
      if (!known_prop_info) {
16389
        // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
16390
10
        prop_info_ref = ir_LOAD_L(
16391
10
          ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16392
10
        if_typed = ir_IF(ir_AND_U32(
16393
10
          ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16394
10
          ir_CONST_U32(_ZEND_TYPE_MASK)));
16395
10
        ir_IF_FALSE(if_typed);
16396
10
        ir_END_list(merge);
16397
10
        ir_IF_TRUE(if_typed);
16398
10
      }
16399
      // JIT: zend_throw_error(NULL, "Typed static property %s::$%s must not be accessed before initialization",
16400
      //      ZSTR_VAL(property_info->ce->name),
16401
      //      zend_get_unmangled_property_name(property_info->name));
16402
10
      jit_SET_EX_OPLINE(jit, opline);
16403
10
      ir_CALL(IR_VOID, ir_CONST_FC_FUNC(zend_jit_uninit_static_prop));
16404
10
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
16405
16406
10
      ir_IF_TRUE(if_def);
16407
10
      if (!known_prop_info) {
16408
10
        ir_END_list(merge);
16409
10
        ir_MERGE_list(merge);
16410
10
      }
16411
10
    }
16412
10
  } else if (fetch_type == BP_VAR_W) {
16413
2
    flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS;
16414
2
    if (flags && (!known_prop_info || ZEND_TYPE_IS_SET(known_prop_info->type))) {
16415
2
        ir_ref merge = IR_UNUSED;
16416
16417
2
      if (!known_prop_info) {
16418
        // JIT: if (ZEND_TYPE_IS_SET(property_info->type))
16419
0
        prop_info_ref = ir_LOAD_L(
16420
0
          ir_ADD_OFFSET(ir_LOAD_A(jit_EX(run_time_cache)), cache_slot + sizeof(void*) * 2));
16421
0
        if_typed = ir_IF(ir_AND_U32(
16422
0
          ir_LOAD_U32(ir_ADD_OFFSET(prop_info_ref, offsetof(zend_property_info, type.type_mask))),
16423
0
          ir_CONST_U32(_ZEND_TYPE_MASK)));
16424
0
        ir_IF_FALSE(if_typed);
16425
0
        ir_END_list(merge);
16426
0
        ir_IF_TRUE(if_typed);
16427
2
      } else {
16428
2
        prop_info_ref = ir_CONST_ADDR(known_prop_info);
16429
2
      }
16430
16431
      // JIT: zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags);
16432
2
      ir_ref if_ok = ir_IF(ir_CALL_5(IR_BOOL, ir_CONST_FUNC(zend_handle_fetch_obj_flags),
16433
2
        IR_NULL, ref, IR_NULL, prop_info_ref, ir_CONST_U32(flags)));
16434
2
      ir_IF_FALSE_cold(if_ok);
16435
2
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_exception_handler_undef));
16436
2
      ir_IF_TRUE(if_ok);
16437
2
      if (!known_prop_info) {
16438
0
        ir_END_list(merge);
16439
0
        ir_MERGE_list(merge);
16440
0
      }
16441
2
    }
16442
2
  }
16443
16444
12
  fast_path = ir_END();
16445
16446
12
  ir_IF_FALSE_cold(if_cached);
16447
12
  jit_SET_EX_OPLINE(jit, opline);
16448
12
  ref2 = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_fetch_static_property), jit_FP(jit), ir_CONST_I32(fetch_type));
16449
12
  zend_jit_check_exception_undef_result(jit, opline);
16450
12
  cold_path = ir_END();
16451
16452
12
  ir_MERGE_2(fast_path, cold_path);
16453
12
  ref = ir_PHI_2(IR_ADDR, ref, ref2);
16454
16455
12
  if (fetch_type == BP_VAR_R || fetch_type == BP_VAR_IS) {
16456
    // JIT: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), result);
16457
10
    if (!zend_jit_zval_copy_deref(jit, res_addr, ZEND_ADDR_REF_ZVAL(ref),
16458
10
        jit_Z_TYPE_INFO_ref(jit, ref))) {
16459
0
      return 0;
16460
0
    }
16461
10
  } else {
16462
    // JIT: ZVAL_INDIRECT(EX_VAR(opline->result.var), result);
16463
2
    jit_set_Z_PTR(jit, res_addr, ref);
16464
2
    jit_set_Z_TYPE_INFO(jit, res_addr, IS_INDIRECT);
16465
2
  }
16466
16467
12
  return 1;
16468
12
}
16469
16470
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)
16471
10
{
16472
10
  HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2));
16473
10
  const zend_op *next_opline = NULL;
16474
10
  ir_refs *slow_inputs;
16475
16476
10
  ir_refs_init(slow_inputs, 8);
16477
16478
10
  if (trace) {
16479
0
    ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END);
16480
0
    ZEND_ASSERT(trace->opline != NULL);
16481
0
    next_opline = trace->opline;
16482
0
  }
16483
16484
10
  if (opline->op1_type == IS_CONST) {
16485
0
    zval *zv = RT_CONSTANT(opline, opline->op1);
16486
0
    zval *jump_zv = NULL;
16487
0
    const zend_op *target;
16488
0
    int b;
16489
16490
    /* Wrong type for SWITCH_LONG/SWITCH_STRING falls back to the ZEND_CASE chain */
16491
0
    target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16492
0
    if (opline->opcode == ZEND_SWITCH_LONG) {
16493
0
      if (Z_TYPE_P(zv) == IS_LONG) {
16494
0
        jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16495
0
      } else {
16496
0
        target = opline + 1;
16497
0
      }
16498
0
    } else if (opline->opcode == ZEND_SWITCH_STRING) {
16499
0
      if (Z_TYPE_P(zv) == IS_STRING) {
16500
0
        jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16501
0
      } else {
16502
0
        target = opline + 1;
16503
0
      }
16504
0
    } else if (opline->opcode == ZEND_MATCH) {
16505
0
      if (Z_TYPE_P(zv) == IS_LONG) {
16506
0
        jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv));
16507
0
      } else if (Z_TYPE_P(zv) == IS_STRING) {
16508
0
        jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv));
16509
0
      }
16510
0
    } else {
16511
0
      ZEND_UNREACHABLE();
16512
0
    }
16513
0
    if (jump_zv != NULL) {
16514
0
      target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv));
16515
0
    }
16516
0
    if (next_opline) {
16517
0
      ZEND_ASSERT(target == next_opline);
16518
0
    } else {
16519
0
      b = ssa->cfg.map[target - op_array->opcodes];
16520
0
      _zend_jit_add_predecessor_ref(jit, b, jit->b, ir_END());
16521
0
      jit->b = -1;
16522
0
    }
16523
10
  } else {
16524
10
    zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
16525
10
    uint32_t op1_info = OP1_INFO();
16526
10
    zend_jit_addr op1_addr = OP1_ADDR();
16527
10
    const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
16528
10
    const zend_op *target;
16529
10
    int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes];
16530
10
    int b;
16531
10
    int32_t exit_point;
16532
10
    const void *exit_addr;
16533
10
    const void *default_label = NULL;
16534
10
    zval *zv;
16535
16536
10
    if (next_opline) {
16537
0
      if (next_opline != default_opline) {
16538
0
        exit_point = zend_jit_trace_get_exit_point(default_opline, 0);
16539
0
        default_label = zend_jit_trace_get_exit_addr(exit_point);
16540
0
        if (!default_label) {
16541
0
          return 0;
16542
0
        }
16543
0
      }
16544
0
    }
16545
16546
10
    if (opline->opcode == ZEND_SWITCH_LONG) {
16547
0
      if (op1_info & MAY_BE_LONG) {
16548
0
        const void *fallback_label = NULL;
16549
16550
0
        if (next_opline) {
16551
0
          if (next_opline != opline + 1) {
16552
0
            exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16553
0
            fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16554
0
            if (!fallback_label) {
16555
0
              return 0;
16556
0
            }
16557
0
          }
16558
0
        }
16559
0
        if (op1_info & MAY_BE_REF) {
16560
0
          ir_ref ref, if_long, fast_path, ref2;
16561
16562
0
          ref = jit_ZVAL_ADDR(jit, op1_addr);
16563
0
          if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16564
0
          ir_IF_TRUE(if_long);
16565
0
          fast_path = ir_END();
16566
0
          ir_IF_FALSE_cold(if_long);
16567
16568
          // JIT: ZVAL_DEREF(op)
16569
0
          if (fallback_label) {
16570
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16571
0
          } else {
16572
0
            ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
16573
0
            ir_IF_FALSE_cold(if_ref);
16574
0
            ir_refs_add(slow_inputs, ir_END());
16575
0
            ir_IF_TRUE(if_ref);
16576
0
          }
16577
16578
0
          ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16579
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16580
16581
0
          if (fallback_label) {
16582
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16583
0
          } else {
16584
0
            if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16585
0
            ir_IF_FALSE_cold(if_long);
16586
0
            ir_refs_add(slow_inputs, ir_END());
16587
0
            ir_IF_TRUE(if_long);
16588
0
          }
16589
16590
0
          ir_MERGE_2(fast_path, ir_END());
16591
0
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
16592
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16593
0
        } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16594
0
          if (fallback_label) {
16595
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, fallback_label);
16596
0
          } else {
16597
0
            ir_ref if_long = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16598
0
            ir_IF_FALSE_cold(if_long);
16599
0
            ir_refs_add(slow_inputs, ir_END());
16600
0
            ir_IF_TRUE(if_long);
16601
0
          }
16602
0
        }
16603
0
        ir_ref ref = jit_Z_LVAL(jit, op1_addr);
16604
16605
0
        if (!HT_IS_PACKED(jumptable)) {
16606
0
          ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16607
0
            ir_CONST_ADDR(jumptable), ref);
16608
0
          ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16609
          /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16610
0
          if (sizeof(Bucket) == 32) {
16611
0
            ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16612
0
          } else {
16613
0
            ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16614
0
          }
16615
0
        }
16616
0
        ref = ir_SWITCH(ref);
16617
16618
0
        if (next_opline) {
16619
0
          ir_ref continue_list = IR_UNUSED;
16620
16621
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16622
0
            ir_ref idx;
16623
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16624
16625
0
            if (HT_IS_PACKED(jumptable)) {
16626
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16627
0
            } else {
16628
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16629
0
            }
16630
0
            ir_CASE_VAL(ref, idx);
16631
0
            if (target == next_opline) {
16632
0
              ir_END_list(continue_list);
16633
0
            } else {
16634
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16635
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16636
0
              if (!exit_addr) {
16637
0
                return 0;
16638
0
              }
16639
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16640
0
            }
16641
0
          } ZEND_HASH_FOREACH_END();
16642
16643
0
          ir_CASE_DEFAULT(ref);
16644
0
          if (next_opline == default_opline) {
16645
0
            ir_END_list(continue_list);
16646
0
          } else {
16647
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16648
0
          }
16649
0
          if (continue_list) {
16650
0
            ir_MERGE_list(continue_list);
16651
0
          } else {
16652
0
            ZEND_ASSERT(slow_inputs->count);
16653
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16654
0
          }
16655
0
        } else {
16656
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16657
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16658
0
            b = ssa->cfg.map[target - op_array->opcodes];
16659
0
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16660
0
          } ZEND_HASH_FOREACH_END();
16661
16662
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16663
0
          if (slow_inputs->count) {
16664
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16665
0
            _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16666
0
          }
16667
0
          jit->b = -1;
16668
0
        }
16669
0
      } else if (!next_opline) {
16670
0
        _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16671
0
        jit->b = -1;
16672
0
      }
16673
10
    } else if (opline->opcode == ZEND_SWITCH_STRING) {
16674
0
      if (op1_info & MAY_BE_STRING) {
16675
0
        const void *fallback_label = NULL;
16676
16677
0
        if (next_opline) {
16678
0
          if (next_opline != opline + 1) {
16679
0
            exit_point = zend_jit_trace_get_exit_point(opline + 1, 0);
16680
0
            fallback_label = zend_jit_trace_get_exit_addr(exit_point);
16681
0
            if (!fallback_label) {
16682
0
              return 0;
16683
0
            }
16684
0
          }
16685
0
        }
16686
0
        if (op1_info & MAY_BE_REF) {
16687
0
          ir_ref ref, if_string, fast_path, ref2;
16688
16689
0
          ref = jit_ZVAL_ADDR(jit, op1_addr);
16690
0
          if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16691
0
          ir_IF_TRUE(if_string);
16692
0
          fast_path = ir_END();
16693
0
          ir_IF_FALSE_cold(if_string);
16694
16695
          // JIT: ZVAL_DEREF(op)
16696
0
          if (fallback_label) {
16697
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_REFERENCE, fallback_label);
16698
0
          } else {
16699
0
            ir_ref if_ref = jit_if_Z_TYPE(jit, op1_addr, IS_REFERENCE);
16700
0
            ir_IF_FALSE_cold(if_ref);
16701
0
            ir_refs_add(slow_inputs, ir_END());
16702
0
            ir_IF_TRUE(if_ref);
16703
0
          }
16704
16705
0
          ref2 = ir_ADD_OFFSET(jit_Z_PTR(jit, op1_addr), offsetof(zend_reference, val));
16706
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref2);
16707
16708
0
          if (fallback_label) {
16709
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16710
0
          } else {
16711
0
            if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16712
0
            ir_IF_FALSE_cold(if_string);
16713
0
            ir_refs_add(slow_inputs, ir_END());
16714
0
            ir_IF_TRUE(if_string);
16715
0
          }
16716
16717
0
          ir_MERGE_2(fast_path, ir_END());
16718
0
          ref = ir_PHI_2(IR_ADDR, ref, ref2);
16719
0
          op1_addr = ZEND_ADDR_REF_ZVAL(ref);
16720
0
        } else if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) {
16721
0
          if (fallback_label) {
16722
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, fallback_label);
16723
0
          } else {
16724
0
            ir_ref if_string = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16725
0
            ir_IF_FALSE_cold(if_string);
16726
0
            ir_refs_add(slow_inputs, ir_END());
16727
0
            ir_IF_TRUE(if_string);
16728
0
          }
16729
0
        }
16730
16731
0
        ir_ref ref = jit_Z_PTR(jit, op1_addr);
16732
0
        ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16733
0
          ir_CONST_ADDR(jumptable), ref);
16734
0
        ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16735
        /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16736
0
        if (sizeof(Bucket) == 32) {
16737
0
          ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16738
0
        } else {
16739
0
          ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16740
0
        }
16741
0
        ref = ir_SWITCH(ref);
16742
16743
0
        if (next_opline) {
16744
0
          ir_ref continue_list = IR_UNUSED;
16745
16746
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16747
0
            ir_ref idx;
16748
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16749
16750
0
            if (HT_IS_PACKED(jumptable)) {
16751
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16752
0
            } else {
16753
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16754
0
            }
16755
0
            ir_CASE_VAL(ref, idx);
16756
0
            if (target == next_opline) {
16757
0
              ir_END_list(continue_list);
16758
0
            } else {
16759
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16760
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16761
0
              if (!exit_addr) {
16762
0
                return 0;
16763
0
              }
16764
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16765
0
            }
16766
0
          } ZEND_HASH_FOREACH_END();
16767
16768
0
          ir_CASE_DEFAULT(ref);
16769
0
          if (next_opline == default_opline) {
16770
0
            ir_END_list(continue_list);
16771
0
          } else {
16772
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16773
0
          }
16774
0
          if (continue_list) {
16775
0
            ir_MERGE_list(continue_list);
16776
0
          } else {
16777
0
            ZEND_ASSERT(slow_inputs->count);
16778
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16779
0
          }
16780
0
        } else {
16781
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16782
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16783
0
            b = ssa->cfg.map[target - op_array->opcodes];
16784
0
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16785
0
          } ZEND_HASH_FOREACH_END();
16786
0
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16787
0
          if (slow_inputs->count) {
16788
0
            ir_MERGE_N(slow_inputs->count, slow_inputs->refs);
16789
0
            _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16790
0
          }
16791
0
          jit->b = -1;
16792
0
        }
16793
0
      } else if (!next_opline) {
16794
0
        _zend_jit_add_predecessor_ref(jit, jit->b + 1, jit->b, ir_END());
16795
0
        jit->b = -1;
16796
0
      }
16797
10
    } else if (opline->opcode == ZEND_MATCH) {
16798
10
      ir_ref if_type = IR_UNUSED, default_input_list = IR_UNUSED, ref = IR_UNUSED;
16799
10
      ir_ref continue_list = IR_UNUSED;
16800
16801
10
      if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) {
16802
6
        ir_ref long_path = IR_UNUSED;
16803
16804
6
        if (op1_info & MAY_BE_REF) {
16805
6
          op1_addr = jit_ZVAL_DEREF(jit, op1_addr);
16806
6
        }
16807
6
        if (op1_info & MAY_BE_LONG) {
16808
6
          if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) {
16809
6
            if (op1_info & (MAY_BE_STRING|MAY_BE_UNDEF)) {
16810
6
              if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16811
6
              ir_IF_TRUE(if_type);
16812
6
            } else if (default_label) {
16813
0
              jit_guard_Z_TYPE(jit, op1_addr, IS_LONG, default_label);
16814
0
            } else if (next_opline) {
16815
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16816
0
              ir_IF_FALSE(if_type);
16817
0
              ir_END_list(continue_list);
16818
0
              ir_IF_TRUE(if_type);
16819
0
            } else {
16820
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_LONG);
16821
0
              ir_IF_FALSE(if_type);
16822
0
              ir_END_list(default_input_list);
16823
0
              ir_IF_TRUE(if_type);
16824
0
            }
16825
6
          }
16826
6
          ref = jit_Z_LVAL(jit, op1_addr);
16827
6
          ref = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_index_find),
16828
6
            ir_CONST_ADDR(jumptable), ref);
16829
6
          if (op1_info & MAY_BE_STRING) {
16830
6
            long_path = ir_END();
16831
6
          }
16832
6
        }
16833
6
        if (op1_info & MAY_BE_STRING) {
16834
6
          if (if_type) {
16835
6
            ir_IF_FALSE(if_type);
16836
6
            if_type = IS_UNUSED;
16837
6
          }
16838
6
          if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) {
16839
6
            if (op1_info & MAY_BE_UNDEF) {
16840
6
              if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16841
6
              ir_IF_TRUE(if_type);
16842
6
            } else if (default_label) {
16843
0
              jit_guard_Z_TYPE(jit, op1_addr, IS_STRING, default_label);
16844
0
            } else if (next_opline) {
16845
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16846
0
              ir_IF_FALSE(if_type);
16847
0
              ir_END_list(continue_list);
16848
0
              ir_IF_TRUE(if_type);
16849
0
            } else {
16850
0
              ir_ref if_type = jit_if_Z_TYPE(jit, op1_addr, IS_STRING);
16851
0
              ir_IF_FALSE(if_type);
16852
0
              ir_END_list(default_input_list);
16853
0
              ir_IF_TRUE(if_type);
16854
0
            }
16855
6
          }
16856
6
          ir_ref ref2 = jit_Z_PTR(jit, op1_addr);
16857
6
          ref2 = ir_CALL_2(IR_LONG, ir_CONST_FC_FUNC(zend_hash_find),
16858
6
            ir_CONST_ADDR(jumptable), ref2);
16859
6
          if (op1_info & MAY_BE_LONG) {
16860
6
            ir_MERGE_WITH(long_path);
16861
6
            ref = ir_PHI_2(IR_LONG, ref2, ref);
16862
6
          } else {
16863
0
            ref = ref2;
16864
0
          }
16865
6
        }
16866
16867
6
        ref = ir_SUB_L(ref, ir_CONST_LONG((uintptr_t)jumptable->arData));
16868
        /* Signed DIV by power of 2 may be optimized into SHR only for positive operands */
16869
6
        if (HT_IS_PACKED(jumptable)) {
16870
5
          ZEND_ASSERT(sizeof(zval) == 16);
16871
5
          ref = ir_SHR_L(ref, ir_CONST_LONG(4));
16872
5
        } else {
16873
1
          if (sizeof(Bucket) == 32) {
16874
1
            ref = ir_SHR_L(ref, ir_CONST_LONG(5));
16875
1
          } else {
16876
0
            ref = ir_DIV_L(ref, ir_CONST_LONG(sizeof(Bucket)));
16877
0
          }
16878
1
        }
16879
6
        ref = ir_SWITCH(ref);
16880
16881
6
        if (next_opline) {
16882
0
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16883
0
            ir_ref idx;
16884
0
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16885
16886
0
            if (HT_IS_PACKED(jumptable)) {
16887
0
              idx = ir_CONST_LONG(zv - jumptable->arPacked);
16888
0
            } else {
16889
0
              idx = ir_CONST_LONG((Bucket*)zv - jumptable->arData);
16890
0
            }
16891
0
            ir_CASE_VAL(ref, idx);
16892
0
            if (target == next_opline) {
16893
0
              ir_END_list(continue_list);
16894
0
            } else {
16895
0
              exit_point = zend_jit_trace_get_exit_point(target, 0);
16896
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
16897
0
              if (!exit_addr) {
16898
0
                return 0;
16899
0
              }
16900
0
              jit_SIDE_EXIT(jit, ir_CONST_ADDR(exit_addr));
16901
0
            }
16902
0
          } ZEND_HASH_FOREACH_END();
16903
16904
0
          ir_CASE_DEFAULT(ref);
16905
0
          if (next_opline == default_opline) {
16906
0
            ir_END_list(continue_list);
16907
0
          } else {
16908
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16909
0
          }
16910
6
        } else {
16911
31
          ZEND_HASH_FOREACH_VAL(jumptable, zv) {
16912
31
            target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv));
16913
31
            b = ssa->cfg.map[target - op_array->opcodes];
16914
31
            _zend_jit_add_predecessor_ref(jit, b, jit->b, ref);
16915
31
          } ZEND_HASH_FOREACH_END();
16916
6
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ref);
16917
6
        }
16918
6
      } else if (!(op1_info & MAY_BE_UNDEF)) {
16919
2
        if (next_opline) {
16920
0
          if (next_opline == default_opline) {
16921
0
            ir_END_list(continue_list);
16922
0
          } else {
16923
0
            jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16924
0
          }
16925
2
        } else {
16926
2
          _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16927
2
        }
16928
2
      }
16929
16930
10
      if (op1_info & MAY_BE_UNDEF) {
16931
8
        if (if_type) {
16932
6
          ir_IF_FALSE(if_type);
16933
6
          if_type = IS_UNUSED;
16934
6
        }
16935
8
        if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) {
16936
6
          if (default_label) {
16937
0
            jit_guard_Z_TYPE(jit, op1_addr, IS_UNDEF, default_label);
16938
6
          } else if (next_opline) {
16939
0
            ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16940
0
            ir_IF_TRUE(if_def);
16941
0
            ir_END_list(continue_list);
16942
0
            ir_IF_FALSE_cold(if_def);
16943
6
          } else {
16944
6
            ir_ref if_def = ir_IF(jit_Z_TYPE(jit, op1_addr));
16945
6
            ir_IF_TRUE(if_def);
16946
6
            ir_END_list(default_input_list);
16947
6
            ir_IF_FALSE_cold(if_def);
16948
6
          }
16949
6
        }
16950
16951
8
        jit_SET_EX_OPLINE(jit, opline);
16952
8
        ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_undefined_op_helper),
16953
8
          ir_CONST_U32(opline->op1.var));
16954
8
        zend_jit_check_exception_undef_result(jit, opline);
16955
8
        if (default_label) {
16956
0
          jit_SIDE_EXIT(jit, ir_CONST_ADDR(default_label));
16957
8
        } else if (next_opline) {
16958
0
          ir_END_list(continue_list);
16959
8
        } else {
16960
8
          ir_END_list(default_input_list);
16961
8
        }
16962
8
      }
16963
10
      if (next_opline) {
16964
0
        ZEND_ASSERT(continue_list);
16965
0
        ir_MERGE_list(continue_list);
16966
10
      } else {
16967
10
        if (default_input_list) {
16968
8
          if (jit->ctx.ir_base[ref].op == IR_SWITCH) {
16969
6
            ZEND_ASSERT(jit->ctx.ir_base[ref].op3 == IR_UNUSED);
16970
6
            jit->ctx.ir_base[ref].op3 = default_input_list;
16971
6
          } else {
16972
2
            ir_MERGE_list(default_input_list);
16973
2
            _zend_jit_add_predecessor_ref(jit, default_b, jit->b, ir_END());
16974
2
          }
16975
8
        }
16976
10
        jit->b = -1;
16977
10
      }
16978
10
    } else {
16979
0
      ZEND_UNREACHABLE();
16980
0
    }
16981
10
  }
16982
10
  return 1;
16983
10
}
16984
16985
static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend_ssa *ssa)
16986
7.32k
{
16987
7.32k
  uint32_t i, count;
16988
7.32k
  zend_basic_block *bb;
16989
16990
7.32k
  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));
16991
16992
7.32k
  jit->ctx.spill_base = ZREG_FP;
16993
16994
7.32k
  jit->op_array = jit->current_op_array = op_array;
16995
7.32k
  jit->ssa = ssa;
16996
7.32k
  jit->bb_start_ref = zend_arena_calloc(&CG(arena), ssa->cfg.blocks_count * 2, sizeof(ir_ref));
16997
7.32k
  jit->bb_predecessors = jit->bb_start_ref + ssa->cfg.blocks_count;
16998
16999
7.32k
  count = 0;
17000
19.4k
  for (i = 0, bb = ssa->cfg.blocks; i < ssa->cfg.blocks_count; i++, bb++) {
17001
12.1k
    jit->bb_predecessors[i] = count;
17002
12.1k
    count += bb->predecessors_count;
17003
12.1k
  }
17004
7.32k
  jit->bb_edges = zend_arena_calloc(&CG(arena), count, sizeof(ir_ref));
17005
17006
7.32k
  if (!GCC_GLOBAL_REGS) {
17007
7.32k
    if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
17008
0
      ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
17009
0
      ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
17010
0
      jit_STORE_FP(jit, execute_data_ref);
17011
0
      jit_STORE_IP(jit, opline_ref);
17012
0
    }
17013
7.32k
    jit->ctx.flags |= IR_FASTCALL_FUNC;
17014
7.32k
  }
17015
17016
7.32k
  return 1;
17017
7.32k
}
17018
17019
static zend_vm_opcode_handler_t zend_jit_finish(zend_jit_ctx *jit)
17020
9.83k
{
17021
9.83k
  void *entry;
17022
9.83k
  size_t size;
17023
9.83k
  zend_string *str = NULL;
17024
17025
9.83k
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP|
17026
9.83k
      ZEND_JIT_DEBUG_IR_SRC|ZEND_JIT_DEBUG_IR_AFTER_SCCP|ZEND_JIT_DEBUG_IR_AFTER_SCCP|
17027
9.83k
      ZEND_JIT_DEBUG_IR_AFTER_SCHEDULE|ZEND_JIT_DEBUG_IR_AFTER_REGS|ZEND_JIT_DEBUG_IR_FINAL|ZEND_JIT_DEBUG_IR_CODEGEN)) {
17028
0
    if (jit->name) {
17029
0
      str = zend_string_copy(jit->name);
17030
0
    } else {
17031
0
      str = zend_jit_func_name(jit->op_array);
17032
0
    }
17033
0
  }
17034
17035
9.83k
  if (jit->op_array) {
17036
    /* Only for function JIT */
17037
7.32k
    _zend_jit_fix_merges(jit);
17038
#if defined(IR_TARGET_AARCH64)
17039
  } else if (jit->trace) {
17040
    jit->ctx.deoptimization_exits = jit->trace->exit_count;
17041
    jit->ctx.get_exit_addr = zend_jit_trace_get_exit_addr;
17042
#endif
17043
7.32k
  } else {
17044
2.50k
#if defined(IR_TARGET_X86) || defined(IR_TARGET_X64)
17045
2.50k
    jit->ctx.flags |= IR_GEN_CACHE_DEMOTE;
17046
2.50k
#endif
17047
2.50k
  }
17048
17049
9.83k
  entry = zend_jit_ir_compile(&jit->ctx, &size, str ? ZSTR_VAL(str) : NULL);
17050
9.83k
  if (entry) {
17051
9.83k
    if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
17052
#ifdef HAVE_CAPSTONE
17053
      if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
17054
        if (str) {
17055
          ir_disasm_add_symbol(ZSTR_VAL(str), (uintptr_t)entry, size);
17056
        }
17057
        ir_disasm(str ? ZSTR_VAL(str) : "unknown",
17058
          entry, size,
17059
          (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) != 0,
17060
          &jit->ctx, stderr);
17061
      }
17062
#endif
17063
0
#ifndef _WIN32
17064
0
      if (str) {
17065
0
        if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) {
17066
0
          uintptr_t sp_offset = 0;
17067
17068
//          ir_mem_unprotect(entry, size);
17069
0
          if (!(jit->ctx.flags & IR_FUNCTION)
17070
0
           && ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
17071
0
#if !defined(ZEND_WIN32) && !defined(IR_TARGET_AARCH64)
17072
0
            sp_offset = zend_jit_hybrid_vm_sp_adj;
17073
#else
17074
            sp_offset = sizeof(void*);
17075
#endif
17076
0
          } else {
17077
0
            sp_offset = sizeof(void*);
17078
0
          }
17079
0
          ir_gdb_register(ZSTR_VAL(str), entry, size, sp_offset, 0);
17080
//          ir_mem_protect(entry, size);
17081
0
        }
17082
17083
0
        if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) {
17084
0
          ir_perf_map_register(ZSTR_VAL(str), entry, size);
17085
0
          if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) {
17086
0
            ir_perf_jitdump_register(ZSTR_VAL(str), entry, size);
17087
0
          }
17088
0
        }
17089
0
      }
17090
0
#endif
17091
0
    }
17092
17093
9.83k
    if (jit->op_array) {
17094
      /* Only for function JIT */
17095
7.32k
      const zend_op_array *op_array = jit->op_array;
17096
7.32k
      zend_op *opline = (zend_op*)op_array->opcodes;
17097
17098
7.32k
      if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
17099
7.33k
        while (opline->opcode == ZEND_RECV) {
17100
15
          opline++;
17101
15
        }
17102
7.31k
      }
17103
7.32k
      opline->handler = (zend_vm_opcode_handler_t)entry;
17104
17105
7.32k
      if (jit->ctx.entries_count) {
17106
        /* For all entries */
17107
3.03k
        int i = jit->ctx.entries_count;
17108
3.16k
        do {
17109
3.16k
          ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
17110
3.16k
          op_array->opcodes[insn->op2].handler = (zend_vm_opcode_handler_t)((char*)entry + insn->op3);
17111
3.16k
        } while (i != 0);
17112
3.03k
      }
17113
7.32k
    } else {
17114
      /* Only for tracing JIT */
17115
2.50k
      zend_jit_trace_info *t = jit->trace;
17116
2.50k
      zend_jit_trace_stack *stack;
17117
2.50k
      uint32_t i;
17118
17119
2.50k
      if (t) {
17120
5.84k
        for (i = 0; i < t->stack_map_size; i++) {
17121
3.34k
          stack = t->stack_map + i;
17122
3.34k
          if (stack->flags & ZREG_SPILL_SLOT) {
17123
4
            stack->reg = (jit->ctx.flags & IR_USE_FRAME_POINTER) ? IR_REG_FP : IR_REG_SP;
17124
4
            stack->ref = ir_get_spill_slot_offset(&jit->ctx, stack->ref);
17125
4
          }
17126
3.34k
        }
17127
2.50k
      }
17128
17129
2.50k
      zend_jit_trace_add_code(entry, size);
17130
2.50k
    }
17131
9.83k
  }
17132
17133
9.83k
  if (str) {
17134
0
    zend_string_release(str);
17135
0
  }
17136
17137
9.83k
  return (zend_vm_opcode_handler_t)entry;
17138
9.83k
}
17139
17140
static const void *zend_jit_trace_allocate_exit_group(uint32_t n)
17141
1
{
17142
1
  const void *entry;
17143
1
  size_t size;
17144
1
  ir_code_buffer code_buffer;
17145
17146
1
  code_buffer.start = dasm_buf;
17147
1
  code_buffer.end = dasm_end;
17148
1
  code_buffer.pos = *dasm_ptr;
17149
17150
1
  entry = ir_emit_exitgroup(n, ZEND_JIT_EXIT_POINTS_PER_GROUP, zend_jit_stub_handlers[jit_stub_trace_exit],
17151
1
    &code_buffer, &size);
17152
17153
1
  *dasm_ptr = code_buffer.pos;
17154
17155
1
  if (entry) {
17156
#ifdef HAVE_CAPSTONE
17157
    if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) {
17158
      uint32_t i;
17159
      char name[32];
17160
17161
      for (i = 0; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) {
17162
        snprintf(name, sizeof(name), "jit$$trace_exit_%d", n + i);
17163
        ir_disasm_add_symbol(name, (uintptr_t)entry + (i * ZEND_JIT_EXIT_POINTS_SPACING), ZEND_JIT_EXIT_POINTS_SPACING);
17164
      }
17165
    }
17166
#endif
17167
1
  }
17168
17169
1
  return entry;
17170
1
}
17171
17172
static int zend_jit_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var, uint8_t type)
17173
1.42k
{
17174
1.42k
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17175
1.42k
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17176
1.42k
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
17177
17178
1.42k
  if (!exit_addr) {
17179
0
    return 0;
17180
0
  }
17181
1.42k
  ir_GUARD(ir_EQ(jit_Z_TYPE(jit, addr), ir_CONST_U8(type)), ir_CONST_ADDR(exit_addr));
17182
17183
1.42k
  return 1;
17184
1.42k
}
17185
17186
static int zend_jit_scalar_type_guard(zend_jit_ctx *jit, const zend_op *opline, uint32_t var)
17187
0
{
17188
0
  int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17189
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17190
0
  zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var);
17191
17192
0
  if (!exit_addr) {
17193
0
    return 0;
17194
0
  }
17195
0
  ir_GUARD(ir_LT(jit_Z_TYPE(jit, addr), ir_CONST_U8(IS_STRING)), ir_CONST_ADDR(exit_addr));
17196
17197
0
  return 1;
17198
0
}
17199
17200
static bool zend_jit_noref_guard(zend_jit_ctx *jit, const zend_op *opline, zend_jit_addr var_addr)
17201
0
{
17202
0
  uint32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17203
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17204
17205
0
  if (!exit_addr) {
17206
0
    return false;
17207
0
  }
17208
0
  ir_GUARD(ir_NE(jit_Z_TYPE(jit, var_addr), ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17209
17210
0
  return true;
17211
0
}
17212
17213
static int zend_jit_trace_opline_guard(zend_jit_ctx *jit, const zend_op *opline)
17214
0
{
17215
0
  uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0);
17216
0
  const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17217
17218
0
  if (!exit_addr) {
17219
0
    return 0;
17220
0
  }
17221
17222
0
  ir_GUARD(jit_CMP_IP(jit, IR_EQ, opline), ir_CONST_ADDR(exit_addr));
17223
0
  zend_jit_set_last_valid_opline(jit, opline);
17224
17225
0
  return 1;
17226
0
}
17227
17228
static bool zend_jit_guard_reference(zend_jit_ctx  *jit,
17229
                                     const zend_op *opline,
17230
                                     zend_jit_addr *var_addr_ptr,
17231
                                     zend_jit_addr *ref_addr_ptr,
17232
                                     bool           add_ref_guard)
17233
3
{
17234
3
  zend_jit_addr var_addr = *var_addr_ptr;
17235
3
  const void *exit_addr = NULL;
17236
3
  ir_ref ref;
17237
17238
3
  if (add_ref_guard) {
17239
3
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17240
17241
3
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17242
3
    if (!exit_addr) {
17243
0
      return false;
17244
0
    }
17245
17246
3
    ref = jit_Z_TYPE(jit, var_addr);
17247
3
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17248
3
  }
17249
17250
3
  ref = jit_Z_PTR(jit, var_addr);
17251
3
  *ref_addr_ptr = ZEND_ADDR_REF_ZVAL(ref);
17252
3
  ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
17253
3
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
17254
3
  *var_addr_ptr = var_addr;
17255
17256
3
  return true;
17257
3
}
17258
17259
static bool zend_jit_fetch_reference(zend_jit_ctx  *jit,
17260
                                     const zend_op *opline,
17261
                                     uint8_t        var_type,
17262
                                     uint32_t      *var_info_ptr,
17263
                                     zend_jit_addr *var_addr_ptr,
17264
                                     bool           add_ref_guard,
17265
                                     bool           add_type_guard)
17266
0
{
17267
0
  zend_jit_addr var_addr = *var_addr_ptr;
17268
0
  uint32_t var_info = *var_info_ptr;
17269
0
  const void *exit_addr = NULL;
17270
0
  ir_ref ref;
17271
17272
0
  if (add_ref_guard || add_type_guard) {
17273
0
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17274
17275
0
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17276
0
    if (!exit_addr) {
17277
0
      return false;
17278
0
    }
17279
0
  }
17280
17281
0
  if (add_ref_guard) {
17282
0
    ref = jit_Z_TYPE(jit, var_addr);
17283
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(IS_REFERENCE)), ir_CONST_ADDR(exit_addr));
17284
0
  }
17285
0
  if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) {
17286
    /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */
17287
0
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_unref_helper),
17288
0
      jit_ZVAL_ADDR(jit, var_addr));
17289
0
    *var_addr_ptr = var_addr;
17290
0
  } else {
17291
0
    ref = jit_Z_PTR(jit, var_addr);
17292
0
    ref = ir_ADD_OFFSET(ref, offsetof(zend_reference, val));
17293
0
    var_addr = ZEND_ADDR_REF_ZVAL(ref);
17294
0
    *var_addr_ptr = var_addr;
17295
0
  }
17296
17297
0
  if (var_type != IS_UNKNOWN) {
17298
0
    var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED);
17299
0
  }
17300
0
  if (add_type_guard
17301
0
   && var_type != IS_UNKNOWN
17302
0
   && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
17303
0
    ref = jit_Z_TYPE(jit, var_addr);
17304
0
    ir_GUARD(ir_EQ(ref, ir_CONST_U8(var_type)), ir_CONST_ADDR(exit_addr));
17305
17306
0
    ZEND_ASSERT(var_info & (1 << var_type));
17307
0
    if (var_type < IS_STRING) {
17308
0
      var_info = (1 << var_type);
17309
0
    } else if (var_type != IS_ARRAY) {
17310
0
      var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
17311
0
    } else {
17312
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));
17313
0
    }
17314
17315
0
    *var_info_ptr = var_info;
17316
0
  } else {
17317
0
    var_info &= ~MAY_BE_REF;
17318
0
    *var_info_ptr = var_info;
17319
0
  }
17320
0
  *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */
17321
17322
0
  return true;
17323
0
}
17324
17325
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)
17326
28
{
17327
28
  zend_jit_addr var_addr = *var_addr_ptr;
17328
28
  uint32_t var_info = *var_info_ptr;
17329
28
  int32_t exit_point;
17330
28
  const void *exit_addr;
17331
28
  ir_ref ref = IR_UNUSED;
17332
17333
28
  if (add_indirect_guard) {
17334
25
    int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0);
17335
25
    const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17336
17337
25
    if (!exit_addr) {
17338
0
      return false;
17339
0
    }
17340
25
    jit_guard_Z_TYPE(jit, var_addr, IS_INDIRECT, exit_addr);
17341
25
    ref = jit_Z_PTR(jit, var_addr);
17342
25
  } else {
17343
    /* This LOAD of INDIRECT VAR, stored by the previous FETCH_(DIM/OBJ)_W,
17344
     * is eliminated by store forwarding (S2L) */
17345
3
    ref = jit_Z_PTR(jit, var_addr);
17346
3
  }
17347
28
  *var_info_ptr &= ~MAY_BE_INDIRECT;
17348
28
  var_addr = ZEND_ADDR_REF_ZVAL(ref);
17349
28
  *var_addr_ptr = var_addr;
17350
17351
28
  if (var_type != IS_UNKNOWN) {
17352
28
    var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED);
17353
28
  }
17354
28
  if (!(var_type & IS_TRACE_REFERENCE)
17355
28
   && var_type != IS_UNKNOWN
17356
28
   && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) {
17357
28
    exit_point = zend_jit_trace_get_exit_point(opline, 0);
17358
28
    exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17359
17360
28
    if (!exit_addr) {
17361
0
      return false;
17362
0
    }
17363
17364
28
    jit_guard_Z_TYPE(jit, var_addr, var_type, exit_addr);
17365
17366
    //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info);
17367
28
    ZEND_ASSERT(var_info & (1 << var_type));
17368
28
    if (var_type < IS_STRING) {
17369
28
      var_info = (1 << var_type);
17370
28
    } else if (var_type != IS_ARRAY) {
17371
0
      var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN));
17372
0
    } else {
17373
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));
17374
0
    }
17375
17376
28
    *var_info_ptr = var_info;
17377
28
  }
17378
17379
28
  return true;
17380
28
}
17381
17382
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)
17383
5.25k
{
17384
5.25k
  zend_jit_op_array_trace_extension *jit_extension =
17385
5.25k
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
17386
5.25k
  size_t offset = jit_extension->offset;
17387
5.25k
  zend_vm_opcode_handler_func_t handler =
17388
5.25k
    ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
17389
5.25k
  ir_ref ref;
17390
17391
5.25k
  zend_jit_set_ip(jit, opline);
17392
5.25k
  if (GCC_GLOBAL_REGS) {
17393
0
    ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
17394
5.25k
  } else {
17395
5.25k
    ref = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
17396
5.25k
    if (opline->opcode == ZEND_RETURN ||
17397
2.88k
        opline->opcode == ZEND_RETURN_BY_REF ||
17398
2.88k
        opline->opcode == ZEND_DO_UCALL ||
17399
2.88k
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
17400
2.88k
        opline->opcode == ZEND_DO_FCALL ||
17401
2.88k
        opline->opcode == ZEND_GENERATOR_CREATE ||
17402
2.88k
        opline->opcode == ZEND_INCLUDE_OR_EVAL ||
17403
        /* May enter a simple get hook. */
17404
2.79k
        opline->opcode == ZEND_FETCH_OBJ_R ||
17405
2.77k
      opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
17406
17407
2.47k
      jit_STORE_IP(jit, ir_AND_A(ref, ir_CONST_ADDR(~ZEND_VM_ENTER_BIT)));
17408
2.77k
    } else {
17409
2.77k
      jit_STORE_IP(jit, ref);
17410
2.77k
    }
17411
5.25k
  }
17412
5.25k
  if (may_throw
17413
4.85k
   && opline->opcode != ZEND_RETURN
17414
2.48k
   && opline->opcode != ZEND_RETURN_BY_REF) {
17415
2.48k
    zend_jit_check_exception(jit);
17416
2.48k
  }
17417
17418
5.25k
  while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) {
17419
5
    trace++;
17420
5
  }
17421
17422
5.25k
  if ((!GCC_GLOBAL_REGS
17423
5.25k
   && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN))
17424
5.25k
   || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
17425
5.25k
    if (opline->opcode == ZEND_RETURN ||
17426
2.88k
        opline->opcode == ZEND_RETURN_BY_REF ||
17427
2.88k
        opline->opcode == ZEND_DO_UCALL ||
17428
2.88k
        opline->opcode == ZEND_DO_FCALL_BY_NAME ||
17429
2.88k
        opline->opcode == ZEND_DO_FCALL ||
17430
2.88k
        opline->opcode == ZEND_GENERATOR_CREATE ||
17431
2.88k
        opline->opcode == ZEND_INCLUDE_OR_EVAL ||
17432
        /* May enter a simple get hook. */
17433
2.79k
        opline->opcode == ZEND_FETCH_OBJ_R ||
17434
2.77k
      opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
17435
17436
2.47k
      ir_ref addr = jit_EG(current_execute_data);
17437
17438
2.47k
      jit_STORE_FP(jit, ir_LOAD_A(addr));
17439
2.47k
    }
17440
5.25k
  }
17441
17442
5.25k
  if (zend_jit_trace_may_exit(op_array, opline)) {
17443
2.53k
    if (opline->opcode == ZEND_RETURN ||
17444
170
        opline->opcode == ZEND_RETURN_BY_REF ||
17445
2.37k
        opline->opcode == ZEND_GENERATOR_CREATE) {
17446
17447
2.37k
      if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) {
17448
0
        if (trace->op != ZEND_JIT_TRACE_END ||
17449
0
            (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
17450
0
             trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
17451
          /* this check may be handled by the following OPLINE guard or jmp [IP] */
17452
0
          ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
17453
0
            jit_STUB_ADDR(jit, jit_stub_trace_halt));
17454
0
        }
17455
2.37k
      } else {
17456
        /* IP has been cleared of ZEND_VM_ENTER_BIT already */
17457
2.37k
        ir_GUARD(jit_IP(jit), jit_STUB_ADDR(jit, jit_stub_trace_halt));
17458
2.37k
      }
17459
2.37k
    } else if (opline->opcode == ZEND_GENERATOR_RETURN ||
17460
167
               opline->opcode == ZEND_YIELD ||
17461
167
               opline->opcode == ZEND_YIELD_FROM) {
17462
0
      ir_IJMP(jit_STUB_ADDR(jit, jit_stub_trace_halt));
17463
0
      ir_BEGIN(IR_UNUSED); /* unreachable block */
17464
0
    }
17465
2.53k
    if (trace->op != ZEND_JIT_TRACE_END ||
17466
2.46k
        (trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
17467
91
         trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
17468
17469
78
      const zend_op *next_opline = trace->opline;
17470
78
      const zend_op *exit_opline = NULL;
17471
78
      uint32_t exit_point;
17472
78
      const void *exit_addr;
17473
78
      uint32_t old_info = 0;
17474
78
      uint32_t old_res_info = 0;
17475
78
      zend_jit_trace_stack *stack = JIT_G(current_frame)->stack;
17476
17477
78
      if (zend_is_smart_branch(opline)) {
17478
0
        bool exit_if_true = false;
17479
0
        exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true);
17480
78
      } else {
17481
78
        switch (opline->opcode) {
17482
0
          case ZEND_JMPZ:
17483
0
          case ZEND_JMPNZ:
17484
0
          case ZEND_JMPZ_EX:
17485
0
          case ZEND_JMPNZ_EX:
17486
8
          case ZEND_JMP_SET:
17487
39
          case ZEND_COALESCE:
17488
51
          case ZEND_JMP_NULL:
17489
51
          case ZEND_FE_RESET_R:
17490
52
          case ZEND_FE_RESET_RW:
17491
52
            exit_opline = (trace->opline == opline + 1) ?
17492
52
              OP_JMP_ADDR(opline, opline->op2) :
17493
52
              opline + 1;
17494
52
            break;
17495
0
          case ZEND_FE_FETCH_R:
17496
1
          case ZEND_FE_FETCH_RW:
17497
1
            exit_opline = (trace->opline == opline + 1) ?
17498
1
              ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) :
17499
1
              opline + 1;
17500
1
            break;
17501
17502
78
        }
17503
78
      }
17504
17505
78
      switch (opline->opcode) {
17506
0
        case ZEND_FE_FETCH_R:
17507
1
        case ZEND_FE_FETCH_RW:
17508
1
          if (opline->op2_type != IS_UNUSED) {
17509
1
            old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var));
17510
1
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
17511
1
          }
17512
1
          break;
17513
1
        case ZEND_FE_RESET_RW:
17514
1
        case ZEND_BIND_INIT_STATIC_OR_JMP:
17515
1
          if (opline->op1_type == IS_CV) {
17516
0
            old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
17517
0
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
17518
0
          }
17519
1
          break;
17520
78
      }
17521
78
      if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17522
72
        old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
17523
72
        SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
17524
72
      }
17525
78
      exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
17526
78
      exit_addr = zend_jit_trace_get_exit_addr(exit_point);
17527
17528
78
      if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) {
17529
72
        SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info);
17530
72
      }
17531
78
      switch (opline->opcode) {
17532
0
        case ZEND_FE_FETCH_R:
17533
1
        case ZEND_FE_FETCH_RW:
17534
1
          if (opline->op2_type != IS_UNUSED) {
17535
1
            SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info);
17536
1
          }
17537
1
          break;
17538
1
        case ZEND_FE_RESET_RW:
17539
1
        case ZEND_BIND_INIT_STATIC_OR_JMP:
17540
1
          if (opline->op1_type == IS_CV) {
17541
0
            SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
17542
0
          }
17543
1
          break;
17544
78
      }
17545
17546
78
      if (!exit_addr) {
17547
0
        return 0;
17548
0
      }
17549
78
      ir_GUARD(jit_CMP_IP(jit, IR_EQ, next_opline), ir_CONST_ADDR(exit_addr));
17550
78
    }
17551
2.53k
  }
17552
17553
5.25k
  zend_jit_set_last_valid_opline(jit, trace->opline);
17554
17555
5.25k
  return 1;
17556
5.25k
}
17557
17558
static int zend_jit_deoptimizer_start(zend_jit_ctx        *jit,
17559
                                      zend_string         *name,
17560
                                      uint32_t             trace_num,
17561
                                      zend_jit_trace_info *parent,
17562
                                      uint32_t             exit_num)
17563
0
{
17564
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);
17565
17566
0
  jit->ctx.spill_base = ZREG_FP;
17567
17568
0
  jit->op_array = NULL;
17569
0
  jit->ssa = NULL;
17570
0
  jit->name = zend_string_copy(name);
17571
17572
0
  jit->ctx.flags |= IR_SKIP_PROLOGUE;
17573
17574
0
  zend_jit_preserve_parent_regs(jit, NULL, parent, exit_num);
17575
17576
0
  return 1;
17577
0
}
17578
17579
static int zend_jit_trace_start(zend_jit_ctx        *jit,
17580
                                const zend_op_array *op_array,
17581
                                zend_ssa            *ssa,
17582
                                zend_string         *name,
17583
                                uint32_t             trace_num,
17584
                                zend_jit_trace_info *parent,
17585
                                uint32_t             exit_num)
17586
2.50k
{
17587
2.50k
  zend_jit_init_ctx(jit, (ZEND_VM_KIND == ZEND_VM_KIND_CALL || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) ? 0 : IR_START_BR_TARGET);
17588
17589
2.50k
  jit->ctx.spill_base = ZREG_FP;
17590
17591
2.50k
  jit->op_array = NULL;
17592
2.50k
  jit->current_op_array = op_array;
17593
2.50k
  jit->ssa = ssa;
17594
2.50k
  jit->name = zend_string_copy(name);
17595
17596
2.50k
  if (!GCC_GLOBAL_REGS) {
17597
2.50k
    if (!parent) {
17598
2.48k
      if (ZEND_VM_KIND != ZEND_VM_KIND_TAILCALL) {
17599
0
        ir_ref execute_data_ref = ir_PARAM(IR_ADDR, "execute_data", 1);
17600
0
        ir_ref opline_ref = ir_PARAM(IR_ADDR, "opline", 2);
17601
0
        jit_STORE_FP(jit, execute_data_ref);
17602
0
        jit_STORE_IP(jit, opline_ref);
17603
0
      }
17604
2.48k
      jit->ctx.flags |= IR_FASTCALL_FUNC;
17605
2.48k
    }
17606
2.50k
  }
17607
17608
2.50k
  if (parent) {
17609
18
    jit->ctx.flags |= IR_SKIP_PROLOGUE;
17610
18
  }
17611
17612
2.50k
  zend_jit_preserve_parent_regs(jit, ssa, parent, exit_num);
17613
17614
2.50k
  ir_STORE(jit_EG(jit_trace_num), ir_CONST_U32(trace_num));
17615
17616
2.50k
  return 1;
17617
2.50k
}
17618
17619
static void zend_jit_preserve_parent_regs(zend_jit_ctx *jit,
17620
                                          zend_ssa *ssa,
17621
                                          zend_jit_trace_info *parent,
17622
                                          uint32_t exit_num)
17623
2.50k
{
17624
  /* Emit early RLOADs of registers used for deoptimization to prevent
17625
   * clobbering. zend_jit_deopt_rload() will reference these. */
17626
17627
2.50k
  if (parent) {
17628
18
    int i;
17629
18
    int parent_vars_count = parent->exit_info[exit_num].stack_size;
17630
18
    zend_jit_trace_stack *parent_stack = parent_vars_count == 0 ? NULL :
17631
18
      parent->stack_map +
17632
5
      parent->exit_info[exit_num].stack_offset;
17633
17634
37
    for (i = 0; i < parent_vars_count; i++) {
17635
19
      if (STACK_FLAGS(parent_stack, i) != ZREG_CONST
17636
19
       && STACK_REG(parent_stack, i) != ZREG_NONE) {
17637
4
        int32_t reg = STACK_REG(parent_stack, i);
17638
4
        ir_type type;
17639
17640
4
        if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
17641
0
          type = IR_ADDR;
17642
4
        } else if (STACK_TYPE(parent_stack, i) == IS_LONG) {
17643
4
          type = IR_LONG;
17644
4
        } else if (STACK_TYPE(parent_stack, i) == IS_DOUBLE) {
17645
0
          type = IR_DOUBLE;
17646
0
        } else {
17647
0
          ZEND_UNREACHABLE();
17648
0
        }
17649
4
        if (ssa && ssa->vars[i].no_val) {
17650
          /* pass */
17651
4
        } else {
17652
4
          ir_ref ref = ir_RLOAD(type, reg);
17653
17654
4
          if (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) {
17655
            /* op3 is used as a flag that the value is already stored in memory.
17656
             * In case the IR framework decides to spill the result of IR_LOAD,
17657
             * it doesn't have to store the value once again.
17658
             *
17659
             * See: insn->op3 check in ir_emit_rload()
17660
             */
17661
0
            ir_set_op(&jit->ctx, ref, 3, EX_NUM_TO_VAR(i));
17662
0
          }
17663
4
        }
17664
4
      }
17665
19
    }
17666
18
  }
17667
17668
2.50k
  if (parent && parent->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
17669
0
    ZEND_ASSERT(parent->exit_info[exit_num].poly_func.reg >= 0 && parent->exit_info[exit_num].poly_this.reg >= 0);
17670
0
    if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_func.reg)) {
17671
0
      ir_RLOAD_A(parent->exit_info[exit_num].poly_func.reg);
17672
0
    }
17673
0
    if (!IR_REG_SPILLED(parent->exit_info[exit_num].poly_this.reg)) {
17674
0
      ir_RLOAD_A(parent->exit_info[exit_num].poly_this.reg);
17675
0
    }
17676
0
  }
17677
2.50k
}
17678
17679
static int zend_jit_trace_begin_loop(zend_jit_ctx *jit)
17680
13
{
17681
13
  return ir_LOOP_BEGIN(ir_END());
17682
13
}
17683
17684
static void zend_jit_trace_gen_phi(zend_jit_ctx *jit, zend_ssa_phi *phi)
17685
0
{
17686
0
  int dst_var = phi->ssa_var;
17687
0
  int src_var = phi->sources[0];
17688
0
  ir_ref ref;
17689
17690
0
  ZEND_ASSERT(!(jit->ra[dst_var].flags & ZREG_LOAD));
17691
0
  ZEND_ASSERT(jit->ra[src_var].ref != IR_UNUSED && jit->ra[src_var].ref != IR_NULL);
17692
17693
0
  ref = ir_PHI_2(
17694
0
    (jit->ssa->var_info[src_var].type & MAY_BE_LONG) ? IR_LONG : IR_DOUBLE,
17695
0
    zend_jit_use_reg(jit, ZEND_ADDR_REG(src_var)), IR_UNUSED);
17696
17697
0
  src_var = phi->sources[1];
17698
0
  ZEND_ASSERT(jit->ra[src_var].ref == IR_NULL);
17699
0
  jit->ra[src_var].flags |= ZREG_FORWARD;
17700
17701
0
  zend_jit_def_reg(jit, ZEND_ADDR_REG(dst_var), ref);
17702
0
}
17703
17704
static int zend_jit_trace_end_loop(zend_jit_ctx *jit, int loop_ref, const void *timeout_exit_addr)
17705
13
{
17706
13
  if (timeout_exit_addr) {
17707
13
    zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17708
13
  }
17709
13
  ZEND_ASSERT(jit->ctx.ir_base[loop_ref].op2 == IR_UNUSED);
17710
13
  ir_MERGE_SET_OP(loop_ref, 2, ir_LOOP_END());
17711
13
  return 1;
17712
13
}
17713
17714
static int zend_jit_trace_return(zend_jit_ctx *jit, bool original_handler, const zend_op *opline)
17715
2.46k
{
17716
2.46k
  if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) {
17717
2.46k
    if (!original_handler) {
17718
2.46k
      zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit)));
17719
2.46k
    } else {
17720
0
      zend_jit_tailcall_handler(jit, zend_jit_orig_opline_handler(jit));
17721
0
    }
17722
2.46k
  } else {
17723
0
    if (original_handler) {
17724
0
      ir_ref ref;
17725
0
      ir_ref addr = zend_jit_orig_opline_handler(jit);
17726
17727
#if defined(IR_TARGET_X86)
17728
      addr = ir_CAST_FC_FUNC(addr);
17729
#endif
17730
0
      ref = ir_CALL_2(IR_ADDR, addr, jit_FP(jit), jit_IP(jit));
17731
0
      zend_jit_vm_enter(jit, ref);
17732
0
      return 1;
17733
0
    }
17734
0
    zend_jit_vm_enter(jit, jit_IP(jit));
17735
0
  }
17736
2.46k
  return 1;
17737
2.46k
}
17738
17739
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)
17740
18
{
17741
18
  return ir_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr);
17742
18
}
17743
17744
static int zend_jit_trace_link_to_root(zend_jit_ctx *jit, zend_jit_trace_info *t, const void *timeout_exit_addr)
17745
26
{
17746
26
  const void *link_addr;
17747
17748
  /* Skip prologue. */
17749
26
  ZEND_ASSERT(zend_jit_trace_prologue_size != (size_t)-1);
17750
26
  link_addr = (const void*)((const char*)t->code_start + zend_jit_trace_prologue_size);
17751
17752
26
  if (timeout_exit_addr) {
17753
16
    zend_jit_check_timeout(jit, NULL, timeout_exit_addr);
17754
16
  }
17755
26
  ir_IJMP(ir_CONST_ADDR(link_addr));
17756
17757
26
  return 1;
17758
26
}
17759
17760
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)
17761
8.96k
{
17762
8.96k
  uint32_t op1_info, op2_info;
17763
17764
8.96k
  switch (opline->opcode) {
17765
19
    case ZEND_SEND_VAR:
17766
288
    case ZEND_SEND_VAL:
17767
292
    case ZEND_SEND_VAL_EX:
17768
292
      return (opline->op2_type != IS_CONST) && (opline->opcode != ZEND_SEND_VAL_EX || opline->op2.num <= MAX_ARG_FLAG_NUM);
17769
73
    case ZEND_QM_ASSIGN:
17770
179
    case ZEND_IS_SMALLER:
17771
192
    case ZEND_IS_SMALLER_OR_EQUAL:
17772
211
    case ZEND_IS_EQUAL:
17773
219
    case ZEND_IS_NOT_EQUAL:
17774
221
    case ZEND_IS_IDENTICAL:
17775
222
    case ZEND_IS_NOT_IDENTICAL:
17776
222
    case ZEND_CASE:
17777
222
      return true;
17778
2.38k
    case ZEND_RETURN:
17779
2.38k
      return (op_array->type != ZEND_EVAL_CODE && op_array->function_name);
17780
186
    case ZEND_ASSIGN:
17781
186
      return (opline->op1_type == IS_CV);
17782
81
    case ZEND_ASSIGN_OP:
17783
81
      if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
17784
47
        return false;
17785
47
      }
17786
34
      op1_info = OP1_INFO();
17787
34
      op2_info = OP2_INFO();
17788
34
      return zend_jit_supported_binary_op(opline->extended_value, op1_info, op2_info);
17789
160
    case ZEND_ADD:
17790
393
    case ZEND_SUB:
17791
577
    case ZEND_MUL:
17792
577
      op1_info = OP1_INFO();
17793
577
      op2_info = OP2_INFO();
17794
577
      if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
17795
172
        return false;
17796
172
      }
17797
405
      if (trace && trace->op1_type != IS_UNKNOWN) {
17798
299
        op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17799
299
      }
17800
405
      if (trace && trace->op2_type != IS_UNKNOWN) {
17801
177
        op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17802
177
      }
17803
405
      return !(op1_info & MAY_BE_UNDEF)
17804
405
        && !(op2_info & MAY_BE_UNDEF)
17805
405
        && (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
17806
346
        && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
17807
92
    case ZEND_BW_OR:
17808
493
    case ZEND_BW_AND:
17809
500
    case ZEND_BW_XOR:
17810
539
    case ZEND_SL:
17811
551
    case ZEND_SR:
17812
964
    case ZEND_MOD:
17813
964
      op1_info = OP1_INFO();
17814
964
      op2_info = OP2_INFO();
17815
964
      if (trace && trace->op1_type != IS_UNKNOWN) {
17816
533
        op1_info &= 1U << (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17817
533
      }
17818
964
      if (trace && trace->op2_type != IS_UNKNOWN) {
17819
184
        op2_info &= 1U << (trace->op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
17820
184
      }
17821
964
      return (op1_info & MAY_BE_LONG)
17822
483
        && (op2_info & MAY_BE_LONG);
17823
59
    case ZEND_PRE_INC:
17824
64
    case ZEND_PRE_DEC:
17825
69
    case ZEND_POST_INC:
17826
70
    case ZEND_POST_DEC:
17827
70
      op1_info = OP1_INFO();
17828
70
      return opline->op1_type == IS_CV
17829
61
        && (op1_info & MAY_BE_LONG)
17830
53
        && !(op1_info & MAY_BE_REF);
17831
0
    case ZEND_STRLEN:
17832
0
      op1_info = OP1_INFO();
17833
0
      return (opline->op1_type & (IS_CV|IS_CONST))
17834
0
        && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING;
17835
0
    case ZEND_COUNT:
17836
0
      op1_info = OP1_INFO();
17837
0
      return (opline->op1_type & (IS_CV|IS_CONST))
17838
0
        && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY;
17839
17
    case ZEND_JMPZ:
17840
20
    case ZEND_JMPNZ:
17841
20
      if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17842
0
        if (!ssa->cfg.map) {
17843
0
          return false;
17844
0
        }
17845
0
        if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start &&
17846
0
            ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
17847
0
          return false;
17848
0
        }
17849
0
      }
17850
20
      ZEND_FALLTHROUGH;
17851
26
    case ZEND_BOOL:
17852
75
    case ZEND_BOOL_NOT:
17853
81
    case ZEND_JMPZ_EX:
17854
81
    case ZEND_JMPNZ_EX:
17855
81
      return true;
17856
3
    case ZEND_FETCH_CONSTANT:
17857
3
      return true;
17858
3
    case ZEND_ISSET_ISEMPTY_DIM_OBJ:
17859
3
      if ((opline->extended_value & ZEND_ISEMPTY)) {
17860
0
        return false;
17861
0
      }
17862
3
      ZEND_FALLTHROUGH;
17863
69
    case ZEND_FETCH_DIM_R:
17864
96
    case ZEND_FETCH_DIM_IS:
17865
97
    case ZEND_FETCH_LIST_R:
17866
97
      op1_info = OP1_INFO();
17867
97
      op2_info = OP2_INFO();
17868
97
      if (trace
17869
97
       && trace->op1_type != IS_UNKNOWN
17870
67
       && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17871
7
        op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17872
7
      }
17873
97
      return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17874
25
          (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17875
7
           ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17876
153
    case ZEND_ASSIGN_DIM_OP:
17877
153
      if (opline->result_type != IS_UNUSED) {
17878
20
        return false;
17879
20
      }
17880
133
      if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17881
16
        return false;
17882
16
      }
17883
117
      ZEND_FALLTHROUGH;
17884
206
    case ZEND_ASSIGN_DIM:
17885
223
    case ZEND_FETCH_DIM_W:
17886
230
    case ZEND_FETCH_DIM_RW:
17887
231
    case ZEND_FETCH_LIST_W:
17888
231
      op1_info = OP1_INFO();
17889
231
      op2_info = OP2_INFO();
17890
231
      if (trace) {
17891
231
        if (opline->op1_type == IS_CV) {
17892
202
          if ((opline->opcode == ZEND_ASSIGN_DIM
17893
129
            || opline->opcode == ZEND_ASSIGN_DIM_OP)
17894
184
           && (opline+1)->op1_type == IS_CV
17895
13
           && (opline+1)->op1.var == opline->op1.var) {
17896
            /* skip $a[x] = $a; */
17897
0
            return false;
17898
0
          }
17899
202
        } else if (opline->op1_type == IS_VAR) {
17900
29
          if (trace->op1_type == IS_UNKNOWN
17901
29
           || !(trace->op1_type & IS_TRACE_INDIRECT)
17902
28
           || opline->result_type != IS_UNUSED) {
17903
12
            return false;
17904
12
          }
17905
29
        }
17906
219
        if (trace->op1_type != IS_UNKNOWN
17907
219
         && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) {
17908
34
          op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY);
17909
34
        }
17910
219
      } else {
17911
0
        if (opline->op1_type != IS_CV) {
17912
0
          return false;
17913
0
        }
17914
0
      }
17915
219
      return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
17916
34
          (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
17917
32
           ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
17918
0
    case ZEND_ASSIGN_OBJ_OP:
17919
0
      if (opline->result_type != IS_UNUSED) {
17920
0
        return false;
17921
0
      }
17922
0
      if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
17923
0
        return false;
17924
0
      }
17925
0
      ZEND_FALLTHROUGH;
17926
45
    case ZEND_FETCH_OBJ_R:
17927
45
    case ZEND_ASSIGN_OBJ:
17928
45
      if (opline->op2_type != IS_CONST
17929
42
       || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
17930
42
       || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
17931
4
        return false;
17932
4
      }
17933
41
      op1_info = OP1_INFO();
17934
41
      return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
17935
8.96k
  }
17936
3.69k
  return false;
17937
8.96k
}
17938
17939
static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var)
17940
1.35k
{
17941
1.35k
  if (ssa->vars[var].no_val) {
17942
    /* we don't need the value */
17943
221
    return false;
17944
221
  }
17945
17946
1.13k
  if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) {
17947
    /* Disable global register allocation,
17948
     * register allocation for SSA variables connected through Phi functions
17949
     */
17950
0
    if (ssa->vars[var].definition_phi) {
17951
0
      return false;
17952
0
    }
17953
0
    if (ssa->vars[var].phi_use_chain) {
17954
0
      zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
17955
0
      do {
17956
0
        if (!ssa->vars[phi->ssa_var].no_val) {
17957
0
          return false;
17958
0
        }
17959
0
        phi = zend_ssa_next_use_phi(ssa, var, phi);
17960
0
      } while (phi);
17961
0
    }
17962
0
  }
17963
17964
1.13k
  if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) &&
17965
1.05k
      ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) {
17966
      /* bad type */
17967
601
    return false;
17968
601
  }
17969
17970
533
  return true;
17971
1.13k
}
17972
17973
static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var)
17974
516
{
17975
516
  if (!zend_jit_var_supports_reg(ssa, var)) {
17976
507
    return false;
17977
507
  }
17978
17979
9
  if (ssa->vars[var].definition >= 0) {
17980
7
    uint32_t def = ssa->vars[var].definition;
17981
7
    if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) {
17982
1
      return false;
17983
1
    }
17984
7
  }
17985
17986
8
  if (ssa->vars[var].use_chain >= 0) {
17987
4
    int use = ssa->vars[var].use_chain;
17988
17989
4
    do {
17990
4
      if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) &&
17991
4
          !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) {
17992
2
        return false;
17993
2
      }
17994
2
      use = zend_ssa_next_use(ssa->ops, var, use);
17995
2
    } while (use >= 0);
17996
4
  }
17997
17998
6
  if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) {
17999
6
    uint32_t def_block, use_block;
18000
6
    int b, use;
18001
6
    uint32_t j;
18002
6
    zend_basic_block *bb;
18003
6
    zend_ssa_phi *p;
18004
6
    bool ret = true;
18005
6
    zend_worklist worklist;
18006
6
    ALLOCA_FLAG(use_heap)
18007
18008
    /* Check if live range is split by ENTRY block */
18009
6
    if (ssa->vars[var].definition >= 0) {
18010
6
      def_block =ssa->cfg.map[ssa->vars[var].definition];
18011
6
    } else {
18012
0
      ZEND_ASSERT(ssa->vars[var].definition_phi);
18013
0
      def_block = ssa->vars[var].definition_phi->block;
18014
0
    }
18015
18016
6
    ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
18017
18018
6
    if (ssa->vars[var].use_chain >= 0) {
18019
2
      use = ssa->vars[var].use_chain;
18020
2
      do {
18021
2
        use_block = ssa->cfg.map[use];
18022
2
        if (use_block != def_block) {
18023
0
          zend_worklist_push(&worklist, use_block);
18024
0
        }
18025
2
        use = zend_ssa_next_use(ssa->ops, var, use);
18026
2
      } while (use >= 0);
18027
2
    }
18028
18029
6
    p = ssa->vars[var].phi_use_chain;
18030
10
    while (p) {
18031
4
      use_block = p->block;
18032
4
      if (use_block != def_block) {
18033
4
        bb = &ssa->cfg.blocks[use_block];
18034
12
        for (j = 0; j < bb->predecessors_count; j++) {
18035
8
          if (p->sources[j] == var) {
18036
4
            use_block = ssa->cfg.predecessors[bb->predecessor_offset + j];
18037
4
            if (use_block != def_block) {
18038
0
              zend_worklist_push(&worklist, use_block);
18039
0
            }
18040
4
          }
18041
8
        }
18042
4
      }
18043
4
      p = zend_ssa_next_use_phi(ssa, var, p);
18044
4
    }
18045
18046
6
    while (zend_worklist_len(&worklist) != 0) {
18047
0
      b = zend_worklist_pop(&worklist);
18048
0
      bb = &ssa->cfg.blocks[b];
18049
0
      if (bb->flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) {
18050
0
        ret = false;
18051
0
        break;
18052
0
      }
18053
0
      for (j = 0; j < bb->predecessors_count; j++) {
18054
0
        b = ssa->cfg.predecessors[bb->predecessor_offset + j];
18055
0
        if (b != def_block) {
18056
0
          zend_worklist_push(&worklist, b);
18057
0
        }
18058
0
      }
18059
0
    }
18060
18061
6
    ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
18062
18063
6
    return ret;
18064
6
  }
18065
18066
0
  return true;
18067
6
}
18068
18069
0
static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
18070
  // JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
18071
0
  ir_ref observer_handler;
18072
0
  zend_function *fbc = ZEND_FLF_FUNC(opline);
18073
  // Not need for runtime cache or generator checks here, we just need if_unobserved
18074
0
  ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
18075
18076
  // Call zend_frameless_observed_call for the main logic.
18077
0
  ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
18078
18079
0
  ir_ref skip = ir_END();
18080
0
  ir_IF_TRUE(if_unobserved);
18081
0
  return skip;
18082
0
}
18083
18084
static bool jit_frameless_interrupt_check(zend_jit_ctx *jit, const zend_op *next_opline)
18085
0
{
18086
0
  if (zend_interrupt_function) {
18087
    /* Mirrors ZEND_VM_FCALL_INTERRUPT_CHECK(), call before advancing opline. */
18088
    // JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
18089
0
    ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
18090
0
    ir_IF_TRUE_cold(if_interrupt);
18091
0
    ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), jit_FP(jit));
18092
0
    ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
18093
0
  } else {
18094
0
    const void *exit_addr = NULL;
18095
18096
0
    if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
18097
0
      uint32_t exit_point = zend_jit_trace_get_exit_point(next_opline, ZEND_JIT_EXIT_TO_VM);
18098
0
      exit_addr = zend_jit_trace_get_exit_addr(exit_point);
18099
0
      if (!exit_addr) {
18100
0
        return false;
18101
0
      }
18102
0
    }
18103
18104
0
    zend_jit_check_timeout(jit, next_opline, exit_addr);
18105
0
  }
18106
18107
0
  return true;
18108
0
}
18109
18110
static bool jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
18111
0
{
18112
0
  jit_SET_EX_OPLINE(jit, opline);
18113
18114
0
  void *function = ZEND_FLF_HANDLER(opline);
18115
0
  zend_jit_addr res_addr = RES_ADDR();
18116
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
18117
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
18118
18119
0
  ir_ref skip_observer = IR_UNUSED;
18120
0
  if (ZEND_OBSERVER_ENABLED) {
18121
0
    skip_observer = jit_frameless_observer(jit, opline);
18122
0
  }
18123
18124
0
  ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
18125
18126
0
  if (skip_observer != IR_UNUSED) {
18127
0
    ir_MERGE_WITH(skip_observer);
18128
0
  }
18129
18130
0
  if (!jit_frameless_interrupt_check(jit, opline+1)) {
18131
0
    return false;
18132
0
  }
18133
0
  zend_jit_check_exception(jit);
18134
0
  return true;
18135
0
}
18136
18137
static bool jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info)
18138
0
{
18139
0
  jit_SET_EX_OPLINE(jit, opline);
18140
18141
  /* Avoid dropping RC check in case op escapes. */
18142
0
  if (op1_info & MAY_BE_RC1) {
18143
0
    op1_info |= MAY_BE_RCN;
18144
0
  }
18145
18146
0
  void *function = ZEND_FLF_HANDLER(opline);
18147
0
  zend_jit_addr res_addr = RES_ADDR();
18148
0
  zend_jit_addr op1_addr = OP1_ADDR();
18149
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
18150
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
18151
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
18152
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
18153
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
18154
0
    op1_info &= ~MAY_BE_UNDEF;
18155
0
    op1_info |= MAY_BE_NULL;
18156
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
18157
0
  }
18158
0
  if (op1_info & MAY_BE_REF) {
18159
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
18160
0
  }
18161
18162
0
  ir_ref skip_observer = IR_UNUSED;
18163
0
  if (ZEND_OBSERVER_ENABLED) {
18164
0
    skip_observer = jit_frameless_observer(jit, opline);
18165
0
  }
18166
18167
0
  ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
18168
18169
0
  if (skip_observer != IR_UNUSED) {
18170
0
    ir_MERGE_WITH(skip_observer);
18171
0
  }
18172
18173
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
18174
0
  if (!jit_frameless_interrupt_check(jit, opline+1)) {
18175
0
    return false;
18176
0
  }
18177
0
  zend_jit_check_exception(jit);
18178
0
  return true;
18179
0
}
18180
18181
static bool jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info)
18182
0
{
18183
0
  jit_SET_EX_OPLINE(jit, opline);
18184
18185
  /* Avoid dropping RC check in case op escapes. */
18186
0
  if (op1_info & MAY_BE_RC1) {
18187
0
    op1_info |= MAY_BE_RCN;
18188
0
  }
18189
0
  if (op2_info & MAY_BE_RC1) {
18190
0
    op2_info |= MAY_BE_RCN;
18191
0
  }
18192
18193
0
  void *function = ZEND_FLF_HANDLER(opline);
18194
0
  zend_jit_addr res_addr = RES_ADDR();
18195
0
  zend_jit_addr op1_addr = OP1_ADDR();
18196
0
  zend_jit_addr op2_addr = OP2_ADDR();
18197
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
18198
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
18199
0
  ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
18200
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
18201
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
18202
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
18203
0
    op1_info &= ~MAY_BE_UNDEF;
18204
0
    op1_info |= MAY_BE_NULL;
18205
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
18206
0
  }
18207
0
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
18208
0
    op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, true);
18209
0
    op2_info &= ~MAY_BE_UNDEF;
18210
0
    op2_info |= MAY_BE_NULL;
18211
0
    op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
18212
0
  }
18213
0
  if (op1_info & MAY_BE_REF) {
18214
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
18215
0
  }
18216
0
  if (op2_info & MAY_BE_REF) {
18217
0
    op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
18218
0
  }
18219
18220
0
  ir_ref skip_observer = IR_UNUSED;
18221
0
  if (ZEND_OBSERVER_ENABLED) {
18222
0
    skip_observer = jit_frameless_observer(jit, opline);
18223
0
  }
18224
18225
0
  ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
18226
18227
0
  if (skip_observer != IR_UNUSED) {
18228
0
    ir_MERGE_WITH(skip_observer);
18229
0
  }
18230
18231
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
18232
  /* Set OP1 to UNDEF in case FREE_OP2() throws. */
18233
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0
18234
0
   && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
18235
0
   && (op2_info & MAY_BE_RC1)
18236
0
   && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) {
18237
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
18238
0
    if (JIT_G(current_frame)) {
18239
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18240
0
        EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
18241
0
    }
18242
0
  }
18243
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
18244
0
  if (!jit_frameless_interrupt_check(jit, opline+1)) {
18245
0
    return false;
18246
0
  }
18247
0
  zend_jit_check_exception(jit);
18248
0
  return true;
18249
0
}
18250
18251
static bool jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, uint32_t op1_data_info)
18252
0
{
18253
0
  jit_SET_EX_OPLINE(jit, opline);
18254
18255
  /* Avoid dropping RC check in case op escapes. */
18256
0
  if (op1_info & MAY_BE_RC1) {
18257
0
    op1_info |= MAY_BE_RCN;
18258
0
  }
18259
0
  if (op2_info & MAY_BE_RC1) {
18260
0
    op2_info |= MAY_BE_RCN;
18261
0
  }
18262
0
  if (op1_data_info & MAY_BE_RC1) {
18263
0
    op1_data_info |= MAY_BE_RCN;
18264
0
  }
18265
18266
0
  void *function = ZEND_FLF_HANDLER(opline);
18267
0
  uint8_t op_data_type = (opline + 1)->op1_type;
18268
0
  zend_jit_addr res_addr = RES_ADDR();
18269
0
  zend_jit_addr op1_addr = OP1_ADDR();
18270
0
  zend_jit_addr op2_addr = OP2_ADDR();
18271
0
  zend_jit_addr op3_addr = OP1_DATA_ADDR();
18272
0
  ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
18273
0
  ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
18274
0
  ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
18275
0
  ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
18276
0
  jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
18277
0
  if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
18278
0
    op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, true);
18279
0
    op1_info &= ~MAY_BE_UNDEF;
18280
0
    op1_info |= MAY_BE_NULL;
18281
0
    op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
18282
0
  }
18283
0
  if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
18284
0
    op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, true);
18285
0
    op2_info &= ~MAY_BE_UNDEF;
18286
0
    op2_info |= MAY_BE_NULL;
18287
0
    op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
18288
0
  }
18289
0
  if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
18290
0
    op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, true);
18291
0
    op1_data_info &= ~MAY_BE_UNDEF;
18292
0
    op1_data_info |= MAY_BE_NULL;
18293
0
    op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
18294
0
  }
18295
0
  if (op1_info & MAY_BE_REF) {
18296
0
    op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
18297
0
  }
18298
0
  if (op2_info & MAY_BE_REF) {
18299
0
    op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
18300
0
  }
18301
0
  if (op1_data_info & MAY_BE_REF) {
18302
0
    op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
18303
0
  }
18304
18305
0
  ir_ref skip_observer = IR_UNUSED;
18306
0
  if (ZEND_OBSERVER_ENABLED) {
18307
0
    skip_observer = jit_frameless_observer(jit, opline);
18308
0
  }
18309
18310
0
  ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
18311
18312
0
  if (skip_observer != IR_UNUSED) {
18313
0
    ir_MERGE_WITH(skip_observer);
18314
0
  }
18315
18316
0
  jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
18317
  /* Set OP1 to UNDEF in case FREE_OP2() throws. */
18318
0
  bool op1_undef = false;
18319
0
  if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
18320
0
   && (((opline->op2_type & (IS_VAR|IS_TMP_VAR))
18321
0
     && (op2_info & MAY_BE_RC1)
18322
0
     && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)))
18323
0
    || ((op_data_type & (IS_VAR|IS_TMP_VAR))
18324
0
     && (op1_data_info & MAY_BE_RC1)
18325
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))))) {
18326
0
      op1_undef = true;
18327
0
    jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
18328
0
    if (JIT_G(current_frame)) {
18329
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18330
0
        EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1);
18331
0
    }
18332
0
  }
18333
0
  jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
18334
  /* If OP1 is set to UNDEF, we don't need to set OP2 to UNDEF on free because
18335
   * zend_fetch_debug_backtrace aborts when it encounters the first UNDEF TMP|VAR. */
18336
0
  if (!op1_undef
18337
0
   && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
18338
0
   && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0
18339
0
   && (op1_data_info & MAY_BE_RC1)
18340
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))) {
18341
0
    jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
18342
0
    if (JIT_G(current_frame)) {
18343
0
      SET_STACK_TYPE(JIT_G(current_frame)->stack,
18344
0
        EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1);
18345
0
    }
18346
0
  }
18347
0
  jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
18348
0
  if (!jit_frameless_interrupt_check(jit, opline+2)) {
18349
0
    return false;
18350
0
  }
18351
0
  zend_jit_check_exception(jit);
18352
  return true;
18353
0
}
18354
18355
/*
18356
 * Local variables:
18357
 * tab-width: 4
18358
 * c-basic-offset: 4
18359
 * indent-tabs-mode: t
18360
 * End:
18361
 */