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_trace.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_jit.h"
18
#include "zend_jit_internal.h"
19
#include "zend_shared_alloc.h"
20
#include "ir/ir.h"
21
#include "zend_vm_opcodes.h"
22
23
static zend_jit_trace_info *zend_jit_traces = NULL;
24
static const void **zend_jit_exit_groups = NULL;
25
26
16.2k
#define ZEND_JIT_COUNTER_NUM   zend_jit_traces[0].root
27
91.3k
#define ZEND_JIT_TRACE_NUM     zend_jit_traces[0].id
28
2.35k
#define ZEND_JIT_EXIT_NUM      zend_jit_traces[0].exit_count
29
7.52k
#define ZEND_JIT_EXIT_COUNTERS zend_jit_traces[0].exit_counters
30
31
#define ZEND_JIT_TRACE_STOP_DESCRIPTION(name, description) \
32
  description,
33
34
static const char * zend_jit_trace_stop_description[] = {
35
  ZEND_JIT_TRACE_STOP(ZEND_JIT_TRACE_STOP_DESCRIPTION)
36
};
37
38
static zend_always_inline const char *zend_jit_trace_star_desc(uint8_t trace_flags)
39
0
{
40
0
  if (trace_flags & ZEND_JIT_TRACE_START_LOOP) {
41
0
    return "loop";
42
0
  } else if (trace_flags & ZEND_JIT_TRACE_START_ENTER) {
43
0
    return "enter";
44
0
  } else if (trace_flags & ZEND_JIT_TRACE_START_RETURN) {
45
0
    return "return";
46
0
  } else {
47
0
    ZEND_UNREACHABLE();
48
0
    return "???";
49
0
  }
50
0
}
51
52
static void zend_jit_trace_startup(bool reattached)
53
4
{
54
4
  if (!reattached) {
55
4
    zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces));
56
4
    if (!zend_jit_traces) {
57
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not allocate JIT root traces buffer!");
58
0
    }
59
4
    zend_jit_exit_groups = (const void**)zend_shared_alloc(sizeof(void*) * (ZEND_JIT_TRACE_MAX_EXITS/ZEND_JIT_EXIT_POINTS_PER_GROUP));
60
4
    if (!zend_jit_exit_groups) {
61
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not allocate JIT exit groups buffer!");
62
0
    }
63
4
    ZEND_JIT_TRACE_NUM = 1;
64
4
    ZEND_JIT_COUNTER_NUM = 0;
65
4
    ZEND_JIT_EXIT_NUM = 0;
66
4
    ZEND_JIT_EXIT_COUNTERS = 0;
67
4
    ZCSG(jit_traces) = zend_jit_traces;
68
4
    ZCSG(jit_exit_groups) = zend_jit_exit_groups;
69
4
    ZCSG(jit_counters_stopped) = false;
70
4
  } else {
71
0
    zend_jit_traces = ZCSG(jit_traces);
72
0
    if (!zend_jit_traces) {
73
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not obtain JIT traces buffer!");
74
0
    }
75
0
    zend_jit_exit_groups = ZCSG(jit_exit_groups);
76
0
    if (!zend_jit_exit_groups) {
77
0
      zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not obtain JIT exit groups buffer!");
78
0
    }
79
0
  }
80
81
4
  JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
82
4
  if (JIT_G(exit_counters) == NULL) {
83
0
    zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Could not allocate JIT exit counters buffer!");
84
0
  }
85
4
}
86
87
static const void *zend_jit_trace_allocate_exit_point(uint32_t n)
88
1
{
89
1
  const void *group = NULL;
90
91
1
  if (UNEXPECTED(n >= ZEND_JIT_TRACE_MAX_EXITS)) {
92
0
    return NULL;
93
0
  }
94
1
  do {
95
1
    group = zend_jit_trace_allocate_exit_group(ZEND_JIT_EXIT_NUM);
96
1
    if (!group) {
97
0
      return NULL;
98
0
    }
99
1
    zend_jit_exit_groups[ZEND_JIT_EXIT_NUM / ZEND_JIT_EXIT_POINTS_PER_GROUP] =
100
1
      group;
101
1
    ZEND_JIT_EXIT_NUM += ZEND_JIT_EXIT_POINTS_PER_GROUP;
102
1
  } while (n >= ZEND_JIT_EXIT_NUM);
103
1
  return (const void*)
104
1
    ((const char*)group +
105
1
    ((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
106
1
}
107
108
static const void *zend_jit_trace_get_exit_addr(uint32_t n)
109
2.26k
{
110
2.26k
  if (UNEXPECTED(n >= ZEND_JIT_EXIT_NUM)) {
111
1
    return zend_jit_trace_allocate_exit_point(n);
112
1
  }
113
2.26k
  return (const void*)
114
2.26k
    ((const char*)zend_jit_exit_groups[n / ZEND_JIT_EXIT_POINTS_PER_GROUP] +
115
2.26k
    ((n % ZEND_JIT_EXIT_POINTS_PER_GROUP) * ZEND_JIT_EXIT_POINTS_SPACING));
116
2.26k
}
117
118
static uint32_t zend_jit_exit_point_by_addr(const void *addr)
119
2.34k
{
120
2.34k
  uint32_t n = (ZEND_JIT_EXIT_NUM + (ZEND_JIT_EXIT_POINTS_PER_GROUP - 1)) / ZEND_JIT_EXIT_POINTS_PER_GROUP;
121
2.34k
  uint32_t i;
122
123
2.34k
  for (i = 0; i < n; i++) {
124
2.34k
    if ((char*)addr >= (char*)zend_jit_exit_groups[i]
125
2.34k
     && (char*)addr <= (char*)zend_jit_exit_groups[i] + ((ZEND_JIT_EXIT_POINTS_PER_GROUP - 1) * ZEND_JIT_EXIT_POINTS_SPACING)) {
126
2.34k
      return (i * ZEND_JIT_EXIT_POINTS_PER_GROUP) +
127
2.34k
        (((char*)addr - (char*)zend_jit_exit_groups[i]) / ZEND_JIT_EXIT_POINTS_SPACING);
128
2.34k
    }
129
2.34k
  }
130
0
  return (uint32_t)-1;
131
2.34k
}
132
133
static uint32_t _zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags ZEND_FILE_LINE_DC)
134
2.25k
{
135
2.25k
  zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
136
2.25k
  uint32_t exit_point;
137
2.25k
  const zend_op_array *op_array;
138
2.25k
  uint32_t stack_offset = (uint32_t)-1;
139
2.25k
  uint32_t stack_size;
140
2.25k
  zend_jit_trace_stack *stack = NULL;
141
142
2.25k
  if (delayed_call_chain) {
143
32
    assert(to_opline != NULL); /* CALL and IP share the same register */
144
32
    flags |= ZEND_JIT_EXIT_RESTORE_CALL;
145
32
  }
146
2.25k
  if (JIT_G(current_frame)) {
147
2.25k
    op_array = &JIT_G(current_frame)->func->op_array;
148
2.25k
    if (!(op_array->fn_flags & ZEND_ACC_IMMUTABLE)) {
149
2.23k
      zend_jit_op_array_trace_extension *jit_extension =
150
2.23k
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
151
2.23k
      op_array = jit_extension->op_array;
152
2.23k
    }
153
2.25k
    stack_size = op_array->last_var + op_array->T;
154
2.25k
    if (stack_size) {
155
1.96k
      stack = JIT_G(current_frame)->stack;
156
5.09k
      do {
157
5.09k
        if (STACK_TYPE(stack, stack_size-1) != IS_UNKNOWN
158
4.14k
         || STACK_MEM_TYPE(stack, stack_size-1) != IS_UNKNOWN
159
4.14k
         || STACK_REF(stack, stack_size-1) != IR_UNUSED
160
5.09k
        ) {
161
953
          break;
162
953
        }
163
4.13k
        stack_size--;
164
4.13k
      } while (stack_size);
165
1.96k
    }
166
2.25k
  } else {
167
0
    op_array = NULL;
168
0
    stack_size = 0;
169
0
  }
170
171
  /* Try to reuse exit points */
172
2.25k
  if (to_opline != NULL
173
2.22k
   && !(flags & ZEND_JIT_EXIT_METHOD_CALL)
174
2.22k
   && t->exit_count > 0) {
175
1.37k
    uint32_t i = t->exit_count;
176
177
2.66k
    do {
178
2.66k
      i--;
179
2.66k
      if (stack_size == 0
180
1.79k
       || (t->exit_info[i].stack_size >= stack_size
181
1.15k
        && memcmp(t->stack_map + t->exit_info[i].stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack)) == 0)) {
182
1.15k
        if (t->exit_info[i].opline == to_opline
183
237
         && t->exit_info[i].flags == flags
184
214
         && t->exit_info[i].stack_size == stack_size
185
214
#if ZEND_DEBUG
186
214
         && (((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) == 0)
187
0
           || (strcmp(t->exit_info[i].filename, __zend_filename) == 0
188
0
             && t->exit_info[i].lineno == __zend_lineno))
189
1.15k
#endif
190
1.15k
        ) {
191
214
          return i;
192
214
        }
193
1.15k
      }
194
2.66k
    } while (i > 0);
195
1.37k
  }
196
197
2.03k
  exit_point = t->exit_count;
198
2.03k
  if (exit_point < ZEND_JIT_TRACE_MAX_EXITS) {
199
2.03k
    if (stack_size != 0 && stack_offset == (uint32_t)-1) {
200
893
      stack_offset = t->stack_map_size;
201
893
      t->stack_map_size += stack_size;
202
      // TODO: reduce number of reallocations ???
203
893
      t->stack_map = erealloc(t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
204
893
      memcpy(t->stack_map + stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack));
205
893
    }
206
2.03k
    t->exit_count++;
207
2.03k
    t->exit_info[exit_point].opline = to_opline;
208
2.03k
    t->exit_info[exit_point].op_array = op_array;
209
2.03k
    t->exit_info[exit_point].flags = flags;
210
2.03k
    t->exit_info[exit_point].stack_size = stack_size;
211
2.03k
    t->exit_info[exit_point].stack_offset = stack_offset;
212
2.03k
    t->exit_info[exit_point].poly_func = (zend_jit_ref_snapshot){.reg = ZREG_NONE};
213
2.03k
    t->exit_info[exit_point].poly_this = (zend_jit_ref_snapshot){.reg = ZREG_NONE};
214
2.03k
#if ZEND_DEBUG
215
2.03k
    if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) != 0) {
216
0
      t->exit_info[exit_point].filename = __zend_filename;
217
0
      t->exit_info[exit_point].lineno = __zend_lineno;
218
2.03k
    } else {
219
2.03k
      t->exit_info[exit_point].filename = NULL;
220
2.03k
      t->exit_info[exit_point].lineno = 0;
221
2.03k
    }
222
2.03k
#endif
223
2.03k
  }
224
225
2.03k
  return exit_point;
226
2.25k
}
227
228
static void zend_jit_trace_add_code(const void *start, uint32_t size)
229
2.50k
{
230
2.50k
  zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
231
232
2.50k
  t->code_start = start;
233
2.50k
  t->code_size  = size;
234
2.50k
}
235
236
/**
237
 * Locate a trace in the #zend_jit_traces array with the specified
238
 * #code_start address.
239
 *
240
 * @return the #zend_jit_traces index or 0 if no such #code_start
241
 * address was found
242
 */
243
static uint32_t zend_jit_find_trace(const void *addr)
244
26
{
245
26
  uint32_t i;
246
247
48.3k
  for (i = 1; i < ZEND_JIT_TRACE_NUM; i++) {
248
48.3k
    if (zend_jit_traces[i].code_start == addr) {
249
26
      return i;
250
26
    }
251
48.3k
  }
252
0
  return 0;
253
26
}
254
255
static zend_string *zend_jit_trace_name(const zend_op_array *op_array, uint32_t lineno)
256
2.50k
{
257
2.50k
  smart_str buf = {0};
258
259
2.50k
  smart_str_appends(&buf, TRACE_PREFIX);
260
2.50k
  smart_str_append_long(&buf, (zend_long)ZEND_JIT_TRACE_NUM);
261
2.50k
  smart_str_appendc(&buf, '$');
262
2.50k
  if (op_array->function_name) {
263
2
    if (op_array->scope) {
264
0
      smart_str_append(&buf, op_array->scope->name);
265
0
      smart_str_appends(&buf, "::");
266
0
      smart_str_append(&buf, op_array->function_name);
267
2
    } else {
268
2
      smart_str_append(&buf, op_array->function_name);
269
2
    }
270
2.50k
  } else if (op_array->filename) {
271
2.50k
    smart_str_append(&buf, op_array->filename);
272
2.50k
  }
273
2.50k
  smart_str_appendc(&buf, '$');
274
2.50k
  smart_str_append_long(&buf, (zend_long)lineno);
275
2.50k
  smart_str_0(&buf);
276
2.50k
  return buf.s;
277
2.50k
}
278
279
static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline)
280
5.25k
{
281
5.25k
  switch (opline->opcode) {
282
0
    case ZEND_IS_IDENTICAL:
283
0
    case ZEND_IS_NOT_IDENTICAL:
284
0
    case ZEND_IS_EQUAL:
285
0
    case ZEND_IS_NOT_EQUAL:
286
0
    case ZEND_IS_SMALLER:
287
0
    case ZEND_IS_SMALLER_OR_EQUAL:
288
0
    case ZEND_CASE:
289
0
    case ZEND_CASE_STRICT:
290
0
    case ZEND_ISSET_ISEMPTY_CV:
291
0
    case ZEND_ISSET_ISEMPTY_VAR:
292
0
    case ZEND_ISSET_ISEMPTY_DIM_OBJ:
293
0
    case ZEND_ISSET_ISEMPTY_PROP_OBJ:
294
0
    case ZEND_ISSET_ISEMPTY_STATIC_PROP:
295
0
    case ZEND_INSTANCEOF:
296
0
    case ZEND_TYPE_CHECK:
297
0
    case ZEND_DEFINED:
298
0
    case ZEND_IN_ARRAY:
299
0
    case ZEND_ARRAY_KEY_EXISTS:
300
0
      if (opline->result_type & (IS_SMART_BRANCH_JMPNZ | IS_SMART_BRANCH_JMPZ)) {
301
        /* smart branch */
302
0
        return 1;
303
0
      }
304
0
      break;
305
0
    case ZEND_JMPZ:
306
0
    case ZEND_JMPNZ:
307
0
    case ZEND_JMPZ_EX:
308
0
    case ZEND_JMPNZ_EX:
309
8
    case ZEND_JMP_SET:
310
39
    case ZEND_COALESCE:
311
51
    case ZEND_JMP_NULL:
312
51
    case ZEND_FE_RESET_R:
313
52
    case ZEND_FE_RESET_RW:
314
56
    case ZEND_ASSERT_CHECK:
315
56
    case ZEND_FE_FETCH_R:
316
57
    case ZEND_FE_FETCH_RW:
317
57
    case ZEND_SWITCH_LONG:
318
57
    case ZEND_SWITCH_STRING:
319
57
    case ZEND_MATCH:
320
57
    case ZEND_BIND_INIT_STATIC_OR_JMP:
321
57
    case ZEND_JMP_FRAMELESS:
322
      /* branch opcodes */
323
57
      return 1;
324
10
    case ZEND_NEW:
325
10
      if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
326
        /* NEW may skip constructor without arguments */
327
8
        return 1;
328
8
      }
329
2
      break;
330
2
    case ZEND_CATCH:
331
0
    case ZEND_FAST_CALL:
332
0
    case ZEND_FAST_RET:
333
1
    case ZEND_GENERATOR_CREATE:
334
1
    case ZEND_GENERATOR_RETURN:
335
1
    case ZEND_YIELD:
336
1
    case ZEND_YIELD_FROM:
337
91
    case ZEND_INCLUDE_OR_EVAL:
338
91
    case ZEND_MATCH_ERROR:
339
      /* unsupported */
340
91
      return 1;
341
0
    case ZEND_DO_FCALL:
342
      /* potentially polymorphic call */
343
0
      return 1;
344
#if 0
345
    case ZEND_DO_UCALL:
346
    case ZEND_DO_FCALL_BY_NAME:
347
      /* monomorphic call */
348
      // TODO: recompilation may change target ???
349
      return 0;
350
#endif
351
    /* FETCH_OBJ_FUNC_ARG may dispatch into the FETCH_OBJ_R handler (if sent by value). */
352
0
    case ZEND_FETCH_OBJ_FUNC_ARG:
353
15
    case ZEND_FETCH_OBJ_R:
354
15
      if (opline->op2_type == IS_CONST) {
355
12
        const zend_class_entry *ce = opline->op1_type == IS_UNUSED ? op_array->scope : NULL;
356
12
        if (!ce || !(ce->ce_flags & ZEND_ACC_FINAL) || ce->num_hooked_props > 0) {
357
12
          return 1;
358
12
        }
359
12
      }
360
3
      break;
361
3
    case ZEND_RETURN_BY_REF:
362
2.36k
    case ZEND_RETURN:
363
      /* return */
364
2.36k
      return !JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame));
365
2.70k
    default:
366
2.70k
      break;
367
5.25k
  }
368
2.71k
  return 0;
369
5.25k
}
370
371
static zend_always_inline uint32_t zend_jit_trace_type_to_info_ex(uint8_t type, uint32_t info)
372
2.41k
{
373
2.41k
  if (type == IS_UNKNOWN) {
374
393
    return info;
375
393
  }
376
2.02k
  ZEND_ASSERT(info & (1 << type));
377
2.02k
  if (type < IS_STRING) {
378
1.89k
    return (1 << type);
379
1.89k
  } else if (type != IS_ARRAY) {
380
45
    return (1 << type) | (info & (MAY_BE_RC1|MAY_BE_RCN));
381
77
  } else {
382
77
    return MAY_BE_ARRAY | (info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN));
383
77
  }
384
2.02k
}
385
386
static zend_always_inline uint32_t zend_jit_trace_type_to_info(uint8_t type)
387
1.55k
{
388
1.55k
  return zend_jit_trace_type_to_info_ex(type, -1);
389
1.55k
}
390
391
static zend_always_inline zend_ssa_alias_kind zend_jit_var_may_alias(const zend_op_array *op_array, const zend_ssa *ssa, uint32_t var)
392
5.49k
{
393
5.49k
  if (var >= op_array->last_var) {
394
3.44k
    return NO_ALIAS;
395
3.44k
  } else if ((!op_array->function_name || (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS))) {
396
2.01k
    return SYMTABLE_ALIAS;
397
2.01k
  } else if (ssa->vars) {
398
31
    return ssa->vars[var].alias;
399
31
  } else if (zend_string_equals_literal(op_array->vars[var], "http_response_header")) {
400
0
    return HTTP_RESPONSE_HEADER_ALIAS;
401
0
  }
402
0
  return NO_ALIAS;
403
5.49k
}
404
405
static zend_always_inline void zend_jit_trace_add_op_guard(zend_ssa             *tssa,
406
                                                           int                   ssa_var,
407
                                                           uint8_t               op_type)
408
2.56k
{
409
2.56k
  zend_ssa_var_info *info = &tssa->var_info[ssa_var];
410
411
2.56k
  if ((info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << op_type)) {
412
1.69k
    if (UNEXPECTED(tssa->vars[ssa_var].alias != NO_ALIAS)) {
413
868
      info->type |= MAY_BE_GUARD;
414
868
    } else {
415
826
      info->type = MAY_BE_GUARD | zend_jit_trace_type_to_info_ex(op_type, info->type);
416
826
    }
417
1.69k
  }
418
2.56k
}
419
420
8.61k
#define ADD_OP_GUARD(_ssa_var, _op_type) do { \
421
8.61k
    if (_ssa_var >= 0 && _op_type != IS_UNKNOWN) { \
422
2.56k
      zend_jit_trace_add_op_guard(tssa, _ssa_var, _op_type); \
423
2.56k
    } \
424
8.61k
  } while (0)
425
426
9.04k
#define CHECK_OP_TRACE_TYPE(_var, _ssa_var, op_info, op_type) do { \
427
9.04k
    if (op_type != IS_UNKNOWN) { \
428
2.84k
      if ((op_info & MAY_BE_GUARD) != 0) { \
429
1.42k
        if (!zend_jit_type_guard(&ctx, opline, _var, op_type)) { \
430
0
          goto jit_failure; \
431
0
        } \
432
1.42k
        if (ssa->vars[_ssa_var].alias != NO_ALIAS) { \
433
882
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), IS_UNKNOWN, 1); \
434
882
          op_info = zend_jit_trace_type_to_info(op_type); \
435
882
        } else { \
436
538
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), op_type, 1); \
437
538
          op_info &= ~MAY_BE_GUARD; \
438
538
          ssa->var_info[_ssa_var].type &= op_info; \
439
538
        } \
440
1.42k
      } \
441
2.84k
    } \
442
9.04k
  } while (0)
443
444
#define ADD_OP1_TRACE_GUARD() \
445
6.37k
  ADD_OP_GUARD(tssa->ops[idx].op1_use, op1_type)
446
#define ADD_OP2_TRACE_GUARD() \
447
2.05k
  ADD_OP_GUARD(tssa->ops[idx].op2_use, op2_type)
448
#define ADD_OP1_DATA_TRACE_GUARD() \
449
183
  ADD_OP_GUARD(tssa->ops[idx+1].op1_use, op3_type)
450
451
#define CHECK_OP1_TRACE_TYPE() \
452
6.48k
  CHECK_OP_TRACE_TYPE(opline->op1.var, ssa_op->op1_use, op1_info, op1_type)
453
#define CHECK_OP2_TRACE_TYPE() \
454
2.35k
  CHECK_OP_TRACE_TYPE(opline->op2.var, ssa_op->op2_use, op2_info, op2_type)
455
#define CHECK_OP1_DATA_TRACE_TYPE() \
456
206
  CHECK_OP_TRACE_TYPE((opline+1)->op1.var, (ssa_op+1)->op1_use, op1_data_info, op3_type)
457
458
static zend_always_inline size_t zend_jit_trace_frame_size(const zend_op_array *op_array, uint32_t num_args)
459
8.43k
{
460
8.43k
  if (op_array && op_array->type == ZEND_USER_FUNCTION) {
461
7.66k
    return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE((op_array->last_var + op_array->T) * sizeof(zend_jit_trace_stack)));
462
7.66k
  } else if (op_array) {
463
763
    return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE(op_array->num_args * sizeof(zend_jit_trace_stack)));
464
763
  } else {
465
8
    return ZEND_MM_ALIGNED_SIZE(offsetof(zend_jit_trace_stack_frame, stack) + ZEND_MM_ALIGNED_SIZE(num_args * sizeof(zend_jit_trace_stack)));
466
8
  }
467
8.43k
}
468
469
static zend_jit_trace_stack_frame* zend_jit_trace_call_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array, uint32_t num_args)
470
5.47k
{
471
5.47k
  return (zend_jit_trace_stack_frame*)((char*)frame + zend_jit_trace_frame_size(op_array, num_args));
472
5.47k
}
473
474
static zend_jit_trace_stack_frame* zend_jit_trace_ret_frame(zend_jit_trace_stack_frame *frame, const zend_op_array *op_array)
475
34
{
476
34
  return (zend_jit_trace_stack_frame*)((char*)frame - zend_jit_trace_frame_size(op_array, 0));
477
34
}
478
479
static void zend_jit_trace_send_type(const zend_op *opline, zend_jit_trace_stack_frame *call, uint8_t type)
480
290
{
481
290
  zend_jit_trace_stack *stack = call->stack;
482
290
  const zend_op_array *op_array = &call->func->op_array;
483
290
  uint32_t arg_num = opline->op2.num;
484
485
290
  if (arg_num > op_array->num_args) {
486
6
    return;
487
6
  }
488
284
  if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
489
283
    zend_arg_info *arg_info;
490
491
283
    ZEND_ASSERT(arg_num <= op_array->num_args);
492
283
    arg_info = &op_array->arg_info[arg_num-1];
493
494
    /* Record scalars and object class types, even if there's no "object" type declaration.
495
     * This allows RECV to record and skip object type checks. */
496
283
    if (ZEND_TYPE_IS_SET(arg_info->type)
497
283
     && !(ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))
498
4
     && !(type == IS_OBJECT && call->func->type == ZEND_USER_FUNCTION)) {
499
4
      return;
500
4
    }
501
283
  }
502
280
  SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
503
280
}
504
505
static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info)
506
775
{
507
775
  if (func
508
775
   && func->type == ZEND_INTERNAL_FUNCTION
509
775
   && (func->internal_function.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0
510
748
   && arg_num < func->internal_function.num_args) {
511
740
    const zend_arg_info *arg_info = &func->internal_function.arg_info[arg_num];
512
513
740
    if (ZEND_ARG_SEND_MODE(arg_info) == ZEND_SEND_BY_VAL
514
739
     && ZEND_TYPE_IS_SET(arg_info->type)
515
739
     && (ZEND_TYPE_FULL_MASK(arg_info->type) & MAY_BE_ANY) != MAY_BE_ANY) {
516
522
      if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE
517
225
       && JIT_G(current_frame)
518
225
       && JIT_G(current_frame)->call
519
225
       && JIT_G(current_frame)->call->func) {
520
225
        uint32_t type = STACK_TYPE(JIT_G(current_frame)->call->stack, arg_num);
521
522
225
        if (type != IS_UNKNOWN
523
221
         && type < IS_STRING
524
39
         && ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type)) {
525
39
          return false;
526
39
        }
527
225
      }
528
483
      if (call_info && arg_num < call_info->num_args && call_info->arg_info[arg_num].opline) {
529
483
        const zend_op *opline = call_info->arg_info[arg_num].opline;
530
531
483
        if (opline->opcode == ZEND_SEND_VAL && opline->op1_type == IS_CONST) {
532
460
          zval *zv = RT_CONSTANT(opline, opline->op1);
533
534
460
          if (!Z_REFCOUNTED_P(zv)) {
535
460
            uint32_t type = Z_TYPE_P(zv);
536
537
            // TODO: few functions (e.g. pcntl_exec) modify arrays in-place ???
538
460
            if (type != IS_ARRAY
539
459
             && (ZEND_TYPE_FULL_MASK(arg_info->type) & (1u << type))) {
540
445
              return false;
541
445
            }
542
460
          }
543
460
        }
544
483
      }
545
483
    }
546
740
  }
547
548
291
  return true;
549
775
}
550
551
static zend_ssa *zend_jit_trace_build_ssa(const zend_op_array *op_array, zend_script *script)
552
2.52k
{
553
2.52k
  zend_jit_op_array_trace_extension *jit_extension;
554
2.52k
  zend_ssa *ssa;
555
556
2.52k
  jit_extension =
557
2.52k
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
558
2.52k
  jit_extension->func_info.num = 0;
559
2.52k
  jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
560
2.52k
    | ZEND_FUNC_JIT_ON_PROF_REQUEST
561
2.52k
    | ZEND_FUNC_JIT_ON_HOT_COUNTERS
562
2.52k
    | ZEND_FUNC_JIT_ON_HOT_TRACE;
563
2.52k
  memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
564
2.52k
  ssa = &jit_extension->func_info.ssa;
565
566
2.52k
  if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
567
2.52k
    do {
568
2.52k
      if (zend_jit_op_array_analyze1(op_array, script, ssa) != SUCCESS) {
569
0
        break;
570
0
      }
571
572
2.52k
      if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
573
2.52k
        zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, (zend_op_array*)op_array, &jit_extension->func_info);
574
2.52k
        jit_extension->func_info.call_map = zend_build_call_map(&CG(arena), &jit_extension->func_info, op_array);
575
2.52k
        if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
576
0
          zend_init_func_return_info(op_array, script, &jit_extension->func_info.return_info);
577
0
        }
578
2.52k
      }
579
580
2.52k
      if (zend_jit_op_array_analyze2(op_array, script, ssa, 0) != SUCCESS) {
581
0
        break;
582
0
      }
583
584
2.52k
      if (JIT_G(debug) & ZEND_JIT_DEBUG_SSA) {
585
0
        zend_dump_op_array(op_array, ZEND_DUMP_HIDE_UNREACHABLE|ZEND_DUMP_RC_INFERENCE|ZEND_DUMP_SSA, "JIT", ssa);
586
0
      }
587
2.52k
      return ssa;
588
2.52k
    } while (0);
589
2.52k
  }
590
591
0
  memset(ssa, 0, sizeof(zend_ssa));
592
0
  ssa->cfg.blocks_count = 1;
593
594
0
  if (JIT_G(opt_level) == ZEND_JIT_LEVEL_INLINE) {
595
0
    zend_cfg cfg;
596
0
    void *checkpoint = zend_arena_checkpoint(CG(arena));
597
598
0
    if (zend_jit_build_cfg(op_array, &cfg) == SUCCESS) {
599
0
      ssa->cfg.flags = cfg.flags;
600
0
    } else{
601
0
      ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
602
0
    }
603
604
    /* TODO: move this to zend_cfg.c ? */
605
0
    if (!op_array->function_name) {
606
0
      ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
607
0
    }
608
609
0
    zend_arena_release(&CG(arena), checkpoint);
610
0
  }
611
612
0
  return ssa;
613
2.52k
}
614
615
static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa);
616
static void zend_jit_dump_exit_info(zend_jit_trace_info *t);
617
618
static zend_always_inline int zend_jit_trace_op_len(const zend_op *opline)
619
45.0k
{
620
45.0k
  int len;
621
622
45.0k
  switch (opline->opcode) {
623
356
    case ZEND_ASSIGN_DIM:
624
356
    case ZEND_ASSIGN_OBJ:
625
356
    case ZEND_ASSIGN_STATIC_PROP:
626
968
    case ZEND_ASSIGN_DIM_OP:
627
968
    case ZEND_ASSIGN_OBJ_OP:
628
968
    case ZEND_ASSIGN_STATIC_PROP_OP:
629
968
    case ZEND_ASSIGN_OBJ_REF:
630
968
    case ZEND_ASSIGN_STATIC_PROP_REF:
631
968
    case ZEND_FRAMELESS_ICALL_3:
632
968
    case ZEND_DECLARE_ATTRIBUTED_CONST:
633
968
      return 2; /* OP_DATA */
634
8
    case ZEND_RECV_INIT:
635
8
      len = 1;
636
8
      opline++;
637
8
      while (opline->opcode == ZEND_RECV_INIT) {
638
0
        len++;
639
0
        opline++;
640
0
      }
641
8
      return len;
642
12
    case ZEND_BIND_GLOBAL:
643
12
      len = 1;
644
12
      opline++;
645
12
      while (opline->opcode == ZEND_BIND_GLOBAL) {
646
0
        len++;
647
0
        opline++;
648
0
      }
649
12
      return len;
650
//    case ZEND_IS_IDENTICAL:
651
//    case ZEND_IS_NOT_IDENTICAL:
652
//    case ZEND_IS_EQUAL:
653
//    case ZEND_IS_NOT_EQUAL:
654
//    case ZEND_IS_SMALLER:
655
//    case ZEND_IS_SMALLER_OR_EQUAL:
656
//    case ZEND_CASE:
657
//    case ZEND_ISSET_ISEMPTY_CV:
658
//    case ZEND_ISSET_ISEMPTY_VAR:
659
//    case ZEND_ISSET_ISEMPTY_DIM_OBJ:
660
//    case ZEND_ISSET_ISEMPTY_PROP_OBJ:
661
//    case ZEND_ISSET_ISEMPTY_STATIC_PROP:
662
//    case ZEND_INSTANCEOF:
663
//    case ZEND_TYPE_CHECK:
664
//    case ZEND_DEFINED:
665
//    case ZEND_IN_ARRAY:
666
//    case ZEND_ARRAY_KEY_EXISTS:
667
44.0k
    default:
668
44.0k
      if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
669
15
        return 2; /* JMPZ/JMPNZ */
670
15
      }
671
44.0k
      return 1;
672
45.0k
  }
673
45.0k
}
674
675
static int zend_jit_trace_add_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
676
13
{
677
13
  const zend_op_array *op_array;
678
13
  zend_jit_trace_rec *p;
679
13
  int k, vars_count;
680
13
  zend_bitset use, def;
681
13
  uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
682
13
  uint32_t set_size;
683
13
  zend_ssa_phi *prev = NULL;
684
13
  int level = 0;
685
13
  ALLOCA_FLAG(use_heap);
686
687
13
  op_array = trace_buffer->op_array;
688
13
  set_size = zend_bitset_len(op_array->last_var + op_array->T);
689
13
  use = ZEND_BITSET_ALLOCA(set_size * 2, use_heap);
690
13
  memset(use, 0, set_size * 2 * ZEND_BITSET_ELM_SIZE);
691
13
  def = use + set_size;
692
13
  p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
693
98
  for (;;p++) {
694
98
    if (p->op == ZEND_JIT_TRACE_VM && level == 0) {
695
85
      const zend_op *opline = p->opline;
696
85
      int len;
697
698
85
      zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
699
85
      len = zend_jit_trace_op_len(opline);
700
85
      while (len > 1) {
701
0
        opline++;
702
0
        if (opline->opcode != ZEND_OP_DATA) {
703
0
          zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
704
0
        }
705
0
        len--;
706
0
      }
707
85
    } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
708
13
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
709
13
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
710
0
      level++;
711
13
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
712
0
      if (level == 0) {
713
        // Phi for recursive calls and returns are not supported yet ???
714
0
        assert(0);
715
0
      } else {
716
0
        level--;
717
0
      }
718
13
    } else if (p->op == ZEND_JIT_TRACE_END) {
719
13
      break;
720
13
    }
721
98
  }
722
723
13
  zend_bitset_intersection(use, def, set_size);
724
725
13
  if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
726
0
    vars_count = op_array->last_var;
727
13
  } else {
728
13
    vars_count = op_array->last_var + op_array->T;
729
13
  }
730
78
  for (k = 0; k < vars_count; k++) {
731
65
    if (zend_bitset_in(use, k)) {
732
16
      zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
733
16
        ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
734
16
        ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
735
16
        sizeof(void*) * 2);
736
16
      phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
737
16
      phi->sources[0] = STACK_VAR(stack, k);
738
16
      phi->sources[1] = -1;
739
16
      phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
740
16
      phi->pi = -1;
741
16
      phi->var = k;
742
16
      phi->ssa_var = ssa_vars_count;
743
16
      SET_STACK_VAR(stack, k, ssa_vars_count);
744
16
      ssa_vars_count++;
745
16
      phi->block = 1;
746
16
      if (prev) {
747
4
        prev->next = phi;
748
12
      } else {
749
12
        tssa->blocks[1].phis = phi;
750
12
      }
751
16
      prev = phi;
752
16
    }
753
65
  }
754
755
13
  free_alloca(use, use_heap);
756
757
13
  return ssa_vars_count;
758
13
}
759
760
static int zend_jit_trace_add_call_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
761
0
{
762
0
  zend_ssa_phi *prev = NULL;
763
0
  const zend_op_array *op_array = trace_buffer->op_array;
764
0
  const zend_op *opline = trace_buffer[1].opline;
765
0
  int count = opline - op_array->opcodes;
766
0
  int i;
767
768
0
  for(i = 0; i < count; i++) {
769
0
    zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
770
0
      ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
771
0
      ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
772
0
      sizeof(void*) * 2);
773
0
    phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
774
0
    phi->sources[0] = STACK_VAR(stack, i);
775
0
    phi->sources[1] = -1;
776
0
    phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
777
0
    phi->pi = -1;
778
0
    phi->var = i;
779
0
    phi->ssa_var = ssa_vars_count;
780
0
    SET_STACK_VAR(stack, i, ssa_vars_count);
781
0
    ssa_vars_count++;
782
0
    phi->block = 1;
783
0
    if (prev) {
784
0
      prev->next = phi;
785
0
    } else {
786
0
      tssa->blocks[1].phis = phi;
787
0
    }
788
0
    prev = phi;
789
0
  }
790
0
  return ssa_vars_count;
791
0
}
792
793
static int zend_jit_trace_add_ret_phis(zend_jit_trace_rec *trace_buffer, uint32_t ssa_vars_count, zend_ssa *tssa, zend_jit_trace_stack *stack)
794
0
{
795
0
  const zend_op *opline = trace_buffer[1].opline - 1;
796
0
  int i;
797
798
0
  if (RETURN_VALUE_USED(opline)) {
799
0
    zend_ssa_phi *phi = zend_arena_calloc(&CG(arena), 1,
800
0
      ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)) +
801
0
      ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2) +
802
0
      sizeof(void*) * 2);
803
804
0
    i = EX_VAR_TO_NUM(opline->result.var);
805
0
    phi->sources = (int*)(((char*)phi) + ZEND_MM_ALIGNED_SIZE(sizeof(zend_ssa_phi)));
806
0
    phi->sources[0] = STACK_VAR(stack, i);
807
0
    phi->sources[1] = -1;
808
0
    phi->use_chains = (zend_ssa_phi**)(((char*)phi->sources) + ZEND_MM_ALIGNED_SIZE(sizeof(int) * 2));
809
0
    phi->pi = -1;
810
0
    phi->var = i;
811
0
    phi->ssa_var = ssa_vars_count;
812
0
    SET_STACK_VAR(stack, i, ssa_vars_count);
813
0
    ssa_vars_count++;
814
0
    phi->block = 1;
815
0
    tssa->blocks[1].phis = phi;
816
0
  }
817
0
  return ssa_vars_count;
818
0
}
819
820
static bool zend_jit_trace_is_false_loop(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa)
821
0
{
822
0
  const zend_op *opline;
823
0
  uint32_t b;
824
0
  zend_basic_block *bb;
825
826
0
  ZEND_ASSERT(tssa->cfg.blocks_count == 2);
827
0
  ZEND_ASSERT(tssa->cfg.blocks[1].len > 0);
828
829
0
  b = ssa->cfg.map[tssa_opcodes[0] - op_array->opcodes];
830
0
  opline = tssa_opcodes[tssa->cfg.blocks[1].len - 1];
831
0
  if (opline >= op_array->opcodes && opline < op_array->opcodes + op_array->last) {
832
0
    bb = ssa->cfg.blocks + ssa->cfg.map[opline - op_array->opcodes];
833
0
    return bb->loop_header != b;
834
0
  } else {
835
0
    return false;
836
0
  }
837
0
}
838
839
static int zend_jit_trace_copy_ssa_var_info(const zend_op_array  *op_array,
840
                                            const zend_ssa       *ssa,
841
                                            const zend_op       **tssa_opcodes,
842
                                            zend_ssa             *tssa,
843
                                            int                   ssa_var,
844
                                            const zend_op        *opline)
845
2
{
846
2
  int var, use, def, src;
847
2
  zend_ssa_op *op;
848
849
2
  if (tssa->vars[ssa_var].definition_phi) {
850
0
    uint32_t b = ssa->cfg.map[tssa_opcodes[0] - op_array->opcodes];
851
0
    zend_basic_block *bb = ssa->cfg.blocks + b;
852
853
0
    if ((bb->flags & ZEND_BB_LOOP_HEADER)
854
0
     && !zend_jit_trace_is_false_loop(op_array, ssa, tssa_opcodes, tssa)) {
855
0
      zend_ssa_phi *phi = ssa->blocks[b].phis;
856
0
      zend_ssa_phi *pi = NULL;
857
858
0
      var = tssa->vars[ssa_var].var;
859
0
      while (phi) {
860
0
        if (ssa->vars[phi->ssa_var].var == var) {
861
0
          if (phi->pi >= 0) {
862
0
            pi = phi;
863
0
          } else {
864
0
            src = phi->ssa_var;
865
0
            goto copy_info;
866
0
          }
867
0
        }
868
0
        phi = phi->next;
869
0
      }
870
0
      if (pi) {
871
0
        src = pi->ssa_var;
872
0
        goto copy_info;
873
0
      }
874
#if 0
875
      while (bb->idom >= 0) {
876
        uint32_t n;
877
878
        b = bb->idom;
879
        bb = ssa->cfg.blocks + b;
880
881
        for (n = bb->len, op = ssa->ops + bb->start + n; n > 0; n--) {
882
          op--;
883
          if (op->result_def >= 0 && ssa->vars[op->result_def].var == var) {
884
            src = op->result_def;
885
            goto copy_info;
886
          } else if (op->op2_def >= 0 && ssa->vars[op->op2_def].var == var) {
887
            src = op->op2_def;
888
            goto copy_info;
889
          } else if (op->op1_def >= 0 && ssa->vars[op->op1_def].var == var) {
890
            src = op->op1_def;
891
            goto copy_info;
892
          }
893
        }
894
895
        phi = ssa->blocks[b].phis;
896
        zend_ssa_phi *pi = NULL;
897
        while (phi) {
898
          if (ssa->vars[phi->ssa_var].var == var) {
899
            if (phi->pi >= 0) {
900
              pi = phi;
901
            } else {
902
              src = phi->ssa_var;
903
              goto copy_info;
904
            }
905
          }
906
          phi = phi->next;
907
        }
908
        if (pi) {
909
          src = pi->ssa_var;
910
          goto copy_info;
911
        }
912
      }
913
#endif
914
0
    }
915
2
  } else if (tssa->vars[ssa_var].definition >= 0) {
916
0
    def = tssa->vars[ssa_var].definition;
917
0
    ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
918
0
    op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
919
0
    if (tssa->ops[def].op1_def == ssa_var) {
920
0
      src = op->op1_def;
921
0
    } else if (tssa->ops[def].op2_def == ssa_var) {
922
0
      src = op->op2_def;
923
0
    } else if (tssa->ops[def].result_def == ssa_var) {
924
0
      src = op->result_def;
925
0
    } else {
926
0
      assert(0);
927
0
      return 0;
928
0
    }
929
0
    goto copy_info;
930
0
  }
931
932
2
  if (tssa->vars[ssa_var].phi_use_chain) {
933
    // TODO: this may be incorrect ???
934
0
    var = tssa->vars[ssa_var].phi_use_chain->ssa_var;
935
2
  } else {
936
2
    var = ssa_var;
937
2
  }
938
2
  use = tssa->vars[var].use_chain;
939
2
  if (use >= 0) {
940
2
    ZEND_ASSERT((tssa_opcodes[use] - op_array->opcodes) < op_array->last);
941
2
    op = ssa->ops + (tssa_opcodes[use] - op_array->opcodes);
942
2
    if (tssa->ops[use].op1_use == var) {
943
0
      src = op->op1_use;
944
2
    } else if (tssa->ops[use].op2_use == var) {
945
0
      src = op->op2_use;
946
2
    } else if (tssa->ops[use].result_use == var) {
947
2
      src = op->result_use;
948
2
    } else {
949
0
      assert(0);
950
0
      return 0;
951
0
    }
952
2
    if (opline) {
953
      /* Try to find a definition in SSA dominators tree */
954
0
      var = tssa->vars[ssa_var].var;
955
0
      uint32_t op_num = opline - op_array->opcodes;
956
0
      uint32_t b = ssa->cfg.map[op_num];
957
0
      zend_basic_block *bb = ssa->cfg.blocks + b;
958
0
      zend_ssa_phi *pi, *phi;
959
960
0
      while (1) {
961
0
        while (op_num > bb->start) {
962
0
          op_num--;
963
0
          op = ssa->ops + op_num;
964
0
          if (op->result_def >= 0 && ssa->vars[op->result_def].var == var) {
965
0
            src = op->result_def;
966
0
            goto copy_info;
967
0
          } else if (op->op2_def >= 0 && ssa->vars[op->op2_def].var == var) {
968
0
            src = op->op2_def;
969
0
            goto copy_info;
970
0
          } else if (op->op1_def >= 0 && ssa->vars[op->op1_def].var == var) {
971
0
            src = op->op1_def;
972
0
            goto copy_info;
973
0
          }
974
0
        }
975
0
        phi = ssa->blocks[b].phis;
976
0
        pi = NULL;
977
0
        while (phi) {
978
0
          if (ssa->vars[phi->ssa_var].var == var) {
979
0
            if (phi->pi >= 0) {
980
0
              pi = phi;
981
0
            } else {
982
0
              src = phi->ssa_var;
983
0
              goto copy_info;
984
0
            }
985
0
          }
986
0
          phi = phi->next;
987
0
        }
988
0
        if (pi) {
989
0
          src = pi->ssa_var;
990
0
          goto copy_info;
991
0
        }
992
0
        if (bb->idom < 0) {
993
0
          break;
994
0
        }
995
0
        b = bb->idom;
996
0
        bb = ssa->cfg.blocks + b;
997
0
        op_num = bb->start + bb->len;
998
0
      }
999
0
    }
1000
2
    goto copy_info;
1001
2
  }
1002
0
  return 0;
1003
1004
2
copy_info:
1005
2
  tssa->vars[ssa_var].no_val = ssa->vars[src].no_val;
1006
2
  tssa->vars[ssa_var].alias = ssa->vars[src].alias;
1007
2
  memcpy(&tssa->var_info[ssa_var], &ssa->var_info[src], sizeof(zend_ssa_var_info));
1008
2
  return 1;
1009
2
}
1010
1011
static void zend_jit_trace_propagate_range(const zend_op_array *op_array, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
1012
3.42k
{
1013
3.42k
  zend_ssa_range tmp;
1014
3.42k
  int def = tssa->vars[ssa_var].definition;
1015
1016
3.42k
  if (tssa->vars[ssa_var].alias == NO_ALIAS
1017
3.42k
   && zend_inference_propagate_range(op_array, tssa, tssa_opcodes[def], &tssa->ops[def], ssa_var, &tmp)) {
1018
38
    tssa->var_info[ssa_var].range.min = tmp.min;
1019
38
    tssa->var_info[ssa_var].range.max = tmp.max;
1020
38
    tssa->var_info[ssa_var].range.underflow = tmp.underflow;
1021
38
    tssa->var_info[ssa_var].range.overflow = tmp.overflow;
1022
38
    tssa->var_info[ssa_var].has_range = 1;
1023
38
  }
1024
3.42k
}
1025
1026
static void zend_jit_trace_copy_ssa_var_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
1027
63
{
1028
63
  int def;
1029
63
  zend_ssa_op *op;
1030
63
  zend_ssa_var_info *info;
1031
63
  unsigned int no_val;
1032
63
  zend_ssa_alias_kind alias;
1033
1034
63
  def = tssa->vars[ssa_var].definition;
1035
63
  if (def >= 0) {
1036
63
    ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
1037
63
    op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
1038
63
    if (tssa->ops[def].op1_def == ssa_var) {
1039
21
      no_val = ssa->vars[op->op1_def].no_val;
1040
21
      alias = ssa->vars[op->op1_def].alias;
1041
21
      info = ssa->var_info + op->op1_def;
1042
42
    } else if (tssa->ops[def].op2_def == ssa_var) {
1043
6
      no_val = ssa->vars[op->op2_def].no_val;
1044
6
      alias = ssa->vars[op->op2_def].alias;
1045
6
      info = ssa->var_info + op->op2_def;
1046
36
    } else if (tssa->ops[def].result_def == ssa_var) {
1047
36
      no_val = ssa->vars[op->result_def].no_val;
1048
36
      alias = ssa->vars[op->result_def].alias;
1049
36
      info = ssa->var_info + op->result_def;
1050
36
    } else {
1051
0
      assert(0);
1052
0
      return;
1053
0
    }
1054
1055
63
    tssa->vars[ssa_var].no_val = no_val;
1056
63
    tssa->vars[ssa_var].alias = alias;
1057
1058
63
    if (!(info->type & MAY_BE_REF)) {
1059
61
      zend_jit_trace_propagate_range(op_array, tssa_opcodes, tssa, ssa_var);
1060
61
    }
1061
1062
63
    if (info->has_range) {
1063
32
      if (tssa->var_info[ssa_var].has_range) {
1064
23
        tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
1065
23
        tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
1066
23
        tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
1067
23
        tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
1068
23
      } else {
1069
9
        tssa->var_info[ssa_var].has_range = 1;
1070
9
        tssa->var_info[ssa_var].range = info->range;
1071
9
      }
1072
32
    }
1073
63
  }
1074
63
}
1075
1076
static int zend_jit_trace_restrict_ssa_var_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op **tssa_opcodes, zend_ssa *tssa, int ssa_var)
1077
63
{
1078
63
  int def;
1079
63
  zend_ssa_op *op;
1080
63
  zend_ssa_var_info *info;
1081
1082
63
  def = tssa->vars[ssa_var].definition;
1083
63
  if (def >= 0) {
1084
63
    ZEND_ASSERT((tssa_opcodes[def] - op_array->opcodes) < op_array->last);
1085
63
    op = ssa->ops + (tssa_opcodes[def] - op_array->opcodes);
1086
63
    if (tssa->ops[def].op1_def == ssa_var) {
1087
21
      info = ssa->var_info + op->op1_def;
1088
42
    } else if (tssa->ops[def].op2_def == ssa_var) {
1089
6
      info = ssa->var_info + op->op2_def;
1090
36
    } else if (tssa->ops[def].result_def == ssa_var) {
1091
36
      info = ssa->var_info + op->result_def;
1092
36
    } else {
1093
0
      assert(0);
1094
0
      return 0;
1095
0
    }
1096
63
    tssa->var_info[ssa_var].type &= info->type;
1097
63
    if (info->ce) {
1098
0
      if (tssa->var_info[ssa_var].ce) {
1099
0
        if (tssa->var_info[ssa_var].ce != info->ce) {
1100
0
          if (instanceof_function(tssa->var_info[ssa_var].ce, info->ce)) {
1101
            /* everything fine */
1102
0
          } else if (instanceof_function(info->ce, tssa->var_info[ssa_var].ce)) {
1103
            // TODO: TSSA may miss Pi() functions and corresponding instanceof() constraints ???
1104
0
          } else {
1105
            // TODO: classes may implement the same interface ???
1106
            //ZEND_UNREACHABLE();
1107
0
          }
1108
0
        }
1109
0
        tssa->var_info[ssa_var].is_instanceof =
1110
0
          tssa->var_info[ssa_var].is_instanceof && info->is_instanceof;
1111
0
      } else {
1112
0
        tssa->var_info[ssa_var].ce = info->ce;
1113
0
        tssa->var_info[ssa_var].is_instanceof = info->is_instanceof;
1114
0
      }
1115
0
    }
1116
63
    if (info->has_range) {
1117
32
      if (tssa->var_info[ssa_var].has_range) {
1118
32
        tssa->var_info[ssa_var].range.min = MAX(tssa->var_info[ssa_var].range.min, info->range.min);
1119
32
        tssa->var_info[ssa_var].range.max = MIN(tssa->var_info[ssa_var].range.max, info->range.max);
1120
32
        tssa->var_info[ssa_var].range.underflow = tssa->var_info[ssa_var].range.underflow && info->range.underflow;
1121
32
        tssa->var_info[ssa_var].range.overflow = tssa->var_info[ssa_var].range.overflow && info->range.overflow;
1122
32
      } else {
1123
0
        tssa->var_info[ssa_var].has_range = 1;
1124
0
        tssa->var_info[ssa_var].range = info->range;
1125
0
      }
1126
32
    }
1127
63
    return 1;
1128
63
  }
1129
0
  return 0;
1130
63
}
1131
1132
static int find_return_ssa_var(zend_jit_trace_rec *p, zend_ssa_op *ssa_op)
1133
17
{
1134
17
  while (1) {
1135
17
    if (p->op == ZEND_JIT_TRACE_VM) {
1136
17
      if (p->opline->opcode == ZEND_DO_UCALL
1137
1
       || p->opline->opcode == ZEND_DO_FCALL_BY_NAME
1138
17
       || p->opline->opcode == ZEND_DO_FCALL) {
1139
17
        if (p->opline->result_type != IS_UNUSED) {
1140
0
          return ssa_op->result_def;
1141
0
        }
1142
17
      }
1143
17
      return -1;
1144
17
    } else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
1145
      /*skip */
1146
0
    } else {
1147
0
      return -1;
1148
0
    }
1149
0
    p--;
1150
0
  }
1151
17
}
1152
1153
static const zend_op *zend_jit_trace_find_init_fcall_op(zend_jit_trace_rec *p, const zend_op_array *op_array)
1154
214
{
1155
214
  if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
1156
214
    p--;
1157
217
    while (1) {
1158
217
      if (p->op == ZEND_JIT_TRACE_VM) {
1159
214
        if (p->opline->opcode == ZEND_INIT_FCALL
1160
7
         || p->opline->opcode == ZEND_INIT_FCALL_BY_NAME
1161
7
         || p->opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME
1162
7
         || p->opline->opcode == ZEND_INIT_DYNAMIC_CALL
1163
6
         || p->opline->opcode == ZEND_INIT_USER_CALL
1164
6
         || p->opline->opcode == ZEND_NEW
1165
2
         || p->opline->opcode == ZEND_INIT_METHOD_CALL
1166
0
         || p->opline->opcode == ZEND_INIT_STATIC_METHOD_CALL
1167
214
         || p->opline->opcode == ZEND_INIT_PARENT_PROPERTY_HOOK_CALL) {
1168
214
          return p->opline;
1169
214
        }
1170
0
        return NULL;
1171
214
      } else if (p->op >= ZEND_JIT_TRACE_OP1_TYPE && p->op <= ZEND_JIT_TRACE_VAL_INFO) {
1172
        /*skip */
1173
3
      } else {
1174
0
        return NULL;
1175
0
      }
1176
3
      p--;
1177
3
    }
1178
214
  } else {
1179
0
    const zend_op *opline = NULL;
1180
0
    int call_level = 0;
1181
1182
    /* Scan trace buffer forward to find the first recorded opline after
1183
     * the sequence of ZEND_JIT_TRACE_INIT_CALL, and keep track of the
1184
     * call level. */
1185
0
    p++;
1186
0
    while (1) {
1187
0
      if (p->op == ZEND_JIT_TRACE_VM) {
1188
0
        opline = p->opline;
1189
0
        break;
1190
0
      } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1191
0
        call_level++;
1192
        /*skip */
1193
0
      } else {
1194
0
        return NULL;
1195
0
      }
1196
0
      p++;
1197
0
    }
1198
    /* Scan oplines backward to find the init fcall op */
1199
0
    if (opline) {
1200
0
      while (opline > op_array->opcodes) {
1201
0
        opline--;
1202
0
        if (zend_jit_inc_call_level(opline->opcode)) {
1203
0
          if (call_level == 0) {
1204
0
            return opline;
1205
0
          }
1206
0
          call_level--;
1207
0
        } else if (zend_jit_dec_call_level(opline->opcode)) {
1208
0
          call_level++;
1209
0
        }
1210
0
      }
1211
0
    }
1212
0
  }
1213
0
  return NULL;
1214
214
}
1215
1216
static int is_checked_guard(const zend_ssa *tssa, const zend_op **ssa_opcodes, uint32_t var, uint32_t phi_var)
1217
0
{
1218
0
  if ((tssa->var_info[phi_var].type & MAY_BE_ANY) == MAY_BE_LONG
1219
0
   && !(tssa->var_info[var].type & MAY_BE_REF)) {
1220
0
    int idx = tssa->vars[var].definition;
1221
1222
0
    if (idx >= 0) {
1223
0
      if (tssa->ops[idx].op1_def == var) {
1224
0
        const zend_op *opline = ssa_opcodes[idx];
1225
0
        if (opline->opcode == ZEND_PRE_DEC
1226
0
         || opline->opcode == ZEND_PRE_INC
1227
0
         || opline->opcode == ZEND_POST_DEC
1228
0
         || opline->opcode == ZEND_POST_INC) {
1229
0
          if (tssa->ops[idx].op1_use >= 0
1230
0
           && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_STRING)) {
1231
0
            return 0;
1232
0
          }
1233
0
          if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1234
0
            return 0;
1235
0
          }
1236
0
          return 1;
1237
0
        } else if (opline->opcode == ZEND_ASSIGN_OP
1238
0
         && (opline->extended_value == ZEND_ADD
1239
0
          || opline->extended_value == ZEND_SUB
1240
0
          || opline->extended_value == ZEND_MUL)) {
1241
0
          if ((opline->op2_type & (IS_VAR|IS_CV))
1242
0
            && tssa->ops[idx].op2_use >= 0
1243
0
            && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1244
0
            return 0;
1245
0
          }
1246
0
          if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1247
0
            return 0;
1248
0
          }
1249
0
          if (opline->op2_type == IS_CONST) {
1250
0
            zval *zv = RT_CONSTANT(opline, opline->op2);
1251
0
            if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1252
0
              return 0;
1253
0
            }
1254
0
          } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1255
0
            return 0;
1256
0
          }
1257
0
          return 1;
1258
0
        }
1259
0
      }
1260
0
      if (tssa->ops[idx].result_def == var) {
1261
0
        const zend_op *opline = ssa_opcodes[idx];
1262
0
        if (opline->opcode == ZEND_ADD
1263
0
         || opline->opcode == ZEND_SUB
1264
0
         || opline->opcode == ZEND_MUL) {
1265
0
          if ((opline->op1_type & (IS_VAR|IS_CV))
1266
0
            && tssa->ops[idx].op1_use >= 0
1267
0
            && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1268
0
            return 0;
1269
0
          }
1270
0
          if ((opline->op2_type & (IS_VAR|IS_CV))
1271
0
            && tssa->ops[idx].op2_use >= 0
1272
0
            && (tssa->var_info[tssa->ops[idx].op2_use].type & MAY_BE_REF)) {
1273
0
            return 0;
1274
0
          }
1275
0
          if (opline->op1_type == IS_CONST) {
1276
0
            zval *zv = RT_CONSTANT(opline, opline->op1);
1277
0
            if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1278
0
              return 0;
1279
0
            }
1280
0
          } else if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1281
0
            return 0;
1282
0
          }
1283
0
          if (opline->op2_type == IS_CONST) {
1284
0
            zval *zv = RT_CONSTANT(opline, opline->op2);
1285
0
            if (Z_TYPE_P(zv) != IS_LONG && Z_TYPE_P(zv) != IS_DOUBLE) {
1286
0
              return 0;
1287
0
            }
1288
0
          } else if (!(tssa->var_info[tssa->ops[idx].op2_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1289
0
            return 0;
1290
0
          }
1291
0
          return 1;
1292
0
        } else if (opline->opcode == ZEND_PRE_DEC
1293
0
         || opline->opcode == ZEND_PRE_INC
1294
0
         || opline->opcode == ZEND_POST_DEC
1295
0
         || opline->opcode == ZEND_POST_INC) {
1296
0
          if ((opline->op1_type & (IS_VAR|IS_CV))
1297
0
            && tssa->ops[idx].op1_use >= 0
1298
0
            && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
1299
0
            return 0;
1300
0
          }
1301
0
          if (!(tssa->var_info[tssa->ops[idx].op1_use].type & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1302
0
            return 0;
1303
0
          }
1304
0
          return 1;
1305
0
        }
1306
0
      }
1307
0
    }
1308
0
  }
1309
0
  return 0;
1310
0
}
1311
1312
typedef struct _zend_tssa {
1313
  zend_ssa        ssa;
1314
  const zend_op **tssa_opcodes;
1315
  int             used_stack;
1316
} zend_tssa;
1317
1318
static const zend_op _nop_opcode = {0};
1319
1320
static uint32_t find_trampoline_num_args(zend_jit_trace_rec *start, zend_jit_trace_rec *p)
1321
2
{
1322
2
  int inline_level = 0, call_level = 0;
1323
1324
2
  p--;
1325
4
  while (p != start) {
1326
4
    if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1327
2
      if (inline_level == 0) {
1328
2
        if (call_level == 0) {
1329
2
          ZEND_ASSERT(!p->op_array);
1330
2
          return ZEND_JIT_TRACE_NUM_ARGS(p->info);
1331
2
        } else {
1332
0
          call_level--;
1333
0
        }
1334
2
      }
1335
2
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
1336
0
      if (inline_level == 0) {
1337
0
        call_level++;
1338
0
      }
1339
2
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
1340
0
      if (inline_level) {
1341
0
        inline_level--;
1342
0
      } else {
1343
0
        return 0;
1344
0
      }
1345
2
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
1346
0
      inline_level++;
1347
0
    }
1348
2
    p--;
1349
2
  }
1350
0
  return 0;
1351
2
}
1352
1353
static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num, zend_script *script, const zend_op_array **op_arrays, int *num_op_arrays_ptr)
1354
2.50k
{
1355
2.50k
  zend_ssa *tssa;
1356
2.50k
  zend_ssa_op *ssa_ops, *op;
1357
2.50k
  zend_ssa_var *ssa_vars;
1358
2.50k
  zend_ssa_var_info *ssa_var_info;
1359
2.50k
  const zend_op_array *op_array;
1360
2.50k
  const zend_op *opline;
1361
2.50k
  const zend_op **ssa_opcodes;
1362
2.50k
  zend_jit_trace_rec *p;
1363
2.50k
  int i, v, idx, len, ssa_ops_count, vars_count, ssa_vars_count;
1364
2.50k
  zend_jit_trace_stack *stack;
1365
2.50k
  uint32_t build_flags = ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS;
1366
2.50k
  uint32_t optimization_level = 0;
1367
2.50k
  int call_level, level, num_op_arrays, used_stack, max_used_stack;
1368
2.50k
  size_t frame_size, stack_top, stack_size, stack_bottom;
1369
2.50k
  zend_jit_op_array_trace_extension *jit_extension;
1370
2.50k
  zend_ssa *ssa;
1371
2.50k
  zend_jit_trace_stack_frame *frame, *top, *call;
1372
2.50k
  zend_ssa_var_info return_value_info;
1373
1374
  /* 1. Count number of TSSA opcodes;
1375
   *    Count number of activation frames;
1376
   *    Calculate size of abstract stack;
1377
   *    Construct regular SSA for involved op_array */
1378
2.50k
  op_array = trace_buffer->op_array;
1379
2.50k
  stack_top = stack_size = zend_jit_trace_frame_size(op_array, 0);
1380
2.50k
  stack_bottom = 0;
1381
2.50k
  p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1382
2.50k
  ssa_ops_count = 0;
1383
2.50k
  call_level = 0;
1384
2.50k
  level = 0;
1385
2.50k
  num_op_arrays = 0;
1386
  /* Remember op_array to cleanup */
1387
2.50k
  op_arrays[num_op_arrays++] = op_array;
1388
  /* Build SSA */
1389
2.50k
  ssa = zend_jit_trace_build_ssa(op_array, script);
1390
12.0k
  for (;;p++) {
1391
12.0k
    if (p->op == ZEND_JIT_TRACE_VM) {
1392
8.95k
      if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1393
0
        const zend_op *opline = p->opline;
1394
1395
0
        switch (opline->opcode) {
1396
0
          case ZEND_INCLUDE_OR_EVAL:
1397
0
            ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1398
0
            break;
1399
0
          case ZEND_FETCH_R:
1400
0
          case ZEND_FETCH_W:
1401
0
          case ZEND_FETCH_RW:
1402
0
          case ZEND_FETCH_FUNC_ARG:
1403
0
          case ZEND_FETCH_IS:
1404
0
          case ZEND_FETCH_UNSET:
1405
0
          case ZEND_UNSET_VAR:
1406
0
          case ZEND_ISSET_ISEMPTY_VAR:
1407
0
            if (opline->extended_value & ZEND_FETCH_LOCAL) {
1408
0
              ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1409
0
            } else if ((opline->extended_value & (ZEND_FETCH_GLOBAL | ZEND_FETCH_GLOBAL_LOCK)) &&
1410
0
                       !op_array->function_name) {
1411
0
              ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1412
0
            }
1413
0
            break;
1414
0
        }
1415
0
      }
1416
8.95k
      ssa_ops_count += zend_jit_trace_op_len(p->opline);
1417
8.95k
    } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
1418
214
      call_level++;
1419
214
      stack_top += zend_jit_trace_frame_size(p->op_array, ZEND_JIT_TRACE_NUM_ARGS(p->info));
1420
214
      if (stack_top > stack_size) {
1421
210
        stack_size = stack_top;
1422
210
      }
1423
2.84k
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
1424
186
      uint32_t num_args = 0;
1425
186
      if (JIT_G(opt_level) < ZEND_JIT_LEVEL_OPT_FUNC) {
1426
0
        if (p->func
1427
0
         && p->func != (zend_function*)&zend_pass_function
1428
0
         && (zend_string_equals_literal(p->func->common.function_name, "extract")
1429
0
          || zend_string_equals_literal(p->func->common.function_name, "compact")
1430
0
          || zend_string_equals_literal(p->func->common.function_name, "get_defined_vars"))) {
1431
0
          ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
1432
0
        }
1433
0
      }
1434
186
      if (!p->func) {
1435
        /* Find num_args in the corresponding ZEND_JIT_TRACE_INIT_CALL record */
1436
2
        num_args = find_trampoline_num_args(trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE, p);
1437
2
      }
1438
186
      frame_size = zend_jit_trace_frame_size(p->op_array, num_args);
1439
186
      if (call_level == 0) {
1440
0
        if (stack_top + frame_size > stack_size) {
1441
0
          stack_size = stack_top + frame_size;
1442
0
        }
1443
186
      } else {
1444
186
        call_level--;
1445
186
        stack_top -= frame_size;
1446
186
      }
1447
2.65k
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
1448
17
      op_array = p->op_array;
1449
17
      if (call_level == 0) {
1450
0
        stack_top += zend_jit_trace_frame_size(op_array, 0);
1451
0
        if (stack_top > stack_size) {
1452
0
          stack_size = stack_top;
1453
0
        }
1454
17
      } else {
1455
17
        call_level--;
1456
17
      }
1457
17
      level++;
1458
17
      jit_extension =
1459
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1460
17
      ssa = &jit_extension->func_info.ssa;
1461
17
      if (ssa->cfg.blocks_count) {
1462
        /* pass */
1463
17
      } else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1464
        /* Too many functions in single trace */
1465
0
        *num_op_arrays_ptr = num_op_arrays;
1466
0
        return NULL;
1467
17
      } else {
1468
        /* Remember op_array to cleanup */
1469
17
        op_arrays[num_op_arrays++] = op_array;
1470
        /* Build SSA */
1471
17
        ssa = zend_jit_trace_build_ssa(op_array, script);
1472
17
      }
1473
2.64k
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
1474
17
      if (level == 0) {
1475
0
        stack_bottom += zend_jit_trace_frame_size(p->op_array, 0);
1476
0
        jit_extension =
1477
0
          (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1478
0
        ssa = &jit_extension->func_info.ssa;
1479
0
        if (ssa->cfg.blocks_count) {
1480
          /* pass */
1481
0
        } else if (num_op_arrays == ZEND_JIT_TRACE_MAX_FUNCS) {
1482
          /* Too many functions in single trace */
1483
0
          *num_op_arrays_ptr = num_op_arrays;
1484
0
          return NULL;
1485
0
        } else {
1486
          /* Remember op_array to cleanup */
1487
0
          op_arrays[num_op_arrays++] = op_array;
1488
          /* Build SSA */
1489
0
          ssa = zend_jit_trace_build_ssa(op_array, script);
1490
0
        }
1491
17
      } else {
1492
17
        stack_top -= zend_jit_trace_frame_size(op_array, 0);
1493
17
        level--;
1494
17
      }
1495
17
      op_array = p->op_array;
1496
2.62k
    } else if (p->op == ZEND_JIT_TRACE_END) {
1497
2.50k
      break;
1498
2.50k
    }
1499
12.0k
  }
1500
2.50k
  *num_op_arrays_ptr = num_op_arrays;
1501
1502
  /* Allocate space for abstract stack */
1503
2.50k
  JIT_G(current_frame) = frame = (zend_jit_trace_stack_frame*)((char*)zend_arena_alloc(&CG(arena), stack_bottom + stack_size) + stack_bottom);
1504
1505
  /* 2. Construct TSSA */
1506
2.50k
  tssa = zend_arena_calloc(&CG(arena), 1, sizeof(zend_tssa));
1507
2.50k
  tssa->cfg.flags = ZEND_SSA_TSSA;
1508
2.50k
  tssa->cfg.blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_basic_block));
1509
2.50k
  tssa->blocks = zend_arena_calloc(&CG(arena), 2, sizeof(zend_ssa_block));
1510
2.50k
  tssa->cfg.predecessors = zend_arena_calloc(&CG(arena), 2, sizeof(int));
1511
1512
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1513
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1514
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1515
13
    tssa->cfg.blocks_count = 2;
1516
13
    tssa->cfg.edges_count = 2;
1517
1518
13
    tssa->cfg.predecessors[0] = 0;
1519
13
    tssa->cfg.predecessors[1] = 1;
1520
1521
13
    tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_REACHABLE;
1522
13
    tssa->cfg.blocks[0].successors_count = 1;
1523
13
    tssa->cfg.blocks[0].predecessors_count = 0;
1524
13
    tssa->cfg.blocks[0].successors = tssa->cfg.blocks[0].successors_storage;
1525
13
    tssa->cfg.blocks[0].successors[0] = 1;
1526
1527
13
    tssa->cfg.blocks[1].flags = ZEND_BB_FOLLOW|ZEND_BB_TARGET|ZEND_BB_LOOP_HEADER|ZEND_BB_REACHABLE;
1528
13
    tssa->cfg.blocks[1].len = ssa_ops_count;
1529
13
    tssa->cfg.blocks[1].successors_count = 1;
1530
13
    tssa->cfg.blocks[1].predecessors_count = 2;
1531
13
    tssa->cfg.blocks[1].successors = tssa->cfg.blocks[1].successors_storage;
1532
13
    tssa->cfg.blocks[1].successors[1] = 1;
1533
2.49k
  } else {
1534
2.49k
    tssa->cfg.blocks_count = 1;
1535
2.49k
    tssa->cfg.edges_count = 0;
1536
1537
2.49k
    tssa->cfg.blocks[0].flags = ZEND_BB_START|ZEND_BB_EXIT|ZEND_BB_REACHABLE;
1538
2.49k
    tssa->cfg.blocks[0].len = ssa_ops_count;
1539
2.49k
    tssa->cfg.blocks[0].successors_count = 0;
1540
2.49k
    tssa->cfg.blocks[0].predecessors_count = 0;
1541
2.49k
  }
1542
2.50k
  ((zend_tssa*)tssa)->used_stack = -1;
1543
1544
2.50k
  if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1545
0
    return tssa;
1546
0
  }
1547
1548
2.50k
  tssa->ops = ssa_ops = zend_arena_alloc(&CG(arena), ssa_ops_count * sizeof(zend_ssa_op));
1549
2.50k
  memset(ssa_ops, -1, ssa_ops_count * sizeof(zend_ssa_op));
1550
2.50k
  ssa_opcodes = zend_arena_calloc(&CG(arena), ssa_ops_count + 1, sizeof(zend_op*));
1551
2.50k
  ((zend_tssa*)tssa)->tssa_opcodes = ssa_opcodes;
1552
2.50k
  ssa_opcodes[ssa_ops_count] = &_nop_opcode;
1553
1554
2.50k
  op_array = trace_buffer->op_array;
1555
2.50k
  if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1556
2.47k
    ssa_vars_count = op_array->last_var;
1557
2.47k
  } else {
1558
33
    ssa_vars_count = op_array->last_var + op_array->T;
1559
33
  }
1560
2.50k
  stack = frame->stack;
1561
3.85k
  for (i = 0; i < ssa_vars_count; i++) {
1562
1.34k
    SET_STACK_VAR(stack, i, i);
1563
1.34k
  }
1564
1565
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1566
    // TODO: For tracing, it's possible, to create pseudo Phi functions
1567
    //       at the end of loop, without this additional pass (like LuaJIT) ???
1568
13
    ssa_vars_count = zend_jit_trace_add_phis(trace_buffer, ssa_vars_count, tssa, stack);
1569
2.49k
  } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
1570
0
    ssa_vars_count = zend_jit_trace_add_call_phis(trace_buffer, ssa_vars_count, tssa, stack);
1571
2.49k
  } else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1572
0
    ssa_vars_count = zend_jit_trace_add_ret_phis(trace_buffer, ssa_vars_count, tssa, stack);
1573
0
  }
1574
1575
2.50k
  p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1576
2.50k
  idx = 0;
1577
2.50k
  level = 0;
1578
12.0k
  for (;;p++) {
1579
12.0k
    if (p->op == ZEND_JIT_TRACE_VM) {
1580
8.95k
      opline = p->opline;
1581
8.95k
      ssa_opcodes[idx] = opline;
1582
8.95k
      ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1583
8.95k
      idx++;
1584
8.95k
      len = zend_jit_trace_op_len(p->opline);
1585
9.19k
      while (len > 1) {
1586
245
        opline++;
1587
245
        ssa_opcodes[idx] = opline;
1588
245
        if (opline->opcode != ZEND_OP_DATA) {
1589
3
          ssa_vars_count = zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (int*)stack);
1590
3
        }
1591
245
        idx++;
1592
245
        len--;
1593
245
      }
1594
8.95k
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
1595
17
      frame = zend_jit_trace_call_frame(frame, op_array, 0);
1596
17
      stack = frame->stack;
1597
17
      op_array = p->op_array;
1598
17
      level++;
1599
17
      if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1600
0
        return NULL;
1601
0
      }
1602
17
      ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1603
54
      for (i = 0; i < op_array->last_var; i++) {
1604
37
        SET_STACK_VAR(stack, i, ssa_vars_count++);
1605
37
      }
1606
3.04k
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
1607
17
      op_array = p->op_array;
1608
17
      frame = zend_jit_trace_ret_frame(frame, op_array);
1609
17
      stack = frame->stack;
1610
17
      if (level == 0) {
1611
0
        if (ssa_vars_count >= ZEND_JIT_TRACE_MAX_SSA_VAR) {
1612
0
          return NULL;
1613
0
        }
1614
0
        ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(p->info, ssa_vars_count);
1615
0
        for (i = 0; i < op_array->last_var + op_array->T; i++) {
1616
0
          SET_STACK_VAR(stack, i, ssa_vars_count++);
1617
0
        }
1618
17
      } else {
1619
17
        level--;
1620
17
      }
1621
3.02k
    } else if (p->op == ZEND_JIT_TRACE_END) {
1622
2.50k
      break;
1623
2.50k
    }
1624
12.0k
  }
1625
1626
2.50k
  op_array = trace_buffer->op_array;
1627
2.50k
  tssa->vars_count = ssa_vars_count;
1628
2.50k
  tssa->vars = ssa_vars = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var));
1629
2.50k
  if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1630
2.47k
    vars_count = op_array->last_var;
1631
2.47k
  } else {
1632
33
    vars_count = op_array->last_var + op_array->T;
1633
33
  }
1634
2.50k
  i = 0;
1635
3.85k
  while (i < vars_count) {
1636
1.34k
    ssa_vars[i].var = i;
1637
1.34k
    ssa_vars[i].scc = -1;
1638
1.34k
    ssa_vars[i].definition = -1;
1639
1.34k
    ssa_vars[i].use_chain = -1;
1640
1.34k
    i++;
1641
1.34k
  }
1642
6.72k
  while (i < tssa->vars_count) {
1643
4.21k
    ssa_vars[i].var = -1;
1644
4.21k
    ssa_vars[i].scc = -1;
1645
4.21k
    ssa_vars[i].definition = -1;
1646
4.21k
    ssa_vars[i].use_chain = -1;
1647
4.21k
    i++;
1648
4.21k
  }
1649
1650
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1651
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1652
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1653
    /* Update Phi sources */
1654
13
    zend_ssa_phi *phi = tssa->blocks[1].phis;
1655
1656
29
    while (phi) {
1657
16
      phi->sources[1] = STACK_VAR(stack, phi->var);
1658
16
      ssa_vars[phi->ssa_var].var = phi->var;
1659
16
      ssa_vars[phi->ssa_var].definition_phi = phi;
1660
16
      ssa_vars[phi->sources[0]].phi_use_chain = phi;
1661
16
      ssa_vars[phi->sources[1]].phi_use_chain = phi;
1662
16
      phi = phi->next;
1663
16
    }
1664
13
  }
1665
1666
  /* 3. Compute use-def chains */
1667
2.50k
  idx = (ssa_ops_count - 1);
1668
2.50k
  op = ssa_ops + idx;
1669
11.7k
  while (idx >= 0) {
1670
9.19k
    opline = ssa_opcodes[idx];
1671
9.19k
    if (op->op1_use >= 0) {
1672
3.48k
      op->op1_use_chain = ssa_vars[op->op1_use].use_chain;
1673
3.48k
      ssa_vars[op->op1_use].use_chain = idx;
1674
3.48k
    }
1675
9.19k
    if (op->op2_use >= 0 && op->op2_use != op->op1_use) {
1676
1.13k
      op->op2_use_chain = ssa_vars[op->op2_use].use_chain;
1677
1.13k
      ssa_vars[op->op2_use].use_chain = idx;
1678
1.13k
    }
1679
9.19k
    if (op->result_use >= 0 && op->result_use != op->op1_use && op->result_use != op->op2_use) {
1680
14
      op->res_use_chain = ssa_vars[op->result_use].use_chain;
1681
14
      ssa_vars[op->result_use].use_chain = idx;
1682
14
    }
1683
9.19k
    if (op->op1_def >= 0) {
1684
682
      ssa_vars[op->op1_def].var = EX_VAR_TO_NUM(opline->op1.var);
1685
682
      ssa_vars[op->op1_def].definition = idx;
1686
682
    }
1687
9.19k
    if (op->op2_def >= 0) {
1688
88
      ssa_vars[op->op2_def].var = EX_VAR_TO_NUM(opline->op2.var);
1689
88
      ssa_vars[op->op2_def].definition = idx;
1690
88
    }
1691
9.19k
    if (op->result_def >= 0) {
1692
3.39k
      ssa_vars[op->result_def].var = EX_VAR_TO_NUM(opline->result.var);
1693
3.39k
      ssa_vars[op->result_def].definition = idx;
1694
3.39k
    }
1695
9.19k
    op--;
1696
9.19k
    idx--;
1697
9.19k
  }
1698
1699
  /* 4. Type inference */
1700
2.50k
  op_array = trace_buffer->op_array;
1701
2.50k
  opline = trace_buffer[1].opline;
1702
2.50k
  jit_extension =
1703
2.50k
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
1704
2.50k
  ssa = &jit_extension->func_info.ssa;
1705
1706
2.50k
  tssa->var_info = ssa_var_info = zend_arena_calloc(&CG(arena), tssa->vars_count, sizeof(zend_ssa_var_info));
1707
1708
2.50k
  if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
1709
2.47k
    i = 0;
1710
3.66k
    while (i < op_array->last_var) {
1711
1.18k
      if (i < op_array->num_args) {
1712
0
        if (ssa->var_info
1713
0
         && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i, NULL)) {
1714
          /* pass */
1715
0
        } else {
1716
0
          if (ssa->vars) {
1717
0
            ssa_vars[i].no_val = ssa->vars[i].no_val;
1718
0
            ssa_vars[i].alias = ssa->vars[i].alias;
1719
0
          } else {
1720
0
            ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1721
0
          }
1722
0
          if (op_array->arg_info && i < trace_buffer[1].opline - op_array->opcodes) {
1723
0
            zend_arg_info *arg_info = &op_array->arg_info[i];
1724
0
            zend_class_entry *ce;
1725
0
            uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
1726
1727
0
            if (ZEND_ARG_SEND_MODE(arg_info)) {
1728
0
              tmp |= MAY_BE_REF;
1729
0
            }
1730
0
            ssa_var_info[i].type = tmp;
1731
0
            ssa_var_info[i].ce = ce;
1732
0
            ssa_var_info[i].is_instanceof = 1;
1733
0
          } else {
1734
0
            ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1735
0
          }
1736
0
        }
1737
1.18k
      } else {
1738
1.18k
        if (ssa->vars) {
1739
0
          ssa_vars[i].no_val = ssa->vars[i].no_val;
1740
0
          ssa_vars[i].alias = ssa->vars[i].alias;
1741
1.18k
        } else {
1742
1.18k
          ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1743
1.18k
        }
1744
1.18k
        if (ssa_vars[i].alias == NO_ALIAS) {
1745
0
          ssa_var_info[i].type = MAY_BE_UNDEF;
1746
1.18k
        } else {
1747
1.18k
          ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1748
1.18k
        }
1749
1.18k
      }
1750
1.18k
      i++;
1751
1.18k
    }
1752
2.47k
  } else {
1753
33
    int parent_vars_count = 0;
1754
33
    zend_jit_trace_stack *parent_stack = NULL;
1755
1756
33
    i = 0;
1757
33
    if (parent_trace) {
1758
18
      parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
1759
18
        op_array->last_var + op_array->T);
1760
18
      if (parent_vars_count) {
1761
5
        parent_stack =
1762
5
          zend_jit_traces[parent_trace].stack_map +
1763
5
          zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
1764
5
      }
1765
18
    }
1766
193
    while (i < op_array->last_var + op_array->T) {
1767
160
      if (!ssa->var_info
1768
160
       || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i, opline)) {
1769
160
        if (ssa->vars && i < ssa->vars_count) {
1770
0
          ssa_vars[i].alias = ssa->vars[i].alias;
1771
160
        } else {
1772
160
          ssa_vars[i].alias = zend_jit_var_may_alias(op_array, ssa, i);
1773
160
        }
1774
160
        if (i < op_array->last_var) {
1775
75
          ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1776
85
        } else {
1777
85
          ssa_var_info[i].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_INDIRECT | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
1778
85
        }
1779
160
      }
1780
160
      if (i < parent_vars_count) {
1781
        /* Initialize TSSA variable from parent trace */
1782
19
        uint8_t op_type = STACK_TYPE(parent_stack, i);
1783
1784
19
        if (op_type != IS_UNKNOWN) {
1785
6
          ssa_var_info[i].type &= zend_jit_trace_type_to_info(op_type);
1786
6
          if (!ssa_var_info[i].type
1787
0
           && op_type == IS_UNDEF
1788
0
           && i >= op_array->last_var) {
1789
            // TODO: It's better to use NULL instead of UNDEF for temporary variables
1790
0
            ssa_var_info[i].type |= MAY_BE_UNDEF;
1791
0
          }
1792
6
        }
1793
19
      }
1794
160
      i++;
1795
160
    }
1796
33
  }
1797
1798
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1799
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1800
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1801
    /* Propagate initial value through Phi functions */
1802
13
    zend_ssa_phi *phi = tssa->blocks[1].phis;
1803
1804
29
    while (phi) {
1805
16
      if (!ssa->var_info
1806
16
       || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, phi->ssa_var, NULL)) {
1807
16
        ssa_vars[phi->ssa_var].alias = ssa_vars[phi->sources[0]].alias;
1808
16
        ssa_var_info[phi->ssa_var].type = ssa_var_info[phi->sources[0]].type;
1809
16
      }
1810
16
      phi = phi->next;
1811
16
    }
1812
13
  }
1813
1814
2.50k
  frame = JIT_G(current_frame);
1815
2.50k
  top = zend_jit_trace_call_frame(frame, op_array, 0);
1816
2.50k
  TRACE_FRAME_INIT(frame, op_array, 0, 0);
1817
2.50k
  TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
1818
2.50k
  frame->used_stack = 0;
1819
2.50k
  memset(&return_value_info, 0, sizeof(return_value_info));
1820
1821
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1822
13
    max_used_stack = used_stack = 0;
1823
2.49k
  } else {
1824
2.49k
    max_used_stack = used_stack = -1;
1825
2.49k
  }
1826
1827
2.50k
  p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
1828
2.50k
  idx = 0;
1829
2.50k
  level = 0;
1830
2.50k
  opline = NULL;
1831
11.8k
  for (;;p++) {
1832
11.8k
    if (p->op == ZEND_JIT_TRACE_VM) {
1833
8.95k
      uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
1834
8.95k
      uint8_t val_type = IS_UNKNOWN;
1835
//      zend_class_entry *op1_ce = NULL;
1836
8.95k
      zend_class_entry *op2_ce = NULL;
1837
1838
8.95k
      opline = p->opline;
1839
1840
8.95k
      op1_type = orig_op1_type = p->op1_type;
1841
8.95k
      op2_type = orig_op2_type = p->op2_type;
1842
8.95k
      op3_type = p->op3_type;
1843
8.95k
      if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1844
5.87k
        op1_type = IS_UNKNOWN;
1845
5.87k
      }
1846
8.95k
      if (op1_type != IS_UNKNOWN) {
1847
3.07k
        op1_type &= ~IS_TRACE_PACKED;
1848
3.07k
      }
1849
8.95k
      if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1850
7.79k
        op2_type = IS_UNKNOWN;
1851
7.79k
      }
1852
8.95k
      if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
1853
8.85k
        op3_type = IS_UNKNOWN;
1854
8.85k
      }
1855
1856
8.95k
      if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
1857
//        op1_ce = (zend_class_entry*)(p+1)->ce;
1858
49
        p++;
1859
49
      }
1860
8.95k
      if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
1861
14
        op2_ce = (zend_class_entry*)(p+1)->ce;
1862
14
        p++;
1863
14
      }
1864
8.95k
      if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
1865
55
        val_type = (p+1)->op1_type;
1866
55
        p++;
1867
55
      }
1868
1869
8.95k
      switch (opline->opcode) {
1870
81
        case ZEND_ASSIGN_OP:
1871
81
          if (opline->extended_value == ZEND_POW
1872
81
           || opline->extended_value == ZEND_DIV) {
1873
            // TODO: check for division by zero ???
1874
1
            break;
1875
1
          }
1876
80
          if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1877
47
            break;
1878
47
          }
1879
33
          ADD_OP1_TRACE_GUARD();
1880
33
          ADD_OP2_TRACE_GUARD();
1881
33
          break;
1882
153
        case ZEND_ASSIGN_DIM_OP:
1883
153
          if (opline->result_type != IS_UNUSED) {
1884
20
            break;
1885
20
          }
1886
133
          if (op3_type != IS_UNKNOWN
1887
33
           && !zend_jit_supported_binary_op(
1888
33
              opline->extended_value, MAY_BE_ANY, (1<<op3_type))) {
1889
23
            break;
1890
23
          }
1891
110
          ZEND_FALLTHROUGH;
1892
199
        case ZEND_ASSIGN_DIM:
1893
199
          if (opline->opcode == ZEND_ASSIGN_DIM
1894
89
           && opline->op1_type == IS_CV
1895
73
           && (opline+1)->op1_type == IS_CV
1896
13
           && (opline+1)->op1.var == opline->op1.var) {
1897
            /* skip $a[x] = $a; */
1898
0
            break;
1899
0
          }
1900
199
          if (opline->op1_type == IS_CV || opline->opcode == ZEND_ASSIGN_DIM_OP) {
1901
183
            ADD_OP1_DATA_TRACE_GUARD();
1902
183
          }
1903
199
          ADD_OP2_TRACE_GUARD();
1904
199
          ADD_OP1_TRACE_GUARD();
1905
199
          if (op1_type == IS_ARRAY
1906
36
           && ((opline->op2_type == IS_CONST
1907
19
             && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
1908
34
            || (opline->op2_type != IS_CONST
1909
17
             && op2_type == IS_LONG))) {
1910
1911
2
            if (!(orig_op1_type & IS_TRACE_PACKED)) {
1912
1
              zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1913
1914
1
              if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
1915
1
               && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1916
0
                info->type |= MAY_BE_PACKED_GUARD;
1917
0
                info->type &= ~MAY_BE_ARRAY_PACKED;
1918
0
              }
1919
1
            } else if (opline->opcode == ZEND_ASSIGN_DIM_OP
1920
0
                && val_type != IS_UNKNOWN
1921
0
                && val_type != IS_UNDEF) {
1922
0
              zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
1923
1924
0
              if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
1925
0
               && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1926
0
                info->type |= MAY_BE_PACKED_GUARD;
1927
0
                info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
1928
0
              }
1929
0
            }
1930
2
          }
1931
199
          break;
1932
0
        case ZEND_ASSIGN_OBJ_OP:
1933
0
          if (opline->extended_value == ZEND_POW
1934
0
           || opline->extended_value == ZEND_DIV) {
1935
            // TODO: check for division by zero ???
1936
0
            break;
1937
0
          }
1938
0
          if (opline->result_type != IS_UNUSED) {
1939
0
            break;
1940
0
          }
1941
0
          ZEND_FALLTHROUGH;
1942
0
        case ZEND_ASSIGN_OBJ:
1943
0
        case ZEND_PRE_INC_OBJ:
1944
0
        case ZEND_PRE_DEC_OBJ:
1945
0
        case ZEND_POST_INC_OBJ:
1946
0
        case ZEND_POST_DEC_OBJ:
1947
0
          if (opline->op2_type != IS_CONST
1948
0
           || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1949
0
           || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1950
0
            break;
1951
0
          }
1952
0
          if (opline->opcode == ZEND_ASSIGN_OBJ
1953
0
           || opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1954
0
            if (opline->op1_type == IS_CV
1955
0
             && (opline+1)->op1_type == IS_CV
1956
0
             && (opline+1)->op1.var == opline->op1.var) {
1957
              /* skip $a->prop += $a; */
1958
0
              break;
1959
0
            }
1960
0
            ADD_OP1_DATA_TRACE_GUARD();
1961
0
          }
1962
0
          ADD_OP1_TRACE_GUARD();
1963
0
          break;
1964
52
        case ZEND_CONCAT:
1965
142
        case ZEND_FAST_CONCAT:
1966
142
          if ((opline->op1_type == IS_CONST || orig_op1_type == IS_STRING)
1967
85
           && (opline->op2_type == IS_CONST || orig_op2_type == IS_STRING)) {
1968
6
            ADD_OP2_TRACE_GUARD();
1969
6
            ADD_OP1_TRACE_GUARD();
1970
6
          }
1971
142
          break;
1972
160
        case ZEND_ADD:
1973
393
        case ZEND_SUB:
1974
577
        case ZEND_MUL:
1975
//        case ZEND_DIV: // TODO: check for division by zero ???
1976
577
          if (orig_op1_type == IS_UNDEF || orig_op2_type == IS_UNDEF) {
1977
166
            break;
1978
166
          }
1979
411
          ZEND_FALLTHROUGH;
1980
430
        case ZEND_IS_EQUAL:
1981
438
        case ZEND_IS_NOT_EQUAL:
1982
544
        case ZEND_IS_SMALLER:
1983
557
        case ZEND_IS_SMALLER_OR_EQUAL:
1984
557
        case ZEND_CASE:
1985
559
        case ZEND_IS_IDENTICAL:
1986
560
        case ZEND_IS_NOT_IDENTICAL:
1987
560
        case ZEND_CASE_STRICT:
1988
652
        case ZEND_BW_OR:
1989
1.05k
        case ZEND_BW_AND:
1990
1.06k
        case ZEND_BW_XOR:
1991
1.09k
        case ZEND_SL:
1992
1.11k
        case ZEND_SR:
1993
1.52k
        case ZEND_MOD:
1994
1.52k
          ADD_OP2_TRACE_GUARD();
1995
1.52k
          ZEND_FALLTHROUGH;
1996
2.95k
        case ZEND_ECHO:
1997
2.95k
        case ZEND_STRLEN:
1998
2.95k
        case ZEND_COUNT:
1999
3.02k
        case ZEND_QM_ASSIGN:
2000
3.03k
        case ZEND_FE_RESET_R:
2001
3.03k
          ADD_OP1_TRACE_GUARD();
2002
3.03k
          break;
2003
2
        case ZEND_FE_FETCH_R:
2004
2
          ADD_OP1_TRACE_GUARD();
2005
2
          if (op1_type == IS_ARRAY && (orig_op1_type & ~IS_TRACE_PACKED) == IS_ARRAY) {
2006
2007
2
            zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
2008
2009
2
            if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
2010
2
             && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
2011
2
              info->type |= MAY_BE_PACKED_GUARD;
2012
2
              if (orig_op1_type & IS_TRACE_PACKED) {
2013
2
                info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2014
2
              } else {
2015
0
                info->type &= ~MAY_BE_ARRAY_PACKED;
2016
0
              }
2017
2
            }
2018
2
          }
2019
2
          break;
2020
0
        case ZEND_VERIFY_RETURN_TYPE:
2021
0
          if (opline->op1_type == IS_UNUSED) {
2022
            /* Always throws */
2023
0
            break;
2024
0
          }
2025
0
          if (opline->op1_type == IS_CONST) {
2026
            /* TODO Different instruction format, has return value */
2027
0
            break;
2028
0
          }
2029
0
          if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
2030
            /* Not worth bothering with */
2031
0
            break;
2032
0
          }
2033
0
          ADD_OP1_TRACE_GUARD();
2034
0
          break;
2035
2
        case ZEND_FETCH_DIM_FUNC_ARG:
2036
2
          if (!frame
2037
2
           || !frame->call
2038
2
           || !frame->call->func
2039
2
           || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
2040
0
            break;
2041
0
          }
2042
2
          ADD_OP2_TRACE_GUARD();
2043
2
          ADD_OP1_TRACE_GUARD();
2044
2
          break;
2045
59
        case ZEND_PRE_INC:
2046
64
        case ZEND_PRE_DEC:
2047
69
        case ZEND_POST_INC:
2048
70
        case ZEND_POST_DEC:
2049
70
          if (opline->op1_type != IS_CV) {
2050
9
            break;
2051
9
          }
2052
61
          ADD_OP1_TRACE_GUARD();
2053
61
          break;
2054
186
        case ZEND_ASSIGN:
2055
186
          if (opline->op1_type != IS_CV) {
2056
18
            break;
2057
18
          }
2058
168
          ADD_OP2_TRACE_GUARD();
2059
168
          if (op1_type != IS_UNKNOWN
2060
165
           && (tssa->var_info[tssa->ops[idx].op1_use].type & MAY_BE_REF)) {
2061
159
            ADD_OP1_TRACE_GUARD();
2062
159
          }
2063
168
          break;
2064
29
        case ZEND_CAST:
2065
29
          if (opline->extended_value != op1_type) {
2066
26
            break;
2067
26
          }
2068
3
          ADD_OP1_TRACE_GUARD();
2069
3
          break;
2070
17
        case ZEND_JMPZ:
2071
20
        case ZEND_JMPNZ:
2072
26
        case ZEND_JMPZ_EX:
2073
26
        case ZEND_JMPNZ_EX:
2074
32
        case ZEND_BOOL:
2075
81
        case ZEND_BOOL_NOT:
2076
81
          ADD_OP1_TRACE_GUARD();
2077
81
          break;
2078
0
        case ZEND_ISSET_ISEMPTY_CV:
2079
0
          ADD_OP1_TRACE_GUARD();
2080
0
          break;
2081
0
        case ZEND_IN_ARRAY:
2082
0
          if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
2083
0
            break;
2084
0
          }
2085
0
          ADD_OP1_TRACE_GUARD();
2086
0
          break;
2087
3
        case ZEND_ISSET_ISEMPTY_DIM_OBJ:
2088
3
          if ((opline->extended_value & ZEND_ISEMPTY)) {
2089
            // TODO: support for empty() ???
2090
0
            break;
2091
0
          }
2092
3
          ZEND_FALLTHROUGH;
2093
69
        case ZEND_FETCH_DIM_R:
2094
96
        case ZEND_FETCH_DIM_IS:
2095
97
        case ZEND_FETCH_LIST_R:
2096
97
          ADD_OP1_TRACE_GUARD();
2097
97
          ADD_OP2_TRACE_GUARD();
2098
2099
97
          if (op1_type == IS_ARRAY
2100
7
           && opline->op1_type != IS_CONST
2101
7
           && ((opline->op2_type == IS_CONST
2102
6
             && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
2103
5
            || (opline->op2_type != IS_CONST
2104
2
             && op2_type == IS_LONG))) {
2105
2106
2
            zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
2107
2108
2
            if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
2109
2
             && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
2110
2
              info->type |= MAY_BE_PACKED_GUARD;
2111
2
              if (orig_op1_type & IS_TRACE_PACKED) {
2112
2
                info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2113
2
              } else {
2114
0
                info->type &= ~MAY_BE_ARRAY_PACKED;
2115
0
              }
2116
2
            }
2117
2
          }
2118
97
          break;
2119
17
        case ZEND_FETCH_DIM_W:
2120
24
        case ZEND_FETCH_DIM_RW:
2121
//        case ZEND_FETCH_DIM_UNSET:
2122
25
        case ZEND_FETCH_LIST_W:
2123
25
          if (opline->op1_type != IS_CV
2124
7
           && (orig_op1_type == IS_UNKNOWN
2125
7
            || !(orig_op1_type & IS_TRACE_INDIRECT))) {
2126
1
            break;
2127
1
          }
2128
24
          ADD_OP1_TRACE_GUARD();
2129
24
          ADD_OP2_TRACE_GUARD();
2130
24
          if (op1_type == IS_ARRAY
2131
2
           && !(orig_op1_type & IS_TRACE_PACKED)
2132
2
           && ((opline->op2_type == IS_CONST
2133
1
             && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
2134
2
            || (opline->op2_type != IS_CONST
2135
1
             && op2_type == IS_LONG))) {
2136
2137
0
            zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
2138
2139
0
            if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)
2140
0
             && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
2141
0
              info->type |= MAY_BE_PACKED_GUARD;
2142
0
              info->type &= ~MAY_BE_ARRAY_PACKED;
2143
0
            }
2144
0
          }
2145
24
          break;
2146
0
        case ZEND_SEND_VAL_EX:
2147
0
        case ZEND_SEND_VAR_EX:
2148
0
        case ZEND_SEND_VAR_NO_REF_EX:
2149
0
          if (opline->op2_type == IS_CONST) {
2150
            /* Named parameters not supported in JIT */
2151
0
            break;
2152
0
          }
2153
0
          if (opline->op2.num > MAX_ARG_FLAG_NUM) {
2154
0
            goto propagate_arg;
2155
0
          }
2156
0
          ZEND_FALLTHROUGH;
2157
269
        case ZEND_SEND_VAL:
2158
288
        case ZEND_SEND_VAR:
2159
288
        case ZEND_SEND_VAR_NO_REF:
2160
290
        case ZEND_SEND_FUNC_ARG:
2161
290
          if (opline->op2_type == IS_CONST) {
2162
            /* Named parameters not supported in JIT */
2163
0
            break;
2164
0
          }
2165
290
          ADD_OP1_TRACE_GUARD();
2166
290
propagate_arg:
2167
          /* Propagate argument type */
2168
290
          if (frame->call
2169
290
           && frame->call->func
2170
290
           && frame->call->func->type == ZEND_USER_FUNCTION
2171
1
           && opline->op2.num <= frame->call->func->op_array.num_args) {
2172
0
            uint32_t info;
2173
2174
0
            if (opline->op1_type == IS_CONST) {
2175
0
              info = _const_op_type(RT_CONSTANT(opline, opline->op1));
2176
0
            } else {
2177
0
              ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
2178
0
              info = ssa_var_info[ssa_ops[idx].op1_use].type & ~MAY_BE_GUARD;
2179
0
            }
2180
0
            if (frame->call->func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) {
2181
0
              zend_arg_info *arg_info;
2182
2183
0
              ZEND_ASSERT(frame->call->func->op_array.arg_info);
2184
0
              arg_info = &frame->call->func->op_array.arg_info[opline->op2.num - 1];
2185
0
              if (ZEND_TYPE_IS_SET(arg_info->type)) {
2186
0
                zend_class_entry *ce;
2187
0
                uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2188
0
                info &= tmp;
2189
0
                if (!info) {
2190
0
                  break;
2191
0
                }
2192
0
              }
2193
0
            }
2194
0
            if (opline->op1_type == IS_CV && (info & MAY_BE_RC1)) {
2195
0
              info |= MAY_BE_RCN;
2196
0
            }
2197
0
            if (info & MAY_BE_UNDEF) {
2198
0
              info |= MAY_BE_NULL;
2199
0
              info &= ~MAY_BE_UNDEF;
2200
0
            }
2201
0
            if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2202
0
              info |= MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_KEY_ANY;
2203
0
            }
2204
0
            SET_STACK_INFO(frame->call->stack, opline->op2.num - 1, info);
2205
0
          }
2206
290
          break;
2207
2.38k
        case ZEND_RETURN:
2208
2.38k
          ADD_OP1_TRACE_GUARD();
2209
          /* Propagate return value types */
2210
2.38k
          if (opline->op1_type == IS_UNUSED) {
2211
0
            return_value_info.type = MAY_BE_NULL;
2212
2.38k
          } else if (opline->op1_type == IS_CONST) {
2213
2.38k
            return_value_info.type = _const_op_type(RT_CONSTANT(opline, opline->op1));
2214
2.38k
          } else {
2215
0
            ZEND_ASSERT(ssa_ops[idx].op1_use >= 0);
2216
0
            return_value_info = ssa_var_info[ssa_ops[idx].op1_use];
2217
0
            if (return_value_info.type & MAY_BE_UNDEF) {
2218
0
              return_value_info.type &= ~MAY_BE_UNDEF;
2219
0
              return_value_info.type |= MAY_BE_NULL;
2220
0
            }
2221
0
            if (return_value_info.type & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) {
2222
              /* CVs are going to be destructed and the reference-counter
2223
                 of return value may be decremented to 1 */
2224
0
              return_value_info.type |= MAY_BE_RC1;
2225
0
            }
2226
0
            return_value_info.type &= ~MAY_BE_GUARD;
2227
0
          }
2228
2.38k
          break;
2229
2.38k
        case ZEND_CHECK_FUNC_ARG:
2230
2
          if (!frame
2231
2
           || !frame->call
2232
2
           || !frame->call->func) {
2233
0
            break;
2234
0
          }
2235
2
          if (opline->op2_type == IS_CONST
2236
2
           || opline->op2.num > MAX_ARG_FLAG_NUM) {
2237
            /* Named parameters not supported in JIT */
2238
0
            TRACE_FRAME_SET_LAST_SEND_UNKNOWN(frame->call);
2239
0
            break;
2240
0
          }
2241
2
          if (ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2242
0
            TRACE_FRAME_SET_LAST_SEND_BY_REF(frame->call);
2243
2
          } else {
2244
2
            TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame->call);
2245
2
          }
2246
2
          break;
2247
0
        case ZEND_FETCH_OBJ_FUNC_ARG:
2248
0
          if (!frame
2249
0
           || !frame->call
2250
0
           || !frame->call->func
2251
0
           || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame->call)) {
2252
0
            break;
2253
0
          }
2254
0
          ZEND_FALLTHROUGH;
2255
45
        case ZEND_FETCH_OBJ_R:
2256
46
        case ZEND_FETCH_OBJ_IS:
2257
46
        case ZEND_FETCH_OBJ_W:
2258
46
          if (opline->op2_type != IS_CONST
2259
43
           || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2260
43
           || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
2261
4
            break;
2262
4
          }
2263
42
          if (opline->op1_type != IS_UNUSED && op1_type == IS_OBJECT) {
2264
4
            ADD_OP1_TRACE_GUARD();
2265
4
          }
2266
42
          break;
2267
2
        case ZEND_INIT_METHOD_CALL:
2268
2
          if (opline->op2_type != IS_CONST
2269
2
           || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
2270
0
            break;
2271
0
          }
2272
2
          ADD_OP1_TRACE_GUARD();
2273
2
          break;
2274
1
        case ZEND_INIT_DYNAMIC_CALL:
2275
1
          if (orig_op2_type == IS_OBJECT && op2_ce == zend_ce_closure) {
2276
1
            ADD_OP2_TRACE_GUARD();
2277
1
          }
2278
1
          break;
2279
0
        case ZEND_SEND_ARRAY:
2280
0
        case ZEND_SEND_UNPACK:
2281
0
        case ZEND_CHECK_UNDEF_ARGS:
2282
90
        case ZEND_INCLUDE_OR_EVAL:
2283
90
          max_used_stack = used_stack = -1;
2284
90
          break;
2285
0
        case ZEND_TYPE_CHECK:
2286
0
          if (opline->extended_value == MAY_BE_RESOURCE) {
2287
            // TODO: support for is_resource() ???
2288
0
            break;
2289
0
          }
2290
0
          if (op1_type != IS_UNKNOWN
2291
0
           && (opline->extended_value == (1 << op1_type)
2292
0
            || opline->extended_value == MAY_BE_ANY - (1 << op1_type))) {
2293
            /* add guards only for exact checks, to avoid code duplication */
2294
0
            ADD_OP1_TRACE_GUARD();
2295
0
          }
2296
0
          break;
2297
59
        case ZEND_ROPE_INIT:
2298
179
        case ZEND_ROPE_ADD:
2299
238
        case ZEND_ROPE_END:
2300
238
          if (op2_type == IS_STRING) {
2301
0
            ADD_OP2_TRACE_GUARD();
2302
0
          }
2303
238
          break;
2304
1.74k
        default:
2305
1.74k
          break;
2306
8.95k
      }
2307
8.95k
      len = zend_jit_trace_op_len(opline);
2308
8.95k
      if (ssa->var_info) {
2309
        /* Add statically inferred ranges */
2310
61
        if (ssa_ops[idx].op1_def >= 0) {
2311
21
          zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2312
21
        }
2313
61
        if (ssa_ops[idx].op2_def >= 0) {
2314
6
          zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2315
6
        }
2316
61
        if (ssa_ops[idx].result_def >= 0) {
2317
36
          zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2318
36
        }
2319
61
        if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2320
0
          if (ssa_ops[idx+1].op1_def >= 0) {
2321
0
            zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2322
0
          }
2323
0
          if (ssa_ops[idx+1].op2_def >= 0) {
2324
0
            zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2325
0
          }
2326
0
          if (ssa_ops[idx+1].result_def >= 0) {
2327
0
            zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2328
0
          }
2329
0
        }
2330
8.88k
      } else {
2331
8.88k
        if (ssa_ops[idx].op1_def >= 0) {
2332
644
          ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2333
644
          if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2334
2
            zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2335
2
          }
2336
644
        }
2337
8.88k
        if (ssa_ops[idx].op2_def >= 0) {
2338
82
          ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2339
82
          if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2340
1
            zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2341
1
          }
2342
82
        }
2343
8.88k
        if (ssa_ops[idx].result_def >= 0) {
2344
3.36k
          ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2345
3.36k
          if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2346
3.36k
            zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2347
3.36k
          }
2348
3.36k
        }
2349
8.88k
        if (len == 2 && (opline+1)->opcode == ZEND_OP_DATA) {
2350
242
          if (ssa_ops[idx+1].op1_def >= 0) {
2351
17
            ssa_vars[ssa_ops[idx+1].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op1.var));
2352
17
            if (ssa_ops[idx+1].op1_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op1_use].type & MAY_BE_REF)) {
2353
0
              zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2354
0
            }
2355
17
          }
2356
242
          if (ssa_ops[idx+1].op2_def >= 0) {
2357
0
            ssa_vars[ssa_ops[idx+1].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->op2.var));
2358
0
            if (ssa_ops[idx+1].op2_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op2_use].type & MAY_BE_REF)) {
2359
0
              zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2360
0
            }
2361
0
          }
2362
242
          if (ssa_ops[idx+1].result_def >= 0) {
2363
0
            ssa_vars[ssa_ops[idx+1].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM((opline+1)->result.var));
2364
0
            if (ssa_ops[idx+1].result_use < 0 || !(ssa_var_info[ssa_ops[idx+1].result_use].type & MAY_BE_REF)) {
2365
0
              zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2366
0
            }
2367
0
          }
2368
242
        }
2369
8.88k
      }
2370
8.95k
      if (opline->opcode == ZEND_RECV_INIT
2371
2
       && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2372
        /* RECV_INIT always copy the constant */
2373
2
        ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2374
8.94k
      } else if ((opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW)
2375
3
       && ssa_opcodes[idx + 1] == ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2376
0
        if (ssa_ops[idx].op2_use >= 0 && ssa_ops[idx].op2_def >= 0) {
2377
0
          ssa_var_info[ssa_ops[idx].op2_def] = ssa_var_info[ssa_ops[idx].op2_use];
2378
0
        }
2379
0
        if (ssa_ops[idx].result_use >= 0 && ssa_ops[idx].result_def >= 0) {
2380
0
          ssa_var_info[ssa_ops[idx].result_def] = ssa_var_info[ssa_ops[idx].result_use];
2381
0
        }
2382
8.94k
      } else {
2383
8.94k
        if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2384
          // TODO:
2385
0
          assert(0);
2386
0
        }
2387
8.94k
        if (opline->opcode == ZEND_ASSIGN_DIM_OP
2388
153
         && ssa_ops[idx].op1_def >= 0
2389
143
         && op1_type == IS_ARRAY
2390
30
         && (orig_op1_type & IS_TRACE_PACKED)
2391
11
         && val_type != IS_UNKNOWN
2392
5
         && val_type != IS_UNDEF
2393
2
         && ((opline->op2_type == IS_CONST
2394
0
           && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
2395
2
          || (opline->op2_type != IS_CONST
2396
2
           && op2_type == IS_LONG))) {
2397
0
          zend_ssa_var_info *info = &ssa_var_info[ssa_ops[idx].op1_def];
2398
2399
0
          info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
2400
0
        }
2401
8.94k
      }
2402
8.95k
      if (ssa->var_info) {
2403
        /* Add statically inferred restrictions */
2404
61
        if (ssa_ops[idx].op1_def >= 0) {
2405
21
          if (opline->opcode == ZEND_SEND_VAR_EX
2406
0
           && frame
2407
0
           && frame->call
2408
0
           && frame->call->func
2409
0
           && !ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
2410
0
            ssa_var_info[ssa_ops[idx].op1_def] = ssa_var_info[ssa_ops[idx].op1_use];
2411
0
            ssa_var_info[ssa_ops[idx].op1_def].type &= ~MAY_BE_GUARD;
2412
0
            if (ssa_var_info[ssa_ops[idx].op1_def].type & MAY_BE_RC1) {
2413
0
              ssa_var_info[ssa_ops[idx].op1_def].type |= MAY_BE_RCN;
2414
0
            }
2415
21
          } else {
2416
21
            zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2417
21
          }
2418
21
        }
2419
61
        if (ssa_ops[idx].op2_def >= 0) {
2420
6
          if ((opline->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_FE_FETCH_RW)
2421
6
           || ssa_opcodes[idx + 1] != ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value)) {
2422
6
            zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2423
6
          }
2424
6
        }
2425
61
        if (ssa_ops[idx].result_def >= 0) {
2426
36
          zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2427
36
        }
2428
61
      }
2429
8.95k
      idx++;
2430
9.19k
      while (len > 1) {
2431
245
        opline++;
2432
245
        if (opline->opcode != ZEND_OP_DATA) {
2433
3
          if (ssa->var_info) {
2434
            /* Add statically inferred ranges */
2435
0
            if (ssa_ops[idx].op1_def >= 0) {
2436
0
              zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2437
0
            }
2438
0
            if (ssa_ops[idx].op2_def >= 0) {
2439
0
              zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2440
0
            }
2441
0
            if (ssa_ops[idx].result_def >= 0) {
2442
0
              zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2443
0
            }
2444
3
          } else {
2445
3
            if (ssa_ops[idx].op1_def >= 0) {
2446
0
              ssa_vars[ssa_ops[idx].op1_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op1.var));
2447
0
              if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].type & MAY_BE_REF)) {
2448
0
                zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2449
0
              }
2450
0
            }
2451
3
            if (ssa_ops[idx].op2_def >= 0) {
2452
0
              ssa_vars[ssa_ops[idx].op2_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->op2.var));
2453
0
              if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].type & MAY_BE_REF)) {
2454
0
                zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2455
0
              }
2456
0
            }
2457
3
            if (ssa_ops[idx].result_def >= 0) {
2458
0
              ssa_vars[ssa_ops[idx].result_def].alias = zend_jit_var_may_alias(op_array, ssa, EX_VAR_TO_NUM(opline->result.var));
2459
0
              if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].type & MAY_BE_REF)) {
2460
0
                zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2461
0
              }
2462
0
            }
2463
3
          }
2464
3
          if (opline->opcode == ZEND_RECV_INIT
2465
0
           && !(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2466
            /* RECV_INIT always copy the constant */
2467
0
            ssa_var_info[ssa_ops[idx].result_def].type = _const_op_type(RT_CONSTANT(opline, opline->op2));
2468
3
          } else {
2469
3
            if (zend_update_type_info(op_array, tssa, script, (zend_op*)opline, ssa_ops + idx, ssa_opcodes, optimization_level) == FAILURE) {
2470
              // TODO:
2471
0
              assert(0);
2472
0
            }
2473
3
          }
2474
3
        }
2475
245
        if (ssa->var_info) {
2476
          /* Add statically inferred restrictions */
2477
0
          if (ssa_ops[idx].op1_def >= 0) {
2478
0
            zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2479
0
          }
2480
0
          if (ssa_ops[idx].op2_def >= 0) {
2481
0
            zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2482
0
          }
2483
0
          if (ssa_ops[idx].result_def >= 0) {
2484
0
            zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2485
0
          }
2486
0
        }
2487
245
        idx++;
2488
245
        len--;
2489
245
      }
2490
2491
8.95k
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
2492
17
      op_array = p->op_array;
2493
17
      jit_extension =
2494
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2495
17
      ssa = &jit_extension->func_info.ssa;
2496
2497
17
      call = frame->call;
2498
17
      if (!call) {
2499
        /* Trace missed INIT_FCALL opcode */
2500
0
        call = top;
2501
0
        TRACE_FRAME_INIT(call, op_array, 0, 0);
2502
0
        call->used_stack = 0;
2503
0
        top = zend_jit_trace_call_frame(top, op_array, 0);
2504
17
      } else {
2505
17
        ZEND_ASSERT(&call->func->op_array == op_array);
2506
17
      }
2507
17
      frame->call = call->prev;
2508
17
      call->prev = frame;
2509
17
      TRACE_FRAME_SET_RETURN_SSA_VAR(call, find_return_ssa_var(p - 1, ssa_ops + (idx - 1)));
2510
17
      frame = call;
2511
2512
17
      level++;
2513
17
      i = 0;
2514
17
      v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2515
54
      while (i < op_array->last_var) {
2516
37
        ssa_vars[v].var = i;
2517
37
        if (i < op_array->num_args) {
2518
2
          if (ssa->var_info
2519
2
           && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v, NULL)) {
2520
            /* pass */
2521
2
          } else {
2522
0
            ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2523
0
            if (op_array->arg_info) {
2524
0
              zend_arg_info *arg_info = &op_array->arg_info[i];
2525
0
              zend_class_entry *ce;
2526
0
              uint32_t tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
2527
2528
0
              if (ZEND_ARG_SEND_MODE(arg_info)) {
2529
0
                tmp |= MAY_BE_REF;
2530
0
              }
2531
0
              ssa_var_info[v].type = tmp;
2532
0
              ssa_var_info[v].ce = ce;
2533
0
              ssa_var_info[v].is_instanceof = 1;
2534
0
            } else {
2535
0
              ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2536
0
            }
2537
0
          }
2538
35
        } else {
2539
35
          if (ssa->vars) {
2540
31
            ssa_vars[v].no_val = ssa->vars[i].no_val;
2541
31
            ssa_vars[v].alias = ssa->vars[i].alias;
2542
31
          } else {
2543
4
            ssa_vars[v].alias = zend_jit_var_may_alias(op_array, ssa, i);
2544
4
          }
2545
35
          if (ssa_vars[v].alias == NO_ALIAS) {
2546
31
            ssa_var_info[v].type = MAY_BE_UNDEF;
2547
31
          } else {
2548
4
            ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2549
4
          }
2550
35
        }
2551
37
        if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
2552
37
         && i < op_array->num_args) {
2553
          /* Propagate argument type */
2554
2
          ssa_var_info[v].type &= STACK_INFO(frame->stack, i);
2555
2
        }
2556
37
        i++;
2557
37
        v++;
2558
37
      }
2559
2.92k
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
2560
17
      op_array = p->op_array;
2561
17
      jit_extension =
2562
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2563
17
      ssa = &jit_extension->func_info.ssa;
2564
17
      if (level == 0) {
2565
0
        i = 0;
2566
0
        v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
2567
0
        while (i < op_array->last_var) {
2568
0
          ssa_vars[v].var = i;
2569
0
          if (!ssa->var_info
2570
0
           || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v, NULL)) {
2571
0
            ssa_var_info[v].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2572
0
          }
2573
0
          i++;
2574
0
          v++;
2575
0
        }
2576
0
        while (i < op_array->last_var + op_array->T) {
2577
0
          ssa_vars[v].var = i;
2578
0
          if (!ssa->var_info
2579
0
           || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, v, NULL)) {
2580
0
            ssa_var_info[v].type = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
2581
0
          }
2582
0
          i++;
2583
0
          v++;
2584
0
        }
2585
0
        if (return_value_info.type != 0) {
2586
0
          zend_jit_trace_rec *q = p + 1;
2587
0
          while (q->op == ZEND_JIT_TRACE_INIT_CALL) {
2588
0
            q++;
2589
0
          }
2590
0
          if (q->op == ZEND_JIT_TRACE_VM
2591
0
           || (q->op == ZEND_JIT_TRACE_END
2592
0
            && q->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)) {
2593
0
            const zend_op *opline = q->opline - 1;
2594
0
            if (opline->result_type != IS_UNUSED) {
2595
0
              ssa_var_info[
2596
0
                ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info) +
2597
0
                EX_VAR_TO_NUM(opline->result.var)] = return_value_info;
2598
0
            }
2599
0
          }
2600
0
          memset(&return_value_info, 0, sizeof(return_value_info));
2601
0
        }
2602
17
      } else {
2603
17
        level--;
2604
17
        if (return_value_info.type != 0) {
2605
16
          if ((p+1)->op == ZEND_JIT_TRACE_VM) {
2606
16
            const zend_op *opline = (p+1)->opline - 1;
2607
16
            if (opline->result_type != IS_UNUSED) {
2608
0
              if (TRACE_FRAME_RETURN_SSA_VAR(frame) >= 0) {
2609
0
                ssa_var_info[TRACE_FRAME_RETURN_SSA_VAR(frame)] = return_value_info;
2610
0
              }
2611
0
            }
2612
16
          }
2613
16
          memset(&return_value_info, 0, sizeof(return_value_info));
2614
16
        }
2615
17
      }
2616
2617
17
      top = frame;
2618
17
      if (frame->prev) {
2619
17
        if (used_stack > 0) {
2620
0
          used_stack -= frame->used_stack;
2621
0
        }
2622
17
        frame = frame->prev;
2623
17
        ZEND_ASSERT(&frame->func->op_array == op_array);
2624
17
      } else {
2625
0
        max_used_stack = used_stack = -1;
2626
0
        frame = zend_jit_trace_ret_frame(frame, op_array);
2627
0
        TRACE_FRAME_INIT(frame, op_array, 0, 0);
2628
0
        TRACE_FRAME_SET_RETURN_SSA_VAR(frame, -1);
2629
0
        frame->used_stack = 0;
2630
0
      }
2631
2632
2.90k
    } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
2633
214
      call = top;
2634
214
      TRACE_FRAME_INIT(call, p->func, 0, 0);
2635
214
      call->prev = frame->call;
2636
214
      call->used_stack = 0;
2637
214
      frame->call = call;
2638
214
      top = zend_jit_trace_call_frame(top, p->op_array, ZEND_JIT_TRACE_NUM_ARGS(p->info));
2639
214
      if (p->func && p->func->type == ZEND_USER_FUNCTION) {
2640
77
        for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
2641
58
          SET_STACK_INFO(call->stack, i, -1);
2642
58
        }
2643
19
      }
2644
214
      if (used_stack >= 0
2645
0
       && !(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
2646
0
        if (p->func == NULL || (p-1)->op != ZEND_JIT_TRACE_VM) {
2647
0
          max_used_stack = used_stack = -1;
2648
0
        } else {
2649
0
          const zend_op *opline = (p-1)->opline;
2650
2651
0
          switch (opline->opcode) {
2652
0
            case ZEND_INIT_FCALL:
2653
0
            case ZEND_INIT_FCALL_BY_NAME:
2654
0
            case ZEND_INIT_NS_FCALL_BY_NAME:
2655
0
            case ZEND_INIT_METHOD_CALL:
2656
0
            case ZEND_INIT_DYNAMIC_CALL:
2657
0
            case ZEND_INIT_STATIC_METHOD_CALL:
2658
            //case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
2659
            //case ZEND_INIT_USER_CALL:
2660
            //case ZEND_NEW:
2661
0
              frame->used_stack = zend_vm_calc_used_stack(opline->extended_value, (zend_function*)p->func);
2662
0
              used_stack += frame->used_stack;
2663
0
              if (used_stack > max_used_stack) {
2664
0
                max_used_stack = used_stack;
2665
0
              }
2666
0
              break;
2667
0
            default:
2668
0
              max_used_stack = used_stack = -1;
2669
0
          }
2670
0
        }
2671
0
      }
2672
2.69k
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
2673
186
      call = frame->call;
2674
186
      if (call) {
2675
186
        top = call;
2676
186
        frame->call = call->prev;
2677
186
      }
2678
2679
186
      if (idx > 0
2680
186
       && ssa_ops[idx-1].result_def >= 0
2681
2
       && p->func
2682
0
       && (p->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)
2683
0
       && !(p->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
2684
0
        ZEND_ASSERT(ssa_opcodes[idx-1] == opline);
2685
0
        ZEND_ASSERT(opline->opcode == ZEND_DO_ICALL ||
2686
0
          opline->opcode == ZEND_DO_FCALL ||
2687
0
          opline->opcode == ZEND_DO_FCALL_BY_NAME);
2688
2689
0
        if (opline->result_type != IS_UNDEF) {
2690
0
          zend_class_entry *ce;
2691
0
          const zend_function *func = p->func;
2692
0
          zend_arg_info *ret_info = func->common.arg_info - 1;
2693
0
          uint32_t ret_type = zend_fetch_arg_info_type(NULL, ret_info, &ce);
2694
2695
0
          ssa_var_info[ssa_ops[idx-1].result_def].type &= ret_type;
2696
0
        }
2697
0
      }
2698
2.50k
    } else if (p->op == ZEND_JIT_TRACE_END) {
2699
2.50k
      break;
2700
2.50k
    }
2701
11.8k
  }
2702
2703
2.50k
  ((zend_tssa*)tssa)->used_stack = max_used_stack;
2704
2705
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2706
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2707
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2708
    /* Propagate guards through Phi sources */
2709
13
    zend_ssa_phi *phi = tssa->blocks[1].phis;
2710
2711
13
    op_array = trace_buffer->op_array;
2712
13
    jit_extension =
2713
13
      (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2714
13
    ssa = &jit_extension->func_info.ssa;
2715
2716
29
    while (phi) {
2717
16
      uint32_t t = ssa_var_info[phi->ssa_var].type;
2718
2719
16
      if ((t & MAY_BE_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2720
0
        uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2721
0
        uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2722
2723
0
        if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2724
0
          if (!((t0 | t1) & MAY_BE_GUARD)) {
2725
0
            ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2726
0
          }
2727
0
        } else if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2728
0
          if (!(t1 & MAY_BE_GUARD)
2729
0
           || is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2730
0
            ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2731
0
            t0 = (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2732
0
              (t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2733
0
              MAY_BE_GUARD;
2734
0
            if (!(t0 & MAY_BE_ARRAY)) {
2735
0
              t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2736
0
            }
2737
0
            if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2738
0
              t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2739
0
            }
2740
0
            ssa_var_info[phi->sources[0]].type = t0;
2741
0
            ssa_var_info[phi->sources[0]].type = t0;
2742
0
          }
2743
0
        } else {
2744
0
          if ((t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2745
0
            t0 = (t & t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2746
0
              (t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2747
0
              MAY_BE_GUARD;
2748
0
            if (!(t0 & MAY_BE_ARRAY)) {
2749
0
              t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2750
0
            }
2751
0
            if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2752
0
              t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2753
0
            }
2754
0
            ssa_var_info[phi->sources[0]].type = t0;
2755
0
          }
2756
0
          if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
2757
0
            if (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0
2758
0
             && is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
2759
0
              t1 = (t & t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2760
0
                (t1 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
2761
0
                MAY_BE_GUARD;
2762
0
              if (!(t1 & MAY_BE_ARRAY)) {
2763
0
                t1 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
2764
0
              }
2765
0
              if (!(t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
2766
0
                t1 &= ~(MAY_BE_RC1|MAY_BE_RCN);
2767
0
              }
2768
0
              ssa_var_info[phi->sources[1]].type = t1;
2769
0
              ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
2770
0
            }
2771
0
          }
2772
0
        }
2773
0
        t = ssa_var_info[phi->ssa_var].type;
2774
0
      }
2775
2776
16
      if ((t & MAY_BE_PACKED_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
2777
0
        uint32_t t0 = ssa_var_info[phi->sources[0]].type;
2778
0
        uint32_t t1 = ssa_var_info[phi->sources[1]].type;
2779
2780
0
        if (((t0 | t1) & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2781
0
          if (!((t0 | t1) & MAY_BE_PACKED_GUARD)) {
2782
0
            ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2783
0
          }
2784
0
        } else if ((t1 & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
2785
0
          if (!(t1 & MAY_BE_PACKED_GUARD)) {
2786
0
            ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
2787
0
            ssa_var_info[phi->sources[0]].type =
2788
0
              (t0 & ~MAY_BE_ARRAY_KEY_ANY) | (t & MAY_BE_ARRAY_KEY_ANY) | MAY_BE_PACKED_GUARD;
2789
0
          }
2790
0
        }
2791
0
      }
2792
16
      phi = phi->next;
2793
16
    }
2794
13
  }
2795
2796
2.50k
  if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_TSSA)) {
2797
0
    if (parent_trace) {
2798
0
      fprintf(stderr, "---- TRACE %d TSSA start (side trace %d/%d) %s%s%s() %s:%d\n",
2799
0
        ZEND_JIT_TRACE_NUM,
2800
0
        parent_trace,
2801
0
        exit_num,
2802
0
        trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2803
0
        trace_buffer->op_array->scope ? "::" : "",
2804
0
        trace_buffer->op_array->function_name ?
2805
0
          ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2806
0
        ZSTR_VAL(trace_buffer->op_array->filename),
2807
0
        trace_buffer[1].opline->lineno);
2808
0
    } else {
2809
0
      fprintf(stderr, "---- TRACE %d TSSA start (%s) %s%s%s() %s:%d\n",
2810
0
        ZEND_JIT_TRACE_NUM,
2811
0
        zend_jit_trace_star_desc(trace_buffer->start),
2812
0
        trace_buffer->op_array->scope ? ZSTR_VAL(trace_buffer->op_array->scope->name) : "",
2813
0
        trace_buffer->op_array->scope ? "::" : "",
2814
0
        trace_buffer->op_array->function_name ?
2815
0
          ZSTR_VAL(trace_buffer->op_array->function_name) : "$main",
2816
0
        ZSTR_VAL(trace_buffer->op_array->filename),
2817
0
        trace_buffer[1].opline->lineno);
2818
0
    }
2819
0
    zend_jit_dump_trace(trace_buffer, tssa);
2820
0
    if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LINK) {
2821
0
      uint32_t idx = trace_buffer[1].last;
2822
0
      uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
2823
0
      fprintf(stderr, "---- TRACE %d TSSA stop (link to %d)\n",
2824
0
        ZEND_JIT_TRACE_NUM,
2825
0
        link_to);
2826
0
    } else {
2827
0
      fprintf(stderr, "---- TRACE %d TSSA stop (%s)\n",
2828
0
        ZEND_JIT_TRACE_NUM,
2829
0
        zend_jit_trace_stop_description[trace_buffer->stop]);
2830
0
    }
2831
0
  }
2832
2833
2.50k
  return tssa;
2834
2.50k
}
2835
2836
4.97k
#define RA_HAS_IVAL(var)          (ra[var].ref != 0)
2837
657
#define RA_IVAL_FLAGS(var)        ra[var].flags
2838
524
#define RA_IVAL_START(var, line)  do {ra[var].ref = IR_NULL;} while (0)
2839
#define RA_IVAL_END(var, line)
2840
#define RA_IVAL_CLOSE(var, line)
2841
205
#define RA_IVAL_DEL(var)          do {ra[var].ref = IR_UNUSED;} while (0)
2842
2.27k
#define RA_HAS_REG(var)           (ra[var].ref != 0)
2843
345
#define RA_REG_FLAGS(var)         ra[var].flags
2844
0
#define RA_REG_START(var, line)   do {ra[var].ref = IR_NULL;} while (0)
2845
2
#define RA_REG_DEL(var)           do {ra[var].ref = IR_UNUSED;} while (0)
2846
2847
static void zend_jit_trace_use_var(int line, int var, int def, int use_chain, zend_jit_reg_var *ra, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array, const zend_ssa *op_array_ssa)
2848
319
{
2849
319
  ZEND_ASSERT(RA_HAS_IVAL(var));
2850
319
  ZEND_ASSERT(!(RA_IVAL_FLAGS(var) & ZREG_LAST_USE));
2851
319
  RA_IVAL_END(var, line);
2852
319
  if (def >= 0) {
2853
2
    RA_IVAL_FLAGS(var) |= ZREG_LAST_USE;
2854
317
  } else if (use_chain < 0 && (RA_IVAL_FLAGS(var) & (ZREG_LOAD|ZREG_STORE))) {
2855
2
    RA_IVAL_FLAGS(var) |= ZREG_LAST_USE;
2856
315
  } else if (use_chain >= 0 && !zend_ssa_is_no_val_use(ssa_opcodes[use_chain], ssa->ops + use_chain, var)) {
2857
    /* pass */
2858
315
  } else if (op_array_ssa->vars) {
2859
18
    uint32_t use = ssa_opcodes[line] - op_array->opcodes;
2860
2861
18
    if (ssa->ops[line].op1_use == var) {
2862
9
      if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op1_use, use)) {
2863
9
        RA_IVAL_FLAGS(var) |= ZREG_LAST_USE;
2864
9
      }
2865
9
    } else if (ssa->ops[line].op2_use == var) {
2866
9
      if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].op2_use, use)) {
2867
9
        RA_IVAL_FLAGS(var) |= ZREG_LAST_USE;
2868
9
      }
2869
9
    } else if (ssa->ops[line].result_use == var) {
2870
0
      if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->ops[use].result_use, use)) {
2871
0
        RA_IVAL_FLAGS(var) |= ZREG_LAST_USE;
2872
0
      }
2873
0
    }
2874
18
  }
2875
319
}
2876
2877
static zend_jit_reg_var* zend_jit_trace_allocate_registers(zend_jit_trace_rec *trace_buffer, zend_ssa *ssa, uint32_t parent_trace, uint32_t exit_num)
2878
2.50k
{
2879
2.50k
  const zend_op **ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
2880
2.50k
  zend_jit_trace_rec *p;
2881
2.50k
  const zend_op_array *op_array;
2882
2.50k
  zend_jit_op_array_trace_extension *jit_extension;
2883
2.50k
  const zend_ssa *op_array_ssa;
2884
2.50k
  const zend_ssa_op *ssa_op;
2885
2.50k
  int i, j, idx, count, level;
2886
2.50k
  zend_jit_reg_var *ra;
2887
2.50k
  const zend_op_array **vars_op_array;
2888
2.50k
  void *checkpoint;
2889
2.50k
  zend_jit_trace_stack_frame *frame;
2890
2.50k
  zend_jit_trace_stack *stack;
2891
2.50k
  uint32_t parent_vars_count = parent_trace ?
2892
2.48k
    zend_jit_traces[parent_trace].exit_info[exit_num].stack_size : 0;
2893
2.50k
  zend_jit_trace_stack *parent_stack = parent_vars_count ?
2894
5
    zend_jit_traces[parent_trace].stack_map +
2895
2.50k
    zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset : NULL;
2896
2.50k
  checkpoint = zend_arena_checkpoint(CG(arena));
2897
2.50k
  ra = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_reg_var));
2898
2.50k
  vars_op_array = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_op_array*));
2899
2.50k
  memset(ZEND_VOIDP(vars_op_array), 0, sizeof(zend_op_array*) * ssa->vars_count);
2900
2901
2.50k
  op_array = trace_buffer->op_array;
2902
2.50k
  jit_extension =
2903
2.50k
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
2904
2.50k
  op_array_ssa = &jit_extension->func_info.ssa;
2905
2.50k
  frame = JIT_G(current_frame);
2906
2.50k
  frame->prev = NULL;
2907
2.50k
  frame->func = (const zend_function*)op_array;
2908
2.50k
  stack = frame->stack;
2909
2910
2.50k
  count = 0;
2911
2912
2.50k
  i = 0;
2913
2.50k
  j = op_array->last_var;
2914
2.50k
  if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
2915
33
    j += op_array->T;
2916
33
  }
2917
3.85k
  while (i < j) {
2918
1.34k
    SET_STACK_VAR(stack, i, i);
2919
1.34k
    vars_op_array[i] = op_array;
2920
    /* We don't start intervals for variables used in Phi */
2921
1.34k
    if ((ssa->vars[i].use_chain >= 0 /*|| ssa->vars[i].phi_use_chain*/)
2922
1.22k
     && !zend_ssa_is_no_val_use(ssa_opcodes[ssa->vars[i].use_chain], ssa->ops + ssa->vars[i].use_chain, i)
2923
1.09k
     && ssa->vars[i].alias == NO_ALIAS
2924
15
     && zend_jit_var_supports_reg(ssa, i)) {
2925
10
      RA_IVAL_START(i, 0);
2926
10
      if (i < parent_vars_count
2927
7
       && STACK_REG(parent_stack, i) != ZREG_NONE
2928
4
       && STACK_FLAGS(parent_stack, i) != ZREG_ZVAL_COPY
2929
10
       ) {
2930
        /* We will try to reuse register from parent trace */
2931
4
        RA_IVAL_FLAGS(i) = STACK_FLAGS(parent_stack, i);
2932
4
        count += 2;
2933
6
      } else {
2934
6
        RA_IVAL_FLAGS(i) = ZREG_LOAD;
2935
6
        count++;
2936
6
      }
2937
10
    }
2938
1.34k
    i++;
2939
1.34k
  }
2940
2941
2.50k
  if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
2942
2.47k
    j = op_array->last_var + op_array->T;
2943
4.45k
    while (i < j) {
2944
1.97k
      SET_STACK_VAR(stack, i, -1);
2945
1.97k
      i++;
2946
1.97k
    }
2947
2.47k
  }
2948
2949
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2950
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2951
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2952
13
    zend_ssa_phi *phi = ssa->blocks[1].phis;
2953
2954
29
    while (phi) {
2955
16
      SET_STACK_VAR(stack, phi->var, phi->ssa_var);
2956
16
      vars_op_array[phi->ssa_var] = op_array;
2957
16
      if (ssa->vars[phi->ssa_var].use_chain >= 0
2958
16
       && ssa->vars[phi->ssa_var].alias == NO_ALIAS
2959
0
       && zend_jit_var_supports_reg(ssa, phi->ssa_var)) {
2960
0
        RA_IVAL_START(phi->ssa_var, 0);
2961
0
        count++;
2962
0
      }
2963
16
      phi = phi->next;
2964
16
    }
2965
13
  }
2966
2967
2.50k
  p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
2968
2.50k
  level = 0;
2969
2.50k
  ssa_op = ssa->ops;
2970
2.50k
  idx = 0;
2971
12.0k
  for (;;p++) {
2972
12.0k
    if (p->op == ZEND_JIT_TRACE_VM) {
2973
8.95k
      const zend_op *opline = p->opline;
2974
8.95k
      int len;
2975
8.95k
      bool support_opline;
2976
2977
8.95k
      support_opline =
2978
8.95k
        zend_jit_opline_supports_reg(op_array, ssa, opline, ssa_op, p);
2979
2980
8.95k
      if (support_opline
2981
1.42k
       && opline->opcode == ZEND_ASSIGN
2982
168
       && opline->op1_type == IS_CV
2983
168
       && ssa_op->op1_def >= 0
2984
168
       && ssa->vars[ssa_op->op1_def].alias != NO_ALIAS) {
2985
        /* avoid register allocation in case of possibility of indirect modification*/
2986
162
        support_opline = false;
2987
162
      }
2988
2989
8.95k
      if (ssa_op->op1_use >= 0
2990
3.39k
       && RA_HAS_IVAL(ssa_op->op1_use)) {
2991
390
        if (!support_opline) {
2992
137
          RA_IVAL_DEL(ssa_op->op1_use);
2993
137
          count--;
2994
253
        } else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
2995
253
          zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain,
2996
253
            ra,
2997
253
            ssa, ssa_opcodes, op_array, op_array_ssa);
2998
253
          if (opline->op1_type != IS_CV) {
2999
246
            if (opline->opcode == ZEND_CASE
3000
246
             || opline->opcode == ZEND_CASE_STRICT
3001
246
             || opline->opcode == ZEND_SWITCH_LONG
3002
246
             || opline->opcode == ZEND_MATCH
3003
246
             || opline->opcode == ZEND_FETCH_LIST_R
3004
246
             || opline->opcode == ZEND_COPY_TMP
3005
246
             || opline->opcode == ZEND_SWITCH_STRING
3006
246
             || opline->opcode == ZEND_FE_FETCH_R
3007
246
             || opline->opcode == ZEND_FE_FETCH_RW
3008
246
             || opline->opcode == ZEND_FETCH_LIST_W
3009
246
             || opline->opcode == ZEND_VERIFY_RETURN_TYPE
3010
246
             || opline->opcode == ZEND_BIND_LEXICAL
3011
246
             || opline->opcode == ZEND_ROPE_ADD) {
3012
              /* The value is kept alive and may be used outside of the trace */
3013
0
              RA_IVAL_FLAGS(ssa_op->op1_use) |= ZREG_STORE;
3014
246
            } else {
3015
246
              RA_IVAL_FLAGS(ssa_op->op1_use) |= ZREG_LAST_USE;
3016
246
            }
3017
246
          }
3018
253
        }
3019
390
      }
3020
8.95k
      if (ssa_op->op2_use >= 0
3021
1.18k
       && ssa_op->op2_use != ssa_op->op1_use
3022
1.13k
       && RA_HAS_IVAL(ssa_op->op2_use)) {
3023
132
        if (!support_opline) {
3024
66
          RA_IVAL_DEL(ssa_op->op2_use);
3025
66
          count--;
3026
66
        } else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op2_use)) {
3027
66
          zend_jit_trace_use_var(idx, ssa_op->op2_use, ssa_op->op2_def, ssa_op->op2_use_chain,
3028
66
            ra,
3029
66
            ssa, ssa_opcodes, op_array, op_array_ssa);
3030
66
          if (opline->op2_type != IS_CV) {
3031
62
            RA_IVAL_FLAGS(ssa_op->op2_use) |= ZREG_LAST_USE;
3032
62
          }
3033
66
        }
3034
132
      }
3035
8.95k
      if (ssa_op->result_use >= 0
3036
21
       && ssa_op->result_use != ssa_op->op1_use
3037
14
       && ssa_op->result_use != ssa_op->op2_use
3038
14
       && RA_HAS_IVAL(ssa_op->result_use)) {
3039
0
        if (!support_opline) {
3040
0
          RA_IVAL_DEL(ssa_op->result_use);
3041
0
          count--;
3042
0
        } else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->result_use)) {
3043
0
          zend_jit_trace_use_var(idx, ssa_op->result_use, ssa_op->result_def, ssa_op->res_use_chain,
3044
0
            ra,
3045
0
            ssa, ssa_opcodes, op_array, op_array_ssa);
3046
0
        }
3047
0
      }
3048
3049
8.95k
      if (ssa_op->op1_def >= 0) {
3050
665
        RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->op1.var), idx);
3051
665
        SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
3052
665
      }
3053
8.95k
      if (ssa_op->op2_def >= 0) {
3054
88
        RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->op2.var), idx);
3055
88
        SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op2.var), ssa_op->op2_def);
3056
88
      }
3057
8.95k
      if (ssa_op->result_def >= 0) {
3058
3.39k
        RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->result.var), idx);
3059
3.39k
        SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
3060
3.39k
      }
3061
3062
8.95k
      if (support_opline) {
3063
1.26k
        if (ssa_op->result_def >= 0
3064
916
         && (ssa->vars[ssa_op->result_def].use_chain >= 0
3065
134
            || ssa->vars[ssa_op->result_def].phi_use_chain)
3066
782
         && ssa->vars[ssa_op->result_def].alias == NO_ALIAS
3067
782
         && zend_jit_var_supports_reg(ssa, ssa_op->result_def)) {
3068
505
          if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
3069
184
           || opline->opcode == ZEND_PRE_INC
3070
184
           || opline->opcode == ZEND_PRE_DEC
3071
184
           || opline->opcode == ZEND_POST_INC
3072
184
           || opline->opcode == ZEND_POST_DEC
3073
184
           || opline->opcode == ZEND_ADD
3074
150
           || opline->opcode == ZEND_SUB
3075
46
           || opline->opcode == ZEND_MUL
3076
0
           || opline->opcode == ZEND_FETCH_DIM_R
3077
0
           || opline->opcode == ZEND_FETCH_OBJ_R
3078
505
           || opline->opcode == ZEND_FETCH_CONSTANT) {
3079
505
            if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_DOUBLE)
3080
505
             || (opline->opcode != ZEND_PRE_INC && opline->opcode != ZEND_PRE_DEC)) {
3081
505
              vars_op_array[ssa_op->result_def] = op_array;
3082
505
              RA_IVAL_START(ssa_op->result_def, idx);
3083
505
              count++;
3084
505
            }
3085
505
          }
3086
505
        }
3087
1.26k
        if (ssa_op->op1_def >= 0
3088
84
         && (ssa->vars[ssa_op->op1_def].use_chain >= 0
3089
54
            || ssa->vars[ssa_op->op1_def].phi_use_chain)
3090
30
         && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
3091
6
         && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)
3092
6
         && (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
3093
2
          || opline->opcode == ZEND_PRE_INC
3094
2
          || opline->opcode == ZEND_PRE_DEC
3095
2
          || opline->opcode == ZEND_POST_INC
3096
6
          || opline->opcode == ZEND_POST_DEC)) {
3097
6
          vars_op_array[ssa_op->op1_def] = op_array;
3098
6
          RA_IVAL_START(ssa_op->op1_def, idx);
3099
6
          count++;
3100
6
        }
3101
1.26k
        if (ssa_op->op2_def >= 0
3102
6
         && (ssa->vars[ssa_op->op2_def].use_chain >= 0
3103
3
            || ssa->vars[ssa_op->op2_def].phi_use_chain)
3104
3
         && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS
3105
3
         && zend_jit_var_supports_reg(ssa, ssa_op->op2_def)
3106
3
         && !(ssa->var_info[ssa_op->op2_def].type & MAY_BE_GUARD)) {
3107
3
          vars_op_array[ssa_op->op2_def] = op_array;
3108
3
          RA_IVAL_START(ssa_op->op2_def, idx);
3109
3
          count++;
3110
3
        }
3111
1.26k
      }
3112
3113
8.95k
      len = zend_jit_trace_op_len(opline);
3114
8.95k
      switch (opline->opcode) {
3115
89
        case ZEND_ASSIGN_DIM:
3116
89
        case ZEND_ASSIGN_OBJ:
3117
89
        case ZEND_ASSIGN_STATIC_PROP:
3118
242
        case ZEND_ASSIGN_DIM_OP:
3119
242
        case ZEND_ASSIGN_OBJ_OP:
3120
242
        case ZEND_ASSIGN_STATIC_PROP_OP:
3121
242
        case ZEND_ASSIGN_OBJ_REF:
3122
242
        case ZEND_ASSIGN_STATIC_PROP_REF:
3123
242
        case ZEND_FRAMELESS_ICALL_3:
3124
          /* OP_DATA */
3125
242
          ssa_op++;
3126
242
          opline++;
3127
242
          if (ssa_op->op1_use >= 0
3128
93
           && RA_HAS_IVAL(ssa_op->op1_use)
3129
2
           && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->op1_use)) {
3130
2
            if (support_opline) {
3131
0
              zend_jit_trace_use_var(idx, ssa_op->op1_use, ssa_op->op1_def, ssa_op->op1_use_chain,
3132
0
                ra,
3133
0
                ssa, ssa_opcodes, op_array, op_array_ssa);
3134
0
              if (opline->op1_type != IS_CV) {
3135
0
                RA_IVAL_FLAGS(ssa_op->op1_use) |= ZREG_LAST_USE;
3136
0
              }
3137
2
            } else {
3138
2
              RA_IVAL_DEL(ssa_op->op1_use);
3139
2
              count--;
3140
2
            }
3141
2
          }
3142
242
          if (ssa_op->op1_def >= 0) {
3143
17
            RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->op1.var), idx);
3144
17
            SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
3145
17
            if (support_opline
3146
0
             && (ssa->vars[ssa_op->op1_def].use_chain >= 0
3147
0
                || ssa->vars[ssa_op->op1_def].phi_use_chain)
3148
0
             && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS
3149
0
             && zend_jit_var_supports_reg(ssa, ssa_op->op1_def)
3150
0
             && !(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)) {
3151
0
              vars_op_array[ssa_op->op1_def] = op_array;
3152
0
              RA_IVAL_START(ssa_op->op1_def, idx);
3153
0
              count++;
3154
0
            }
3155
17
          }
3156
242
          ssa_op++;
3157
242
          opline++;
3158
242
          idx+=2;
3159
242
          break;
3160
2
        case ZEND_RECV_INIT:
3161
2
            ssa_op++;
3162
2
          opline++;
3163
2
          idx++;
3164
2
          while (opline->opcode == ZEND_RECV_INIT) {
3165
            /* RECV_INIT doesn't support registers */
3166
0
            if (ssa_op->result_use >= 0 && RA_HAS_IVAL(ssa_op->result_use)) {
3167
0
              RA_IVAL_DEL(ssa_op->result_use);
3168
0
              count--;
3169
0
            }
3170
0
            if (ssa_op->result_def >= 0) {
3171
0
              RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->result.var), idx);
3172
0
              SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->result.var), ssa_op->result_def);
3173
0
            }
3174
0
            ssa_op++;
3175
0
            opline++;
3176
0
            idx++;
3177
0
          }
3178
2
          break;
3179
3
        case ZEND_BIND_GLOBAL:
3180
3
          ssa_op++;
3181
3
          opline++;
3182
3
          idx++;
3183
3
          while (opline->opcode == ZEND_BIND_GLOBAL) {
3184
            /* BIND_GLOBAL doesn't support registers */
3185
0
            if (ssa_op->op1_def >= 0) {
3186
0
              RA_IVAL_CLOSE(EX_VAR_TO_NUM(opline->op1.var), idx);
3187
0
              SET_STACK_VAR(stack, EX_VAR_TO_NUM(opline->op1.var), ssa_op->op1_def);
3188
0
            }
3189
0
            ssa_op++;
3190
0
            opline++;
3191
0
            idx++;
3192
0
          }
3193
3
          break;
3194
8.70k
        default:
3195
8.70k
          ssa_op += len;
3196
8.70k
          idx += len;
3197
8.70k
          break;
3198
8.95k
      }
3199
8.95k
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
3200
      /* New call frames */
3201
17
      zend_jit_trace_stack_frame *prev_frame = frame;
3202
3203
      /* Clear allocated registers */
3204
18
      for (i = 0; i < op_array->last_var + op_array->T; i++) {
3205
1
        j = STACK_VAR(stack, i);
3206
1
        if (j >= 0 && RA_HAS_IVAL(j) && !(RA_IVAL_FLAGS(j) & ZREG_LAST_USE)) {
3207
0
          RA_IVAL_DEL(j);
3208
0
          count--;
3209
0
        }
3210
1
      }
3211
3212
17
      frame = zend_jit_trace_call_frame(frame, op_array, 0);
3213
17
      frame->prev = prev_frame;
3214
17
      frame->func = (const zend_function*)p->op_array;
3215
17
      stack = frame->stack;
3216
17
      op_array = p->op_array;
3217
17
      jit_extension =
3218
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3219
17
      op_array_ssa = &jit_extension->func_info.ssa;
3220
17
      j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3221
54
      for (i = 0; i < op_array->last_var; i++) {
3222
37
        SET_STACK_VAR(stack, i, j);
3223
37
        vars_op_array[j] = op_array;
3224
37
        if (ssa->vars[j].use_chain >= 0
3225
37
         && ssa->vars[j].alias == NO_ALIAS
3226
33
         && zend_jit_var_supports_reg(ssa, j)) {
3227
0
          RA_IVAL_START(j, idx);
3228
0
          RA_IVAL_FLAGS(j) = ZREG_LOAD;
3229
0
          count++;
3230
0
        }
3231
37
        j++;
3232
37
      }
3233
36
      for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) {
3234
19
        SET_STACK_VAR(stack, i, -1);
3235
19
      }
3236
17
      level++;
3237
3.04k
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
3238
      /* Close exiting call frames */
3239
54
      for (i = 0; i < op_array->last_var; i++) {
3240
37
        RA_IVAL_CLOSE(i, idx-1);
3241
37
      }
3242
17
      op_array = p->op_array;
3243
17
      jit_extension =
3244
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
3245
17
      op_array_ssa = &jit_extension->func_info.ssa;
3246
17
      frame = zend_jit_trace_ret_frame(frame, op_array);
3247
17
      stack = frame->stack;
3248
17
      if (level == 0) {
3249
        /* New return frames */
3250
0
        frame->prev = NULL;
3251
0
        frame->func = (const zend_function*)op_array;
3252
0
        j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
3253
0
        for (i = 0; i < op_array->last_var + op_array->T; i++) {
3254
0
          SET_STACK_VAR(stack, i, j);
3255
0
          vars_op_array[j] = op_array;
3256
0
          if (ssa->vars[j].use_chain >= 0
3257
0
           && ssa->vars[j].alias == NO_ALIAS
3258
0
           && zend_jit_var_supports_reg(ssa, j)
3259
0
           && !(ssa->var_info[j].type & MAY_BE_GUARD)) {
3260
0
            RA_IVAL_START(j, idx);
3261
0
            RA_IVAL_FLAGS(j) = ZREG_LOAD;
3262
0
            count++;
3263
0
          }
3264
0
          j++;
3265
0
        }
3266
17
      } else {
3267
17
        level--;
3268
17
      }
3269
3.02k
    } else if (p->op == ZEND_JIT_TRACE_END) {
3270
2.50k
      break;
3271
2.50k
    }
3272
12.0k
  }
3273
3274
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3275
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3276
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3277
13
    zend_ssa_phi *phi = ssa->blocks[1].phis;
3278
3279
29
    while (phi) {
3280
16
      i = phi->sources[1];
3281
16
      if (RA_HAS_IVAL(i) && !ssa->vars[phi->ssa_var].no_val) {
3282
0
        RA_IVAL_END(i, idx);
3283
0
        RA_IVAL_FLAGS(i) &= ~ZREG_LAST_USE;
3284
0
      }
3285
16
      phi = phi->next;
3286
16
    }
3287
3288
13
    if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
3289
43
      for (i = 0; i < op_array->last_var; i++) {
3290
30
        if (RA_HAS_IVAL(i) && !ssa->vars[i].phi_use_chain) {
3291
0
          RA_IVAL_END(i, idx);
3292
0
          RA_IVAL_FLAGS(i) &= ~ZREG_LAST_USE;
3293
30
        } else {
3294
30
          RA_IVAL_CLOSE(i, idx);
3295
30
        }
3296
30
      }
3297
13
    }
3298
13
  }
3299
3300
2.50k
  if (count) {
3301
1.20k
    for (i = 0; i < ssa->vars_count; i++) {
3302
1.05k
      if (RA_HAS_REG(i)) {
3303
319
        if ((RA_REG_FLAGS(i) & ZREG_LOAD) &&
3304
2
            (RA_REG_FLAGS(i) & ZREG_LAST_USE) &&
3305
2
            (i >= parent_vars_count || STACK_REG(parent_stack, i) == ZREG_NONE) &&
3306
2
            zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0) {
3307
          /* skip life range with single use */
3308
2
          RA_REG_DEL(i);
3309
2
          count--;
3310
2
        }
3311
319
      }
3312
1.05k
    }
3313
153
  }
3314
3315
2.50k
  if (count) {
3316
    /* SSA resolution */
3317
152
    if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3318
145
     || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3319
145
     || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3320
7
      zend_ssa_phi *phi = ssa->blocks[1].phis;
3321
3322
17
      while (phi) {
3323
10
        int def = phi->ssa_var;
3324
10
        int use = phi->sources[1];
3325
3326
10
        if (RA_HAS_REG(def)) {
3327
0
          if (!RA_HAS_REG(use)) {
3328
0
            RA_REG_FLAGS(def) |= ZREG_LOAD;
3329
0
            if ((RA_REG_FLAGS(def) & ZREG_LAST_USE)
3330
0
             && ssa->vars[def].use_chain >= 0
3331
0
             && !ssa->vars[def].phi_use_chain
3332
0
             && zend_ssa_next_use(ssa->ops, def, ssa->vars[def].use_chain) < 0
3333
0
            ) {
3334
              /* remove interval used once */
3335
0
              RA_REG_DEL(def);
3336
0
              count--;
3337
0
            }
3338
0
          } else if ((ssa->var_info[def].type & MAY_BE_ANY) != (ssa->var_info[use].type & MAY_BE_ANY)) {
3339
0
            RA_REG_FLAGS(def) |= ZREG_LOAD;
3340
0
            RA_REG_FLAGS(use) |= ZREG_STORE;
3341
0
          } else {
3342
            /* trace-entry value */
3343
0
            use = phi->sources[0];
3344
0
            if (zend_jit_var_supports_reg(ssa, use)) {
3345
0
              ZEND_ASSERT(!RA_HAS_REG(use));
3346
0
              RA_REG_START(use, 0);
3347
0
              RA_REG_FLAGS(use) = ZREG_LOAD;
3348
0
              count++;
3349
0
            } else {
3350
0
              RA_REG_FLAGS(def) |= ZREG_LOAD;
3351
              /* back-edge value */
3352
0
              RA_REG_FLAGS(phi->sources[1]) |= ZREG_STORE;
3353
0
            }
3354
0
          }
3355
10
        } else if (RA_HAS_REG(use)) {
3356
0
          if (ssa->vars[use].use_chain >= 0) {
3357
0
            RA_REG_FLAGS(use) |= ZREG_STORE; // TODO: ext/opcache/tests/jit/reg_alloc_00[67].phpt ???
3358
0
          } else {
3359
0
            RA_REG_DEL(use);
3360
0
            count--;
3361
0
          }
3362
0
        }
3363
10
        phi = phi->next;
3364
10
      }
3365
145
    } else if (p->stop >= ZEND_JIT_TRACE_STOP_LINK) {
3366
71
      for (i = 0; i < op_array->last_var + op_array->T; i++) {
3367
60
        int var = STACK_VAR(stack, i);
3368
60
        if (var >= 0 && RA_HAS_REG(var)
3369
11
         && !(RA_REG_FLAGS(var) & (ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE))) {
3370
0
          RA_REG_FLAGS(var) |= ZREG_STORE;
3371
0
        }
3372
60
      }
3373
11
    }
3374
3375
152
    if (!count) {
3376
0
      zend_arena_release(&CG(arena), checkpoint);
3377
0
      return NULL;
3378
0
    }
3379
3380
152
    if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) {
3381
0
      fprintf(stderr, "---- TRACE %d Live Ranges \"%s\"\n", ZEND_JIT_TRACE_NUM, op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
3382
0
      for (i = 0; i < ssa->vars_count; i++) {
3383
0
        if (RA_HAS_REG(i)) {
3384
0
          fprintf(stderr, "#%d.", i);
3385
0
          uint32_t var_num = ssa->vars[i].var;
3386
0
          zend_dump_var(vars_op_array[i], (var_num < vars_op_array[i]->last_var ? IS_CV : 0), var_num);
3387
0
          if (RA_REG_FLAGS(i) & ZREG_LAST_USE) {
3388
0
            fprintf(stderr, " last_use");
3389
0
          }
3390
0
          if (RA_REG_FLAGS(i) & ZREG_LOAD) {
3391
0
            fprintf(stderr, " load");
3392
0
          }
3393
0
          if (RA_REG_FLAGS(i) & ZREG_STORE) {
3394
0
            fprintf(stderr, " store");
3395
0
          }
3396
0
          fprintf(stderr, "\n");
3397
0
        }
3398
0
      }
3399
0
      fprintf(stderr, "\n");
3400
0
    }
3401
3402
152
    return ra;
3403
152
  }
3404
3405
2.35k
  zend_arena_release(&CG(arena), checkpoint);
3406
2.35k
  return NULL;
3407
2.50k
}
3408
3409
static void zend_jit_trace_cleanup_stack(zend_jit_ctx *jit, zend_jit_trace_stack *stack, const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes)
3410
1.18k
{
3411
1.18k
  if (ssa_op->op1_use >= 0
3412
700
   && jit->ra[ssa_op->op1_use].ref
3413
263
   && (jit->ra[ssa_op->op1_use].flags & ZREG_LAST_USE)
3414
263
   && (ssa_op->op1_use_chain == -1
3415
263
    || zend_ssa_is_no_val_use(ssa_opcodes[ssa_op->op1_use_chain], ssa->ops + ssa_op->op1_use_chain, ssa_op->op1_use))) {
3416
263
    CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->op1.var));
3417
263
  }
3418
1.18k
  if (ssa_op->op2_use >= 0
3419
272
   && ssa_op->op2_use != ssa_op->op1_use
3420
256
   && jit->ra[ssa_op->op2_use].ref
3421
65
   && (jit->ra[ssa_op->op2_use].flags & ZREG_LAST_USE)
3422
65
   && (ssa_op->op2_use_chain == -1
3423
65
    || zend_ssa_is_no_val_use(ssa_opcodes[ssa_op->op2_use_chain], ssa->ops + ssa_op->op2_use_chain, ssa_op->op2_use))) {
3424
65
    CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->op2.var));
3425
65
  }
3426
1.18k
  if (ssa_op->result_use >= 0
3427
4
   && ssa_op->result_use != ssa_op->op1_use
3428
0
   && ssa_op->result_use != ssa_op->op2_use
3429
0
   && jit->ra[ssa_op->result_use].ref
3430
0
   && (jit->ra[ssa_op->result_use].flags & ZREG_LAST_USE)
3431
0
   && (ssa_op->res_use_chain == -1
3432
0
    || zend_ssa_is_no_val_use(ssa_opcodes[ssa_op->res_use_chain], ssa->ops + ssa_op->res_use_chain, ssa_op->result_use))) {
3433
0
    CLEAR_STACK_REF(stack, EX_VAR_TO_NUM(opline->result.var));
3434
0
  }
3435
1.18k
}
3436
3437
static void zend_jit_trace_setup_ret_counter(const zend_op *opline, size_t offset)
3438
90
{
3439
90
  zend_op *next_opline = (zend_op*)(opline + 1);
3440
3441
90
  if (JIT_G(hot_return) && !ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags) {
3442
90
    ZEND_ASSERT(zend_jit_ret_trace_counter_handler != NULL);
3443
90
    if (!ZEND_OP_TRACE_INFO(next_opline, offset)->counter) {
3444
90
      ZEND_OP_TRACE_INFO(next_opline, offset)->counter =
3445
90
        &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
3446
90
      ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
3447
90
    }
3448
90
    ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags = ZEND_JIT_TRACE_START_RETURN;
3449
90
    next_opline->handler = zend_jit_ret_trace_counter_handler;
3450
90
  }
3451
90
}
3452
3453
static bool zend_jit_may_delay_fetch_this(const zend_op_array *op_array, zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_ssa_op *ssa_op)
3454
0
{
3455
0
  int var = ssa_op->result_def;
3456
0
  int i;
3457
0
  int use = ssa->vars[var].use_chain;
3458
0
  const zend_op *opline;
3459
3460
0
  if (use < 0
3461
0
   || ssa->vars[var].phi_use_chain
3462
0
   || ssa->ops[use].op1_use != var
3463
0
   || ssa->ops[use].op1_use_chain != -1) {
3464
0
    return false;
3465
0
  }
3466
3467
0
  opline = ssa_opcodes[use];
3468
0
  if (opline->opcode == ZEND_INIT_METHOD_CALL) {
3469
0
    return (opline->op2_type == IS_CONST &&
3470
0
      Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING);
3471
0
  } else if (opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG) {
3472
0
    if (!JIT_G(current_frame)
3473
0
     || !JIT_G(current_frame)->call
3474
0
     || !JIT_G(current_frame)->call->func
3475
0
     || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
3476
0
      return false;
3477
0
    }
3478
0
  } else if (opline->opcode != ZEND_FETCH_OBJ_R
3479
0
      && opline->opcode != ZEND_FETCH_OBJ_IS
3480
0
      && opline->opcode != ZEND_FETCH_OBJ_W
3481
0
      && opline->opcode != ZEND_ASSIGN_OBJ
3482
0
      && opline->opcode != ZEND_ASSIGN_OBJ_OP
3483
0
      && opline->opcode != ZEND_PRE_INC_OBJ
3484
0
      && opline->opcode != ZEND_PRE_DEC_OBJ
3485
0
      && opline->opcode != ZEND_POST_INC_OBJ
3486
0
      && opline->opcode != ZEND_POST_DEC_OBJ) {
3487
0
    return false;
3488
0
  }
3489
3490
0
  if (opline->op2_type != IS_CONST
3491
0
   || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3492
0
   || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3493
0
    return false;
3494
0
  }
3495
3496
0
  if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
3497
0
    if (opline->op1_type == IS_CV
3498
0
     && (opline+1)->op1_type == IS_CV
3499
0
     && (opline+1)->op1.var == opline->op1.var) {
3500
      /* skip $a->prop += $a; */
3501
0
      return false;
3502
0
    }
3503
0
    if (!zend_jit_supported_binary_op(
3504
0
        opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
3505
0
      return false;
3506
0
    }
3507
0
  }
3508
3509
0
  for (i = ssa->vars[var].definition; i < use; i++) {
3510
0
    if (ssa_opcodes[i]->opcode == ZEND_DO_UCALL
3511
0
     || ssa_opcodes[i]->opcode == ZEND_DO_FCALL_BY_NAME
3512
0
     || ssa_opcodes[i]->opcode == ZEND_DO_FCALL
3513
0
     || ssa_opcodes[i]->opcode == ZEND_INCLUDE_OR_EVAL) {
3514
0
      return false;
3515
0
    }
3516
0
  }
3517
3518
0
  return true;
3519
0
}
3520
3521
static int zend_jit_trace_stack_needs_deoptimization(zend_jit_trace_stack *stack, uint32_t stack_size)
3522
7
{
3523
7
  uint32_t i;
3524
3525
46
  for (i = 0; i < stack_size; i++) {
3526
39
    if (STACK_FLAGS(stack, i) & ~(ZREG_LOAD|ZREG_STORE|ZREG_LAST_USE)) {
3527
0
      return 1;
3528
39
    } else if (STACK_REG(stack, i) != ZREG_NONE) {
3529
0
      return 1;
3530
0
    }
3531
39
  }
3532
7
  return 0;
3533
7
}
3534
3535
/* While a trace is being compiled, a register-allocated variable is tracked by
3536
 * its IR reference only (STACK_REG() is still ZREG_NONE). */
3537
static bool zend_jit_trace_stack_has_unstored_refs(zend_jit_trace_stack *stack, uint32_t stack_size)
3538
7
{
3539
7
  uint32_t i;
3540
3541
46
  for (i = 0; i < stack_size; i++) {
3542
39
    if (STACK_REF(stack, i) && !(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE))) {
3543
0
      return 1;
3544
0
    }
3545
39
  }
3546
7
  return 0;
3547
7
}
3548
3549
static int zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num, uint32_t exit_num)
3550
0
{
3551
0
  const zend_op *opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
3552
0
  uint32_t flags = zend_jit_traces[trace_num].exit_info[exit_num].flags;
3553
0
  uint32_t stack_size;
3554
0
  zend_jit_trace_stack *stack;
3555
3556
0
  if (opline || (flags & (ZEND_JIT_EXIT_RESTORE_CALL|ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2|ZEND_JIT_EXIT_CHECK_EXCEPTION))) {
3557
0
    return 1;
3558
0
  }
3559
3560
0
  stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
3561
0
  stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
3562
0
  return zend_jit_trace_stack_needs_deoptimization(stack, stack_size);
3563
0
}
3564
3565
static int zend_jit_trace_deoptimization(
3566
                                         zend_jit_ctx                   *jit,
3567
                                         const zend_jit_trace_exit_info *exit_info,
3568
                                         zend_jit_trace_stack           *parent_stack,
3569
                                         int                             parent_vars_count,
3570
                                         zend_ssa                       *ssa,
3571
                                         zend_jit_trace_stack           *stack,
3572
                                         zend_jit_exit_const            *constants,
3573
                                         bool                            polymorphic_side_trace)
3574
18
{
3575
18
  uint32_t flags = exit_info->flags;
3576
18
  const zend_op *opline = exit_info->opline;
3577
3578
18
  int i;
3579
18
  int check2 = -1;
3580
3581
  // TODO: Merge this loop with the following register LOAD loop to implement parallel move ???
3582
37
  for (i = 0; i < parent_vars_count; i++) {
3583
19
    int8_t reg = STACK_REG(parent_stack, i);
3584
3585
19
    if (STACK_FLAGS(parent_stack, i) == ZREG_CONST) {
3586
0
      uint8_t type = STACK_TYPE(parent_stack, i);
3587
3588
0
      if (type == IS_LONG) {
3589
0
        if (!zend_jit_store_const_long(jit, i,
3590
0
            (zend_long)constants[STACK_REF(parent_stack, i)].i)) {
3591
0
          return 0;
3592
0
        }
3593
0
      } else if (type == IS_DOUBLE) {
3594
0
        if (!zend_jit_store_const_double(jit, i,
3595
0
            constants[STACK_REF(parent_stack, i)].d)) {
3596
0
          return 0;
3597
0
        }
3598
0
      } else {
3599
0
        ZEND_UNREACHABLE();
3600
0
      }
3601
0
      if (stack) {
3602
0
        SET_STACK_TYPE(stack, i, type, 1);
3603
0
        if (jit->ra && jit->ra[i].ref) {
3604
0
          SET_STACK_REF(stack, i, jit->ra[i].ref);
3605
0
        }
3606
0
      }
3607
19
    } else if (STACK_FLAGS(parent_stack, i) == ZREG_TYPE_ONLY) {
3608
0
      ZEND_ASSERT(reg == ZREG_NONE);
3609
3610
0
      uint8_t type = STACK_TYPE(parent_stack, i);
3611
3612
0
      if (!zend_jit_store_type(jit, i, type)) {
3613
0
        return 0;
3614
0
      }
3615
0
      if (stack) {
3616
0
        SET_STACK_TYPE(stack, i, type, 1);
3617
0
      }
3618
19
    } else if (STACK_FLAGS(parent_stack, i) == ZREG_THIS) {
3619
0
      if (polymorphic_side_trace) {
3620
0
        ssa->var_info[i].delayed_fetch_this = 1;
3621
0
        if (stack) {
3622
0
          SET_STACK_REG_EX(stack, i, ZREG_NONE, ZREG_THIS);
3623
0
        }
3624
0
      } else if (!zend_jit_load_this(jit, EX_NUM_TO_VAR(i))) {
3625
0
        return 0;
3626
0
      }
3627
19
    } else if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_ADDREF) {
3628
0
      zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(i));
3629
0
      zend_jit_zval_try_addref(jit, dst);
3630
19
    } else if (STACK_FLAGS(parent_stack, i) == ZREG_ZVAL_COPY) {
3631
0
      ZEND_ASSERT(reg != ZREG_NONE);
3632
0
      ZEND_ASSERT(check2 == -1);
3633
0
      check2 = i;
3634
19
    } else if (STACK_FLAGS(parent_stack, i) & ZREG_SPILL_SLOT) {
3635
0
      if (ssa && ssa->vars[i].no_val) {
3636
        /* pass */
3637
0
      } else {
3638
0
        uint8_t type = STACK_TYPE(parent_stack, i);
3639
3640
0
        if (!zend_jit_store_spill_slot(jit, 1 << type, i, reg, STACK_REF(parent_stack, i),
3641
0
            STACK_MEM_TYPE(parent_stack, i) != type)) {
3642
0
          return 0;
3643
0
        }
3644
0
        if (stack) {
3645
0
          if (jit->ra && jit->ra[i].ref) {
3646
0
            SET_STACK_TYPE(stack, i, type, 0);
3647
0
            if ((STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) != 0) {
3648
0
              SET_STACK_REF_EX(stack, i, jit->ra[i].ref, ZREG_LOAD);
3649
0
            } else {
3650
0
              SET_STACK_REF(stack, i, jit->ra[i].ref);
3651
0
            }
3652
0
          } else {
3653
0
            SET_STACK_TYPE(stack, i, type, 1);
3654
0
          }
3655
0
        }
3656
0
      }
3657
19
    } else if (reg != ZREG_NONE) {
3658
4
      if (ssa && ssa->vars[i].no_val) {
3659
        /* pass */
3660
4
      } else {
3661
4
        uint8_t type = STACK_TYPE(parent_stack, i);
3662
3663
4
        if (!zend_jit_store_reg(jit, 1 << type, i, reg,
3664
4
            (STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) != 0,
3665
4
            STACK_MEM_TYPE(parent_stack, i) != type)) {
3666
0
          return 0;
3667
0
        }
3668
4
        if (stack) {
3669
4
          if (jit->ra && jit->ra[i].ref) {
3670
4
            SET_STACK_TYPE(stack, i, type, 0);
3671
4
            if ((STACK_FLAGS(parent_stack, i) & (ZREG_LOAD|ZREG_STORE)) != 0) {
3672
0
              SET_STACK_REF_EX(stack, i, jit->ra[i].ref, ZREG_LOAD);
3673
4
            } else {
3674
4
              SET_STACK_REF(stack, i, jit->ra[i].ref);
3675
4
            }
3676
4
          } else {
3677
0
            SET_STACK_TYPE(stack, i, type, 1);
3678
0
          }
3679
4
        }
3680
4
      }
3681
4
    }
3682
19
  }
3683
3684
18
  if (check2 != -1) {
3685
0
    int8_t reg = STACK_REG(parent_stack, check2);
3686
3687
0
    ZEND_ASSERT(STACK_FLAGS(parent_stack, check2) == ZREG_ZVAL_COPY);
3688
0
    ZEND_ASSERT(reg != ZREG_NONE);
3689
0
    if (!zend_jit_escape_if_undef(jit, check2, flags, opline, exit_info->op_array, reg)) {
3690
0
      return 0;
3691
0
    }
3692
0
    if (!zend_jit_restore_zval(jit, EX_NUM_TO_VAR(check2), reg)) {
3693
0
      return 0;
3694
0
    }
3695
0
  }
3696
3697
18
  if (flags & ZEND_JIT_EXIT_RESTORE_CALL) {
3698
0
    if (!zend_jit_save_call_chain(jit, -1)) {
3699
0
      return 0;
3700
0
    }
3701
0
  }
3702
3703
18
  if (flags & ZEND_JIT_EXIT_FREE_OP2) {
3704
0
    const zend_op *op = opline - 1;
3705
3706
0
    if (!zend_jit_free_op(jit, op, -1, op->op2.var)) {
3707
0
      return 0;
3708
0
    }
3709
0
  }
3710
3711
18
  if (flags & ZEND_JIT_EXIT_FREE_OP1) {
3712
0
    const zend_op *op = opline - 1;
3713
3714
0
    if (!zend_jit_free_op(jit, op, -1, op->op1.var)) {
3715
0
      return 0;
3716
0
    }
3717
0
  }
3718
3719
18
  if (flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2|ZEND_JIT_EXIT_CHECK_EXCEPTION)) {
3720
0
    zend_jit_check_exception(jit);
3721
0
  }
3722
3723
18
  if (flags & ZEND_JIT_EXIT_METHOD_CALL) {
3724
0
    jit->poly_func_ref = zend_jit_deopt_rload_spilled(jit, IR_ADDR,
3725
0
        exit_info->poly_func.reg, exit_info->poly_func.offset);
3726
0
    jit->poly_this_ref = zend_jit_deopt_rload_spilled(jit, IR_ADDR,
3727
0
        exit_info->poly_this.reg, exit_info->poly_this.offset);
3728
3729
0
    if (!polymorphic_side_trace) {
3730
0
      if (!zend_jit_free_trampoline(jit, jit->poly_func_ref)) {
3731
0
        return 0;
3732
0
      }
3733
0
    }
3734
0
  }
3735
3736
18
  return 1;
3737
18
}
3738
3739
static void zend_jit_trace_set_var_range(zend_ssa_var_info *info, zend_long min, zend_long max)
3740
0
{
3741
0
  info->has_range = 1;
3742
0
  info->range.min = min;
3743
0
  info->range.max = max;
3744
0
  info->range.underflow = 0;
3745
0
  info->range.overflow = 0;
3746
0
}
3747
3748
static void zend_jit_trace_update_condition_ranges(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, bool exit_if_true)
3749
3
{
3750
3
  zend_long op1_min, op1_max, op2_min, op2_max;
3751
3752
3
  if ((OP1_INFO() & MAY_BE_ANY) != MAY_BE_LONG
3753
3
   || (OP2_INFO() & MAY_BE_ANY) != MAY_BE_LONG) {
3754
3
    return;
3755
3
  }
3756
3757
0
  op1_min = OP1_MIN_RANGE();
3758
0
  op1_max = OP1_MAX_RANGE();
3759
0
  op2_min = OP2_MIN_RANGE();
3760
0
  op2_max = OP2_MAX_RANGE();
3761
3762
0
  switch (opline->opcode) {
3763
0
    case ZEND_IS_EQUAL:
3764
0
    case ZEND_CASE:
3765
0
    case ZEND_IS_IDENTICAL:
3766
0
    case ZEND_CASE_STRICT:
3767
0
    case ZEND_IS_NOT_IDENTICAL:
3768
0
      if (!exit_if_true) {
3769
        /* op1 == op2 */
3770
0
        if (ssa_op->op1_use >= 0) {
3771
0
          zend_jit_trace_set_var_range(
3772
0
            &ssa->var_info[ssa_op->op1_use],
3773
0
            MAX(op1_min, op2_min),
3774
0
            MIN(op1_max, op2_max));
3775
0
        }
3776
0
        if (ssa_op->op2_use >= 0) {
3777
0
          zend_jit_trace_set_var_range(
3778
0
            &ssa->var_info[ssa_op->op2_use],
3779
0
            MAX(op2_min, op1_min),
3780
0
            MIN(op2_max, op1_max));
3781
0
        }
3782
0
      }
3783
0
      break;
3784
0
    case ZEND_IS_NOT_EQUAL:
3785
0
      if (exit_if_true) {
3786
        /* op1 == op2 */
3787
0
        if (ssa_op->op1_use >= 0) {
3788
0
          zend_jit_trace_set_var_range(
3789
0
            &ssa->var_info[ssa_op->op1_use],
3790
0
            MAX(op1_min, op2_min),
3791
0
            MIN(op1_max, op2_max));
3792
0
        }
3793
0
        if (ssa_op->op2_use >= 0) {
3794
0
          zend_jit_trace_set_var_range(
3795
0
            &ssa->var_info[ssa_op->op2_use],
3796
0
            MAX(op2_min, op1_min),
3797
0
            MIN(op2_max, op1_max));
3798
0
        }
3799
0
      }
3800
0
      break;
3801
0
    case ZEND_IS_SMALLER_OR_EQUAL:
3802
0
      if (!exit_if_true) {
3803
        /* op1 <= op2 */
3804
0
        if (ssa_op->op1_use >= 0) {
3805
0
          zend_jit_trace_set_var_range(
3806
0
            &ssa->var_info[ssa_op->op1_use],
3807
0
            op1_min,
3808
0
            MIN(op1_max, op2_max));
3809
0
        }
3810
0
        if (ssa_op->op2_use >= 0) {
3811
0
          zend_jit_trace_set_var_range(
3812
0
            &ssa->var_info[ssa_op->op2_use],
3813
0
            MAX(op2_min, op1_min),
3814
0
            op2_max);
3815
0
        }
3816
0
      } else {
3817
        /* op1 > op2 */
3818
0
        if (ssa_op->op1_use >= 0) {
3819
0
          zend_jit_trace_set_var_range(
3820
0
            &ssa->var_info[ssa_op->op1_use],
3821
0
            op2_min != ZEND_LONG_MAX ? MAX(op1_min, op2_min + 1) : op1_min,
3822
0
            op1_max);
3823
0
        }
3824
0
        if (ssa_op->op2_use >= 0) {
3825
0
          zend_jit_trace_set_var_range(
3826
0
            &ssa->var_info[ssa_op->op2_use],
3827
0
            op2_min,
3828
0
            op1_max != ZEND_LONG_MIN ? MIN(op2_max, op1_max - 1) : op2_max);
3829
0
        }
3830
0
      }
3831
0
      break;
3832
0
    case ZEND_IS_SMALLER:
3833
0
      if (!exit_if_true) {
3834
        /* op1 < op2 */
3835
0
        if (ssa_op->op1_use >= 0) {
3836
0
          zend_jit_trace_set_var_range(
3837
0
            &ssa->var_info[ssa_op->op1_use],
3838
0
            op1_min,
3839
0
            op2_max != ZEND_LONG_MIN ? MIN(op1_max, op2_max - 1) : op1_max);
3840
0
        }
3841
0
        if (ssa_op->op2_use >= 0) {
3842
0
          zend_jit_trace_set_var_range(
3843
0
            &ssa->var_info[ssa_op->op2_use],
3844
0
            op1_min != ZEND_LONG_MAX ? MAX(op2_min, op1_min + 1) : op2_min,
3845
0
            op2_max);
3846
0
        }
3847
0
      } else {
3848
        /* op1 >= op2 */
3849
0
        if (ssa_op->op1_use >= 0) {
3850
0
          zend_jit_trace_set_var_range(
3851
0
            &ssa->var_info[ssa_op->op1_use],
3852
0
            MAX(op1_min, op2_min),
3853
0
            op1_max);
3854
0
        }
3855
0
        if (ssa_op->op2_use >= 0) {
3856
0
          zend_jit_trace_set_var_range(
3857
0
            &ssa->var_info[ssa_op->op2_use],
3858
0
            op2_min,
3859
0
            MIN(op2_max, op1_max));
3860
0
        }
3861
0
      }
3862
0
      break;
3863
0
  }
3864
0
}
3865
3866
static bool zend_jit_may_skip_comparison(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_ssa *ssa, const zend_op **ssa_opcodes, const zend_op_array *op_array)
3867
18
{
3868
18
  uint8_t prev_opcode;
3869
3870
18
  if (opline->op1_type == IS_CONST
3871
10
   && Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_LONG
3872
10
   && Z_LVAL_P(RT_CONSTANT(opline, opline->op1)) == 0) {
3873
6
    if (ssa_op->op2_use >= 0) {
3874
5
      if ((ssa_op-1)->op1_def == ssa_op->op2_use) {
3875
0
        ssa_op--;
3876
0
        opline = ssa_opcodes[ssa_op - ssa->ops];
3877
0
        prev_opcode = opline->opcode;
3878
0
        if (prev_opcode == ZEND_PRE_INC
3879
0
         || prev_opcode == ZEND_PRE_DEC
3880
0
         || prev_opcode == ZEND_POST_INC
3881
0
         || prev_opcode == ZEND_POST_DEC) {
3882
0
          return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3883
0
        }
3884
5
      } else if ((ssa_op-1)->result_def == ssa_op->op2_use) {
3885
5
        ssa_op--;
3886
5
        opline = ssa_opcodes[ssa_op - ssa->ops];
3887
5
        prev_opcode = opline->opcode;
3888
5
        if (prev_opcode == ZEND_ADD
3889
5
         || prev_opcode == ZEND_SUB) {
3890
5
          return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3891
5
            (OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3892
5
        }
3893
5
      }
3894
5
    }
3895
12
  } else if (opline->op2_type == IS_CONST
3896
5
   && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG
3897
5
   && Z_LVAL_P(RT_CONSTANT(opline, opline->op2)) == 0) {
3898
0
    if (ssa_op->op1_use >= 0) {
3899
0
      if ((ssa_op-1)->op1_def == ssa_op->op1_use) {
3900
0
        ssa_op--;
3901
0
        opline = ssa_opcodes[ssa_op - ssa->ops];
3902
0
        prev_opcode = opline->opcode;
3903
0
        if (prev_opcode == ZEND_PRE_INC
3904
0
         || prev_opcode == ZEND_PRE_DEC
3905
0
         || prev_opcode == ZEND_POST_INC
3906
0
         || prev_opcode == ZEND_POST_DEC) {
3907
0
          return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3908
0
        }
3909
0
      } else if ((ssa_op-1)->result_def == ssa_op->op1_use) {
3910
0
        ssa_op--;
3911
0
        opline = ssa_opcodes[ssa_op - ssa->ops];
3912
0
        prev_opcode = opline->opcode;
3913
0
        if (prev_opcode == ZEND_ADD
3914
0
         || prev_opcode == ZEND_SUB) {
3915
0
          return (OP1_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0 &&
3916
0
            (OP2_INFO() & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-MAY_BE_LONG)) == 0;
3917
0
        }
3918
0
      }
3919
0
    }
3920
12
  } else {
3921
12
    const zend_ssa_op *prev_ssa_op = ssa_op - 1;
3922
12
    prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3923
3924
12
    if ((prev_opcode == ZEND_JMPZ || prev_opcode == ZEND_JMPNZ)
3925
0
     && prev_ssa_op != ssa->ops
3926
0
     && prev_ssa_op->op1_use >= 0
3927
0
     && prev_ssa_op->op1_use == (prev_ssa_op-1)->result_def) {
3928
0
      prev_ssa_op--;
3929
0
      prev_opcode = ssa_opcodes[prev_ssa_op - ssa->ops]->opcode;
3930
0
    }
3931
3932
12
    if (ssa_op->op1_use == prev_ssa_op->op1_use
3933
2
     && ssa_op->op2_use == prev_ssa_op->op2_use) {
3934
0
      if (prev_opcode == ZEND_IS_EQUAL
3935
0
       || prev_opcode == ZEND_IS_NOT_EQUAL
3936
0
       || prev_opcode == ZEND_IS_SMALLER
3937
0
       || prev_opcode == ZEND_IS_SMALLER_OR_EQUAL
3938
0
       || prev_opcode == ZEND_CASE
3939
0
       || prev_opcode == ZEND_IS_IDENTICAL
3940
0
       || prev_opcode == ZEND_IS_NOT_IDENTICAL
3941
0
       || prev_opcode == ZEND_CASE_STRICT) {
3942
0
        if (ssa_op->op1_use < 0) {
3943
0
          if (RT_CONSTANT(opline, opline->op1) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op1)) {
3944
0
            return false;
3945
0
          }
3946
0
        }
3947
0
        if (ssa_op->op2_use < 0) {
3948
0
          if (RT_CONSTANT(opline, opline->op2) != RT_CONSTANT(&ssa_opcodes[prev_ssa_op - ssa->ops], ssa_opcodes[prev_ssa_op - ssa->ops]->op2)) {
3949
0
            return false;
3950
0
          }
3951
0
        }
3952
0
        return true;
3953
0
      }
3954
0
    }
3955
12
  }
3956
13
  return false;
3957
18
}
3958
3959
static bool zend_jit_trace_next_is_send_result(const zend_op              *opline,
3960
                                               zend_jit_trace_rec         *p,
3961
                                               zend_jit_trace_stack_frame *frame)
3962
348
{
3963
348
  if (opline->result_type == IS_TMP_VAR
3964
347
   && (p+1)->op == ZEND_JIT_TRACE_VM
3965
347
   && (p+1)->opline == opline + 1
3966
347
   && ((opline+1)->opcode == ZEND_SEND_VAL
3967
344
    || ((opline+1)->opcode == ZEND_SEND_VAL_EX
3968
0
     && frame
3969
0
     && frame->call
3970
0
     && frame->call->func
3971
0
     && !ARG_MUST_BE_SENT_BY_REF(frame->call->func, (opline+1)->op2.num)))
3972
3
   && (opline+1)->op1_type == IS_TMP_VAR
3973
3
   && (opline+1)->op2_type != IS_CONST /* Named parameters not supported in JIT */
3974
3
   && (opline+1)->op1.var == opline->result.var) {
3975
3976
3
    if (frame->call && frame->call->func) {
3977
3
      uint8_t res_type = (p+1)->op1_type;
3978
3979
3
      if (res_type != IS_UNKNOWN && !(res_type & IS_TRACE_REFERENCE) ) {
3980
3
        zend_jit_trace_send_type(opline+1, frame->call, res_type);
3981
3
      }
3982
3
    }
3983
3
    return true;
3984
3
  }
3985
345
  return false;
3986
348
}
3987
3988
static int zend_jit_find_ssa_var(const zend_op_array *op_array,
3989
                                 const zend_ssa      *ssa,
3990
                                 uint32_t             opline_num,
3991
                                 uint32_t             var_num)
3992
0
{
3993
0
  int ssa_var, b = ssa->cfg.map[opline_num];
3994
0
  const zend_basic_block *bb = ssa->cfg.blocks + b;
3995
0
  const zend_ssa_phi *phi;
3996
0
  const zend_ssa_op *ssa_op;
3997
0
  zend_worklist worklist;
3998
0
  ALLOCA_FLAG(use_heap)
3999
4000
0
  while (1) {
4001
0
    ssa_op = ssa->ops + opline_num;
4002
0
    ssa_var = ssa_op->result_def;
4003
0
    if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4004
0
      return ssa_var;
4005
0
    }
4006
0
    ssa_var = ssa_op->op2_def;
4007
0
    if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4008
0
      return ssa_var;
4009
0
    }
4010
0
    ssa_var = ssa_op->op1_def;
4011
0
    if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4012
0
      return ssa_var;
4013
0
    }
4014
0
    if (opline_num == bb->start) {
4015
0
      break;
4016
0
    }
4017
0
    opline_num--;
4018
0
  }
4019
0
  phi = ssa->blocks[b].phis;
4020
0
  ssa_var = -1;
4021
0
  while (phi) {
4022
0
    if (phi->var == var_num) {
4023
0
      ssa_var = phi->ssa_var;
4024
0
    }
4025
0
    phi = phi->next;
4026
0
  }
4027
0
  if (ssa_var >= 0) {
4028
0
    return ssa_var;
4029
0
  }
4030
4031
0
  if (!bb->predecessors_count) {
4032
0
    return -1;
4033
0
  }
4034
4035
0
  ZEND_WORKLIST_ALLOCA(&worklist, ssa->cfg.blocks_count, use_heap);
4036
4037
0
  for (uint32_t j = 0; j < bb->predecessors_count; j++) {
4038
0
    b = ssa->cfg.predecessors[bb->predecessor_offset + j];
4039
0
    zend_worklist_push(&worklist, b);
4040
0
  }
4041
4042
0
  while (zend_worklist_len(&worklist) != 0) {
4043
0
    b = zend_worklist_pop(&worklist);
4044
0
    bb = &ssa->cfg.blocks[b];
4045
0
    if (bb->len) {
4046
0
      opline_num = bb->start + bb->len - 1;
4047
0
      while (1) {
4048
0
        ssa_op = ssa->ops + opline_num;
4049
0
        ssa_var = ssa_op->result_def;
4050
0
        if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4051
0
          goto found;
4052
0
        }
4053
0
        ssa_var = ssa_op->op2_def;
4054
0
        if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4055
0
          goto found;
4056
0
        }
4057
0
        ssa_var = ssa_op->op1_def;
4058
0
        if (ssa_var >= 0 && ssa->vars[ssa_var].var == var_num) {
4059
0
          goto found;
4060
0
        }
4061
0
        if (opline_num == bb->start) {
4062
0
          break;
4063
0
        }
4064
0
        opline_num--;
4065
0
      }
4066
0
    }
4067
0
    phi = ssa->blocks[b].phis;
4068
0
    ssa_var = -1;
4069
0
    while (phi) {
4070
0
      if (phi->var == var_num) {
4071
0
        ssa_var = phi->ssa_var;
4072
0
      }
4073
0
      phi = phi->next;
4074
0
    }
4075
0
    if (ssa_var >= 0) {
4076
0
      goto found;
4077
0
    }
4078
0
    for (uint32_t j = 0; j < bb->predecessors_count; j++) {
4079
0
      b = ssa->cfg.predecessors[bb->predecessor_offset + j];
4080
0
      zend_worklist_push(&worklist, b);
4081
0
    }
4082
0
  }
4083
0
  ssa_var = -1;
4084
4085
0
found:
4086
0
  ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
4087
0
  return ssa_var;
4088
0
}
4089
4090
static bool zend_jit_trace_must_store_type(const zend_op_array *op_array,
4091
                                           const zend_ssa      *ssa,
4092
                                           uint32_t             opline_num,
4093
                                           uint32_t             var_num,
4094
                                           uint8_t              type)
4095
0
{
4096
0
  if (ssa->var_info) {
4097
0
    int ssa_var = zend_jit_find_ssa_var(op_array, ssa, opline_num, var_num);
4098
4099
0
    if (ssa_var >= 0) {
4100
0
      if ((ssa->var_info[ssa_var].type & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1U << type)) {
4101
0
        return false;
4102
0
      }
4103
0
    }
4104
0
  }
4105
0
  return true;
4106
0
}
4107
4108
static bool zend_jit_trace_may_throw(const zend_op       *opline,
4109
                                     const zend_ssa_op   *ssa_op,
4110
                                     const zend_op_array *op_array,
4111
                                     const zend_ssa      *ssa,
4112
                                     uint32_t             t1,
4113
                                     uint32_t             t2,
4114
                                     uint32_t             t3,
4115
                                     uint32_t             val_type)
4116
117
{
4117
117
    switch (opline->opcode) {
4118
117
    case ZEND_ASSIGN_DIM_OP:
4119
117
      if (opline->extended_value != ZEND_CONCAT
4120
102
       && val_type == IS_LONG
4121
3
       && (t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_ARRAY
4122
3
       && MAY_BE_PACKED_ONLY(t1)
4123
0
       && !(t1 & MAY_BE_ARRAY_OF_REF)
4124
0
       && (t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_LONG
4125
0
       && (t3 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_LONG) {
4126
0
        return false;
4127
0
      }
4128
117
      break;
4129
117
    default:
4130
0
      break;
4131
117
  }
4132
117
  return zend_may_throw_ex(opline, ssa_op, op_array, ssa, t1, t2);
4133
117
}
4134
4135
static zend_vm_opcode_handler_t zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
4136
2.50k
{
4137
2.50k
  zend_vm_opcode_handler_t handler = NULL;
4138
2.50k
  zend_jit_ctx ctx;
4139
2.50k
  zend_jit_ctx *jit = &ctx;
4140
2.50k
  zend_jit_reg_var *ra = NULL;
4141
2.50k
  zend_script *script = NULL;
4142
2.50k
  zend_string *name = NULL;
4143
2.50k
  void *checkpoint;
4144
2.50k
  const zend_op_array *op_array;
4145
2.50k
  zend_ssa *ssa, *op_array_ssa;
4146
2.50k
  const zend_op **ssa_opcodes;
4147
2.50k
  zend_jit_trace_rec *p;
4148
2.50k
  zend_jit_op_array_trace_extension *jit_extension;
4149
2.50k
  int num_op_arrays = 0;
4150
2.50k
  bool do_bailout = 0;
4151
2.50k
  zend_jit_trace_info *t;
4152
2.50k
  const zend_op_array *op_arrays[ZEND_JIT_TRACE_MAX_FUNCS];
4153
2.50k
  uint8_t smart_branch_opcode;
4154
2.50k
  const void *exit_addr;
4155
2.50k
  uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info, op1_mem_info;
4156
2.50k
  bool send_result = 0;
4157
2.50k
  bool skip_comparison;
4158
2.50k
  zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
4159
2.50k
  zend_class_entry *ce;
4160
2.50k
  bool ce_is_instanceof;
4161
2.50k
  bool on_this = 0;
4162
2.50k
  bool delayed_fetch_this = 0;
4163
2.50k
  bool avoid_refcounting = 0;
4164
2.50k
  bool polymorphic_side_trace =
4165
2.50k
    parent_trace &&
4166
18
    (zend_jit_traces[parent_trace].exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL);
4167
2.50k
  uint32_t i;
4168
2.50k
  zend_jit_trace_stack_frame *frame, *top, *call;
4169
2.50k
  zend_jit_trace_stack *stack;
4170
2.50k
  uint8_t res_type = IS_UNKNOWN;
4171
2.50k
  const zend_op *opline, *orig_opline;
4172
2.50k
  const zend_ssa_op *ssa_op, *orig_ssa_op;
4173
2.50k
  int checked_stack;
4174
2.50k
  int peek_checked_stack;
4175
2.50k
  uint32_t frame_flags = 0;
4176
4177
2.50k
  JIT_G(current_trace) = trace_buffer;
4178
4179
2.50k
  checkpoint = zend_arena_checkpoint(CG(arena));
4180
4181
2.50k
  zend_try {
4182
4183
2.50k
  ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays);
4184
4185
2.50k
  if (!ssa) {
4186
0
    goto jit_cleanup;
4187
0
  }
4188
4189
2.50k
  ssa_opcodes = ((zend_tssa*)ssa)->tssa_opcodes;
4190
4191
2.50k
  op_array = trace_buffer->op_array;
4192
2.50k
  opline = trace_buffer[1].opline;
4193
2.50k
  name = zend_jit_trace_name(op_array, opline->lineno);
4194
2.50k
  zend_jit_trace_start(&ctx, op_array, ssa, name, ZEND_JIT_TRACE_NUM,
4195
2.50k
    parent_trace ? &zend_jit_traces[parent_trace] : NULL, exit_num);
4196
2.50k
  ctx.trace = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
4197
4198
  /* Register allocation */
4199
2.50k
  if ((JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL))
4200
2.50k
   && JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4201
2.50k
    ctx.ra = ra = zend_jit_trace_allocate_registers(trace_buffer, ssa, parent_trace, exit_num);
4202
2.50k
  }
4203
4204
2.50k
  p = trace_buffer;
4205
2.50k
  ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
4206
2.50k
  op_array = p->op_array;
4207
2.50k
  frame = JIT_G(current_frame);
4208
2.50k
  top = zend_jit_trace_call_frame(frame, op_array, 0);
4209
2.50k
  TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
4210
2.50k
  frame->used_stack = checked_stack = peek_checked_stack = 0;
4211
2.50k
  stack = frame->stack;
4212
5.83k
  for (i = 0; i < op_array->last_var + op_array->T; i++) {
4213
3.32k
    SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4214
3.32k
  }
4215
4216
2.50k
  opline = p[1].opline;
4217
2.50k
  p += ZEND_JIT_TRACE_START_REC_SIZE;
4218
4219
2.50k
  jit_extension =
4220
2.50k
    (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
4221
2.50k
  op_array_ssa = &jit_extension->func_info.ssa;
4222
4223
2.50k
  if (!parent_trace) {
4224
2.48k
    zend_jit_set_last_valid_opline(&ctx, opline);
4225
2.48k
    zend_jit_track_last_valid_opline(&ctx);
4226
2.48k
  } else {
4227
18
    if (zend_jit_traces[parent_trace].exit_info[exit_num].opline == NULL) {
4228
0
      zend_jit_trace_opline_guard(&ctx, opline);
4229
18
    } else {
4230
18
      zend_jit_reset_last_valid_opline(&ctx);
4231
18
    }
4232
18
  }
4233
4234
2.50k
  if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4235
2.50k
    int last_var;
4236
2.50k
    int parent_vars_count = 0;
4237
2.50k
    zend_jit_trace_stack *parent_stack = NULL;
4238
2.50k
    int used_stack = ((zend_tssa*)ssa)->used_stack;
4239
4240
2.50k
    if (used_stack > 0) {
4241
0
      peek_checked_stack = used_stack;
4242
0
      if (!zend_jit_stack_check(&ctx, opline, used_stack)) {
4243
0
        goto jit_failure;
4244
0
      }
4245
0
    }
4246
4247
2.50k
    if (parent_trace) {
4248
18
      parent_vars_count = MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
4249
18
        op_array->last_var + op_array->T);
4250
18
      if (parent_vars_count) {
4251
5
        parent_stack =
4252
5
          zend_jit_traces[parent_trace].stack_map +
4253
5
          zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
4254
5
      }
4255
18
    }
4256
4257
2.50k
    last_var = op_array->last_var;
4258
2.50k
    if (trace_buffer->start != ZEND_JIT_TRACE_START_ENTER) {
4259
33
      last_var += op_array->T;
4260
33
    }
4261
4262
3.85k
    for (i = 0; i < last_var; i++) {
4263
1.34k
      uint32_t info = ssa->var_info[i].type;
4264
4265
1.34k
      if (!(info & MAY_BE_GUARD) && has_concrete_type(info)) {
4266
6
        uint8_t type, mem_type;
4267
4268
6
        type = concrete_type(info);
4269
6
        if (i < parent_vars_count
4270
6
         && STACK_TYPE(parent_stack, i) == type) {
4271
6
          mem_type = STACK_MEM_TYPE(parent_stack, i);
4272
6
          if (mem_type != IS_UNKNOWN) {
4273
6
            SET_STACK_TYPE(stack, i, mem_type, 1);
4274
6
          }
4275
6
          SET_STACK_TYPE(stack, i, type, 0);
4276
6
        } else {
4277
0
          SET_STACK_TYPE(stack, i, type, 1);
4278
0
        }
4279
1.34k
      } else if (ssa->vars[i].alias != NO_ALIAS) {
4280
1.26k
        SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
4281
1.26k
      } else if (i < parent_vars_count
4282
3
       && STACK_TYPE(parent_stack, i) != IS_UNKNOWN) {
4283
        /* This must be already handled by trace type inference */
4284
0
        ZEND_ASSERT(ssa->vars[i].use_chain < 0 && !ssa->vars[i].phi_use_chain);
4285
0
        SET_STACK_TYPE(stack, i, STACK_TYPE(parent_stack, i), 1);
4286
79
      } else if ((info & MAY_BE_GUARD) != 0
4287
8
       && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4288
6
        || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4289
6
        || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4290
0
         && EX_VAR_TO_NUM((opline-1)->result.var) == i))
4291
2
       && (ssa->vars[i].use_chain != -1
4292
0
        || (ssa->vars[i].phi_use_chain
4293
2
         && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_GUARD)))) {
4294
        /* Check loop-invariant variable type */
4295
2
        if (!zend_jit_type_guard(&ctx, opline, EX_NUM_TO_VAR(i), concrete_type(info))) {
4296
0
          goto jit_failure;
4297
0
        }
4298
2
        info &= ~MAY_BE_GUARD;
4299
2
        ssa->var_info[i].type = info;
4300
2
        SET_STACK_TYPE(stack, i, concrete_type(info), 1);
4301
77
      } else if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER
4302
0
       && op_array->function_name
4303
0
       && i >= op_array->num_args) {
4304
        /* This must be already handled by trace type inference */
4305
0
        ZEND_UNREACHABLE();
4306
        // SET_STACK_TYPE(stack, i, IS_UNDEF, 1);
4307
0
      }
4308
4309
1.34k
      if ((info & MAY_BE_PACKED_GUARD) != 0
4310
2
       && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4311
0
        || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4312
0
        || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4313
0
         && EX_VAR_TO_NUM((opline-1)->result.var) == i))
4314
2
       && (ssa->vars[i].use_chain != -1
4315
0
        || (ssa->vars[i].phi_use_chain
4316
2
         && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) {
4317
2
        ZEND_ASSERT(STACK_TYPE(stack, i) == IS_ARRAY);
4318
4319
2
        if (!zend_jit_packed_guard(&ctx, opline, EX_NUM_TO_VAR(i), info)) {
4320
0
          goto jit_failure;
4321
0
        }
4322
2
        info &= ~MAY_BE_PACKED_GUARD;
4323
2
        ssa->var_info[i].type = info;
4324
2
      }
4325
1.34k
    }
4326
4327
2.50k
    if (parent_trace) {
4328
      /* Deoptimization */
4329
18
      if (!zend_jit_trace_deoptimization(&ctx,
4330
18
          &zend_jit_traces[parent_trace].exit_info[exit_num],
4331
18
          parent_stack, parent_vars_count, ssa, stack,
4332
18
          zend_jit_traces[parent_trace].constants,
4333
18
          polymorphic_side_trace)) {
4334
0
        goto jit_failure;
4335
0
      }
4336
18
    }
4337
4338
2.50k
    if (ra
4339
152
     && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4340
152
     && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4341
307
      for (i = 0; i < last_var; i++) {
4342
155
        if (RA_HAS_REG(i)
4343
4
         && (RA_REG_FLAGS(i) & ZREG_LOAD) != 0
4344
0
         && ra[i].ref != STACK_REF(stack, i)
4345
155
        ) {
4346
4347
0
          if ((ssa->var_info[i].type & MAY_BE_GUARD) != 0) {
4348
0
            uint8_t op_type;
4349
4350
0
            ssa->var_info[i].type &= ~MAY_BE_GUARD;
4351
0
            op_type = concrete_type(ssa->var_info[i].type);
4352
0
            if (!zend_jit_type_guard(&ctx, opline, EX_NUM_TO_VAR(i), op_type)) {
4353
0
              goto jit_failure;
4354
0
            }
4355
0
            SET_STACK_TYPE(stack, i, op_type, 1);
4356
0
          }
4357
4358
0
          if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
4359
0
            if (!zend_jit_load_var(&ctx, ssa->var_info[i].type, i, i)) {
4360
0
              goto jit_failure;
4361
0
            }
4362
0
            SET_STACK_REF_EX(stack, i, ra[i].ref, ZREG_LOAD);
4363
0
          } else {
4364
0
            SET_STACK_REF_EX(stack, i, IR_NULL, ZREG_LOAD);
4365
0
          }
4366
0
        }
4367
155
      }
4368
152
    }
4369
2.50k
  }
4370
4371
2.50k
  if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4372
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4373
2.49k
   || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4374
4375
13
    jit->trace_loop_ref = zend_jit_trace_begin_loop(&ctx); /* start of of trace loop */
4376
4377
13
    if (ra) {
4378
7
      zend_ssa_phi *phi = ssa->blocks[1].phis;
4379
4380
      /* First try to insert IR Phi */
4381
17
      while (phi) {
4382
10
        if (RA_HAS_REG(phi->ssa_var)
4383
0
         && !(RA_REG_FLAGS(phi->ssa_var) & ZREG_LOAD)) {
4384
0
          zend_jit_trace_gen_phi(&ctx, phi);
4385
0
          SET_STACK_REF(stack, phi->var, ra[phi->ssa_var].ref);
4386
0
        }
4387
10
        phi = phi->next;
4388
10
      }
4389
4390
7
      phi = ssa->blocks[1].phis;
4391
17
      while (phi) {
4392
10
        if (RA_HAS_REG(phi->ssa_var)) {
4393
0
          if (RA_REG_FLAGS(phi->ssa_var) & ZREG_LOAD) {
4394
0
            uint32_t info = ssa->var_info[phi->ssa_var].type;
4395
4396
0
            if (info & MAY_BE_GUARD) {
4397
0
              if (!zend_jit_type_guard(&ctx, opline, EX_NUM_TO_VAR(phi->var), concrete_type(info))) {
4398
0
                goto jit_failure;
4399
0
              }
4400
0
              info &= ~MAY_BE_GUARD;
4401
0
              ssa->var_info[phi->ssa_var].type = info;
4402
0
              SET_STACK_TYPE(stack, phi->var, concrete_type(info), 1);
4403
0
            }
4404
0
            if (!zend_jit_load_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var)) {
4405
0
              goto jit_failure;
4406
0
            }
4407
0
            SET_STACK_REF_EX(stack, phi->var, ra[phi->ssa_var].ref, ZREG_LOAD);
4408
0
          } else if (RA_REG_FLAGS(phi->ssa_var) & ZREG_STORE) {
4409
4410
0
            if (!zend_jit_store_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var,
4411
0
                STACK_MEM_TYPE(stack, phi->var) != ssa->var_info[phi->ssa_var].type)) {
4412
0
              goto jit_failure;
4413
0
            }
4414
0
            SET_STACK_REF_EX(stack, phi->var, ra[phi->ssa_var].ref, ZREG_STORE);
4415
0
          } else {
4416
            /* Register has to be written back on side exit */
4417
0
            SET_STACK_REF(stack, phi->var, ra[phi->ssa_var].ref);
4418
0
          }
4419
0
        }
4420
10
        phi = phi->next;
4421
10
      }
4422
7
    }
4423
4424
//    if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4425
//      if (ra && dzend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T)) {
4426
//        uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
4427
//
4428
//        timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
4429
//        if (!timeout_exit_addr) {
4430
//          goto jit_failure;
4431
//        }
4432
//      }
4433
//    }
4434
4435
13
  }
4436
4437
2.50k
  ssa_op = (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) ? ssa->ops : NULL;
4438
11.8k
  for (;;p++) {
4439
11.8k
    if (p->op == ZEND_JIT_TRACE_VM) {
4440
8.94k
      uint8_t op1_type = p->op1_type;
4441
8.94k
      uint8_t op2_type = p->op2_type;
4442
8.94k
      uint8_t op3_type = p->op3_type;
4443
8.94k
      uint8_t orig_op1_type = op1_type;
4444
8.94k
      uint8_t orig_op2_type = op2_type;
4445
8.94k
      uint8_t val_type = IS_UNKNOWN;
4446
8.94k
      bool op1_indirect;
4447
8.94k
      zend_class_entry *op1_ce = NULL;
4448
8.94k
      zend_class_entry *op2_ce = NULL;
4449
8.94k
      bool gen_handler = false;
4450
4451
8.94k
      opline = p->opline;
4452
8.94k
      if (op1_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4453
5.87k
        op1_type = IS_UNKNOWN;
4454
5.87k
      }
4455
8.94k
      if (op1_type != IS_UNKNOWN) {
4456
3.07k
        op1_type &= ~IS_TRACE_PACKED;
4457
3.07k
      }
4458
8.94k
      if (op2_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4459
7.79k
        op2_type = IS_UNKNOWN;
4460
7.79k
      }
4461
8.94k
      if (op3_type & (IS_TRACE_REFERENCE|IS_TRACE_INDIRECT)) {
4462
8.85k
        op3_type = IS_UNKNOWN;
4463
8.85k
      }
4464
4465
8.94k
      if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
4466
49
        op1_ce = (zend_class_entry*)(p+1)->ce;
4467
49
        p++;
4468
49
      }
4469
8.94k
      if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
4470
14
        op2_ce = (zend_class_entry*)(p+1)->ce;
4471
14
        p++;
4472
14
      }
4473
8.94k
      if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
4474
55
        val_type = (p+1)->op1_type;
4475
55
        p++;
4476
55
      }
4477
4478
8.94k
      frame_flags = 0;
4479
4480
8.94k
      if (zend_jit_inc_call_level(opline->opcode)) {
4481
220
        frame->call_level++;
4482
220
      }
4483
4484
8.94k
      if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
4485
8.94k
        switch (opline->opcode) {
4486
59
          case ZEND_PRE_INC:
4487
64
          case ZEND_PRE_DEC:
4488
69
          case ZEND_POST_INC:
4489
70
          case ZEND_POST_DEC:
4490
70
            if (opline->op1_type != IS_CV) {
4491
9
              break;
4492
9
            }
4493
61
            op1_info = OP1_INFO();
4494
61
            CHECK_OP1_TRACE_TYPE();
4495
61
            if (!(op1_info & MAY_BE_LONG)) {
4496
41
              break;
4497
41
            }
4498
20
            if (opline->result_type != IS_UNUSED) {
4499
14
              res_use_info = zend_jit_trace_type_to_info(
4500
14
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)));
4501
14
              if (opline->result_type == IS_CV) {
4502
0
                res_use_info &= (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4503
0
              }
4504
14
              res_info = RES_INFO();
4505
14
              res_addr = RES_REG_ADDR();
4506
14
            } else {
4507
6
              res_use_info = -1;
4508
6
              res_info = -1;
4509
6
              res_addr = 0;
4510
6
            }
4511
20
            op1_def_info = OP1_DEF_INFO();
4512
20
            if (op1_def_info & MAY_BE_GUARD
4513
7
             && !has_concrete_type(op1_def_info)) {
4514
5
              op1_def_info &= ~MAY_BE_GUARD;
4515
5
            }
4516
20
            if (!zend_jit_inc_dec(&ctx, opline,
4517
20
                op1_info, OP1_REG_ADDR(),
4518
20
                op1_def_info, OP1_DEF_REG_ADDR(),
4519
20
                res_use_info, res_info,
4520
20
                res_addr,
4521
20
                (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4522
20
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
4523
0
              goto jit_failure;
4524
0
            }
4525
20
            if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4526
2
             && !(op1_info & MAY_BE_STRING)) {
4527
2
              ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4528
2
              if (opline->result_type != IS_UNUSED) {
4529
2
                ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4530
2
              }
4531
18
            } else if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD)
4532
0
             && !(op1_info & MAY_BE_STRING)) {
4533
0
              ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4534
0
              if (opline->result_type != IS_UNUSED) {
4535
0
                ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4536
0
              }
4537
0
            }
4538
20
            if (opline->result_type != IS_UNUSED
4539
14
             && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4540
10
             && !(op1_info & MAY_BE_STRING)) {
4541
10
              ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4542
10
            } else if (opline->result_type != IS_UNUSED
4543
4
             && (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD)
4544
0
             && !(res_info & MAY_BE_STRING)) {
4545
0
              ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4546
0
            }
4547
20
            goto done;
4548
92
          case ZEND_BW_OR:
4549
493
          case ZEND_BW_AND:
4550
500
          case ZEND_BW_XOR:
4551
539
          case ZEND_SL:
4552
551
          case ZEND_SR:
4553
962
          case ZEND_MOD:
4554
962
            op1_info = OP1_INFO();
4555
962
            CHECK_OP1_TRACE_TYPE();
4556
962
            op2_info = OP2_INFO();
4557
962
            CHECK_OP2_TRACE_TYPE();
4558
962
            if (!(op1_info & MAY_BE_LONG)
4559
687
             || !(op2_info & MAY_BE_LONG)) {
4560
687
              break;
4561
687
            }
4562
275
            res_addr = RES_REG_ADDR();
4563
275
            if (Z_MODE(res_addr) != IS_REG
4564
122
             && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4565
0
              send_result = 1;
4566
0
              res_use_info = -1;
4567
0
              res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4568
0
              if (!zend_jit_reuse_ip(&ctx)) {
4569
0
                goto jit_failure;
4570
0
              }
4571
275
            } else {
4572
275
              res_use_info = zend_jit_trace_type_to_info(
4573
275
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)));
4574
275
              if (opline->result_type == IS_CV) {
4575
0
                res_use_info &= (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4576
0
              }
4577
275
            }
4578
275
            res_info = RES_INFO();
4579
275
            if (!zend_jit_long_math(&ctx, opline,
4580
275
                op1_info, OP1_RANGE(), OP1_REG_ADDR(),
4581
275
                op2_info, OP2_RANGE(), OP2_REG_ADDR(),
4582
275
                res_use_info, res_info, res_addr,
4583
275
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
4584
0
              goto jit_failure;
4585
0
            }
4586
275
            goto done;
4587
275
          case ZEND_ADD:
4588
393
          case ZEND_SUB:
4589
577
          case ZEND_MUL:
4590
//          case ZEND_DIV: // TODO: check for division by zero ???
4591
577
            op1_info = OP1_INFO();
4592
577
            op1_addr = OP1_REG_ADDR();
4593
577
            op2_info = OP2_INFO();
4594
577
            op2_addr = OP2_REG_ADDR();
4595
577
            if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4596
172
              if (op1_type == IS_LONG || op1_type == IS_DOUBLE) {
4597
33
                CHECK_OP1_TRACE_TYPE();
4598
33
              }
4599
172
              if (op2_type == IS_LONG || op2_type == IS_DOUBLE) {
4600
21
                CHECK_OP2_TRACE_TYPE();
4601
21
              }
4602
172
              break;
4603
172
            }
4604
405
            if (opline->opcode == ZEND_ADD &&
4605
84
                (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4606
3
                (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4607
              /* pass */
4608
402
            } else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
4609
346
                !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4610
104
              if (op1_type == IS_LONG || op1_type == IS_DOUBLE) {
4611
17
                CHECK_OP1_TRACE_TYPE();
4612
17
              }
4613
104
              if (op2_type == IS_LONG || op2_type == IS_DOUBLE) {
4614
9
                CHECK_OP2_TRACE_TYPE();
4615
9
              }
4616
104
              break;
4617
104
            }
4618
301
            if (orig_op1_type != IS_UNKNOWN
4619
235
             && (orig_op1_type & IS_TRACE_REFERENCE)
4620
0
             && opline->op1_type == IS_CV
4621
0
             && (orig_op2_type == IS_UNKNOWN || !(orig_op2_type & IS_TRACE_REFERENCE))) {
4622
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4623
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4624
0
                goto jit_failure;
4625
0
              }
4626
0
              if (ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
4627
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
4628
0
              }
4629
301
            } else {
4630
301
              CHECK_OP1_TRACE_TYPE();
4631
301
            }
4632
301
            if (orig_op2_type != IS_UNKNOWN
4633
124
             && (orig_op2_type & IS_TRACE_REFERENCE)
4634
0
             && opline->op2_type == IS_CV
4635
0
             && (orig_op1_type == IS_UNKNOWN || !(orig_op1_type & IS_TRACE_REFERENCE))) {
4636
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op2_type, &op2_info, &op2_addr,
4637
0
                  !ssa->var_info[ssa_op->op2_use].guarded_reference, 1)) {
4638
0
                goto jit_failure;
4639
0
              }
4640
0
              if (ssa->vars[ssa_op->op2_use].alias == NO_ALIAS) {
4641
0
                ssa->var_info[ssa_op->op2_use].guarded_reference = 1;
4642
0
              }
4643
301
            } else {
4644
301
              CHECK_OP2_TRACE_TYPE();
4645
301
            }
4646
301
            res_addr = RES_REG_ADDR();
4647
301
            if (Z_MODE(res_addr) != IS_REG
4648
156
             && zend_jit_trace_next_is_send_result(opline, p, frame)) {
4649
0
              send_result = 1;
4650
0
              res_use_info = -1;
4651
0
              res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4652
0
              if (!zend_jit_reuse_ip(&ctx)) {
4653
0
                goto jit_failure;
4654
0
              }
4655
301
            } else {
4656
301
              res_use_info = zend_jit_trace_type_to_info(
4657
301
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)));
4658
301
              if (opline->result_type == IS_CV) {
4659
3
                res_use_info &= (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
4660
3
              }
4661
301
            }
4662
301
            res_info = RES_INFO();
4663
301
            if (opline->opcode == ZEND_ADD &&
4664
55
                (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
4665
3
                (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
4666
3
              if (!zend_jit_add_arrays(&ctx, opline, op1_info, op1_addr, op2_info, op2_addr, res_addr)) {
4667
0
                goto jit_failure;
4668
0
              }
4669
298
            } else {
4670
298
              bool may_overflow = (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa);
4671
4672
298
              if (ra
4673
243
               && may_overflow
4674
182
               && ((res_info & MAY_BE_GUARD)
4675
166
               && (res_info & MAY_BE_ANY) == MAY_BE_LONG)
4676
166
               && ((opline->opcode == ZEND_ADD
4677
31
                 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1)
4678
166
                || (opline->opcode == ZEND_SUB
4679
96
                 && Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1))) {
4680
13
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
4681
13
              }
4682
298
              if (!zend_jit_math(&ctx, opline,
4683
298
                  op1_info, op1_addr,
4684
298
                  op2_info, op2_addr,
4685
298
                  res_use_info, res_info, res_addr,
4686
298
                  may_overflow,
4687
298
                  zend_may_throw(opline, ssa_op, op_array, ssa))) {
4688
0
                goto jit_failure;
4689
0
              }
4690
298
              if (((res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4691
115
                || (res_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_DOUBLE|MAY_BE_GUARD))
4692
184
               && has_concrete_type(op1_info)
4693
184
               && (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
4694
184
               && has_concrete_type(op2_info)
4695
184
               && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
4696
184
                ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4697
184
              }
4698
298
            }
4699
301
            goto done;
4700
301
          case ZEND_CONCAT:
4701
142
          case ZEND_FAST_CONCAT:
4702
142
            op1_info = OP1_INFO();
4703
142
            CHECK_OP1_TRACE_TYPE();
4704
142
            op2_info = OP2_INFO();
4705
142
            CHECK_OP2_TRACE_TYPE();
4706
142
            if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
4707
88
              break;
4708
88
            }
4709
54
            if (!(op1_info & MAY_BE_STRING) ||
4710
40
                !(op2_info & MAY_BE_STRING)) {
4711
40
              break;
4712
40
            }
4713
14
            res_addr = RES_REG_ADDR();
4714
14
            if (zend_jit_trace_next_is_send_result(opline, p, frame)) {
4715
3
              send_result = 1;
4716
3
              res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
4717
3
              if (!zend_jit_reuse_ip(&ctx)) {
4718
0
                goto jit_failure;
4719
0
              }
4720
3
            }
4721
14
            if (!zend_jit_concat(&ctx, opline,
4722
14
                op1_info, op2_info, res_addr,
4723
14
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
4724
0
              goto jit_failure;
4725
0
            }
4726
14
            goto done;
4727
81
          case ZEND_ASSIGN_OP:
4728
81
            if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
4729
47
              break;
4730
47
            }
4731
34
            op1_info = OP1_INFO();
4732
34
            CHECK_OP1_TRACE_TYPE();
4733
34
            op2_info = OP2_INFO();
4734
34
            CHECK_OP2_TRACE_TYPE();
4735
34
            if (!zend_jit_supported_binary_op(
4736
34
                opline->extended_value, op1_info, op2_info)) {
4737
27
              break;
4738
27
            }
4739
7
            op1_addr = OP1_REG_ADDR();
4740
7
            if (Z_MODE(op1_addr) != IS_REG
4741
0
             || Z_LOAD(op1_addr)
4742
7
             || Z_STORE(op1_addr)) {
4743
7
              op1_mem_info = op1_info;
4744
7
            } else {
4745
0
              op1_mem_info = zend_jit_trace_type_to_info(
4746
0
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)));
4747
0
            }
4748
7
            op1_def_info = OP1_DEF_INFO();
4749
7
            if (op1_def_info & MAY_BE_GUARD
4750
0
             && !has_concrete_type(op1_def_info)) {
4751
0
              op1_def_info &= ~MAY_BE_GUARD;
4752
0
            }
4753
7
            if (!zend_jit_assign_op(&ctx, opline,
4754
7
                op1_info, op1_addr, OP1_RANGE(),
4755
7
                op1_def_info, OP1_DEF_REG_ADDR(), op1_mem_info,
4756
7
                op2_info, OP2_REG_ADDR(), OP2_RANGE(),
4757
7
                (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & (MAY_BE_DOUBLE|MAY_BE_GUARD)) && zend_may_overflow(opline, ssa_op, op_array, ssa),
4758
7
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
4759
0
              goto jit_failure;
4760
0
            }
4761
7
            if ((op1_def_info & (MAY_BE_ANY|MAY_BE_GUARD)) == (MAY_BE_LONG|MAY_BE_GUARD)
4762
0
             && has_concrete_type(op1_info)
4763
0
             && has_concrete_type(op2_info)) {
4764
0
              ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
4765
0
              if (opline->result_type != IS_UNUSED) {
4766
0
                ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
4767
0
              }
4768
0
            }
4769
7
            goto done;
4770
153
          case ZEND_ASSIGN_DIM_OP:
4771
153
            if (opline->result_type != IS_UNUSED) {
4772
20
              break;
4773
20
            }
4774
133
            if (!zend_jit_supported_binary_op(
4775
133
                opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4776
16
              break;
4777
16
            }
4778
117
            if (opline->op1_type == IS_CV
4779
111
             && (opline+1)->op1_type == IS_CV
4780
0
             && (opline+1)->op1.var == opline->op1.var) {
4781
              /* skip $a[x] += $a; */
4782
0
              break;
4783
0
            }
4784
117
            op1_info = OP1_INFO();
4785
117
            op1_addr = OP1_REG_ADDR();
4786
117
            op1_indirect = 0;
4787
117
            if (opline->op1_type == IS_VAR) {
4788
6
              if (orig_op1_type != IS_UNKNOWN
4789
6
               && (orig_op1_type & IS_TRACE_INDIRECT)) {
4790
6
                op1_indirect = 1;
4791
6
                if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4792
6
                    &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4793
0
                  goto jit_failure;
4794
0
                }
4795
6
              }
4796
6
            }
4797
117
            if (orig_op1_type != IS_UNKNOWN
4798
117
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
4799
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4800
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4801
0
                goto jit_failure;
4802
0
              }
4803
0
              if (opline->op1_type == IS_CV
4804
0
               && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4805
0
                ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4806
0
              }
4807
117
            } else {
4808
117
              CHECK_OP1_TRACE_TYPE();
4809
117
            }
4810
117
            op2_info = OP2_INFO();
4811
117
            CHECK_OP2_TRACE_TYPE();
4812
117
            op1_data_info = OP1_DATA_INFO();
4813
117
            CHECK_OP1_DATA_TRACE_TYPE();
4814
117
            op1_def_info = OP1_DEF_INFO();
4815
117
            if (!zend_jit_assign_dim_op(&ctx, opline,
4816
117
                op1_info, op1_def_info, op1_addr, op1_indirect,
4817
117
                op2_info, (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
4818
117
                (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
4819
117
                op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(), val_type,
4820
117
                zend_jit_trace_may_throw(opline, ssa_op, op_array, ssa,
4821
117
                  op1_info, op2_info, op1_data_info, val_type))) {
4822
0
              goto jit_failure;
4823
0
            }
4824
117
            if (opline->op1_type == IS_VAR && !(op1_info & (MAY_BE_ANY-MAY_BE_NULL))) {
4825
6
              SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_ARRAY, 1);
4826
6
            }
4827
117
            goto done;
4828
0
          case ZEND_PRE_INC_OBJ:
4829
0
          case ZEND_PRE_DEC_OBJ:
4830
0
          case ZEND_POST_INC_OBJ:
4831
0
          case ZEND_POST_DEC_OBJ:
4832
0
            if (opline->op2_type != IS_CONST
4833
0
             || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4834
0
             || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4835
0
              break;
4836
0
            }
4837
0
            ce = NULL;
4838
0
            ce_is_instanceof = 0;
4839
0
            on_this = delayed_fetch_this = 0;
4840
0
            op1_indirect = 0;
4841
0
            if (opline->op1_type == IS_UNUSED) {
4842
0
              op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4843
0
              ce = op_array->scope;
4844
              /* scope is NULL for closures. */
4845
0
              if (ce) {
4846
0
                ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
4847
0
              }
4848
0
              op1_addr = 0;
4849
0
              on_this = 1;
4850
0
            } else {
4851
0
              if (ssa_op->op1_use >= 0) {
4852
0
                delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4853
0
              }
4854
0
              op1_info = OP1_INFO();
4855
0
              if (!(op1_info & MAY_BE_OBJECT)) {
4856
0
                break;
4857
0
              }
4858
0
              op1_addr = OP1_REG_ADDR();
4859
0
              if (opline->op1_type == IS_VAR) {
4860
0
                if (orig_op1_type != IS_UNKNOWN
4861
0
                 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4862
0
                  op1_indirect = 1;
4863
0
                  if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4864
0
                      &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4865
0
                    goto jit_failure;
4866
0
                  }
4867
0
                }
4868
0
              }
4869
0
              if (orig_op1_type != IS_UNKNOWN
4870
0
               && (orig_op1_type & IS_TRACE_REFERENCE)) {
4871
0
                if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4872
0
                    !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4873
0
                  goto jit_failure;
4874
0
                }
4875
0
                if (opline->op1_type == IS_CV
4876
0
                 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4877
0
                  ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4878
0
                }
4879
0
              } else {
4880
0
                CHECK_OP1_TRACE_TYPE();
4881
0
              }
4882
0
              if (!(op1_info & MAY_BE_OBJECT)) {
4883
0
                break;
4884
0
              }
4885
0
              if (ssa->var_info && ssa->ops) {
4886
0
                if (ssa_op->op1_use >= 0) {
4887
0
                  zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4888
0
                  if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4889
0
                    ce = op1_ssa->ce;
4890
0
                    ce_is_instanceof = op1_ssa->is_instanceof;
4891
0
                  }
4892
0
                }
4893
0
              }
4894
0
              if (delayed_fetch_this) {
4895
0
                on_this = 1;
4896
0
              } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4897
0
                on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4898
0
              } else if (op_array_ssa->ops
4899
0
                      && op_array_ssa->vars
4900
0
                  && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4901
0
                  && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4902
0
                on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4903
0
              }
4904
0
            }
4905
0
            if (!zend_jit_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
4906
0
                op1_info, op1_addr,
4907
0
                op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4908
0
                val_type)) {
4909
0
              goto jit_failure;
4910
0
            }
4911
0
            goto done;
4912
0
          case ZEND_ASSIGN_OBJ_OP:
4913
0
            if (opline->result_type != IS_UNUSED) {
4914
0
              break;
4915
0
            }
4916
0
            if (opline->op2_type != IS_CONST
4917
0
             || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
4918
0
             || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
4919
0
              break;
4920
0
            }
4921
0
            if (opline->op1_type == IS_CV
4922
0
             && (opline+1)->op1_type == IS_CV
4923
0
             && (opline+1)->op1.var == opline->op1.var) {
4924
              /* skip $a->prop += $a; */
4925
0
              break;
4926
0
            }
4927
0
            if (!zend_jit_supported_binary_op(
4928
0
                opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
4929
0
              break;
4930
0
            }
4931
0
            ce = NULL;
4932
0
            ce_is_instanceof = 0;
4933
0
            on_this = delayed_fetch_this = 0;
4934
0
            op1_indirect = 0;
4935
0
            if (opline->op1_type == IS_UNUSED) {
4936
0
              op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
4937
0
              ce = op_array->scope;
4938
              /* scope is NULL for closures. */
4939
0
              if (ce) {
4940
0
                ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
4941
0
              }
4942
0
              op1_addr = 0;
4943
0
              on_this = 1;
4944
0
            } else {
4945
0
              if (ssa_op->op1_use >= 0) {
4946
0
                delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
4947
0
              }
4948
0
              op1_info = OP1_INFO();
4949
0
              if (!(op1_info & MAY_BE_OBJECT)) {
4950
0
                break;
4951
0
              }
4952
0
              op1_addr = OP1_REG_ADDR();
4953
0
              if (opline->op1_type == IS_VAR) {
4954
0
                if (orig_op1_type != IS_UNKNOWN
4955
0
                 && (orig_op1_type & IS_TRACE_INDIRECT)) {
4956
0
                  op1_indirect = 1;
4957
0
                  if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4958
0
                      &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
4959
0
                    goto jit_failure;
4960
0
                  }
4961
0
                }
4962
0
              }
4963
0
              if (orig_op1_type != IS_UNKNOWN
4964
0
               && (orig_op1_type & IS_TRACE_REFERENCE)) {
4965
0
                if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4966
0
                    !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
4967
0
                  goto jit_failure;
4968
0
                }
4969
0
                if (opline->op1_type == IS_CV
4970
0
                 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
4971
0
                  ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
4972
0
                }
4973
0
              } else {
4974
0
                CHECK_OP1_TRACE_TYPE();
4975
0
              }
4976
0
              if (!(op1_info & MAY_BE_OBJECT)) {
4977
0
                break;
4978
0
              }
4979
0
              if (ssa->var_info && ssa->ops) {
4980
0
                if (ssa_op->op1_use >= 0) {
4981
0
                  zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
4982
0
                  if (op1_ssa->ce && !op1_ssa->ce->create_object) {
4983
0
                    ce = op1_ssa->ce;
4984
0
                    ce_is_instanceof = op1_ssa->is_instanceof;
4985
0
                  }
4986
0
                }
4987
0
              }
4988
0
              if (delayed_fetch_this) {
4989
0
                on_this = 1;
4990
0
              } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
4991
0
                on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
4992
0
              } else if (op_array_ssa->ops
4993
0
                      && op_array_ssa->vars
4994
0
                  && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
4995
0
                  && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
4996
0
                on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
4997
0
              }
4998
0
            }
4999
0
            op1_data_info = OP1_DATA_INFO();
5000
0
            CHECK_OP1_DATA_TRACE_TYPE();
5001
0
            if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
5002
0
                op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
5003
0
                op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
5004
0
                val_type)) {
5005
0
              goto jit_failure;
5006
0
            }
5007
0
            goto done;
5008
0
          case ZEND_ASSIGN_OBJ:
5009
0
            if (opline->op2_type != IS_CONST
5010
0
             || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
5011
0
             || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
5012
0
              break;
5013
0
            }
5014
0
            ce = NULL;
5015
0
            ce_is_instanceof = 0;
5016
0
            on_this = delayed_fetch_this = 0;
5017
0
            op1_indirect = 0;
5018
0
            if (opline->op1_type == IS_UNUSED) {
5019
0
              op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
5020
0
              ce = op_array->scope;
5021
              /* scope is NULL for closures. */
5022
0
              if (ce) {
5023
0
                ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
5024
0
              }
5025
0
              op1_addr = 0;
5026
0
              on_this = 1;
5027
0
            } else {
5028
0
              if (ssa_op->op1_use >= 0) {
5029
0
                delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
5030
0
              }
5031
0
              op1_info = OP1_INFO();
5032
0
              if (!(op1_info & MAY_BE_OBJECT)) {
5033
0
                break;
5034
0
              }
5035
0
              op1_addr = OP1_REG_ADDR();
5036
0
              if (opline->op1_type == IS_VAR) {
5037
0
                if (orig_op1_type != IS_UNKNOWN
5038
0
                 && (orig_op1_type & IS_TRACE_INDIRECT)) {
5039
0
                  op1_indirect = 1;
5040
0
                  if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
5041
0
                      &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5042
0
                    goto jit_failure;
5043
0
                  }
5044
0
                }
5045
0
              }
5046
0
              if (orig_op1_type != IS_UNKNOWN
5047
0
               && (orig_op1_type & IS_TRACE_REFERENCE)) {
5048
0
                if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5049
0
                    !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5050
0
                  goto jit_failure;
5051
0
                }
5052
0
                if (opline->op1_type == IS_CV
5053
0
                 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5054
0
                  ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5055
0
                }
5056
0
              } else {
5057
0
                CHECK_OP1_TRACE_TYPE();
5058
0
              }
5059
0
              if (!(op1_info & MAY_BE_OBJECT)) {
5060
0
                break;
5061
0
              }
5062
0
              if (ssa->var_info && ssa->ops) {
5063
0
                if (ssa_op->op1_use >= 0) {
5064
0
                  zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
5065
0
                  if (op1_ssa->ce && !op1_ssa->ce->create_object) {
5066
0
                    ce = op1_ssa->ce;
5067
0
                    ce_is_instanceof = op1_ssa->is_instanceof;
5068
0
                  }
5069
0
                }
5070
0
              }
5071
0
              if (delayed_fetch_this) {
5072
0
                on_this = 1;
5073
0
              } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
5074
0
                on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
5075
0
              } else if (op_array_ssa->ops
5076
0
                      && op_array_ssa->vars
5077
0
                  && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
5078
0
                  && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
5079
0
                on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
5080
0
              }
5081
0
            }
5082
0
            op1_data_info = OP1_DATA_INFO();
5083
0
            CHECK_OP1_DATA_TRACE_TYPE();
5084
0
            if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
5085
0
                op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
5086
0
                (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
5087
0
                op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
5088
0
                val_type,
5089
0
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
5090
0
              goto jit_failure;
5091
0
            }
5092
0
            if ((opline+1)->op1_type == IS_CV
5093
0
             && (ssa_op+1)->op1_def >= 0
5094
0
             && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
5095
0
              ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
5096
0
            }
5097
0
            goto done;
5098
89
          case ZEND_ASSIGN_DIM:
5099
89
            op1_info = OP1_INFO();
5100
89
            op1_addr = OP1_REG_ADDR();
5101
89
            op1_indirect = 0;
5102
89
            if (opline->op1_type == IS_CV
5103
73
             && (opline+1)->op1_type == IS_CV
5104
13
             && (opline+1)->op1.var == opline->op1.var) {
5105
              /* skip $a[x] = $a; */
5106
0
              break;
5107
0
            }
5108
89
            if (opline->op1_type == IS_VAR) {
5109
16
              if (orig_op1_type != IS_UNKNOWN
5110
16
               && (orig_op1_type & IS_TRACE_INDIRECT)) {
5111
16
                op1_indirect = 1;
5112
16
                if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
5113
16
                    &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5114
0
                  goto jit_failure;
5115
0
                }
5116
16
              }
5117
16
            }
5118
89
            if (orig_op1_type != IS_UNKNOWN
5119
89
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
5120
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5121
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5122
0
                goto jit_failure;
5123
0
              }
5124
0
              if (opline->op1_type == IS_CV
5125
0
               && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5126
0
                ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5127
0
              }
5128
89
            } else {
5129
89
              CHECK_OP1_TRACE_TYPE();
5130
89
            }
5131
89
            op2_info = OP2_INFO();
5132
89
            CHECK_OP2_TRACE_TYPE();
5133
89
            op1_data_info = OP1_DATA_INFO();
5134
89
            CHECK_OP1_DATA_TRACE_TYPE();
5135
89
            if (!zend_jit_assign_dim(&ctx, opline,
5136
89
                op1_info, op1_addr, op1_indirect,
5137
89
                op2_info, (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
5138
89
                (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
5139
89
                op1_data_info, OP1_DATA_REG_ADDR(),
5140
89
                (ctx.ra && (ssa_op+1)->op1_def >= 0) ? OP1_DATA_DEF_REG_ADDR() : 0,
5141
89
                (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
5142
89
                val_type,
5143
89
                zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
5144
0
              goto jit_failure;
5145
0
            }
5146
89
            if ((opline+1)->op1_type == IS_CV
5147
17
             && (ssa_op+1)->op1_def >= 0
5148
17
             && ssa->vars[(ssa_op+1)->op1_def].alias == NO_ALIAS) {
5149
0
              ssa->var_info[(ssa_op+1)->op1_def].guarded_reference = ssa->var_info[(ssa_op+1)->op1_use].guarded_reference;
5150
0
            }
5151
89
            if (opline->op1_type == IS_VAR && !(op1_info & (MAY_BE_ANY-MAY_BE_NULL))) {
5152
16
              SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_ARRAY, 1);
5153
16
            }
5154
89
            goto done;
5155
186
          case ZEND_ASSIGN:
5156
186
            if (opline->op1_type != IS_CV) {
5157
18
              break;
5158
18
            }
5159
168
            op2_addr = OP2_REG_ADDR();
5160
168
            op2_info = OP2_INFO();
5161
168
            zend_jit_addr ref_addr = 0;
5162
5163
168
            if (ssa_op->op2_def < 0 || (Z_MODE(op2_addr) == IS_REG && ssa->vars[ssa_op->op2_def].no_val)) {
5164
131
              op2_def_addr = op2_addr;
5165
131
            } else {
5166
37
              op2_def_addr = OP2_DEF_REG_ADDR();
5167
37
            }
5168
168
            CHECK_OP2_TRACE_TYPE();
5169
168
            op1_info = OP1_INFO();
5170
168
            op1_def_info = OP1_DEF_INFO();
5171
168
            if (op1_type != IS_UNKNOWN && (op1_info & MAY_BE_GUARD)) {
5172
159
              if (op1_type < IS_STRING
5173
152
               && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (op1_def_info & (MAY_BE_ANY|MAY_BE_UNDEF))) {
5174
0
                if (!zend_jit_scalar_type_guard(&ctx, opline, opline->op1.var)) {
5175
0
                  goto jit_failure;
5176
0
                }
5177
0
                op1_info &= ~(MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD);
5178
159
              } else {
5179
159
                CHECK_OP1_TRACE_TYPE();
5180
159
              }
5181
159
            }
5182
168
            op1_addr = OP1_REG_ADDR();
5183
168
            op1_def_addr = OP1_DEF_REG_ADDR();
5184
168
            if (Z_MODE(op1_def_addr) != IS_REG &&
5185
164
                STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) !=
5186
164
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var))) {
5187
              /* type may be not set */
5188
0
              op1_info |= MAY_BE_NULL;
5189
0
            }
5190
168
            if (orig_op1_type != IS_UNKNOWN) {
5191
168
              if (orig_op1_type & IS_TRACE_REFERENCE) {
5192
3
                if (!zend_jit_guard_reference(&ctx, opline, &op1_addr, &ref_addr,
5193
3
                    !ssa->var_info[ssa_op->op1_use].guarded_reference)) {
5194
0
                  goto jit_failure;
5195
0
                }
5196
3
                op1_info &= ~MAY_BE_REF;
5197
3
                if (opline->op1_type == IS_CV
5198
3
                 && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5199
0
                  ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5200
0
                }
5201
3
                op1_def_addr = op1_addr;
5202
3
                op1_def_info &= ~MAY_BE_REF;
5203
165
              } else if (op1_info & MAY_BE_REF) {
5204
0
                if (!zend_jit_noref_guard(&ctx, opline, op1_addr)) {
5205
0
                  goto jit_failure;
5206
0
                }
5207
0
                op1_info &= ~MAY_BE_REF;
5208
0
                op1_def_info &= ~MAY_BE_REF;
5209
0
              }
5210
168
            }
5211
168
            if (opline->result_type == IS_UNUSED) {
5212
106
              res_addr = 0;
5213
106
              res_info = -1;
5214
106
            } else {
5215
62
              res_addr = RES_REG_ADDR();
5216
62
              res_info = RES_INFO();
5217
62
              if (Z_MODE(res_addr) != IS_REG
5218
               /* assignment to typed reference may cause conversion,
5219
                * so SEND_VAL has to check the type of the result */
5220
58
               && !ref_addr
5221
56
               && zend_jit_trace_next_is_send_result(opline, p, frame)) {
5222
0
                send_result = 1;
5223
0
                res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
5224
0
                if (!zend_jit_reuse_ip(&ctx)) {
5225
0
                  goto jit_failure;
5226
0
                }
5227
0
              }
5228
62
            }
5229
168
            if (!zend_jit_assign(&ctx, opline,
5230
168
                op1_info, op1_addr,
5231
168
                op1_def_info, op1_def_addr,
5232
168
                op2_info, op2_addr, op2_def_addr,
5233
168
                res_info, res_addr,
5234
168
                ref_addr,
5235
168
                zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info))) {
5236
0
              goto jit_failure;
5237
0
            }
5238
168
            if (ssa_op->op2_def >= 0
5239
37
             && Z_MODE(op2_addr) == IS_REG
5240
2
             && ssa->vars[ssa_op->op2_def].no_val) {
5241
0
              uint8_t type = (op2_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5242
0
              uint32_t var_num = EX_VAR_TO_NUM(opline->op2.var);
5243
5244
0
              if (STACK_MEM_TYPE(stack, var_num) != type
5245
0
               && ssa->vars[ssa_op->op2_def].use_chain < 0
5246
0
               && !ssa->vars[ssa_op->op2_def].phi_use_chain) {
5247
0
                if (!zend_jit_store_type(&ctx, var_num, type)) {
5248
0
                  goto jit_failure;
5249
0
                }
5250
0
                SET_STACK_TYPE(stack, var_num, type, 1);
5251
0
              }
5252
0
            }
5253
168
            if (opline->op2_type == IS_CV
5254
37
             && ssa_op->op2_def >= 0
5255
37
             && ssa->vars[ssa_op->op2_def].alias == NO_ALIAS) {
5256
6
              ssa->var_info[ssa_op->op2_def].guarded_reference = ssa->var_info[ssa_op->op2_use].guarded_reference;
5257
6
            }
5258
168
            goto done;
5259
29
          case ZEND_CAST:
5260
29
            if (opline->extended_value != op1_type) {
5261
26
              break;
5262
26
            }
5263
3
            ZEND_FALLTHROUGH;
5264
72
          case ZEND_QM_ASSIGN:
5265
72
            op1_addr = OP1_REG_ADDR();
5266
72
            if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5267
41
              op1_def_addr = op1_addr;
5268
41
            } else {
5269
31
              op1_def_addr = OP1_DEF_REG_ADDR();
5270
31
            }
5271
72
            op1_info = OP1_INFO();
5272
72
            CHECK_OP1_TRACE_TYPE();
5273
72
            res_info = RES_INFO();
5274
72
            res_use_info = zend_jit_trace_type_to_info(
5275
72
              STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)));
5276
72
            if (opline->result_type == IS_CV) {
5277
3
              res_use_info &= (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE);
5278
3
            }
5279
72
            res_addr = RES_REG_ADDR();
5280
72
            if (Z_MODE(res_addr) != IS_REG &&
5281
72
                STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) !=
5282
72
                STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var))) {
5283
              /* type may be not set */
5284
0
              res_use_info |= MAY_BE_NULL;
5285
0
            }
5286
72
            if (!zend_jit_qm_assign(&ctx, opline,
5287
72
                op1_info, op1_addr, op1_def_addr,
5288
72
                res_use_info, res_info, res_addr)) {
5289
0
              goto jit_failure;
5290
0
            }
5291
72
            if (ssa_op->op1_def >= 0
5292
31
             && Z_MODE(op1_addr) == IS_REG
5293
0
             && ssa->vars[ssa_op->op1_def].no_val) {
5294
0
              uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5295
0
              uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5296
5297
0
              if (STACK_MEM_TYPE(stack, var_num) != type
5298
0
               && ssa->vars[ssa_op->op1_def].use_chain < 0
5299
0
               && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5300
0
                if (!zend_jit_store_type(&ctx, var_num, type)) {
5301
0
                  goto jit_failure;
5302
0
                }
5303
0
                SET_STACK_TYPE(stack, var_num, type, 1);
5304
0
              }
5305
0
            }
5306
72
            if (opline->op1_type == IS_CV
5307
31
             && ssa_op->op1_def >= 0
5308
31
             && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5309
3
              ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5310
3
            }
5311
72
            goto done;
5312
207
          case ZEND_INIT_FCALL:
5313
207
          case ZEND_INIT_FCALL_BY_NAME:
5314
207
          case ZEND_INIT_NS_FCALL_BY_NAME:
5315
207
            frame_flags = TRACE_FRAME_MASK_NESTED;
5316
207
            if (!zend_jit_init_fcall(&ctx, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
5317
0
              goto jit_failure;
5318
0
            }
5319
207
            goto done;
5320
266
          case ZEND_SEND_VAL:
5321
266
          case ZEND_SEND_VAL_EX:
5322
266
            if (opline->op2_type == IS_CONST) {
5323
              /* Named parameters not supported in JIT */
5324
0
              break;
5325
0
            }
5326
266
            if (opline->opcode == ZEND_SEND_VAL_EX
5327
0
             && opline->op2.num > MAX_ARG_FLAG_NUM) {
5328
0
              break;
5329
0
            }
5330
266
            op1_info = OP1_INFO();
5331
266
            CHECK_OP1_TRACE_TYPE();
5332
266
            if (!zend_jit_send_val(&ctx, opline,
5333
266
                op1_info, OP1_REG_ADDR())) {
5334
0
              goto jit_failure;
5335
0
            }
5336
266
            if (frame->call && frame->call->func) {
5337
266
              if (opline->op1_type == IS_CONST) {
5338
243
                zend_jit_trace_send_type(opline, frame->call, Z_TYPE_P(RT_CONSTANT(opline, opline->op1)));
5339
243
              } else if (op1_type != IS_UNKNOWN) {
5340
23
                if (op1_type == IS_UNDEF) {
5341
0
                  op1_type = IS_NULL;
5342
0
                }
5343
23
                zend_jit_trace_send_type(opline, frame->call, op1_type);
5344
23
              }
5345
266
            }
5346
266
            goto done;
5347
0
          case ZEND_SEND_REF:
5348
0
            if (opline->op2_type == IS_CONST) {
5349
              /* Named parameters not supported in JIT */
5350
0
              break;
5351
0
            }
5352
0
            op1_info = OP1_INFO();
5353
0
            if (!zend_jit_send_ref(&ctx, opline, op_array,
5354
0
                op1_info, 0)) {
5355
0
              goto jit_failure;
5356
0
            }
5357
0
            if (opline->op1_type == IS_CV
5358
0
             && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5359
0
              ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5360
0
            }
5361
0
            goto done;
5362
19
          case ZEND_SEND_VAR:
5363
19
          case ZEND_SEND_VAR_EX:
5364
19
          case ZEND_SEND_VAR_NO_REF:
5365
19
          case ZEND_SEND_VAR_NO_REF_EX:
5366
21
          case ZEND_SEND_FUNC_ARG:
5367
21
            if (opline->op2_type == IS_CONST) {
5368
              /* Named parameters not supported in JIT */
5369
0
              break;
5370
0
            }
5371
21
            if ((opline->opcode == ZEND_SEND_VAR_EX
5372
21
              || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
5373
0
             && opline->op2.num > MAX_ARG_FLAG_NUM) {
5374
0
              break;
5375
0
            }
5376
21
            op1_addr = OP1_REG_ADDR();
5377
21
            if (ssa_op->op1_def < 0 || (Z_MODE(op1_addr) == IS_REG && ssa->vars[ssa_op->op1_def].no_val)) {
5378
2
              op1_def_addr = op1_addr;
5379
19
            } else {
5380
19
              op1_def_addr = OP1_DEF_REG_ADDR();
5381
19
            }
5382
21
            op1_info = OP1_INFO();
5383
21
            CHECK_OP1_TRACE_TYPE();
5384
21
            if (!zend_jit_send_var(&ctx, opline, op_array,
5385
21
                op1_info, op1_addr, op1_def_addr)) {
5386
0
              goto jit_failure;
5387
0
            }
5388
21
            if (ssa_op->op1_def >= 0
5389
19
             && Z_MODE(op1_addr) == IS_REG
5390
0
             && ssa->vars[ssa_op->op1_def].no_val) {
5391
0
              uint8_t type = (op1_info & MAY_BE_LONG) ? IS_LONG : IS_DOUBLE;
5392
0
              uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var);
5393
5394
0
              if (STACK_MEM_TYPE(stack, var_num) != type
5395
0
               && ssa->vars[ssa_op->op1_def].use_chain < 0
5396
0
               && !ssa->vars[ssa_op->op1_def].phi_use_chain) {
5397
0
                if (!zend_jit_store_type(&ctx, var_num, type)) {
5398
0
                  goto jit_failure;
5399
0
                }
5400
0
                SET_STACK_TYPE(stack, var_num, type, 1);
5401
0
              }
5402
0
            }
5403
21
            if (opline->op1_type == IS_CV
5404
19
             && ssa_op->op1_def >= 0
5405
19
             && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5406
0
              ssa->var_info[ssa_op->op1_def].guarded_reference = ssa->var_info[ssa_op->op1_use].guarded_reference;
5407
0
            }
5408
21
            if (frame->call && frame->call->func) {
5409
21
              if ((opline->opcode == ZEND_SEND_VAR_EX
5410
21
                || opline->opcode == ZEND_SEND_FUNC_ARG)
5411
2
               && ARG_SHOULD_BE_SENT_BY_REF(frame->call->func, opline->op2.num)) {
5412
0
                goto done;
5413
0
              }
5414
21
              if (op1_type != IS_UNKNOWN) {
5415
21
                if (op1_type == IS_UNDEF) {
5416
6
                  op1_type = IS_NULL;
5417
6
                }
5418
21
                zend_jit_trace_send_type(opline, frame->call, op1_type);
5419
21
              }
5420
21
            }
5421
21
            goto done;
5422
21
          case ZEND_CHECK_FUNC_ARG:
5423
2
            if (!JIT_G(current_frame)
5424
2
             || !JIT_G(current_frame)->call
5425
2
             || !JIT_G(current_frame)->call->func) {
5426
0
              break;
5427
0
            }
5428
2
            if (opline->op2_type == IS_CONST
5429
2
             || opline->op2.num > MAX_ARG_FLAG_NUM) {
5430
              /* Named parameters not supported in JIT */
5431
0
              TRACE_FRAME_SET_LAST_SEND_UNKNOWN(JIT_G(current_frame)->call);
5432
0
              break;
5433
0
            }
5434
2
            if (!zend_jit_check_func_arg(&ctx, opline)) {
5435
0
              goto jit_failure;
5436
0
            }
5437
2
            goto done;
5438
2
          case ZEND_CHECK_UNDEF_ARGS:
5439
0
            if (JIT_G(current_frame)
5440
0
             && JIT_G(current_frame)->call) {
5441
0
              TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
5442
0
            }
5443
0
            if (!zend_jit_check_undef_args(&ctx, opline)) {
5444
0
              goto jit_failure;
5445
0
            }
5446
0
            goto done;
5447
16
          case ZEND_DO_UCALL:
5448
16
          case ZEND_DO_ICALL:
5449
16
          case ZEND_DO_FCALL_BY_NAME:
5450
203
          case ZEND_DO_FCALL:
5451
203
            if (!zend_jit_do_fcall(&ctx, opline, op_array, op_array_ssa, frame->call_level, -1, p + 1)) {
5452
0
              goto jit_failure;
5453
0
            }
5454
203
            goto done;
5455
203
          case ZEND_IS_EQUAL:
5456
27
          case ZEND_IS_NOT_EQUAL:
5457
133
          case ZEND_IS_SMALLER:
5458
146
          case ZEND_IS_SMALLER_OR_EQUAL:
5459
146
          case ZEND_CASE:
5460
146
            op1_info = OP1_INFO();
5461
146
            op2_info = OP2_INFO();
5462
146
            skip_comparison =
5463
146
              ssa_op != ssa->ops &&
5464
129
              (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5465
26
              (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5466
18
              zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5467
146
            CHECK_OP1_TRACE_TYPE();
5468
146
            CHECK_OP2_TRACE_TYPE();
5469
146
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5470
3
              bool exit_if_true = 0;
5471
3
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5472
3
              uint32_t exit_point;
5473
5474
3
              if (ra) {
5475
0
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5476
0
              }
5477
3
              exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5478
3
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5479
3
              if (!exit_addr) {
5480
0
                goto jit_failure;
5481
0
              }
5482
3
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5483
3
              if (!zend_jit_cmp(&ctx, opline,
5484
3
                  op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5485
3
                  op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5486
3
                  RES_REG_ADDR(),
5487
3
                  zend_may_throw(opline, ssa_op, op_array, ssa),
5488
3
                  smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5489
0
                goto jit_failure;
5490
0
              }
5491
3
              zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5492
143
            } else {
5493
143
              smart_branch_opcode = 0;
5494
143
              exit_addr = NULL;
5495
143
              if (!zend_jit_cmp(&ctx, opline,
5496
143
                  op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5497
143
                  op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5498
143
                  RES_REG_ADDR(),
5499
143
                  zend_may_throw(opline, ssa_op, op_array, ssa),
5500
143
                  smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5501
0
                goto jit_failure;
5502
0
              }
5503
143
            }
5504
146
            goto done;
5505
146
          case ZEND_IS_IDENTICAL:
5506
3
          case ZEND_IS_NOT_IDENTICAL:
5507
3
          case ZEND_CASE_STRICT:
5508
3
            op1_info = OP1_INFO();
5509
3
            op2_info = OP2_INFO();
5510
3
            skip_comparison =
5511
3
              ssa_op != ssa->ops &&
5512
2
              (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5513
0
              (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG &&
5514
0
              zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5515
3
            CHECK_OP1_TRACE_TYPE();
5516
3
            CHECK_OP2_TRACE_TYPE();
5517
3
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5518
0
              bool exit_if_true = 0;
5519
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5520
0
              uint32_t exit_point;
5521
5522
0
              if (ra) {
5523
0
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5524
0
              }
5525
0
              exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5526
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5527
0
              if (!exit_addr) {
5528
0
                goto jit_failure;
5529
0
              }
5530
0
              if (opline->opcode == ZEND_IS_NOT_IDENTICAL) {
5531
0
                exit_if_true = !exit_if_true;
5532
0
              }
5533
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5534
0
              if (!zend_jit_identical(&ctx, opline,
5535
0
                  op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5536
0
                  op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5537
0
                  RES_REG_ADDR(),
5538
0
                  zend_may_throw(opline, ssa_op, op_array, ssa),
5539
0
                  smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5540
0
                goto jit_failure;
5541
0
              }
5542
0
              zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5543
3
            } else {
5544
3
              smart_branch_opcode = 0;
5545
3
              exit_addr = NULL;
5546
3
              if (!zend_jit_identical(&ctx, opline,
5547
3
                  op1_info, OP1_RANGE(), OP1_REG_ADDR(),
5548
3
                  op2_info, OP2_RANGE(), OP2_REG_ADDR(),
5549
3
                  RES_REG_ADDR(),
5550
3
                  zend_may_throw(opline, ssa_op, op_array, ssa),
5551
3
                  smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5552
0
                goto jit_failure;
5553
0
              }
5554
3
            }
5555
3
            goto done;
5556
3
          case ZEND_DEFINED:
5557
0
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5558
0
              bool exit_if_true = 0;
5559
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5560
0
              uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5561
5562
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5563
0
              if (!exit_addr) {
5564
0
                goto jit_failure;
5565
0
              }
5566
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5567
0
            } else {
5568
0
              smart_branch_opcode = 0;
5569
0
              exit_addr = NULL;
5570
0
            }
5571
0
            if (!zend_jit_defined(&ctx, opline, smart_branch_opcode, -1, -1, exit_addr)) {
5572
0
              goto jit_failure;
5573
0
            }
5574
0
            goto done;
5575
0
          case ZEND_TYPE_CHECK:
5576
0
            if (opline->extended_value == MAY_BE_RESOURCE) {
5577
              // TODO: support for is_resource() ???
5578
0
              break;
5579
0
            }
5580
0
            op1_info = OP1_INFO();
5581
0
            CHECK_OP1_TRACE_TYPE();
5582
0
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5583
0
              bool exit_if_true = 0;
5584
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5585
0
              uint32_t exit_point;
5586
5587
0
              if (ra) {
5588
0
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5589
0
              }
5590
0
              exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5591
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5592
0
              if (!exit_addr) {
5593
0
                goto jit_failure;
5594
0
              }
5595
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5596
0
            } else {
5597
0
              smart_branch_opcode = 0;
5598
0
              exit_addr = NULL;
5599
0
            }
5600
0
            if (!zend_jit_type_check(&ctx, opline, op1_info, smart_branch_opcode, -1, -1, exit_addr)) {
5601
0
              goto jit_failure;
5602
0
            }
5603
0
            goto done;
5604
2.38k
          case ZEND_RETURN:
5605
2.38k
            op1_info = OP1_INFO();
5606
2.38k
            CHECK_OP1_TRACE_TYPE();
5607
2.38k
            if (opline->op1_type == IS_CONST) {
5608
2.38k
              res_type = Z_TYPE_P(RT_CONSTANT(opline, opline->op1));
5609
2.38k
            } else if (op1_type != IS_UNKNOWN) {
5610
0
              res_type = op1_type;
5611
0
              if (res_type == IS_UNDEF) {
5612
0
                res_type = IS_NULL;
5613
0
              }
5614
0
            }
5615
2.38k
            if (op_array->type == ZEND_EVAL_CODE
5616
             // TODO: support for top-level code
5617
2.38k
             || !op_array->function_name
5618
             // TODO: support for IS_UNDEF ???
5619
2.36k
             || (op1_info & MAY_BE_UNDEF)) {
5620
2.36k
              if (!zend_jit_trace_handler(&ctx, op_array, opline, zend_may_throw(opline, ssa_op, op_array, ssa), p + 1)) {
5621
0
                goto jit_failure;
5622
0
              }
5623
2.36k
            } else {
5624
16
              int j;
5625
16
              int may_throw = 0;
5626
16
              bool left_frame = 0;
5627
5628
16
              if (!zend_jit_return(&ctx, opline, op_array,
5629
16
                  op1_info, OP1_REG_ADDR())) {
5630
0
                goto jit_failure;
5631
0
              }
5632
16
              if (op_array->last_var > 100) {
5633
                /* Too many CVs to unroll */
5634
0
                if (!zend_jit_free_cvs(&ctx)) {
5635
0
                  goto jit_failure;
5636
0
                }
5637
0
                left_frame = 1;
5638
0
              }
5639
16
              if (!left_frame) {
5640
53
                for (j = 0 ; j < op_array->last_var; j++) {
5641
37
                  uint32_t info;
5642
37
                  uint8_t type;
5643
5644
37
                  info = zend_ssa_cv_info(op_array, op_array_ssa, j);
5645
37
                  type = STACK_TYPE(stack, j);
5646
37
                  info = zend_jit_trace_type_to_info_ex(type, info);
5647
37
                  if (opline->op1_type == IS_CV
5648
0
                   && EX_VAR_TO_NUM(opline->op1.var) == j
5649
0
                   && !(op1_info & (MAY_BE_REF|MAY_BE_OBJECT))) {
5650
0
                    if (JIT_G(current_frame)
5651
0
                     && TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) {
5652
0
                      continue;
5653
0
                    } else {
5654
0
                      info |= MAY_BE_NULL;
5655
0
                    }
5656
0
                  }
5657
37
                  if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) {
5658
6
                    if (!left_frame) {
5659
3
                      left_frame = 1;
5660
3
                        if (!zend_jit_leave_frame(&ctx)) {
5661
0
                        goto jit_failure;
5662
0
                        }
5663
3
                    }
5664
6
                    if (!zend_jit_free_cv(&ctx, info, j)) {
5665
0
                      goto jit_failure;
5666
0
                    }
5667
6
                    if (info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)) {
5668
6
                      if (info & MAY_BE_RC1) {
5669
6
                        may_throw = 1;
5670
6
                      }
5671
6
                    }
5672
6
                  }
5673
37
                }
5674
16
              }
5675
16
              if (!zend_jit_leave_func(&ctx, op_array, opline, op1_info, left_frame,
5676
16
                  p + 1, &zend_jit_traces[ZEND_JIT_TRACE_NUM],
5677
16
                  (op_array_ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, may_throw)) {
5678
0
                goto jit_failure;
5679
0
              }
5680
16
            }
5681
2.38k
            goto done;
5682
2.38k
          case ZEND_BOOL:
5683
55
          case ZEND_BOOL_NOT:
5684
55
            op1_info = OP1_INFO();
5685
55
            CHECK_OP1_TRACE_TYPE();
5686
55
            if (!zend_jit_bool_jmpznz(&ctx, opline,
5687
55
                op1_info, OP1_REG_ADDR(), RES_REG_ADDR(),
5688
55
                -1, -1,
5689
55
                zend_may_throw(opline, ssa_op, op_array, ssa),
5690
55
                opline->opcode, NULL, true)) {
5691
0
              goto jit_failure;
5692
0
            }
5693
55
            goto done;
5694
55
          case ZEND_JMPZ:
5695
20
          case ZEND_JMPNZ:
5696
26
          case ZEND_JMPZ_EX:
5697
26
          case ZEND_JMPNZ_EX:
5698
26
            op1_info = OP1_INFO();
5699
26
            CHECK_OP1_TRACE_TYPE();
5700
26
            if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
5701
26
              const zend_op *exit_opline = NULL;
5702
26
              uint32_t exit_point;
5703
5704
26
              if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
5705
                /* taken branch */
5706
22
                if (opline->opcode == ZEND_JMPNZ_EX) {
5707
0
                  smart_branch_opcode = ZEND_JMPZ_EX;
5708
22
                } else if (opline->opcode == ZEND_JMPZ_EX) {
5709
5
                  smart_branch_opcode = ZEND_JMPNZ_EX;
5710
17
                } else if (opline->opcode == ZEND_JMPNZ) {
5711
1
                  smart_branch_opcode = ZEND_JMPZ;
5712
16
                } else {
5713
16
                  smart_branch_opcode = ZEND_JMPNZ;
5714
16
                }
5715
22
                exit_opline = opline + 1;
5716
22
              } else if ((p+1)->opline == opline + 1) {
5717
                /* not taken branch */
5718
4
                smart_branch_opcode = opline->opcode;
5719
4
                exit_opline = OP_JMP_ADDR(opline, opline->op2);
5720
4
              } else {
5721
0
                ZEND_UNREACHABLE();
5722
0
              }
5723
26
              if (ra) {
5724
2
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5725
2
              }
5726
26
              if (!(op1_info & MAY_BE_GUARD)
5727
26
               && has_concrete_type(op1_info)
5728
26
               && concrete_type(op1_info) <= IS_TRUE) {
5729
                /* unconditional branch */
5730
10
                exit_addr = NULL;
5731
16
              } else if (opline->result_type == IS_TMP_VAR) {
5732
4
                uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var));
5733
5734
4
                SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
5735
4
                exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5736
4
                SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info);
5737
4
                exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5738
4
                if (!exit_addr) {
5739
0
                  goto jit_failure;
5740
0
                }
5741
12
              } else {
5742
12
                exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5743
12
                exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5744
12
                if (!exit_addr) {
5745
0
                  goto jit_failure;
5746
0
                }
5747
12
              }
5748
26
            } else  {
5749
0
              ZEND_UNREACHABLE();
5750
0
            }
5751
26
            if (opline->result_type == IS_UNDEF) {
5752
20
              res_addr = 0;
5753
20
            } else {
5754
6
              res_addr = RES_REG_ADDR();
5755
6
            }
5756
26
            if (!zend_jit_bool_jmpznz(&ctx, opline,
5757
26
                op1_info, OP1_REG_ADDR(), res_addr,
5758
26
                -1, -1,
5759
26
                zend_may_throw(opline, ssa_op, op_array, ssa),
5760
26
                smart_branch_opcode, exit_addr, true)) {
5761
0
              goto jit_failure;
5762
0
            }
5763
26
            goto done;
5764
26
          case ZEND_JMP_FRAMELESS:
5765
0
            op1_info = OP1_INFO();
5766
0
            ZEND_ASSERT((p+1)->op == ZEND_JIT_TRACE_VM);
5767
0
            const zend_op *exit_opline = NULL;
5768
0
            uint32_t exit_point;
5769
0
            zend_jmp_fl_result guard;
5770
5771
0
            if ((p+1)->opline == OP_JMP_ADDR(opline, opline->op2)) {
5772
              /* taken branch */
5773
0
              guard = ZEND_JMP_FL_HIT;
5774
0
              exit_opline = opline + 1;
5775
0
            } else if ((p+1)->opline == opline + 1) {
5776
              /* not taken branch */
5777
0
              guard = ZEND_JMP_FL_MISS;
5778
0
              exit_opline = OP_JMP_ADDR(opline, opline->op2);
5779
0
            } else {
5780
0
              ZEND_UNREACHABLE();
5781
0
            }
5782
0
            exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5783
0
            exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5784
0
            if (!exit_addr) {
5785
0
              goto jit_failure;
5786
0
            }
5787
0
            if (!zend_jit_jmp_frameless(&ctx, opline, exit_addr, guard)) {
5788
0
              goto jit_failure;
5789
0
            }
5790
0
            goto done;
5791
0
          case ZEND_ISSET_ISEMPTY_CV:
5792
0
            op1_info = OP1_INFO();
5793
0
            op1_addr = OP1_REG_ADDR();
5794
0
            if (orig_op1_type != IS_UNKNOWN
5795
0
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
5796
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5797
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5798
0
                goto jit_failure;
5799
0
              }
5800
0
              if (opline->op1_type == IS_CV
5801
0
               && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5802
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5803
0
              }
5804
0
            } else {
5805
0
              CHECK_OP1_TRACE_TYPE();
5806
0
            }
5807
0
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5808
0
              bool exit_if_true = 0;
5809
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5810
0
              uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5811
5812
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5813
0
              if (!exit_addr) {
5814
0
                goto jit_failure;
5815
0
              }
5816
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5817
0
            } else {
5818
0
              smart_branch_opcode = 0;
5819
0
              exit_addr = NULL;
5820
0
            }
5821
0
            if (!zend_jit_isset_isempty_cv(&ctx, opline,
5822
0
                op1_info, op1_addr,
5823
0
                smart_branch_opcode, -1, -1, exit_addr)) {
5824
0
              goto jit_failure;
5825
0
            }
5826
0
            goto done;
5827
0
          case ZEND_IN_ARRAY:
5828
0
            if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
5829
0
              break;
5830
0
            }
5831
0
            op1_info = OP1_INFO();
5832
0
            op1_addr = OP1_REG_ADDR();
5833
0
            CHECK_OP1_TRACE_TYPE();
5834
0
            if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
5835
0
              break;
5836
0
            }
5837
0
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5838
0
              bool exit_if_true = 0;
5839
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5840
0
              uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5841
5842
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5843
0
              if (!exit_addr) {
5844
0
                goto jit_failure;
5845
0
              }
5846
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
5847
0
            } else {
5848
0
              smart_branch_opcode = 0;
5849
0
              exit_addr = NULL;
5850
0
            }
5851
0
            if (!zend_jit_in_array(&ctx, opline,
5852
0
                op1_info, op1_addr,
5853
0
                smart_branch_opcode, -1, -1, exit_addr)) {
5854
0
              goto jit_failure;
5855
0
            }
5856
0
            goto done;
5857
2
          case ZEND_FETCH_DIM_FUNC_ARG:
5858
2
            if (!JIT_G(current_frame)
5859
2
             || !JIT_G(current_frame)->call
5860
2
             || !JIT_G(current_frame)->call->func
5861
2
             || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
5862
0
              break;
5863
0
            }
5864
2
            ZEND_FALLTHROUGH;
5865
68
          case ZEND_FETCH_DIM_R:
5866
95
          case ZEND_FETCH_DIM_IS:
5867
96
          case ZEND_FETCH_LIST_R:
5868
96
            op1_info = OP1_INFO();
5869
96
            op1_addr = OP1_REG_ADDR();
5870
96
            if (orig_op1_type != IS_UNKNOWN
5871
64
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
5872
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5873
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5874
0
                goto jit_failure;
5875
0
              }
5876
0
              if (opline->op1_type == IS_CV
5877
0
               && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5878
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5879
0
                if (ssa_op->op1_def >= 0) {
5880
0
                  ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5881
0
                }
5882
0
              }
5883
96
            } else {
5884
96
              CHECK_OP1_TRACE_TYPE();
5885
96
            }
5886
96
            op2_info = OP2_INFO();
5887
96
            CHECK_OP2_TRACE_TYPE();
5888
96
            res_info = RES_INFO();
5889
96
            avoid_refcounting =
5890
96
              ssa_op->op1_use >= 0 &&
5891
64
              ssa->var_info[ssa_op->op1_use].avoid_refcounting;
5892
96
            if (op1_info & MAY_BE_PACKED_GUARD) {
5893
2
              ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
5894
94
            } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
5895
38
                && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
5896
16
                && MAY_BE_PACKED(op1_info)
5897
7
                && MAY_BE_HASH(op1_info)
5898
0
                && orig_op1_type != IS_UNKNOWN) {
5899
0
              op1_info |= MAY_BE_PACKED_GUARD;
5900
0
              if (orig_op1_type & IS_TRACE_PACKED) {
5901
0
                op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5902
0
                if (op1_type != IS_UNKNOWN) {
5903
0
                  ssa->var_info[ssa_op->op1_use].type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
5904
0
                }
5905
0
              } else {
5906
0
                op1_info &= ~MAY_BE_ARRAY_PACKED;
5907
0
                if (op1_type != IS_UNKNOWN) {
5908
0
                  ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_ARRAY_PACKED;
5909
0
                }
5910
0
              }
5911
0
            }
5912
96
            if (!zend_jit_fetch_dim_read(&ctx, opline, ssa, ssa_op,
5913
96
                op1_info, op1_addr, avoid_refcounting,
5914
96
                op2_info, OP2_REG_ADDR(), OP2_RANGE(),
5915
96
                res_info, RES_REG_ADDR(), val_type)) {
5916
0
              goto jit_failure;
5917
0
            }
5918
96
            if (ssa_op->op1_def >= 0 && op1_type != IS_UNKNOWN) {
5919
0
              ssa->var_info[ssa_op->op1_def].type = ssa->var_info[ssa_op->op1_use].type;
5920
0
            }
5921
96
            goto done;
5922
17
          case ZEND_FETCH_DIM_W:
5923
24
          case ZEND_FETCH_DIM_RW:
5924
//          case ZEND_FETCH_DIM_UNSET:
5925
25
          case ZEND_FETCH_LIST_W:
5926
25
            if (opline->op1_type != IS_CV
5927
7
             && (orig_op1_type == IS_UNKNOWN
5928
7
              || !(orig_op1_type & IS_TRACE_INDIRECT))) {
5929
1
              break;
5930
1
            }
5931
24
            op1_info = OP1_INFO();
5932
24
            op1_addr = OP1_REG_ADDR();
5933
24
            if (opline->op1_type == IS_VAR) {
5934
6
              if (orig_op1_type != IS_UNKNOWN
5935
6
               && (orig_op1_type & IS_TRACE_INDIRECT)) {
5936
6
                if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
5937
6
                    &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
5938
0
                  goto jit_failure;
5939
0
                }
5940
6
              } else {
5941
0
                break;
5942
0
              }
5943
6
            }
5944
24
            if (orig_op1_type != IS_UNKNOWN
5945
24
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
5946
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5947
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5948
0
                goto jit_failure;
5949
0
              }
5950
0
              if (opline->op1_type == IS_CV
5951
0
               && ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
5952
0
                ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
5953
0
              }
5954
24
            } else {
5955
24
              CHECK_OP1_TRACE_TYPE();
5956
24
            }
5957
24
            op2_info = OP2_INFO();
5958
24
            CHECK_OP2_TRACE_TYPE();
5959
24
            op1_def_info = OP1_DEF_INFO();
5960
24
            if (!zend_jit_fetch_dim(&ctx, opline,
5961
24
                op1_info, op1_addr,
5962
24
                op2_info, (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
5963
24
                (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
5964
24
                RES_REG_ADDR(), val_type)) {
5965
0
              goto jit_failure;
5966
0
            }
5967
24
            if (ssa_op->result_def >= 0
5968
24
             && (opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_LIST_W)
5969
17
             && !(op1_info & (MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))
5970
17
             && !(op2_info & (MAY_BE_UNDEF|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_OBJECT))) {
5971
6
              ssa->var_info[ssa_op->result_def].indirect_reference = 1;
5972
6
            }
5973
24
            goto done;
5974
3
          case ZEND_ISSET_ISEMPTY_DIM_OBJ:
5975
3
            if ((opline->extended_value & ZEND_ISEMPTY)) {
5976
              // TODO: support for empty() ???
5977
0
              break;
5978
0
            }
5979
3
            op1_info = OP1_INFO();
5980
3
            op1_addr = OP1_REG_ADDR();
5981
3
            if (orig_op1_type != IS_UNKNOWN
5982
3
             && (orig_op1_type & IS_TRACE_REFERENCE)) {
5983
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5984
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
5985
0
                goto jit_failure;
5986
0
              }
5987
0
              if (opline->op1_type == IS_CV
5988
0
               && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
5989
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
5990
0
              }
5991
3
            } else {
5992
3
              CHECK_OP1_TRACE_TYPE();
5993
3
            }
5994
3
            op2_info = OP2_INFO();
5995
3
            CHECK_OP2_TRACE_TYPE();
5996
3
            if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
5997
0
              bool exit_if_true = 0;
5998
0
              const zend_op *exit_opline = zend_jit_trace_get_exit_opline(p + 1, opline + 1, &exit_if_true);
5999
0
              uint32_t exit_point;
6000
0
              int32_t old_ref = 0;
6001
0
              uint8_t old_flags = 0;
6002
6003
0
              if (ra) {
6004
0
                if (opline->op2_type != IS_CONST) {
6005
0
                  old_ref = STACK_REF(stack, EX_VAR_TO_NUM(opline->op2.var));
6006
0
                  old_flags = STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op2.var));
6007
0
                }
6008
0
                zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
6009
0
              }
6010
0
              if (ssa_op->op1_use >= 0
6011
0
               && ssa->var_info[ssa_op->op1_use].avoid_refcounting) {
6012
                /* Temporary reset ZREG_ZVAL_TRY_ADDREF */
6013
0
                uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var));
6014
6015
0
                SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
6016
0
                exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6017
0
                SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info);
6018
0
              } else {
6019
0
                exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6020
0
              }
6021
0
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6022
0
              if (!exit_addr) {
6023
0
                goto jit_failure;
6024
0
              }
6025
0
              if (old_ref) {
6026
0
                SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->op2.var), old_ref, old_flags);
6027
0
              }
6028
0
              smart_branch_opcode = exit_if_true ? ZEND_JMPNZ : ZEND_JMPZ;
6029
3
            } else {
6030
3
              smart_branch_opcode = 0;
6031
3
              exit_addr = NULL;
6032
3
            }
6033
3
            avoid_refcounting =
6034
3
              ssa_op->op1_use >= 0 &&
6035
3
              ssa->var_info[ssa_op->op1_use].avoid_refcounting;
6036
3
            if (op1_info & MAY_BE_PACKED_GUARD) {
6037
0
              ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
6038
3
            } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
6039
3
                && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
6040
0
                && MAY_BE_PACKED(op1_info)
6041
0
                && MAY_BE_HASH(op1_info)
6042
0
                && orig_op1_type != IS_UNKNOWN) {
6043
0
              op1_info |= MAY_BE_PACKED_GUARD;
6044
0
              if (orig_op1_type & IS_TRACE_PACKED) {
6045
0
                op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
6046
0
              } else {
6047
0
                op1_info &= ~MAY_BE_ARRAY_PACKED;
6048
0
              }
6049
0
            }
6050
3
            if (!zend_jit_isset_isempty_dim(&ctx, opline,
6051
3
                op1_info, op1_addr, avoid_refcounting,
6052
3
                op2_info, OP2_REG_ADDR(), OP2_RANGE(), val_type,
6053
3
                zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info),
6054
3
                smart_branch_opcode, -1, -1,
6055
3
                exit_addr)) {
6056
0
              goto jit_failure;
6057
0
            }
6058
3
            goto done;
6059
3
          case ZEND_FETCH_OBJ_FUNC_ARG:
6060
0
            if (!JIT_G(current_frame)
6061
0
             || !JIT_G(current_frame)->call
6062
0
             || TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) {
6063
0
              break;
6064
0
            }
6065
0
            if (!JIT_G(current_frame)->call->func
6066
0
             || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
6067
0
              if (!zend_jit_func_arg_by_ref_guard(&ctx, opline)) {
6068
0
                goto jit_failure;
6069
0
              }
6070
0
            }
6071
0
            ZEND_FALLTHROUGH;
6072
45
          case ZEND_FETCH_OBJ_R:
6073
46
          case ZEND_FETCH_OBJ_IS:
6074
46
          case ZEND_FETCH_OBJ_W:
6075
46
            on_this = delayed_fetch_this = 0;
6076
46
            avoid_refcounting = 0;
6077
46
            if (opline->op2_type != IS_CONST
6078
43
             || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
6079
43
             || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
6080
4
              break;
6081
4
            }
6082
42
            ce = NULL;
6083
42
            ce_is_instanceof = 0;
6084
42
            op1_indirect = 0;
6085
42
            if (opline->op1_type == IS_UNUSED) {
6086
0
              op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
6087
0
              ce = op_array->scope;
6088
              /* scope is NULL for closures. */
6089
0
              if (ce) {
6090
0
                ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
6091
0
              }
6092
0
              op1_addr = 0;
6093
0
              on_this = 1;
6094
42
            } else {
6095
42
              op1_info = OP1_INFO();
6096
42
              if (!(op1_info & MAY_BE_OBJECT)) {
6097
11
                break;
6098
11
              }
6099
31
              op1_addr = OP1_REG_ADDR();
6100
31
              if (opline->op1_type == IS_VAR
6101
0
               && opline->opcode == ZEND_FETCH_OBJ_W) {
6102
0
                if (orig_op1_type != IS_UNKNOWN
6103
0
                 && (orig_op1_type & IS_TRACE_INDIRECT)) {
6104
0
                  op1_indirect = 1;
6105
0
                  if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
6106
0
                      &op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
6107
0
                    goto jit_failure;
6108
0
                  }
6109
0
                }
6110
0
              }
6111
31
              if (orig_op1_type != IS_UNKNOWN
6112
31
               && (orig_op1_type & IS_TRACE_REFERENCE)) {
6113
0
                if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6114
0
                    !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6115
0
                  goto jit_failure;
6116
0
                }
6117
0
                if (opline->op1_type == IS_CV
6118
0
                 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6119
0
                  ssa->var_info[ssa_op->op1_def >= 0 ? ssa_op->op1_def : ssa_op->op1_use].guarded_reference = 1;
6120
0
                }
6121
31
              } else {
6122
31
                CHECK_OP1_TRACE_TYPE();
6123
31
              }
6124
31
              if (!(op1_info & MAY_BE_OBJECT)) {
6125
0
                break;
6126
0
              }
6127
31
              if (ssa->var_info && ssa->ops) {
6128
31
                if (ssa_op->op1_use >= 0) {
6129
31
                  zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
6130
31
                  if (op1_ssa->ce && !op1_ssa->ce->create_object) {
6131
0
                    ce = op1_ssa->ce;
6132
0
                    ce_is_instanceof = op1_ssa->is_instanceof;
6133
0
                  }
6134
31
                }
6135
31
              }
6136
31
              if (ssa_op->op1_use >= 0) {
6137
31
                delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
6138
31
                avoid_refcounting = ssa->var_info[ssa_op->op1_use].avoid_refcounting;
6139
31
              }
6140
31
              if (delayed_fetch_this) {
6141
0
                on_this = 1;
6142
31
              } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
6143
13
                on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
6144
18
              } else if (op_array_ssa->ops
6145
0
                      && op_array_ssa->vars
6146
0
                  && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
6147
0
                  && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
6148
0
                on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
6149
0
              }
6150
31
            }
6151
31
            if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
6152
31
                op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
6153
31
                on_this, delayed_fetch_this, avoid_refcounting, op1_ce,
6154
31
                RES_REG_ADDR(), val_type,
6155
31
                zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) {
6156
0
              goto jit_failure;
6157
0
            }
6158
31
            goto done;
6159
31
          case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
6160
0
            if (!JIT_G(current_frame)
6161
0
             || !JIT_G(current_frame)->call
6162
0
             || !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
6163
0
              break;
6164
0
            }
6165
0
            ZEND_FALLTHROUGH;
6166
0
          case ZEND_FETCH_STATIC_PROP_R:
6167
0
          case ZEND_FETCH_STATIC_PROP_IS:
6168
2
          case ZEND_FETCH_STATIC_PROP_W:
6169
2
          case ZEND_FETCH_STATIC_PROP_RW:
6170
2
          case ZEND_FETCH_STATIC_PROP_UNSET:
6171
2
            if (!(opline->op1_type == IS_CONST
6172
2
             && (opline->op2_type == IS_CONST
6173
0
              || (opline->op2_type == IS_UNUSED
6174
0
               && ((opline->op2.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
6175
0
                || (opline->op2.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT))))) {
6176
0
              break;
6177
0
            }
6178
2
            if (!zend_jit_fetch_static_prop(&ctx, opline, op_array)) {
6179
0
              goto jit_failure;
6180
0
            }
6181
2
            goto done;
6182
3
          case ZEND_BIND_GLOBAL:
6183
3
            orig_opline = opline;
6184
3
            orig_ssa_op = ssa_op;
6185
3
            while (1) {
6186
3
              if (!ssa->ops || !ssa->var_info) {
6187
0
                op1_info = MAY_BE_ANY|MAY_BE_REF;
6188
3
              } else {
6189
3
                op1_info = OP1_INFO();
6190
3
              }
6191
3
              if (ssa->vars[ssa_op->op1_def].alias == NO_ALIAS) {
6192
2
                ssa->var_info[ssa_op->op1_def].guarded_reference = 1;
6193
2
              }
6194
3
              if (!zend_jit_bind_global(&ctx, opline, op1_info)) {
6195
0
                goto jit_failure;
6196
0
              }
6197
3
              if ((opline+1)->opcode == ZEND_BIND_GLOBAL) {
6198
0
                opline++;
6199
0
                ssa_op++;
6200
3
              } else {
6201
3
                break;
6202
3
              }
6203
3
            }
6204
3
            opline = orig_opline;
6205
3
            ssa_op = orig_ssa_op;
6206
3
            goto done;
6207
0
          case ZEND_RECV:
6208
0
            if (!zend_jit_recv(&ctx, opline, op_array, op1_ce)) {
6209
0
              goto jit_failure;
6210
0
            }
6211
0
            goto done;
6212
2
          case ZEND_RECV_INIT:
6213
2
            orig_opline = opline;
6214
2
            orig_ssa_op = ssa_op;
6215
2
            while (1) {
6216
2
              if (!zend_jit_recv_init(&ctx, opline, op_array,
6217
2
                  (opline + 1)->opcode != ZEND_RECV_INIT,
6218
2
                  zend_may_throw(opline, ssa_op, op_array, ssa))) {
6219
0
                goto jit_failure;
6220
0
              }
6221
2
              if ((opline+1)->opcode == ZEND_RECV_INIT) {
6222
0
                opline++;
6223
0
                ssa_op++;
6224
2
              } else {
6225
2
                break;
6226
2
              }
6227
2
            }
6228
2
            opline = orig_opline;
6229
2
            ssa_op = orig_ssa_op;
6230
2
            goto done;
6231
327
          case ZEND_FREE:
6232
329
          case ZEND_FE_FREE:
6233
329
            op1_info = OP1_INFO();
6234
329
            if (!zend_jit_free(&ctx, opline, op1_info,
6235
329
                zend_may_throw(opline, ssa_op, op_array, ssa))) {
6236
0
              goto jit_failure;
6237
0
            }
6238
329
            goto done;
6239
1.43k
          case ZEND_ECHO:
6240
1.43k
            op1_info = OP1_INFO();
6241
1.43k
            CHECK_OP1_TRACE_TYPE();
6242
1.43k
            if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
6243
412
              break;
6244
412
            }
6245
1.02k
            if (!zend_jit_echo(&ctx, opline, op1_info)) {
6246
0
              goto jit_failure;
6247
0
            }
6248
1.02k
            goto done;
6249
1.02k
          case ZEND_STRLEN:
6250
0
            op1_info = OP1_INFO();
6251
0
            op1_addr = OP1_REG_ADDR();
6252
0
            if (orig_op1_type == (IS_TRACE_REFERENCE|IS_STRING)) {
6253
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6254
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6255
0
                goto jit_failure;
6256
0
              }
6257
0
              if (opline->op1_type == IS_CV
6258
0
               && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6259
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6260
0
              }
6261
0
            } else {
6262
0
              CHECK_OP1_TRACE_TYPE();
6263
0
              if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
6264
0
                break;
6265
0
              }
6266
0
            }
6267
0
            if (!zend_jit_strlen(&ctx, opline, op1_info, op1_addr, RES_REG_ADDR())) {
6268
0
              goto jit_failure;
6269
0
            }
6270
0
            goto done;
6271
0
          case ZEND_COUNT:
6272
0
            op1_info = OP1_INFO();
6273
0
            op1_addr = OP1_REG_ADDR();
6274
0
            if (orig_op1_type == (IS_TRACE_REFERENCE|IS_ARRAY)) {
6275
0
              if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6276
0
                  !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6277
0
                goto jit_failure;
6278
0
              }
6279
0
              if (opline->op1_type == IS_CV
6280
0
               && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6281
0
                ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6282
0
              }
6283
0
            } else {
6284
0
              CHECK_OP1_TRACE_TYPE();
6285
0
              if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
6286
0
                break;
6287
0
              }
6288
0
            }
6289
0
            if (!zend_jit_count(&ctx, opline, op1_info, op1_addr, RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
6290
0
              goto jit_failure;
6291
0
            }
6292
0
            goto done;
6293
0
          case ZEND_FETCH_THIS:
6294
0
            delayed_fetch_this = 0;
6295
0
            if (ssa_op->result_def >= 0 && opline->result_type != IS_CV) {
6296
0
              if (zend_jit_may_delay_fetch_this(op_array, ssa, ssa_opcodes, ssa_op)) {
6297
0
                ssa->var_info[ssa_op->result_def].delayed_fetch_this = 1;
6298
0
                delayed_fetch_this = 1;
6299
0
              }
6300
0
            }
6301
0
            if (!zend_jit_fetch_this(&ctx, opline, op_array, delayed_fetch_this)) {
6302
0
              goto jit_failure;
6303
0
            }
6304
0
            goto done;
6305
0
          case ZEND_SWITCH_LONG:
6306
0
          case ZEND_SWITCH_STRING:
6307
0
          case ZEND_MATCH:
6308
0
            if (!zend_jit_switch(&ctx, opline, op_array, op_array_ssa, p+1, &zend_jit_traces[ZEND_JIT_TRACE_NUM])) {
6309
0
              goto jit_failure;
6310
0
            }
6311
0
            goto done;
6312
0
          case ZEND_VERIFY_RETURN_TYPE:
6313
0
            if (opline->op1_type == IS_UNUSED) {
6314
              /* Always throws */
6315
0
              break;
6316
0
            }
6317
0
            if (opline->op1_type == IS_CONST) {
6318
              /* TODO Different instruction format, has return value */
6319
0
              break;
6320
0
            }
6321
0
            if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
6322
              /* Not worth bothering with */
6323
0
              break;
6324
0
            }
6325
0
            op1_info = OP1_INFO();
6326
0
            CHECK_OP1_TRACE_TYPE();
6327
0
            if (op1_info & MAY_BE_REF) {
6328
              /* TODO May need reference unwrapping. */
6329
0
              break;
6330
0
            }
6331
0
            if (!zend_jit_verify_return_type(&ctx, opline, op_array, op1_info, op1_ce)) {
6332
0
              goto jit_failure;
6333
0
            }
6334
0
            goto done;
6335
2
          case ZEND_FE_RESET_R:
6336
2
            op1_info = OP1_INFO();
6337
2
            CHECK_OP1_TRACE_TYPE();
6338
2
            if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
6339
0
              break;
6340
0
            }
6341
2
            if (!zend_jit_fe_reset(&ctx, opline, op1_info)) {
6342
0
              goto jit_failure;
6343
0
            }
6344
2
            goto done;
6345
2
          case ZEND_FE_FETCH_R:
6346
2
            op1_info = OP1_INFO();
6347
2
            CHECK_OP1_TRACE_TYPE();
6348
2
            if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
6349
0
              break;
6350
0
            }
6351
2
            if ((p+1)->op == ZEND_JIT_TRACE_VM || (p+1)->op == ZEND_JIT_TRACE_END) {
6352
2
              const zend_op *exit_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value);
6353
2
              uint32_t exit_point;
6354
6355
2
              if ((p+1)->opline == exit_opline) {
6356
                /* taken branch (exit from loop) */
6357
0
                exit_opline = opline;
6358
0
                smart_branch_opcode = ZEND_NOP;
6359
2
              } else if ((p+1)->opline == opline + 1) {
6360
                /* not taken branch (loop) */
6361
2
                smart_branch_opcode = ZEND_JMP;
6362
2
              } else {
6363
0
                ZEND_UNREACHABLE();
6364
0
              }
6365
2
              exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6366
2
              exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6367
2
              if (!exit_addr) {
6368
0
                goto jit_failure;
6369
0
              }
6370
2
            } else  {
6371
0
              ZEND_UNREACHABLE();
6372
0
            }
6373
2
            if (!zend_jit_fe_fetch(&ctx, opline, op1_info, OP2_INFO(),
6374
2
                -1, smart_branch_opcode, exit_addr)) {
6375
0
              goto jit_failure;
6376
0
            }
6377
2
            goto done;
6378
3
          case ZEND_FETCH_CONSTANT:
6379
3
            if (!zend_jit_fetch_constant(&ctx, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
6380
0
              goto jit_failure;
6381
0
            }
6382
3
            goto done;
6383
3
          case ZEND_INIT_METHOD_CALL:
6384
2
            if (opline->op2_type != IS_CONST
6385
2
             || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
6386
0
              break;
6387
0
            }
6388
2
            on_this = delayed_fetch_this = 0;
6389
2
            ce = NULL;
6390
2
            ce_is_instanceof = 0;
6391
2
            if (opline->op1_type == IS_UNUSED) {
6392
0
              op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
6393
0
              ce = op_array->scope;
6394
              /* scope is NULL for closures. */
6395
0
              if (ce) {
6396
0
                ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
6397
0
              }
6398
0
              op1_addr = 0;
6399
0
              on_this = 1;
6400
2
            } else {
6401
2
              op1_info = OP1_INFO();
6402
2
              op1_addr = OP1_REG_ADDR();
6403
2
              if (polymorphic_side_trace) {
6404
0
                op1_info = MAY_BE_OBJECT;
6405
2
              } else if (orig_op1_type != IS_UNKNOWN
6406
2
               && (orig_op1_type & IS_TRACE_REFERENCE)) {
6407
0
                if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6408
0
                    !ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
6409
0
                  goto jit_failure;
6410
0
                }
6411
0
                if (opline->op1_type == IS_CV
6412
0
                 && ssa->vars[ssa_op->op1_use].alias == NO_ALIAS) {
6413
0
                  ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
6414
0
                }
6415
2
              } else {
6416
2
                CHECK_OP1_TRACE_TYPE();
6417
2
              }
6418
2
              if (ssa->var_info && ssa->ops) {
6419
2
                if (ssa_op->op1_use >= 0) {
6420
2
                  zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
6421
2
                  if (op1_ssa->ce && !op1_ssa->ce->create_object) {
6422
0
                    ce = op1_ssa->ce;
6423
0
                    ce_is_instanceof = op1_ssa->is_instanceof;
6424
0
                  }
6425
2
                }
6426
2
              }
6427
2
              if (ssa_op->op1_use >= 0) {
6428
2
                delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
6429
2
              }
6430
2
              if (delayed_fetch_this) {
6431
0
                on_this = 1;
6432
2
              } else if (ssa_op->op1_use >= 0 && ssa->vars[ssa_op->op1_use].definition >= 0) {
6433
2
                on_this = ssa_opcodes[ssa->vars[ssa_op->op1_use].definition]->opcode == ZEND_FETCH_THIS;
6434
2
              } else if (op_array_ssa->ops
6435
0
                      && op_array_ssa->vars
6436
0
                  && op_array_ssa->ops[opline-op_array->opcodes].op1_use >= 0
6437
0
                  && op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition >= 0) {
6438
0
                on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
6439
0
              }
6440
2
            }
6441
2
            frame_flags = TRACE_FRAME_MASK_NESTED;
6442
2
            if (!zend_jit_init_method_call(&ctx, opline,
6443
2
                op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1,
6444
2
                op_array, ssa, ssa_op, frame->call_level,
6445
2
                op1_info, op1_addr, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
6446
2
                p + 1, peek_checked_stack - checked_stack,
6447
2
                polymorphic_side_trace ? jit->poly_func_ref : -1,
6448
2
                polymorphic_side_trace ? jit->poly_this_ref : -1,
6449
2
                polymorphic_side_trace)) {
6450
0
              goto jit_failure;
6451
0
            }
6452
2
            goto done;
6453
2
          case ZEND_INIT_STATIC_METHOD_CALL:
6454
0
            if (!(opline->op2_type == IS_CONST
6455
0
             && (opline->op1_type == IS_CONST
6456
0
              || (opline->op1_type == IS_UNUSED
6457
0
               && ((opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_SELF
6458
0
                || (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT))))) {
6459
0
              break;
6460
0
            }
6461
0
            if (!zend_jit_init_static_method_call(&ctx, opline,
6462
0
                op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1,
6463
0
                op_array, ssa, ssa_op, frame->call_level,
6464
0
                p + 1, peek_checked_stack - checked_stack)) {
6465
0
              goto jit_failure;
6466
0
            }
6467
0
            goto done;
6468
1
          case ZEND_INIT_DYNAMIC_CALL:
6469
1
            if (orig_op2_type != IS_OBJECT || op2_ce != zend_ce_closure) {
6470
0
              break;
6471
0
            }
6472
1
            op2_info = OP2_INFO();
6473
1
            CHECK_OP2_TRACE_TYPE();
6474
1
            frame_flags = TRACE_FRAME_MASK_NESTED;
6475
1
            if (!zend_jit_init_closure_call(&ctx, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
6476
0
              goto jit_failure;
6477
0
            }
6478
1
            goto done;
6479
1
          case ZEND_SEND_ARRAY:
6480
0
          case ZEND_SEND_UNPACK:
6481
0
            if (JIT_G(current_frame)
6482
0
             && JIT_G(current_frame)->call) {
6483
0
              TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(JIT_G(current_frame)->call);
6484
0
            }
6485
0
            break;
6486
59
          case ZEND_ROPE_INIT:
6487
179
          case ZEND_ROPE_ADD:
6488
238
          case ZEND_ROPE_END:
6489
238
            op2_info = OP2_INFO();
6490
238
            CHECK_OP2_TRACE_TYPE();
6491
238
            if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
6492
106
              break;
6493
106
            }
6494
132
            if (!zend_jit_rope(&ctx, opline, op2_info)) {
6495
0
              goto jit_failure;
6496
0
            }
6497
132
            goto done;
6498
132
          case ZEND_FRAMELESS_ICALL_0:
6499
0
            if (!jit_frameless_icall0(jit, opline)) {
6500
0
              goto jit_failure;
6501
0
            }
6502
0
            goto done;
6503
0
          case ZEND_FRAMELESS_ICALL_1:
6504
0
            op1_info = OP1_INFO();
6505
0
            if (!jit_frameless_icall1(jit, opline, op1_info)) {
6506
0
              goto jit_failure;
6507
0
            }
6508
0
            goto done;
6509
0
          case ZEND_FRAMELESS_ICALL_2:
6510
0
            op1_info = OP1_INFO();
6511
0
            op2_info = OP2_INFO();
6512
0
            if (!jit_frameless_icall2(jit, opline, op1_info, op2_info)) {
6513
0
              goto jit_failure;
6514
0
            }
6515
0
            goto done;
6516
0
          case ZEND_FRAMELESS_ICALL_3:
6517
0
            op1_info = OP1_INFO();
6518
0
            op2_info = OP2_INFO();
6519
0
            if (!jit_frameless_icall3(jit, opline, op1_info, op2_info, OP1_DATA_INFO())) {
6520
0
              goto jit_failure;
6521
0
            }
6522
0
            goto done;
6523
1.08k
          default:
6524
1.08k
            break;
6525
8.94k
        }
6526
8.94k
      }
6527
6528
2.91k
      if (opline->opcode != ZEND_NOP && opline->opcode != ZEND_JMP) {
6529
2.88k
        gen_handler = 1;
6530
2.88k
        op1_info = OP1_INFO();
6531
2.88k
        op2_info = OP2_INFO();
6532
2.88k
        if (op1_info & MAY_BE_GUARD) {
6533
295
          op1_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6534
295
        }
6535
2.88k
        if (op2_info & MAY_BE_GUARD) {
6536
77
          op2_info = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY  | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
6537
77
        }
6538
2.88k
        if (!zend_jit_trace_handler(&ctx, op_array, opline,
6539
2.88k
            zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, op2_info), p + 1)) {
6540
0
          goto jit_failure;
6541
0
        }
6542
2.88k
        if ((p+1)->op == ZEND_JIT_TRACE_INIT_CALL && (p+1)->func) {
6543
4
          if (opline->opcode == ZEND_NEW && opline->result_type != IS_UNUSED) {
6544
4
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_OBJECT, 1);
6545
4
          }
6546
4
          if (zend_jit_may_be_polymorphic_call(opline) ||
6547
2
              zend_jit_may_be_modified((p+1)->func, op_array)) {
6548
2
            if (!zend_jit_init_fcall_guard(&ctx, 0, (p+1)->func, opline+1)) {
6549
0
              goto jit_failure;
6550
0
            }
6551
2
          }
6552
4
        }
6553
2.88k
      }
6554
6555
8.94k
done:
6556
8.94k
      polymorphic_side_trace = 0;
6557
8.94k
      if (zend_jit_dec_call_level(opline->opcode)) {
6558
211
        frame->call_level--;
6559
211
      }
6560
6561
8.94k
      if (ra) {
6562
1.17k
        zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
6563
1.17k
      }
6564
6565
8.94k
      if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
6566
2.11k
       && STACK_FLAGS(stack, EX_VAR_TO_NUM(opline->op1.var)) & (ZREG_ZVAL_ADDREF|ZREG_THIS)) {
6567
0
        SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
6568
0
      }
6569
6570
8.94k
      if (opline->opcode == ZEND_ROPE_INIT) {
6571
        /* clear stack slots used by rope */
6572
59
        uint32_t var = EX_VAR_TO_NUM(opline->result.var);
6573
59
        uint32_t count =
6574
59
          ((opline->extended_value * sizeof(void*)) + (sizeof(zval)-1)) / sizeof(zval);
6575
6576
139
        do {
6577
139
          SET_STACK_TYPE(stack, var, IS_UNKNOWN, 1);
6578
139
          var++;
6579
139
          count--;
6580
139
        } while (count);
6581
59
      }
6582
6583
8.94k
      if (ssa_op) {
6584
8.94k
        zend_ssa_range tmp;
6585
6586
        /* Keep information about known types on abstract stack */
6587
8.94k
        if (ssa_op->result_def >= 0) {
6588
3.39k
          uint8_t type = IS_UNKNOWN;
6589
6590
3.39k
          if ((opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0
6591
3.39k
           || send_result) {
6592
            /* we didn't set result variable */
6593
6
            type = IS_UNKNOWN;
6594
3.39k
          } else if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6595
2.77k
           && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6596
1.91k
            type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6597
1.91k
          } else if (opline->opcode == ZEND_QM_ASSIGN) {
6598
57
            if (opline->op1_type != IS_CONST) {
6599
              /* copy */
6600
57
              type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6601
57
            }
6602
1.42k
          } else if (opline->opcode == ZEND_ASSIGN) {
6603
60
            if (opline->op2_type != IS_CONST
6604
44
             && ssa_op->op1_use >= 0
6605
             /* assignment to typed reference may cause conversion */
6606
44
             && (ssa->var_info[ssa_op->op1_use].type & MAY_BE_REF) == 0) {
6607
              /* copy */
6608
0
              type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6609
0
            }
6610
1.36k
          } else if (opline->opcode == ZEND_POST_INC
6611
1.36k
               || opline->opcode == ZEND_POST_DEC) {
6612
            /* copy */
6613
2
            type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6614
2
          }
6615
3.39k
          if (opline->opcode == ZEND_JMP_SET
6616
3.38k
            || opline->opcode == ZEND_COALESCE
6617
3.35k
            || opline->opcode == ZEND_JMP_NULL) {
6618
51
            if ((p+1)->op != ZEND_JIT_TRACE_VM) {
6619
0
              SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1);
6620
51
            } else if ((p+1)->opline != (opline + 1)) {
6621
16
              SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type, 1);
6622
16
            }
6623
3.34k
          } else {
6624
3.34k
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6625
3.34k
              (gen_handler || type == IS_UNKNOWN || !ra || !RA_HAS_REG(ssa_op->result_def)));
6626
6627
3.34k
            if (op_array->last_live_range
6628
1.29k
             && opline->result.var > op_array->last_var
6629
1.29k
             && STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)) != type) {
6630
47
              if (!gen_handler && type != IS_UNKNOWN && ra && RA_HAS_REG(ssa_op->result_def)) {
6631
47
                uint32_t var_num = opline->result.var;
6632
47
                uint32_t op_num = opline - op_array->opcodes;
6633
47
                const zend_live_range *range = op_array->live_range;
6634
6635
47
                op_num += zend_jit_trace_op_len(opline);
6636
65
                for (uint32_t j = 0; j < op_array->last_live_range; range++, j++) {
6637
55
                  if (range->start > op_num) {
6638
                    /* further blocks will not be relevant... */
6639
8
                    break;
6640
47
                  } else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
6641
                    /* check if opcodes in range may throw */
6642
29
                    bool store_type = 0;
6643
29
                    const zend_ssa_op *next_ssa_op = ssa_op + zend_jit_trace_op_len(opline);
6644
29
                    const zend_jit_trace_rec *q = p + 1;
6645
6646
31
                    while (1) {
6647
31
                      if (q->op != ZEND_JIT_TRACE_VM) {
6648
0
                        store_type = 1;
6649
0
                        break;
6650
0
                      }
6651
31
                      op_num = q->opline - op_array->opcodes;
6652
31
                      if (op_num >= range->end || op_num < range->start) {
6653
1
                        break;
6654
1
                      }
6655
30
                      if (zend_may_throw(q->opline, next_ssa_op, op_array, ssa)) {
6656
28
                        store_type = 1;
6657
28
                        break;
6658
28
                      }
6659
2
                      next_ssa_op += zend_jit_trace_op_len(q->opline);
6660
2
                      q++;
6661
2
                    }
6662
29
                    if (store_type) {
6663
28
                      var_num = EX_VAR_TO_NUM(var_num);
6664
6665
28
                      if (!zend_jit_store_type(&ctx, var_num, type)) {
6666
0
                        goto jit_failure;
6667
0
                      }
6668
28
                      SET_STACK_TYPE(stack, var_num, type, 1);
6669
28
                    }
6670
29
                    break;
6671
29
                  }
6672
55
                }
6673
47
              }
6674
47
            }
6675
3.34k
            if (ssa->var_info[ssa_op->result_def].type & MAY_BE_INDIRECT) {
6676
84
              RESET_STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->result.var));
6677
84
            }
6678
3.34k
            if (type != IS_UNKNOWN) {
6679
1.89k
              ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
6680
1.89k
              if (opline->opcode == ZEND_FETCH_THIS
6681
0
               && delayed_fetch_this) {
6682
0
                SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_THIS);
6683
1.89k
              } else if (ssa->var_info[ssa_op->result_def].avoid_refcounting) {
6684
0
                SET_STACK_REG_EX(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NONE, ZREG_ZVAL_ADDREF);
6685
1.89k
              } else if (ra && RA_HAS_REG(ssa_op->result_def)) {
6686
304
                SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def].ref,
6687
304
                  RA_REG_FLAGS(ssa_op->result_def) & ZREG_STORE);
6688
304
              }
6689
1.89k
            }
6690
3.34k
          }
6691
6692
3.39k
          if (type == IS_LONG
6693
1.21k
           && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->result_def, &tmp)) {
6694
21
            ssa->var_info[ssa_op->result_def].range.min = tmp.min;
6695
21
            ssa->var_info[ssa_op->result_def].range.max = tmp.max;
6696
21
            ssa->var_info[ssa_op->result_def].range.underflow = 0;
6697
21
            ssa->var_info[ssa_op->result_def].range.overflow = 0;
6698
21
            ssa->var_info[ssa_op->result_def].has_range = 1;
6699
21
          }
6700
3.39k
        }
6701
8.94k
        if (ssa_op->op1_def >= 0
6702
665
         && ((opline->opcode != ZEND_QM_ASSIGN && opline->opcode != ZEND_CAST)
6703
49
          || opline->result_type != IS_CV
6704
665
          || opline->result.var != opline->op1.var)) {
6705
665
          uint8_t type = IS_UNKNOWN;
6706
6707
665
          if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6708
532
           && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6709
21
            type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6710
644
          } else if (opline->opcode == ZEND_ASSIGN) {
6711
162
            if (!(OP1_INFO() & MAY_BE_REF)
6712
162
             || STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_UNKNOWN) {
6713
0
              if (opline->op2_type != IS_CONST) {
6714
                /* copy */
6715
0
                type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6716
0
              }
6717
0
            }
6718
482
          } else if (opline->opcode == ZEND_SEND_VAR
6719
463
           || opline->opcode == ZEND_CAST
6720
444
           || opline->opcode == ZEND_QM_ASSIGN
6721
417
           || opline->opcode == ZEND_JMP_SET
6722
413
           || opline->opcode == ZEND_COALESCE
6723
410
           || opline->opcode == ZEND_JMP_NULL
6724
410
           || opline->opcode == ZEND_FE_RESET_R) {
6725
            /* keep old value */
6726
72
            type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6727
72
          }
6728
665
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6729
665
            (gen_handler || type == IS_UNKNOWN || !ra ||
6730
665
              (!RA_HAS_REG(ssa_op->op1_def) &&
6731
665
                !(ssa->vars[ssa_op->op1_def].no_val &&
6732
665
                  Z_MODE(OP1_REG_ADDR()) == IS_REG &&
6733
665
                    (opline->opcode == ZEND_QM_ASSIGN ||
6734
665
                      opline->opcode == ZEND_SEND_VAR ||
6735
665
                      opline->opcode == ZEND_SEND_VAR_EX ||
6736
665
                      opline->opcode == ZEND_SEND_VAR_NO_REF ||
6737
665
                      opline->opcode == ZEND_SEND_VAR_NO_REF_EX ||
6738
665
                      opline->opcode == ZEND_SEND_FUNC_ARG)))));
6739
665
          if (type != IS_UNKNOWN) {
6740
21
            ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6741
21
            if (ra && RA_HAS_REG(ssa_op->op1_def)) {
6742
6
              uint8_t flags = RA_REG_FLAGS(ssa_op->op1_def) & ZREG_STORE;
6743
6744
6
              if (ssa_op->op1_use >= 0) {
6745
6
                if (opline->opcode == ZEND_SEND_VAR
6746
6
                 || opline->opcode == ZEND_CAST
6747
6
                 || opline->opcode == ZEND_QM_ASSIGN
6748
6
                 || opline->opcode == ZEND_JMP_SET
6749
6
                 || opline->opcode == ZEND_COALESCE
6750
6
                 || opline->opcode == ZEND_JMP_NULL
6751
6
                 || opline->opcode == ZEND_FE_RESET_R) {
6752
0
                  if (!RA_HAS_REG(ssa_op->op1_use)) {
6753
0
                    flags |= ZREG_LOAD;
6754
0
                  }
6755
0
                }
6756
6
              }
6757
6
              SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def].ref, flags);
6758
6
            }
6759
21
          }
6760
665
          if (type == IS_LONG
6761
15
           && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op1_def, &tmp)) {
6762
7
            ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6763
7
            ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6764
7
            ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6765
7
            ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6766
7
            ssa->var_info[ssa_op->op1_def].has_range = 1;
6767
7
          }
6768
665
        }
6769
8.94k
        if (ssa_op->op2_def >= 0
6770
88
         && (opline->opcode != ZEND_ASSIGN
6771
39
          || opline->op1_type != IS_CV
6772
83
          || opline->op1.var != opline->op2.var)) {
6773
83
          uint8_t type = IS_UNKNOWN;
6774
6775
83
          if (!(ssa->var_info[ssa_op->op2_def].type & MAY_BE_GUARD)
6776
80
           && has_concrete_type(ssa->var_info[ssa_op->op2_def].type)) {
6777
6
            type = concrete_type(ssa->var_info[ssa_op->op2_def].type);
6778
77
          } else if (opline->opcode == ZEND_ASSIGN) {
6779
            /* keep old value */
6780
28
            type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var));
6781
28
          }
6782
83
          SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), type,
6783
83
            (gen_handler || type == IS_UNKNOWN || !ra ||
6784
83
              (!RA_HAS_REG(ssa_op->op2_def) &&
6785
83
                !(ssa->vars[ssa_op->op2_def].no_val &&
6786
83
                  Z_MODE(OP2_REG_ADDR()) == IS_REG &&
6787
83
                  opline->opcode == ZEND_ASSIGN))));
6788
83
          if (type != IS_UNKNOWN) {
6789
6
            ssa->var_info[ssa_op->op2_def].type &= ~MAY_BE_GUARD;
6790
6
            if (ra && RA_HAS_REG(ssa_op->op2_def)) {
6791
3
              uint8_t flags = RA_REG_FLAGS(ssa_op->op2_def) & ZREG_STORE;
6792
6793
3
              if (ssa_op->op2_use >= 0) {
6794
3
                if (opline->opcode == ZEND_ASSIGN) {
6795
3
                  if (!RA_HAS_REG(ssa_op->op2_use)
6796
3
                  ) {
6797
1
                    flags |= ZREG_LOAD;
6798
1
                  }
6799
3
                }
6800
3
              }
6801
3
              SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->op2.var), ra[ssa_op->op2_def].ref, flags);
6802
3
            }
6803
6
          }
6804
83
          if (type == IS_LONG
6805
4
           && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op2_def, &tmp)) {
6806
4
            ssa->var_info[ssa_op->op2_def].range.min = tmp.min;
6807
4
            ssa->var_info[ssa_op->op2_def].range.max = tmp.max;
6808
4
            ssa->var_info[ssa_op->op2_def].range.underflow = 0;
6809
4
            ssa->var_info[ssa_op->op2_def].range.overflow = 0;
6810
4
            ssa->var_info[ssa_op->op2_def].has_range = 1;
6811
4
          }
6812
83
        }
6813
6814
8.94k
        switch (opline->opcode) {
6815
89
          case ZEND_ASSIGN_DIM:
6816
89
          case ZEND_ASSIGN_OBJ:
6817
89
          case ZEND_ASSIGN_STATIC_PROP:
6818
242
          case ZEND_ASSIGN_DIM_OP:
6819
242
          case ZEND_ASSIGN_OBJ_OP:
6820
242
          case ZEND_ASSIGN_STATIC_PROP_OP:
6821
242
          case ZEND_ASSIGN_OBJ_REF:
6822
242
          case ZEND_ASSIGN_STATIC_PROP_REF:
6823
            /* OP_DATA */
6824
242
            ssa_op++;
6825
242
            opline++;
6826
242
            if (ssa_op->op1_def >= 0) {
6827
17
              uint8_t type = IS_UNKNOWN;
6828
6829
17
              if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6830
15
               && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6831
0
                type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6832
17
              } else if ((opline-1)->opcode == ZEND_ASSIGN_DIM
6833
0
               || (opline-1)->opcode == ZEND_ASSIGN_OBJ
6834
17
               || (opline-1)->opcode == ZEND_ASSIGN_STATIC_PROP) {
6835
                /* keep old value */
6836
17
                type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var));
6837
17
              }
6838
17
              SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6839
17
                (gen_handler || type == IS_UNKNOWN || !ra || !RA_HAS_REG(ssa_op->op1_def)));
6840
17
              if (type != IS_UNKNOWN) {
6841
0
                ssa->var_info[ssa_op->op1_def].type &= ~MAY_BE_GUARD;
6842
0
                if (ra && RA_HAS_REG(ssa_op->op1_def)) {
6843
0
                  SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def].ref,
6844
0
                    RA_REG_FLAGS(ssa_op->op1_def) & ZREG_STORE);
6845
0
                }
6846
0
              }
6847
17
              if (type == IS_LONG
6848
0
               && zend_inference_propagate_range(op_array, ssa, opline, ssa_op, ssa_op->op1_def, &tmp)) {
6849
0
                ssa->var_info[ssa_op->op1_def].range.min = tmp.min;
6850
0
                ssa->var_info[ssa_op->op1_def].range.max = tmp.max;
6851
0
                ssa->var_info[ssa_op->op1_def].range.underflow = 0;
6852
0
                ssa->var_info[ssa_op->op1_def].range.overflow = 0;
6853
0
                ssa->var_info[ssa_op->op1_def].has_range = 1;
6854
0
              }
6855
17
            }
6856
242
            ssa_op++;
6857
242
            break;
6858
2
          case ZEND_RECV_INIT:
6859
2
              ssa_op++;
6860
2
            opline++;
6861
2
            while (opline->opcode == ZEND_RECV_INIT) {
6862
0
              if (ssa_op->result_def >= 0) {
6863
0
                uint8_t type = IS_UNKNOWN;
6864
6865
0
                if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_GUARD)
6866
0
                 && has_concrete_type(ssa->var_info[ssa_op->result_def].type)) {
6867
0
                  type = concrete_type(ssa->var_info[ssa_op->result_def].type);
6868
0
                }
6869
0
                SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), type,
6870
0
                  (gen_handler || !ra || !RA_HAS_REG(ssa_op->result_def)));
6871
0
                if (ra && RA_HAS_REG(ssa_op->result_def)) {
6872
0
                  SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->result.var), ra[ssa_op->result_def].ref,
6873
0
                    RA_REG_FLAGS(ssa_op->result_def) & ZREG_STORE);
6874
0
                }
6875
0
              }
6876
0
              ssa_op++;
6877
0
              opline++;
6878
0
            }
6879
2
            break;
6880
3
          case ZEND_BIND_GLOBAL:
6881
3
            ssa_op++;
6882
3
            opline++;
6883
3
            while (opline->opcode == ZEND_BIND_GLOBAL) {
6884
0
              if (ssa_op->op1_def >= 0) {
6885
0
                uint8_t type = IS_UNKNOWN;
6886
6887
0
                if (!(ssa->var_info[ssa_op->op1_def].type & MAY_BE_GUARD)
6888
0
                 && has_concrete_type(ssa->var_info[ssa_op->op1_def].type)) {
6889
0
                  type = concrete_type(ssa->var_info[ssa_op->op1_def].type);
6890
0
                }
6891
0
                SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), type,
6892
0
                  (gen_handler || !ra || !RA_HAS_REG(ssa_op->op1_def)));
6893
0
                if (ra && RA_HAS_REG(ssa_op->op1_def)) {
6894
0
                  SET_STACK_REF_EX(stack, EX_VAR_TO_NUM(opline->op1.var), ra[ssa_op->op1_def].ref,
6895
0
                    RA_REG_FLAGS(ssa_op->op1_def) & ZREG_STORE);
6896
0
                }
6897
0
              }
6898
0
              ssa_op++;
6899
0
              opline++;
6900
0
            }
6901
3
            break;
6902
8.70k
          default:
6903
8.70k
            ssa_op += zend_jit_trace_op_len(opline);
6904
8.70k
            break;
6905
8.94k
        }
6906
6907
8.94k
        if (send_result) {
6908
3
          ssa_op++;
6909
3
          p++;
6910
3
          if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
6911
0
            p++;
6912
0
          }
6913
3
          send_result = 0;
6914
3
        }
6915
8.94k
      }
6916
8.94k
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
6917
17
      call = frame->call;
6918
17
      assert(call && &call->func->op_array == p->op_array);
6919
6920
17
      if (opline->opcode == ZEND_DO_UCALL
6921
1
       || opline->opcode == ZEND_DO_FCALL_BY_NAME
6922
17
       || opline->opcode == ZEND_DO_FCALL) {
6923
6924
17
        frame->call_opline = opline;
6925
6926
        /* Check if SEND_UNPACK/SEND_ARRAY may cause enter at different opline */
6927
17
        if (opline > op_array->opcodes) {
6928
17
          const zend_op *prev_opline = opline - 1;
6929
6930
17
          while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) {
6931
0
            prev_opline--;
6932
0
          }
6933
17
          JIT_G(current_frame) = call;
6934
17
          if ((prev_opline->opcode == ZEND_SEND_ARRAY
6935
17
            || prev_opline->opcode == ZEND_SEND_UNPACK
6936
17
            || prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS)
6937
0
           && p->op_array->num_args
6938
0
           && (p->op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0
6939
0
           && ((p+1)->op == ZEND_JIT_TRACE_VM
6940
0
            || (p+1)->op == ZEND_JIT_TRACE_END)
6941
0
           && (TRACE_FRAME_NUM_ARGS(call) < 0
6942
0
            || TRACE_FRAME_NUM_ARGS(call) < p->op_array->num_args)
6943
0
           && !zend_jit_trace_opline_guard(&ctx, (p+1)->opline)) {
6944
0
            goto jit_failure;
6945
0
          }
6946
17
          JIT_G(current_frame) = frame;
6947
17
        }
6948
17
      }
6949
6950
17
      if ((p+1)->op == ZEND_JIT_TRACE_END) {
6951
0
        p++;
6952
0
        break;
6953
0
      }
6954
17
      if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
6955
0
        if (TRACE_FRAME_IS_THIS_CHECKED(frame)) {
6956
0
          TRACE_FRAME_SET_THIS_CHECKED(call);
6957
0
        }
6958
17
      } else if (op_array->scope && !(op_array->fn_flags & ZEND_ACC_STATIC)) {
6959
0
        TRACE_FRAME_SET_THIS_CHECKED(call);
6960
0
      }
6961
17
      op_array = (zend_op_array*)p->op_array;
6962
17
      ctx.current_op_array = op_array;
6963
17
      jit_extension =
6964
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
6965
17
      op_array_ssa = &jit_extension->func_info.ssa;
6966
17
      frame->call = call->prev;
6967
17
      call->prev = frame;
6968
17
      if (p->info & ZEND_JIT_TRACE_RETURN_VALUE_USED) {
6969
0
        TRACE_FRAME_SET_RETURN_VALUE_USED(call);
6970
17
      } else {
6971
17
        TRACE_FRAME_SET_RETURN_VALUE_UNUSED(call);
6972
17
      }
6973
17
      JIT_G(current_frame) = frame = call;
6974
17
      stack = frame->stack;
6975
17
      if (ra) {
6976
4
        int j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
6977
6978
15
        for (i = 0; i < op_array->last_var; i++, j++) {
6979
11
          if (RA_HAS_REG(j) && (RA_REG_FLAGS(j) & ZREG_LOAD) != 0) {
6980
0
            if ((ssa->var_info[j].type & MAY_BE_GUARD) != 0) {
6981
0
              uint8_t op_type;
6982
6983
0
              ssa->var_info[j].type &= ~MAY_BE_GUARD;
6984
0
              op_type = concrete_type(ssa->var_info[j].type);
6985
0
              if (!zend_jit_type_guard(&ctx, (p+1)->opline, EX_NUM_TO_VAR(i), op_type)) {
6986
0
                goto jit_failure;
6987
0
              }
6988
0
              SET_STACK_TYPE(stack, i, op_type, 1);
6989
0
            }
6990
0
            if (!zend_jit_load_var(&ctx, ssa->var_info[j].type, i, j)) {
6991
0
              goto jit_failure;
6992
0
            }
6993
0
            SET_STACK_REF_EX(stack, i, ra[j].ref, ZREG_LOAD);
6994
0
          }
6995
11
        }
6996
4
      }
6997
2.92k
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
6998
17
      op_array = (zend_op_array*)p->op_array;
6999
17
      ctx.current_op_array = op_array;
7000
17
      jit_extension =
7001
17
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7002
17
      op_array_ssa = &jit_extension->func_info.ssa;
7003
17
      top = frame;
7004
17
      if (frame->prev) {
7005
17
        checked_stack = frame->old_checked_stack;
7006
17
        peek_checked_stack = frame->old_peek_checked_stack;
7007
17
        frame = frame->prev;
7008
17
        stack = frame->stack;
7009
17
        ZEND_ASSERT(&frame->func->op_array == op_array);
7010
17
      } else {
7011
0
        frame = zend_jit_trace_ret_frame(frame, op_array);
7012
0
        TRACE_FRAME_INIT(frame, op_array, TRACE_FRAME_MASK_UNKNOWN_RETURN, -1);
7013
0
        frame->used_stack = checked_stack = peek_checked_stack = 0;
7014
0
        stack = frame->stack;
7015
0
        if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
7016
0
          uint32_t j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7017
7018
0
          for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
7019
            /* Initialize abstract stack using SSA */
7020
0
            if (!(ssa->var_info[j].type & MAY_BE_GUARD)
7021
0
             && has_concrete_type(ssa->var_info[j].type)) {
7022
0
              SET_STACK_TYPE(stack, i, concrete_type(ssa->var_info[j].type), 1);
7023
0
            } else {
7024
0
              SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
7025
0
            }
7026
0
          }
7027
0
          if (ra) {
7028
0
            j = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7029
0
            for (i = 0; i < op_array->last_var + op_array->T; i++, j++) {
7030
0
              if (RA_HAS_REG(j) && (RA_REG_FLAGS(j) & ZREG_LOAD) != 0) {
7031
0
                if (!zend_jit_load_var(&ctx, ssa->var_info[j].type, i, j)) {
7032
0
                  goto jit_failure;
7033
0
                }
7034
0
                SET_STACK_REF_EX(stack, i, ra[j].ref, ZREG_LOAD);
7035
0
              }
7036
0
            }
7037
0
          }
7038
0
        } else {
7039
0
          for (i = 0; i < op_array->last_var + op_array->T; i++) {
7040
0
            SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
7041
0
          }
7042
0
        }
7043
0
        opline = NULL;
7044
0
      }
7045
17
      JIT_G(current_frame) = frame;
7046
17
      if (res_type != IS_UNKNOWN
7047
16
       && (p+1)->op == ZEND_JIT_TRACE_VM) {
7048
16
        const zend_op *opline = (p+1)->opline - 1;
7049
16
        if (opline->result_type != IS_UNUSED) {
7050
0
            SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), res_type, 1);
7051
0
        }
7052
16
      }
7053
17
      res_type = IS_UNKNOWN;
7054
2.90k
    } else if (p->op == ZEND_JIT_TRACE_END) {
7055
2.50k
      break;
7056
2.50k
    } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
7057
214
      const zend_op *init_opline = zend_jit_trace_find_init_fcall_op(p, op_array);
7058
214
      int num_args = -1;
7059
7060
214
      if (init_opline
7061
214
       && init_opline->extended_value <= TRACE_FRAME_MAX_NUM_ARGS) {
7062
214
        num_args = init_opline->extended_value;
7063
214
      }
7064
7065
214
      call = top;
7066
214
      TRACE_FRAME_INIT(call, p->func, frame_flags, num_args);
7067
214
      call->prev = frame->call;
7068
214
      if (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
7069
214
        TRACE_FRAME_SET_LAST_SEND_BY_VAL(call);
7070
214
        if (init_opline && init_opline->opcode == ZEND_INIT_DYNAMIC_CALL) {
7071
1
          TRACE_FRAME_SET_CLOSURE_CALL(call);
7072
1
        }
7073
214
      }
7074
214
      if (init_opline) {
7075
214
        if (init_opline->opcode != ZEND_NEW
7076
210
         && (init_opline->opcode != ZEND_INIT_METHOD_CALL
7077
2
          || init_opline->op1_type == IS_UNDEF
7078
2
          || (!(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)
7079
2
           && ssa_op
7080
2
           && (ssa_op-1)->op1_use >=0
7081
2
           && ssa->var_info[(ssa_op-1)->op1_use].delayed_fetch_this))
7082
208
         && (init_opline->opcode != ZEND_INIT_USER_CALL
7083
0
          || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
7084
208
         && (init_opline->opcode != ZEND_INIT_DYNAMIC_CALL
7085
1
          || (p->func && (!p->func->common.scope || (p->func->common.fn_flags & ZEND_ACC_STATIC))))
7086
214
        ) {
7087
208
          TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(call);
7088
208
        } else if (init_opline->opcode == ZEND_NEW
7089
2
         || (init_opline->opcode == ZEND_INIT_METHOD_CALL
7090
2
          && init_opline->op1_type != IS_UNDEF
7091
2
          && !(p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL)
7092
4
          && p->func && p->func->common.scope && !(p->func->common.fn_flags & ZEND_ACC_STATIC))) {
7093
4
          TRACE_FRAME_SET_ALWAYS_RELEASE_THIS(call);
7094
4
        }
7095
214
      }
7096
214
      frame->call = call;
7097
214
      top = zend_jit_trace_call_frame(top, p->op_array, ZEND_JIT_TRACE_NUM_ARGS(p->info));
7098
214
      if (p->func) {
7099
212
        if (p->func->type == ZEND_USER_FUNCTION) {
7100
19
          if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
7101
19
            zend_jit_op_array_trace_extension *jit_extension =
7102
19
              (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(p->op_array);
7103
7104
19
            i = 0;
7105
23
            while (i < p->op_array->num_args) {
7106
              /* Types of arguments are going to be stored in abstract stack when processing SEV instruction */
7107
4
              SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
7108
4
              i++;
7109
4
            }
7110
54
            while (i < p->op_array->last_var) {
7111
35
              if (jit_extension
7112
35
               && zend_jit_var_may_alias(p->op_array, &jit_extension->func_info.ssa, i) != NO_ALIAS) {
7113
4
                SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
7114
31
              } else {
7115
31
                SET_STACK_TYPE(call->stack, i, IS_UNDEF, 1);
7116
31
              }
7117
35
              i++;
7118
35
            }
7119
38
            while (i < p->op_array->last_var + p->op_array->T) {
7120
19
              SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
7121
19
              i++;
7122
19
            }
7123
19
          } else {
7124
0
            for (i = 0; i < p->op_array->last_var + p->op_array->T; i++) {
7125
0
              SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
7126
0
            }
7127
0
          }
7128
193
        } else {
7129
193
          ZEND_ASSERT(p->func->type == ZEND_INTERNAL_FUNCTION);
7130
624
          for (i = 0; i < p->op_array->num_args; i++) {
7131
431
            SET_STACK_TYPE(call->stack, i, IS_UNKNOWN, 1);
7132
431
          }
7133
193
        }
7134
212
        if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
7135
0
          int skip_guard = 0;
7136
7137
0
          if (init_opline) {
7138
0
            zend_call_info *call_info = jit_extension->func_info.callee_info;
7139
7140
0
            while (call_info) {
7141
0
              if (call_info->caller_init_opline == init_opline
7142
0
                  && !call_info->is_prototype) {
7143
0
                if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
7144
0
                  if (init_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL
7145
0
                   && init_opline->op1_type != IS_CONST) {
7146
0
                    break;
7147
0
                  } else if (init_opline->opcode == ZEND_INIT_METHOD_CALL) {
7148
0
                    break;
7149
0
                  }
7150
0
                }
7151
0
                skip_guard = 1;
7152
0
                break;
7153
0
              }
7154
0
              call_info = call_info->next_callee;
7155
0
            }
7156
0
            if (!skip_guard
7157
0
             && !zend_jit_may_be_polymorphic_call(init_opline)
7158
0
             && !zend_jit_may_be_modified(p->func, op_array)) {
7159
0
              skip_guard = 1;
7160
0
            }
7161
0
          }
7162
7163
0
          if (!skip_guard) {
7164
0
            if (!opline) {
7165
0
              zend_jit_trace_rec *q = p + 1;
7166
0
              while (q->op != ZEND_JIT_TRACE_VM && q->op != ZEND_JIT_TRACE_END) {
7167
0
                q++;
7168
0
              }
7169
0
              opline = q->opline;
7170
0
              ZEND_ASSERT(opline != NULL);
7171
0
            }
7172
0
            if (!zend_jit_init_fcall_guard(&ctx,
7173
0
                ZEND_JIT_TRACE_FAKE_LEVEL(p->info), p->func, opline)) {
7174
0
              goto jit_failure;
7175
0
            }
7176
0
          }
7177
0
        }
7178
212
      }
7179
214
      call->old_checked_stack = checked_stack;
7180
214
      call->old_peek_checked_stack = peek_checked_stack;
7181
214
      if (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) {
7182
0
        frame->call_level++;
7183
0
        call->used_stack = checked_stack = peek_checked_stack = 0;
7184
214
      } else {
7185
214
        if (p->func) {
7186
212
          call->used_stack = zend_vm_calc_used_stack(init_opline->extended_value, (zend_function*)p->func);
7187
212
        } else {
7188
2
          call->used_stack = (ZEND_CALL_FRAME_SLOT + init_opline->extended_value) * sizeof(zval);
7189
2
        }
7190
214
        switch (init_opline->opcode) {
7191
207
          case ZEND_INIT_FCALL:
7192
207
          case ZEND_INIT_FCALL_BY_NAME:
7193
207
          case ZEND_INIT_NS_FCALL_BY_NAME:
7194
209
          case ZEND_INIT_METHOD_CALL:
7195
210
          case ZEND_INIT_DYNAMIC_CALL:
7196
          //case ZEND_INIT_STATIC_METHOD_CALL:
7197
          //case ZEND_INIT_PARENT_PROPERTY_HOOK_CALL:
7198
          //case ZEND_INIT_USER_CALL:
7199
          //case ZEND_NEW:
7200
210
            checked_stack += call->used_stack;
7201
210
            if (checked_stack > peek_checked_stack) {
7202
210
              peek_checked_stack = checked_stack;
7203
210
            }
7204
210
            break;
7205
4
          default:
7206
4
            checked_stack = peek_checked_stack = 0;
7207
214
        }
7208
214
      }
7209
214
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
7210
186
      call = frame->call;
7211
186
      if (call) {
7212
186
        checked_stack = call->old_checked_stack;
7213
186
        peek_checked_stack = call->old_peek_checked_stack;
7214
186
        top = call;
7215
186
        frame->call = call->prev;
7216
186
      }
7217
186
    } else {
7218
0
      ZEND_UNREACHABLE();
7219
0
    }
7220
11.8k
  }
7221
7222
2.50k
  ZEND_ASSERT(p->op == ZEND_JIT_TRACE_END);
7223
7224
2.50k
  t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7225
7226
2.50k
  if (!parent_trace && zend_jit_trace_uses_initial_ip(&ctx)) {
7227
2.32k
    t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
7228
2.32k
  }
7229
7230
2.50k
  if (p->stop == ZEND_JIT_TRACE_STOP_LOOP
7231
2.49k
   || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7232
2.49k
   || p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7233
13
    if (ra) {
7234
7
      zend_ssa_phi *phi = ssa->blocks[1].phis;
7235
7236
17
      while (phi) {
7237
10
        if (RA_HAS_REG(phi->sources[1])
7238
0
         && STACK_MEM_TYPE(stack, phi->var) != STACK_TYPE(stack, phi->var)
7239
0
         && (RA_REG_FLAGS(phi->sources[1]) & (ZREG_LOAD|ZREG_STORE)) == 0) {
7240
7241
0
          if (!RA_HAS_REG(phi->ssa_var)
7242
0
           || (RA_REG_FLAGS(phi->ssa_var) & (ZREG_LOAD|ZREG_STORE)) == 0) {
7243
            /* Store actual type to memory to avoid deoptimization mistakes */
7244
0
            zend_jit_store_var_type(&ctx, phi->var, STACK_TYPE(stack, phi->var));
7245
0
          }
7246
0
        }
7247
10
        phi = phi->next;
7248
10
      }
7249
7
    }
7250
13
    if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7251
13
      if ((t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
7252
13
       && !zend_jit_set_ip(&ctx, p->opline)) {
7253
0
        goto jit_failure;
7254
0
      }
7255
13
    }
7256
13
    t->link = ZEND_JIT_TRACE_NUM;
7257
13
    if (p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7258
13
      t->flags |= ZEND_JIT_TRACE_CHECK_INTERRUPT;
7259
13
    }
7260
13
    if (!(t->flags & ZEND_JIT_TRACE_LOOP)) {
7261
13
      const void *timeout_exit_addr = NULL;
7262
7263
13
      t->flags |= ZEND_JIT_TRACE_LOOP;
7264
7265
13
      if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7266
13
        if (!(t->flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
7267
13
         || (ra
7268
7
          && (zend_jit_trace_stack_needs_deoptimization(stack, op_array->last_var + op_array->T)
7269
7
           || zend_jit_trace_stack_has_unstored_refs(stack, op_array->last_var + op_array->T)))) {
7270
          /* Deoptimize to the first instruction of the loop */
7271
0
          uint32_t exit_point = zend_jit_trace_get_exit_point(trace_buffer[1].opline, ZEND_JIT_EXIT_TO_VM);
7272
7273
0
          timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7274
0
          if (!timeout_exit_addr) {
7275
0
            goto jit_failure;
7276
0
          }
7277
13
        } else {
7278
13
          timeout_exit_addr = zend_jit_stub_handlers[jit_stub_interrupt_handler];
7279
13
        }
7280
13
      }
7281
7282
13
      zend_jit_trace_end_loop(&ctx, jit->trace_loop_ref, timeout_exit_addr); /* jump back to start of the trace loop */
7283
13
    }
7284
2.49k
  } else if (p->stop >= ZEND_JIT_TRACE_STOP_LINK) {
7285
124
    if (ra
7286
11
     && (p-1)->op != ZEND_JIT_TRACE_ENTER
7287
11
     && (p-1)->op != ZEND_JIT_TRACE_BACK
7288
11
     && opline->opcode != ZEND_DO_UCALL
7289
11
     && opline->opcode != ZEND_DO_FCALL
7290
11
     && opline->opcode != ZEND_DO_FCALL_BY_NAME
7291
11
     && opline->opcode != ZEND_INCLUDE_OR_EVAL) {
7292
71
      for (i = 0; i < op_array->last_var + op_array->T; i++) {
7293
60
        int32_t ref = STACK_REF(stack, i);
7294
60
        uint8_t type = STACK_TYPE(stack, i);
7295
7296
60
        if (ref && !(STACK_FLAGS(stack, i) & (ZREG_LOAD|ZREG_STORE))) {
7297
0
          if (!zend_jit_store_ref(jit, 1 << type, i, ref, STACK_MEM_TYPE(stack, i) != type)) {
7298
0
            goto jit_failure;
7299
0
          }
7300
0
          SET_STACK_TYPE(stack, i, type, 1);
7301
60
        } else if (i < op_array->last_var
7302
27
         && type != IS_UNKNOWN
7303
0
         && type != STACK_MEM_TYPE(stack, i)
7304
0
         && zend_jit_trace_must_store_type(op_array, op_array_ssa, opline - op_array->opcodes, i, type)) {
7305
0
          if (!zend_jit_store_type(jit, i, type)) {
7306
0
            goto jit_failure;
7307
0
          }
7308
0
          SET_STACK_TYPE(stack, i, type, 1);
7309
0
        }
7310
60
        CLEAR_STACK_REF(stack, i);
7311
60
      }
7312
11
    }
7313
124
    if (p->stop == ZEND_JIT_TRACE_STOP_LINK) {
7314
26
      const void *timeout_exit_addr = NULL;
7315
7316
26
      t->link = zend_jit_find_trace(p->opline->handler);
7317
26
      if (t->link == 0) {
7318
        /* this can happen if ZEND_JIT_EXIT_INVALIDATE was handled
7319
         * by zend_jit_trace_exit() in another thread after this
7320
         * thread set ZEND_JIT_TRACE_STOP_LINK in zend_jit_trace_execute();
7321
         * ZEND_JIT_EXIT_INVALIDATE resets the opline handler to one of
7322
         * the "_counter_handler" functions, and these are not registered
7323
         * tracer functions */
7324
0
        goto jit_failure;
7325
0
      }
7326
26
      if ((zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)
7327
26
       && !zend_jit_set_ip(&ctx, p->opline)) {
7328
0
        goto jit_failure;
7329
0
      }
7330
26
      if (!parent_trace && zend_jit_trace_uses_initial_ip(&ctx)) {
7331
10
        t->flags |= ZEND_JIT_TRACE_USES_INITIAL_IP;
7332
10
      }
7333
26
      if (parent_trace
7334
16
       && (zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_CHECK_INTERRUPT)
7335
16
       && zend_jit_traces[parent_trace].root == t->link) {
7336
16
        if (!(zend_jit_traces[t->link].flags & ZEND_JIT_TRACE_USES_INITIAL_IP)) {
7337
0
          uint32_t exit_point;
7338
7339
0
          for (i = 0; i < op_array->last_var + op_array->T; i++) {
7340
0
            SET_STACK_TYPE(stack, i, IS_UNKNOWN, 1);
7341
0
          }
7342
0
          exit_point = zend_jit_trace_get_exit_point(zend_jit_traces[t->link].opline, ZEND_JIT_EXIT_TO_VM);
7343
0
          timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7344
0
          if (!timeout_exit_addr) {
7345
0
            goto jit_failure;
7346
0
          }
7347
16
        } else {
7348
16
          timeout_exit_addr = zend_jit_stub_handlers[jit_stub_interrupt_handler];
7349
16
        }
7350
16
      }
7351
26
      zend_jit_trace_link_to_root(&ctx, &zend_jit_traces[t->link], timeout_exit_addr);
7352
98
    } else {
7353
98
      zend_jit_trace_return(&ctx, 0, NULL);
7354
98
    }
7355
2.36k
  } else if (p->stop == ZEND_JIT_TRACE_STOP_RETURN) {
7356
2.36k
    zend_jit_trace_return(&ctx, 0, NULL);
7357
2.36k
  } else {
7358
    // TODO: not implemented ???
7359
0
    ZEND_ASSERT(0 && p->stop);
7360
0
  }
7361
7362
2.50k
  if (ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7363
0
    goto jit_failure;
7364
0
  }
7365
7366
2.50k
  handler = zend_jit_finish(&ctx);
7367
7368
2.50k
  if (handler) {
7369
2.50k
    if (p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
7370
0
      const zend_op_array *rec_op_array;
7371
7372
0
      rec_op_array = op_array = trace_buffer->op_array;
7373
0
      jit_extension =
7374
0
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7375
0
      p = trace_buffer + ZEND_JIT_TRACE_START_REC_SIZE;
7376
0
      for (;;p++) {
7377
0
        if (p->op == ZEND_JIT_TRACE_VM) {
7378
0
          opline = p->opline;
7379
0
        } else if (p->op == ZEND_JIT_TRACE_ENTER) {
7380
0
          if (p->op_array == rec_op_array) {
7381
0
            zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7382
0
          }
7383
0
          op_array = p->op_array;
7384
0
          jit_extension =
7385
0
            (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7386
0
        } else if (p->op == ZEND_JIT_TRACE_BACK) {
7387
0
          op_array = p->op_array;
7388
0
          jit_extension =
7389
0
            (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7390
0
        } else if (p->op == ZEND_JIT_TRACE_END) {
7391
0
          break;
7392
0
        }
7393
0
      }
7394
2.50k
    } else if (p->stop >= ZEND_JIT_TRACE_STOP_LINK) {
7395
124
      if (opline
7396
124
       && (opline->opcode == ZEND_DO_UCALL
7397
124
        || opline->opcode == ZEND_DO_FCALL
7398
124
        || opline->opcode == ZEND_DO_FCALL_BY_NAME
7399
124
        || opline->opcode == ZEND_YIELD
7400
124
        || opline->opcode == ZEND_YIELD_FROM
7401
124
        || opline->opcode == ZEND_INCLUDE_OR_EVAL)) {
7402
90
        zend_jit_trace_setup_ret_counter(opline, jit_extension->offset);
7403
90
      }
7404
124
      if (JIT_G(current_frame)
7405
124
       && JIT_G(current_frame)->prev) {
7406
0
        frame = JIT_G(current_frame)->prev;
7407
0
        do {
7408
0
          if (frame->call_opline) {
7409
0
            op_array = &frame->func->op_array;
7410
0
            jit_extension =
7411
0
              (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7412
0
            zend_jit_trace_setup_ret_counter(frame->call_opline, jit_extension->offset);
7413
0
          }
7414
0
          frame = frame->prev;
7415
0
        } while (frame);
7416
0
      }
7417
124
    }
7418
2.50k
  }
7419
7420
2.50k
jit_failure:
7421
2.50k
  zend_jit_free_ctx(&ctx);
7422
7423
2.50k
  if (name) {
7424
2.50k
    zend_string_release(name);
7425
2.50k
  }
7426
7427
2.50k
jit_cleanup:;
7428
2.50k
  } zend_catch {
7429
0
    do_bailout = 1;
7430
2.50k
  }  zend_end_try();
7431
7432
  /* Clean up used op_arrays */
7433
5.02k
  while (num_op_arrays > 0) {
7434
2.52k
    op_array = op_arrays[--num_op_arrays];
7435
2.52k
    jit_extension =
7436
2.52k
      (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7437
7438
2.52k
      jit_extension->func_info.num = 0;
7439
2.52k
    jit_extension->func_info.flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
7440
2.52k
      | ZEND_FUNC_JIT_ON_PROF_REQUEST
7441
2.52k
      | ZEND_FUNC_JIT_ON_HOT_COUNTERS
7442
2.52k
      | ZEND_FUNC_JIT_ON_HOT_TRACE;
7443
2.52k
    memset(&jit_extension->func_info.ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
7444
2.52k
  }
7445
7446
2.50k
  zend_arena_release(&CG(arena), checkpoint);
7447
7448
2.50k
  JIT_G(current_frame) = NULL;
7449
2.50k
  JIT_G(current_trace) = NULL;
7450
7451
2.50k
  if (do_bailout) {
7452
0
    zend_bailout();
7453
0
  }
7454
7455
2.50k
  return handler;
7456
2.50k
}
7457
7458
static zend_string *zend_jit_trace_escape_name(uint32_t trace_num, uint32_t exit_num)
7459
0
{
7460
0
  smart_str buf = {0};
7461
7462
0
  smart_str_appends(&buf," ESCAPE-");
7463
0
  smart_str_append_long(&buf, (zend_long)trace_num);
7464
0
  smart_str_appendc(&buf, '-');
7465
0
  smart_str_append_long(&buf, (zend_long)exit_num);
7466
0
  smart_str_0(&buf);
7467
0
  return buf.s;
7468
0
}
7469
7470
static zend_vm_opcode_handler_t zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
7471
0
{
7472
0
  zend_vm_opcode_handler_t handler = NULL;
7473
0
  zend_jit_ctx ctx;
7474
0
  zend_string *name;
7475
0
  void *checkpoint;
7476
0
  const zend_op *opline;
7477
0
  uint32_t stack_size;
7478
0
  zend_jit_trace_stack *stack;
7479
0
  bool original_handler = false;
7480
7481
0
  if (!zend_jit_trace_exit_needs_deoptimization(trace_num, exit_num)) {
7482
0
    return zend_jit_stub_handlers[jit_stub_trace_escape];
7483
0
  }
7484
7485
0
  name = zend_jit_trace_escape_name(trace_num, exit_num);
7486
7487
0
  if (!zend_jit_deoptimizer_start(&ctx, name, trace_num, &zend_jit_traces[trace_num], exit_num)) {
7488
0
    zend_string_release(name);
7489
0
    return NULL;
7490
0
  }
7491
7492
0
  checkpoint = zend_arena_checkpoint(CG(arena));;
7493
7494
  /* Deoptimization */
7495
0
  stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
7496
0
  stack =  zend_jit_traces[trace_num].exit_info[exit_num].stack_size ?
7497
0
    zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset :
7498
0
    NULL;
7499
7500
0
  if (!zend_jit_trace_deoptimization(&ctx,
7501
0
      &zend_jit_traces[trace_num].exit_info[exit_num],
7502
0
      stack, stack_size, NULL, NULL,
7503
0
      zend_jit_traces[trace_num].constants,
7504
0
      false)) {
7505
0
    goto jit_failure;
7506
0
  }
7507
7508
0
  opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
7509
0
  if (opline) {
7510
0
    if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) {
7511
0
      zend_jit_op_array_trace_extension *jit_extension =
7512
0
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(zend_jit_traces[zend_jit_traces[trace_num].root].op_array);
7513
7514
0
      if (ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->orig_handler != opline->handler) {
7515
        /* prevent endless loop */
7516
0
        original_handler = true;
7517
0
      }
7518
0
    }
7519
0
    zend_jit_set_ip(&ctx, opline);
7520
0
  }
7521
7522
0
  zend_jit_trace_return(&ctx, original_handler, opline);
7523
7524
0
  handler = zend_jit_finish(&ctx);
7525
7526
0
jit_failure:
7527
0
  zend_jit_free_ctx(&ctx);
7528
0
  zend_string_release(name);
7529
0
  zend_arena_release(&CG(arena), checkpoint);
7530
0
  return handler;
7531
0
}
7532
7533
static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace_buffer, const zend_op *opline, size_t offset)
7534
2.48k
{
7535
2.48k
  zend_jit_trace_stop ret;
7536
2.48k
  zend_vm_opcode_handler_t handler;
7537
2.48k
  uint8_t orig_trigger;
7538
2.48k
  zend_jit_trace_info *t = NULL;
7539
2.48k
  zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
7540
2.48k
  bool do_bailout = 0;
7541
7542
2.48k
  zend_shared_alloc_lock();
7543
7544
  /* Checks under lock */
7545
2.48k
  if ((ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_JITED)) {
7546
0
    ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7547
2.48k
  } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
7548
0
    ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7549
2.48k
  } else {
7550
2.48k
    zend_try {
7551
2.48k
      SHM_UNPROTECT();
7552
2.48k
      zend_jit_unprotect();
7553
7554
2.48k
      t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
7555
7556
2.48k
      t->id = ZEND_JIT_TRACE_NUM;
7557
2.48k
      t->root = ZEND_JIT_TRACE_NUM;
7558
2.48k
      t->parent = 0;
7559
2.48k
      t->link = 0;
7560
2.48k
      t->exit_count = 0;
7561
2.48k
      t->child_count = 0;
7562
2.48k
      t->stack_map_size = 0;
7563
2.48k
      t->flags = 0;
7564
2.48k
      t->polymorphism = 0;
7565
2.48k
      t->jmp_table_size = 0;
7566
2.48k
      t->op_array = trace_buffer[0].op_array;
7567
2.48k
      if (!(t->op_array->fn_flags & ZEND_ACC_IMMUTABLE)) {
7568
2.48k
        zend_jit_op_array_trace_extension *jit_extension =
7569
2.48k
          (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(t->op_array);
7570
2.48k
        t->op_array = jit_extension->op_array;
7571
2.48k
      }
7572
2.48k
      t->opline = trace_buffer[1].opline;
7573
2.48k
      t->exit_info = exit_info;
7574
2.48k
      t->stack_map = NULL;
7575
2.48k
      t->consts_count = 0;
7576
2.48k
      t->constants = NULL;
7577
7578
2.48k
      orig_trigger = JIT_G(trigger);
7579
2.48k
      JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
7580
7581
2.48k
      handler = zend_jit_trace(trace_buffer, 0, 0);
7582
7583
2.48k
      JIT_G(trigger) = orig_trigger;
7584
7585
2.48k
      if (handler) {
7586
2.48k
        zend_jit_trace_exit_info *shared_exit_info = NULL;
7587
7588
2.48k
        t->exit_info = NULL;
7589
2.48k
        if (t->exit_count) {
7590
          /* reallocate exit_info into shared memory */
7591
850
          shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
7592
850
            sizeof(zend_jit_trace_exit_info) * t->exit_count);
7593
7594
850
          if (!shared_exit_info) {
7595
0
              if (t->stack_map) {
7596
0
              efree(t->stack_map);
7597
0
              t->stack_map = NULL;
7598
0
            }
7599
0
            if (t->constants) {
7600
0
              efree(t->constants);
7601
0
              t->constants = NULL;
7602
0
            }
7603
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7604
0
            goto exit;
7605
0
          }
7606
850
          memcpy(shared_exit_info, exit_info,
7607
850
            sizeof(zend_jit_trace_exit_info) * t->exit_count);
7608
850
          t->exit_info = shared_exit_info;
7609
850
        }
7610
7611
2.48k
          if (t->stack_map_size) {
7612
425
          zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
7613
425
          if (!shared_stack_map) {
7614
0
            efree(t->stack_map);
7615
0
            t->stack_map = NULL;
7616
0
            if (t->constants) {
7617
0
              efree(t->constants);
7618
0
              t->constants = NULL;
7619
0
            }
7620
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7621
0
            goto exit;
7622
0
          }
7623
425
          memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
7624
425
          efree(t->stack_map);
7625
425
          t->stack_map = shared_stack_map;
7626
425
          }
7627
7628
2.48k
        if (t->consts_count) {
7629
12
          zend_jit_exit_const *constants = (zend_jit_exit_const*)zend_shared_alloc(t->consts_count * sizeof(zend_jit_exit_const));
7630
12
          if (!constants) {
7631
0
            efree(t->constants);
7632
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7633
0
            goto exit;
7634
0
          }
7635
12
          memcpy(constants, t->constants, t->consts_count * sizeof(zend_jit_exit_const));
7636
12
          efree(t->constants);
7637
12
          t->constants = constants;
7638
12
        }
7639
7640
2.48k
        t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
7641
2.48k
        ZEND_JIT_EXIT_COUNTERS += t->exit_count;
7642
7643
2.48k
        ((zend_op*)opline)->handler = handler;
7644
7645
2.48k
        ZEND_JIT_TRACE_NUM++;
7646
2.48k
        ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_JITED;
7647
7648
2.48k
        ret = ZEND_JIT_TRACE_STOP_COMPILED;
7649
2.48k
      } else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
7650
0
                 ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
7651
0
          if (t->stack_map) {
7652
0
          efree(t->stack_map);
7653
0
          t->stack_map = NULL;
7654
0
        }
7655
0
        if (t->constants) {
7656
0
          efree(t->constants);
7657
0
          t->constants = NULL;
7658
0
        }
7659
0
        ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7660
0
      } else {
7661
0
          if (t->stack_map) {
7662
0
          efree(t->stack_map);
7663
0
          t->stack_map = NULL;
7664
0
        }
7665
0
        if (t->constants) {
7666
0
          efree(t->constants);
7667
0
          t->constants = NULL;
7668
0
        }
7669
0
        ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7670
0
      }
7671
7672
2.48k
exit:;
7673
2.48k
    } zend_catch {
7674
0
      do_bailout = 1;
7675
2.48k
    } zend_end_try();
7676
7677
2.48k
    zend_jit_protect();
7678
2.48k
    SHM_PROTECT();
7679
2.48k
  }
7680
7681
2.48k
  zend_shared_alloc_unlock();
7682
7683
2.48k
  if (do_bailout) {
7684
0
    zend_bailout();
7685
0
  }
7686
7687
2.48k
  if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
7688
0
   && ret == ZEND_JIT_TRACE_STOP_COMPILED
7689
0
   && t->exit_count > 0) {
7690
0
    zend_jit_dump_exit_info(t);
7691
0
  }
7692
7693
2.48k
  return ret;
7694
2.48k
}
7695
7696
/* Set counting handler back to original VM handler. */
7697
static void zend_jit_stop_hot_trace_counters(zend_op_array *op_array)
7698
0
{
7699
0
  zend_jit_op_array_trace_extension *jit_extension;
7700
0
  uint32_t i;
7701
7702
0
  jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
7703
0
  for (i = 0; i < op_array->last; i++) {
7704
    /* Opline with Jit-ed code handler is skipped. */
7705
0
    if (jit_extension->trace_info[i].trace_flags &
7706
0
        (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED)) {
7707
0
      continue;
7708
0
    }
7709
0
    if (jit_extension->trace_info[i].trace_flags &
7710
0
        (ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_START_RETURN)) {
7711
0
      op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
7712
0
    }
7713
0
  }
7714
0
}
7715
7716
/* Get the tracing op_array. */
7717
static void zend_jit_stop_persistent_op_array(zend_op_array *op_array)
7718
0
{
7719
0
  zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
7720
0
  if (!func_info) {
7721
0
    return;
7722
0
  }
7723
0
  if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_TRACE) {
7724
0
    zend_jit_stop_hot_trace_counters(op_array);
7725
0
  }
7726
0
}
7727
7728
/* Get all op_arrays with counter handler. */
7729
static void zend_jit_stop_persistent_script(zend_persistent_script *script)
7730
0
{
7731
0
  zend_class_entry *ce;
7732
0
  zend_op_array *op_array;
7733
7734
0
  zend_jit_stop_persistent_op_array(&script->script.main_op_array);
7735
7736
0
  ZEND_HASH_FOREACH_PTR(&script->script.function_table, op_array) {
7737
0
    zend_jit_stop_persistent_op_array(op_array);
7738
0
  } ZEND_HASH_FOREACH_END();
7739
7740
0
  ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
7741
0
    ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
7742
0
      if (op_array->type == ZEND_USER_FUNCTION) {
7743
0
        zend_jit_stop_persistent_op_array(op_array);
7744
0
      }
7745
0
    } ZEND_HASH_FOREACH_END();
7746
0
  } ZEND_HASH_FOREACH_END();
7747
0
}
7748
7749
/* Get all scripts which are accelerated by JIT */
7750
static void zend_jit_stop_counter_handlers(void)
7751
0
{
7752
0
  if (ZCSG(jit_counters_stopped)) {
7753
0
    return;
7754
0
  }
7755
7756
0
  zend_shared_alloc_lock();
7757
  /* mprotect has an extreme overhead, avoid calls to it for every function. */
7758
0
  SHM_UNPROTECT();
7759
0
  if (!ZCSG(jit_counters_stopped)) {
7760
0
    ZCSG(jit_counters_stopped) = true;
7761
0
    for (uint32_t i = 0; i < ZCSG(hash).max_num_entries; i++) {
7762
0
      zend_accel_hash_entry *cache_entry;
7763
0
      for (cache_entry = ZCSG(hash).hash_table[i]; cache_entry; cache_entry = cache_entry->next) {
7764
0
        zend_persistent_script *script;
7765
0
        if (cache_entry->indirect) continue;
7766
0
        script = (zend_persistent_script *)cache_entry->data;
7767
0
        zend_jit_stop_persistent_script(script);
7768
0
      }
7769
0
    }
7770
0
  }
7771
0
  SHM_PROTECT();
7772
0
  zend_shared_alloc_unlock();
7773
0
}
7774
7775
static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset)
7776
0
{
7777
0
  zend_shared_alloc_lock();
7778
7779
0
  if (!(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {
7780
0
    SHM_UNPROTECT();
7781
0
    zend_jit_unprotect();
7782
7783
0
    ((zend_op*)opline)->handler =
7784
0
      ZEND_OP_TRACE_INFO(opline, offset)->orig_handler;
7785
7786
0
    ZEND_OP_TRACE_INFO(opline, offset)->trace_flags |= ZEND_JIT_TRACE_BLACKLISTED;
7787
7788
0
    zend_jit_protect();
7789
0
    SHM_PROTECT();
7790
0
  }
7791
7792
0
  zend_shared_alloc_unlock();
7793
0
}
7794
7795
0
ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array) {
7796
0
  zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension *)ZEND_FUNC_INFO(op_array);
7797
0
  if (!jit_extension || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE)) {
7798
0
    return;
7799
0
  }
7800
7801
0
  zend_shared_alloc_lock();
7802
0
  SHM_UNPROTECT();
7803
0
  zend_jit_unprotect();
7804
7805
0
  zend_jit_stop_persistent_op_array(op_array);
7806
0
  jit_extension->func_info.flags &= ~ZEND_FUNC_JIT_ON_HOT_TRACE;
7807
7808
0
  zend_jit_protect();
7809
0
  SHM_PROTECT();
7810
0
  zend_shared_alloc_unlock();
7811
0
}
7812
7813
static bool zend_jit_trace_is_bad_root(const zend_op *opline, zend_jit_trace_stop stop, size_t offset)
7814
5.27k
{
7815
5.27k
  const zend_op **cache_opline = JIT_G(bad_root_cache_opline);
7816
5.27k
  uint8_t *cache_count = JIT_G(bad_root_cache_count);
7817
5.27k
  uint8_t *cache_stop = JIT_G(bad_root_cache_stop);
7818
5.27k
  uint32_t cache_slot = JIT_G(bad_root_slot);
7819
5.27k
  uint32_t i;
7820
7821
256k
  for (i = 0; i < ZEND_JIT_TRACE_BAD_ROOT_SLOTS; i++) {
7822
253k
    if (cache_opline[i] == opline) {
7823
2.63k
      if (cache_count[i] >= JIT_G(blacklist_root_trace) - 1) {
7824
0
        cache_opline[i] = NULL;
7825
0
        return true;
7826
2.63k
      } else {
7827
#if 0
7828
        if (ZEND_OP_TRACE_INFO(opline, offset)->counter) {
7829
          *ZEND_OP_TRACE_INFO(opline, offset)->counter =
7830
            random() % ZEND_JIT_TRACE_COUNTER_MAX;
7831
        }
7832
#endif
7833
2.63k
        cache_count[i]++;
7834
2.63k
        cache_stop[i] = stop;
7835
2.63k
        return false;
7836
2.63k
      }
7837
2.63k
    }
7838
253k
  }
7839
2.64k
  i = cache_slot;
7840
2.64k
  cache_opline[i] = opline;
7841
2.64k
  cache_count[i] = 1;
7842
2.64k
  cache_stop[i] = stop;
7843
2.64k
  cache_slot = (i + 1) % ZEND_JIT_TRACE_BAD_ROOT_SLOTS;
7844
2.64k
  JIT_G(bad_root_slot) = cache_slot;
7845
2.64k
  return false;
7846
5.27k
}
7847
7848
static void zend_jit_dump_trace(zend_jit_trace_rec *trace_buffer, zend_ssa *tssa)
7849
0
{
7850
0
  zend_jit_trace_rec *p = trace_buffer;
7851
0
  const zend_op_array *op_array;
7852
0
  const zend_op *opline;
7853
0
  uint32_t level = 1 + trace_buffer[0].level;
7854
0
  int idx, len, i, v, vars_count, call_level;
7855
7856
0
  ZEND_ASSERT(p->op == ZEND_JIT_TRACE_START);
7857
0
  op_array = p->op_array;
7858
0
  p += ZEND_JIT_TRACE_START_REC_SIZE;
7859
0
  idx = 0;
7860
0
  call_level = 0;
7861
7862
0
  if (tssa && tssa->var_info) {
7863
0
    if (trace_buffer->start == ZEND_JIT_TRACE_START_ENTER) {
7864
0
      vars_count = op_array->last_var;
7865
0
    } else {
7866
0
      vars_count = op_array->last_var + op_array->T;
7867
0
    }
7868
0
    for (i = 0; i < vars_count; i++) {
7869
0
      if (tssa->vars[i].use_chain >= 0 || tssa->vars[i].phi_use_chain) {
7870
0
        fprintf(stderr, "    %*c;", level, ' ');
7871
0
        zend_dump_ssa_var(op_array, tssa, i, 0, i, ZEND_DUMP_RC_INFERENCE);
7872
0
        fprintf(stderr, "\n");
7873
0
      }
7874
0
    }
7875
0
    if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
7876
0
     || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7877
0
     || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7878
0
      zend_ssa_phi *p = tssa->blocks[1].phis;
7879
7880
0
      fprintf(stderr, "LOOP:\n");
7881
7882
0
      while (p) {
7883
0
        fprintf(stderr, "     ;");
7884
0
        zend_dump_ssa_var(op_array, tssa, p->ssa_var, 0, p->var, ZEND_DUMP_RC_INFERENCE);
7885
0
        fprintf(stderr, " = Phi(");
7886
0
        zend_dump_ssa_var(op_array, tssa, p->sources[0], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7887
0
        fprintf(stderr, ", ");
7888
0
        zend_dump_ssa_var(op_array, tssa, p->sources[1], 0, p->var, ZEND_DUMP_RC_INFERENCE);
7889
0
        fprintf(stderr, ")\n");
7890
0
        p = p->next;
7891
0
      }
7892
0
    }
7893
0
  }
7894
7895
0
  while (1) {
7896
0
    if (p->op == ZEND_JIT_TRACE_VM) {
7897
0
      uint8_t op1_type, op2_type, op3_type;
7898
7899
0
      opline = p->opline;
7900
0
      fprintf(stderr, "%04d%*c",
7901
0
        (int)(opline - op_array->opcodes),
7902
0
        level, ' ');
7903
0
      zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7904
7905
0
      op1_type = p->op1_type;
7906
0
      op2_type = p->op2_type;
7907
0
      op3_type = p->op3_type;
7908
0
      if (op1_type != IS_UNKNOWN || op2_type != IS_UNKNOWN || op3_type != IS_UNKNOWN) {
7909
0
        fprintf(stderr, " ;");
7910
0
        if (op1_type != IS_UNKNOWN) {
7911
0
          const char *ref = (op1_type & IS_TRACE_INDIRECT) ?
7912
0
            ((op1_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7913
0
            ((op1_type & IS_TRACE_REFERENCE) ? "&" : "");
7914
0
          if ((p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
7915
0
            p++;
7916
0
            fprintf(stderr, " op1(%sobject of class %s)", ref,
7917
0
              ZSTR_VAL(p->ce->name));
7918
0
          } else {
7919
0
            const char *type = ((op1_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED));
7920
0
            fprintf(stderr, " op1(%s%s%s)", ref, (op1_type & IS_TRACE_PACKED) ? "packed " : "", type);
7921
0
          }
7922
0
        }
7923
0
        if (op2_type != IS_UNKNOWN) {
7924
0
          const char *ref = (op2_type & IS_TRACE_INDIRECT) ?
7925
0
            ((op2_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7926
0
            ((op2_type & IS_TRACE_REFERENCE) ? "&" : "");
7927
0
          if ((p+1)->op == ZEND_JIT_TRACE_OP2_TYPE) {
7928
0
            p++;
7929
0
            fprintf(stderr, " op2(%sobject of class %s)", ref,
7930
0
              ZSTR_VAL(p->ce->name));
7931
0
          } else {
7932
0
            const char *type = ((op2_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op2_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7933
0
            fprintf(stderr, " op2(%s%s)", ref, type);
7934
0
          }
7935
0
        }
7936
0
        if (op3_type != IS_UNKNOWN) {
7937
0
          const char *ref = (op3_type & IS_TRACE_INDIRECT) ?
7938
0
            ((op3_type & IS_TRACE_REFERENCE) ? "*&" : "*") :
7939
0
            ((op3_type & IS_TRACE_REFERENCE) ? "&" : "");
7940
0
          const char *type = ((op3_type & ~IS_TRACE_INDIRECT) == 0) ? "undef" : zend_get_type_by_const(op3_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT));
7941
0
          fprintf(stderr, " op3(%s%s)", ref, type);
7942
0
        }
7943
0
      } else if (opline->opcode == ZEND_RECV && (p+1)->op == ZEND_JIT_TRACE_OP1_TYPE) {
7944
        /* Class of the received object */
7945
0
        p++;
7946
0
        fprintf(stderr, " ; arg(object of class %s)", ZSTR_VAL(p->ce->name));
7947
0
      }
7948
0
      if ((p+1)->op == ZEND_JIT_TRACE_VAL_INFO) {
7949
0
        uint8_t val_type;
7950
0
        const char *type;
7951
7952
0
        if (op1_type == IS_UNKNOWN && op2_type == IS_UNKNOWN && op3_type == IS_UNKNOWN) {
7953
0
          fprintf(stderr, " ;");
7954
0
        }
7955
0
        p++;
7956
0
        val_type = p->op1_type;
7957
7958
0
        if (val_type == IS_UNDEF) {
7959
0
          type = "undef";
7960
0
        } else if (val_type == IS_REFERENCE) {
7961
0
          type = "ref";
7962
0
        } else {
7963
0
          type = zend_get_type_by_const(val_type);
7964
0
        }
7965
0
        fprintf(stderr, " val(%s)", type);
7966
0
      }
7967
0
      fprintf(stderr, "\n");
7968
0
      idx++;
7969
7970
0
      len = zend_jit_trace_op_len(opline);
7971
0
      while (len > 1) {
7972
0
        opline++;
7973
0
        fprintf(stderr, "%04d%*c;",
7974
0
          (int)(opline - op_array->opcodes),
7975
0
          level, ' ');
7976
0
        zend_dump_op(op_array, NULL, opline, ZEND_DUMP_RC_INFERENCE, tssa, (tssa && tssa->ops) ? tssa->ops + idx : NULL);
7977
0
        idx++;
7978
0
        len--;
7979
0
        fprintf(stderr, "\n");
7980
0
      }
7981
0
    } else if (p->op == ZEND_JIT_TRACE_ENTER) {
7982
0
      op_array = p->op_array;
7983
0
      fprintf(stderr, "    %*c>enter %s%s%s\n",
7984
0
        level, ' ',
7985
0
        op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
7986
0
        op_array->scope ? "::" : "",
7987
0
        op_array->function_name ?
7988
0
          ZSTR_VAL(op_array->function_name) :
7989
0
          ZSTR_VAL(op_array->filename));
7990
0
      level++;
7991
0
      if (tssa && tssa->var_info) {
7992
0
        call_level++;
7993
0
        v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
7994
0
        vars_count = op_array->last_var;
7995
0
        for (i = 0; i < vars_count; i++, v++) {
7996
0
          if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
7997
0
            fprintf(stderr, "    %*c;", level, ' ');
7998
0
            zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
7999
0
            fprintf(stderr, "\n");
8000
0
          }
8001
0
        }
8002
0
      }
8003
0
    } else if (p->op == ZEND_JIT_TRACE_BACK) {
8004
0
      op_array = p->op_array;
8005
0
      level--;
8006
0
      fprintf(stderr, "    %*c<back %s%s%s\n",
8007
0
        level, ' ',
8008
0
        op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
8009
0
        op_array->scope ? "::" : "",
8010
0
        op_array->function_name ?
8011
0
          ZSTR_VAL(op_array->function_name) :
8012
0
          ZSTR_VAL(op_array->filename));
8013
0
      if (tssa && tssa->var_info) {
8014
0
        if (call_level == 0) {
8015
0
          v = ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(p->info);
8016
0
          vars_count = op_array->last_var + op_array->T;
8017
0
          for (i = 0; i < vars_count; i++, v++) {
8018
0
            if (tssa->vars[v].use_chain >= 0 || tssa->vars[v].phi_use_chain) {
8019
0
              fprintf(stderr, "    %*c;", level, ' ');
8020
0
              zend_dump_ssa_var(op_array, tssa, v, 0, i, ZEND_DUMP_RC_INFERENCE);
8021
0
              fprintf(stderr, "\n");
8022
0
            }
8023
0
          }
8024
0
        } else {
8025
0
          call_level--;
8026
0
        }
8027
0
      }
8028
0
    } else if (p->op == ZEND_JIT_TRACE_INIT_CALL) {
8029
0
      if (p->func != (zend_function*)&zend_pass_function) {
8030
0
        fprintf(stderr, (p->info & ZEND_JIT_TRACE_FAKE_INIT_CALL) ? "    %*c>fake_init %s%s%s\n" : "    %*c>init %s%s%s\n",
8031
0
          level, ' ',
8032
0
          (p->func && p->func->common.scope) ? ZSTR_VAL(p->func->common.scope->name) : "",
8033
0
          (p->func && p->func->common.scope) ? "::" : "",
8034
0
          (p->func  && p->func->common.function_name) ? ZSTR_VAL(p->func->common.function_name) : "???");
8035
0
      } else {
8036
0
        fprintf(stderr, "    %*c>skip\n",
8037
0
          level, ' ');
8038
0
      }
8039
0
    } else if (p->op == ZEND_JIT_TRACE_DO_ICALL) {
8040
0
      if (p->func != (zend_function*)&zend_pass_function) {
8041
0
        fprintf(stderr, "    %*c>call %s%s%s\n",
8042
0
          level, ' ',
8043
0
          (p->func && p->func->common.scope) ? ZSTR_VAL(p->func->common.scope->name) : "",
8044
0
          (p->func && p->func->common.scope) ? "::" : "",
8045
0
          (p->func && p->func->common.function_name) ? ZSTR_VAL(p->func->common.function_name) : "???");
8046
0
      } else {
8047
0
        fprintf(stderr, "    %*c>skip\n",
8048
0
          level, ' ');
8049
0
      }
8050
0
    } else if (p->op == ZEND_JIT_TRACE_END) {
8051
0
      break;
8052
0
    }
8053
0
    p++;
8054
0
  }
8055
0
}
8056
8057
static void zend_jit_dump_ref_snapshot(zend_jit_ref_snapshot *rs)
8058
0
{
8059
0
  if (rs->reg == ZREG_NONE) {
8060
0
    fprintf(stderr, "?");
8061
0
  } else if (!IR_REG_SPILLED(rs->reg)) {
8062
0
    fprintf(stderr, "%s", zend_reg_name(rs->reg));
8063
0
  } else {
8064
0
    fprintf(stderr, "0x%x(%s)", rs->offset, zend_reg_name(IR_REG_NUM(rs->reg)));
8065
0
  }
8066
0
}
8067
8068
static void zend_jit_dump_exit_info(zend_jit_trace_info *t)
8069
0
{
8070
0
  int i, j;
8071
8072
0
  fprintf(stderr, "---- TRACE %d exit info\n", t->id);
8073
0
  for (i = 0; i < t->exit_count; i++) {
8074
0
    const zend_op_array *op_array = t->exit_info[i].op_array;
8075
0
    uint32_t stack_size = t->exit_info[i].stack_size;
8076
0
    zend_jit_trace_stack *stack = t->exit_info[i].stack_size ? t->stack_map + t->exit_info[i].stack_offset : NULL;
8077
8078
0
    fprintf(stderr, "     exit_%d:", i);
8079
0
    if (t->exit_info[i].opline) {
8080
0
      fprintf(stderr, " %04d/", (int)(t->exit_info[i].opline - op_array->opcodes));
8081
0
    } else {
8082
0
      fprintf(stderr, " ----/");
8083
0
    }
8084
0
    if (t->exit_info[i].stack_size) {
8085
0
      fprintf(stderr, "%04d/%d", t->exit_info[i].stack_offset, t->exit_info[i].stack_size);
8086
0
    } else {
8087
0
      fprintf(stderr, "----/0");
8088
0
    }
8089
0
    if (t->exit_info[i].flags & ZEND_JIT_EXIT_TO_VM) {
8090
0
      fprintf(stderr, "/VM");
8091
0
    }
8092
0
    if (t->exit_info[i].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
8093
0
      fprintf(stderr, "/CALL");
8094
0
    }
8095
0
    if (t->exit_info[i].flags & (ZEND_JIT_EXIT_POLYMORPHISM|ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL)) {
8096
0
      fprintf(stderr, "/POLY");
8097
0
      if (t->exit_info[i].flags & ZEND_JIT_EXIT_METHOD_CALL) {
8098
0
        fprintf(stderr, "(");
8099
0
        zend_jit_dump_ref_snapshot(&t->exit_info[i].poly_func);
8100
0
        fprintf(stderr, ", ");
8101
0
        zend_jit_dump_ref_snapshot(&t->exit_info[i].poly_this);
8102
0
        fprintf(stderr, ")");
8103
0
      }
8104
0
    }
8105
0
    if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP1) {
8106
0
      fprintf(stderr, "/FREE_OP1");
8107
0
    }
8108
0
    if (t->exit_info[i].flags & ZEND_JIT_EXIT_FREE_OP2) {
8109
0
      fprintf(stderr, "/FREE_OP2");
8110
0
    }
8111
0
    if (t->exit_info[i].flags & ZEND_JIT_EXIT_CHECK_EXCEPTION) {
8112
0
      fprintf(stderr, "/CHK_EXC");
8113
0
    }
8114
0
    for (j = 0; j < stack_size; j++) {
8115
0
      uint8_t type = STACK_TYPE(stack, j);
8116
0
      if (type != IS_UNKNOWN) {
8117
0
        fprintf(stderr, " ");
8118
0
        zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
8119
0
        fprintf(stderr, ":");
8120
0
        if (type == IS_UNDEF) {
8121
0
          fprintf(stderr, "undef");
8122
0
        } else {
8123
0
          fprintf(stderr, "%s", zend_get_type_by_const(type));
8124
0
        }
8125
0
        if (STACK_FLAGS(stack, j) == ZREG_CONST) {
8126
0
          if (type == IS_LONG) {
8127
0
            fprintf(stderr, "(" ZEND_LONG_FMT ")", (zend_long)t->constants[STACK_REF(stack, j)].i);
8128
0
          } else if (type == IS_DOUBLE) {
8129
0
            fprintf(stderr, "(%g)", t->constants[STACK_REF(stack, j)].d);
8130
0
          } else {
8131
0
            ZEND_UNREACHABLE();
8132
0
          }
8133
0
        } else if (STACK_FLAGS(stack, j) == ZREG_TYPE_ONLY) {
8134
0
          fprintf(stderr, "(type_only)");
8135
0
        } else if (STACK_FLAGS(stack, j) == ZREG_THIS) {
8136
0
          fprintf(stderr, "(this)");
8137
0
        } else if (STACK_FLAGS(stack, j) == ZREG_ZVAL_ADDREF) {
8138
0
          fprintf(stderr, "(zval_try_addref)");
8139
0
        } else if (STACK_FLAGS(stack, j) == ZREG_ZVAL_COPY) {
8140
0
          fprintf(stderr, "zval_copy(%s)", zend_reg_name(STACK_REG(stack, j)));
8141
0
        } else if (STACK_FLAGS(stack, j) & ZREG_SPILL_SLOT) {
8142
0
          if (STACK_REG(stack, j) == ZREG_NONE) {
8143
0
            fprintf(stderr, "(spill=0x%x", STACK_REF(stack, j));
8144
0
          } else {
8145
0
            fprintf(stderr, "(spill=0x%x(%s)", STACK_REF(stack, j), zend_reg_name(STACK_REG(stack, j)));
8146
0
          }
8147
0
          if (STACK_FLAGS(stack, j) != 0) {
8148
0
            fprintf(stderr, ":%x", STACK_FLAGS(stack, j));
8149
0
          }
8150
0
          fprintf(stderr, ")");
8151
0
        } else if (STACK_REG(stack, j) != ZREG_NONE) {
8152
0
          fprintf(stderr, "(%s", zend_reg_name(STACK_REG(stack, j)));
8153
0
          if (STACK_FLAGS(stack, j) != 0) {
8154
0
            fprintf(stderr, ":%x", STACK_FLAGS(stack, j));
8155
0
          }
8156
0
          fprintf(stderr, ")");
8157
0
        }
8158
0
      } else if (STACK_FLAGS(stack, j) == ZREG_ZVAL_ADDREF) {
8159
0
        fprintf(stderr, ":unknown(zval_try_addref)");
8160
0
      } else if (STACK_FLAGS(stack, j) == ZREG_ZVAL_COPY) {
8161
0
        fprintf(stderr, " ");
8162
0
        zend_dump_var(op_array, (j < op_array->last_var) ? IS_CV : 0, j);
8163
0
        fprintf(stderr, ":unknown(zval_copy(%s))", zend_reg_name(STACK_REG(stack, j)));
8164
0
      }
8165
0
    }
8166
0
#if ZEND_DEBUG
8167
0
    if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) != 0) {
8168
0
      fprintf(stderr, " %s:%d", t->exit_info[i].filename, t->exit_info[i].lineno);
8169
0
    }
8170
0
#endif
8171
0
    fprintf(stderr, "\n");
8172
0
  }
8173
0
}
8174
8175
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
8176
7.73k
{
8177
7.73k
  const zend_op *orig_opline;
8178
7.73k
  zend_jit_trace_stop stop;
8179
7.73k
  int ret = 0;
8180
7.73k
  zend_op_array *op_array;
8181
7.73k
  zend_jit_op_array_trace_extension *jit_extension;
8182
7.73k
  size_t offset;
8183
7.73k
  uint32_t trace_num;
8184
7.73k
  zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
8185
8186
7.73k
  ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
8187
7.73k
  ZEND_ASSERT(opline >= EX(func)->op_array.opcodes &&
8188
7.73k
    opline < EX(func)->op_array.opcodes + EX(func)->op_array.last);
8189
8190
7.79k
repeat:
8191
7.79k
  trace_num = ZEND_JIT_TRACE_NUM;
8192
7.79k
  orig_opline = opline;
8193
7.79k
  op_array = &EX(func)->op_array;
8194
7.79k
  jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8195
7.79k
  offset = jit_extension->offset;
8196
8197
7.79k
  EX(opline) = opline;
8198
8199
  /* Lock-free check if the root trace was already JIT-ed or blacklist-ed in another process */
8200
7.79k
  if (ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED)) {
8201
0
    return 0;
8202
0
  }
8203
8204
7.79k
  if (JIT_G(tracing)) {
8205
21
    ++(*ZEND_OP_TRACE_INFO(opline, offset)->counter);
8206
21
    return 0;
8207
21
  }
8208
8209
7.77k
  if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8210
0
    fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8211
0
      trace_num,
8212
0
      zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
8213
0
      EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8214
0
      EX(func)->op_array.scope ? "::" : "",
8215
0
      EX(func)->op_array.function_name ?
8216
0
        ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8217
0
      ZSTR_VAL(EX(func)->op_array.filename),
8218
0
      opline->lineno);
8219
0
  }
8220
8221
7.77k
  if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8222
0
    stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8223
0
    zend_jit_stop_counter_handlers();
8224
0
    goto abort;
8225
0
  }
8226
8227
7.77k
  JIT_G(tracing) = 1;
8228
7.77k
  stop = zend_jit_trace_execute(execute_data, opline, trace_buffer,
8229
7.77k
    ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_START_MASK, 0, 0);
8230
7.77k
  JIT_G(tracing) = 0;
8231
8232
7.77k
  if (stop & ZEND_JIT_TRACE_HALT) {
8233
2.36k
    ret = -1;
8234
2.36k
  }
8235
7.77k
  stop &= ~ZEND_JIT_TRACE_HALT;
8236
8237
7.77k
  if (UNEXPECTED(trace_buffer[1].opline != orig_opline)) {
8238
0
    orig_opline = trace_buffer[1].opline;
8239
0
    op_array = (zend_op_array*)trace_buffer[0].op_array;
8240
0
    jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8241
0
    offset = jit_extension->offset;
8242
0
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8243
0
      const zend_op_array *op_array = trace_buffer[0].op_array;
8244
0
      const zend_op *opline = trace_buffer[1].opline;
8245
0
      zend_jit_op_array_trace_extension *jit_extension =
8246
0
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8247
0
      size_t offset = jit_extension->offset;
8248
8249
0
      fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8250
0
        trace_num,
8251
0
        zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
8252
0
        op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
8253
0
        op_array->scope ? "::" : "",
8254
0
        op_array->function_name ?
8255
0
          ZSTR_VAL(op_array->function_name) : "$main",
8256
0
        ZSTR_VAL(op_array->filename),
8257
0
        opline->lineno);
8258
0
    }
8259
0
  }
8260
8261
7.77k
  if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
8262
0
    zend_jit_dump_trace(trace_buffer, NULL);
8263
0
  }
8264
8265
7.77k
  if (ZEND_JIT_TRACE_STOP_OK(stop)) {
8266
2.48k
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
8267
0
      if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8268
0
        uint32_t idx = trace_buffer[1].last;
8269
0
        uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);
8270
0
        fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
8271
0
          trace_num,
8272
0
          link_to);
8273
0
      } else {
8274
0
        fprintf(stderr, "---- TRACE %d stop (%s)\n",
8275
0
          trace_num,
8276
0
          zend_jit_trace_stop_description[stop]);
8277
0
      }
8278
0
    }
8279
2.48k
    stop = zend_jit_compile_root_trace(trace_buffer, orig_opline, offset);
8280
2.48k
    if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
8281
2.48k
      if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
8282
0
        fprintf(stderr, "---- TRACE %d %s\n",
8283
0
          trace_num,
8284
0
          zend_jit_trace_stop_description[stop]);
8285
0
      }
8286
2.48k
    } else {
8287
0
      goto abort;
8288
0
    }
8289
5.28k
  } else {
8290
5.28k
abort:
8291
5.27k
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
8292
0
      fprintf(stderr, "---- TRACE %d abort (%s)\n",
8293
0
        trace_num,
8294
0
        zend_jit_trace_stop_description[stop]);
8295
0
    }
8296
5.27k
    if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
8297
5.27k
     || zend_jit_trace_is_bad_root(orig_opline, stop, offset)) {
8298
0
      if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8299
0
        fprintf(stderr, "---- TRACE %d blacklisted\n",
8300
0
          trace_num);
8301
0
      }
8302
0
      zend_jit_blacklist_root_trace(orig_opline, offset);
8303
0
    }
8304
5.27k
    if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
8305
62
      execute_data = EG(current_execute_data);
8306
62
      opline = EX(opline);
8307
62
      goto repeat;
8308
62
    }
8309
5.27k
  }
8310
8311
7.69k
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
8312
0
    fprintf(stderr, "\n");
8313
0
  }
8314
8315
7.69k
  return ret;
8316
7.77k
}
8317
8318
static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
8319
0
{
8320
0
  const void *handler;
8321
0
  bool do_bailout = 0;
8322
8323
0
  zend_shared_alloc_lock();
8324
8325
0
  if (!(zend_jit_traces[trace_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED))) {
8326
0
    SHM_UNPROTECT();
8327
0
    zend_jit_unprotect();
8328
8329
0
    zend_try {
8330
0
      handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
8331
8332
0
      if (handler) {
8333
0
        zend_jit_link_side_trace(
8334
0
          zend_jit_traces[trace_num].code_start,
8335
0
          zend_jit_traces[trace_num].code_size,
8336
0
          zend_jit_traces[trace_num].jmp_table_size,
8337
0
          exit_num,
8338
0
          handler);
8339
0
      }
8340
0
      zend_jit_traces[trace_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_BLACKLISTED;
8341
0
    } zend_catch {
8342
0
      do_bailout = 1;
8343
0
    } zend_end_try();
8344
8345
0
    zend_jit_protect();
8346
0
    SHM_PROTECT();
8347
0
  }
8348
8349
0
  zend_shared_alloc_unlock();
8350
8351
0
  if (do_bailout) {
8352
0
    zend_bailout();
8353
0
  }
8354
0
}
8355
8356
static bool zend_jit_trace_exit_is_bad(uint32_t trace_num, uint32_t exit_num)
8357
65
{
8358
65
  uint8_t *counter = JIT_G(exit_counters) +
8359
65
    zend_jit_traces[trace_num].exit_counters + exit_num;
8360
8361
65
  if (*counter + 1 >= JIT_G(hot_side_exit) + JIT_G(blacklist_side_trace)) {
8362
0
    return true;
8363
0
  }
8364
65
  (*counter)++;
8365
65
  return false;
8366
65
}
8367
8368
static bool zend_jit_trace_exit_is_hot(uint32_t trace_num, uint32_t exit_num)
8369
32
{
8370
32
  uint8_t *counter = JIT_G(exit_counters) +
8371
32
    zend_jit_traces[trace_num].exit_counters + exit_num;
8372
8373
32
  if (*counter + 1 >= JIT_G(hot_side_exit)) {
8374
32
    return true;
8375
32
  }
8376
0
  (*counter)++;
8377
0
  return false;
8378
32
}
8379
8380
static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_num, uint32_t exit_num, uint32_t polymorphism)
8381
18
{
8382
18
  zend_jit_trace_stop ret;
8383
18
  const void *handler;
8384
18
  uint8_t orig_trigger;
8385
18
  zend_jit_trace_info *t;
8386
18
  zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
8387
18
  bool do_bailout = 0;
8388
8389
18
  zend_shared_alloc_lock();
8390
8391
  /* Checks under lock */
8392
18
  if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8393
0
    ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
8394
18
  } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8395
0
    ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8396
18
  } else if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >= JIT_G(max_side_traces)) {
8397
0
    ret = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
8398
18
  } else {
8399
18
    SHM_UNPROTECT();
8400
18
    zend_jit_unprotect();
8401
8402
18
    zend_try {
8403
18
      t = &zend_jit_traces[ZEND_JIT_TRACE_NUM];
8404
8405
18
      t->id = ZEND_JIT_TRACE_NUM;
8406
18
      t->root = zend_jit_traces[parent_num].root;
8407
18
      t->parent = parent_num;
8408
18
      t->link = 0;
8409
18
      t->exit_count = 0;
8410
18
      t->child_count = 0;
8411
18
      t->stack_map_size = 0;
8412
18
      t->flags = 0;
8413
18
      t->polymorphism = polymorphism;
8414
18
      t->jmp_table_size = 0;
8415
18
      t->opline = NULL;
8416
18
      t->exit_info = exit_info;
8417
18
      t->stack_map = NULL;
8418
18
      t->consts_count = 0;
8419
18
      t->constants = NULL;
8420
8421
18
      orig_trigger = JIT_G(trigger);
8422
18
      JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
8423
8424
18
      handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
8425
8426
18
      JIT_G(trigger) = orig_trigger;
8427
8428
18
      if (handler) {
8429
18
        zend_jit_trace_exit_info *shared_exit_info = NULL;
8430
8431
18
        t->exit_info = NULL;
8432
18
        if (t->exit_count) {
8433
          /* reallocate exit_info into shared memory */
8434
16
          shared_exit_info = (zend_jit_trace_exit_info*)zend_shared_alloc(
8435
16
            sizeof(zend_jit_trace_exit_info) * t->exit_count);
8436
8437
16
          if (!shared_exit_info) {
8438
0
            if (t->stack_map) {
8439
0
              efree(t->stack_map);
8440
0
              t->stack_map = NULL;
8441
0
            }
8442
0
            if (t->constants) {
8443
0
              efree(t->constants);
8444
0
              t->constants = NULL;
8445
0
            }
8446
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8447
0
            goto exit;
8448
0
          }
8449
16
          memcpy(shared_exit_info, exit_info,
8450
16
            sizeof(zend_jit_trace_exit_info) * t->exit_count);
8451
16
          t->exit_info = shared_exit_info;
8452
16
        }
8453
8454
18
        if (t->stack_map_size) {
8455
16
          zend_jit_trace_stack *shared_stack_map = (zend_jit_trace_stack*)zend_shared_alloc(t->stack_map_size * sizeof(zend_jit_trace_stack));
8456
16
          if (!shared_stack_map) {
8457
0
            efree(t->stack_map);
8458
0
            t->stack_map = NULL;
8459
0
            if (t->constants) {
8460
0
              efree(t->constants);
8461
0
              t->constants = NULL;
8462
0
            }
8463
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8464
0
            goto exit;
8465
0
          }
8466
16
          memcpy(shared_stack_map, t->stack_map, t->stack_map_size * sizeof(zend_jit_trace_stack));
8467
16
          efree(t->stack_map);
8468
16
          t->stack_map = shared_stack_map;
8469
16
          }
8470
8471
18
        if (t->consts_count) {
8472
9
          zend_jit_exit_const *constants = (zend_jit_exit_const*)zend_shared_alloc(t->consts_count * sizeof(zend_jit_exit_const));
8473
9
          if (!constants) {
8474
0
            efree(t->constants);
8475
0
            ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8476
0
            goto exit;
8477
0
          }
8478
9
          memcpy(constants, t->constants, t->consts_count * sizeof(zend_jit_exit_const));
8479
9
          efree(t->constants);
8480
9
          t->constants = constants;
8481
9
        }
8482
8483
18
        zend_jit_link_side_trace(
8484
18
          zend_jit_traces[parent_num].code_start,
8485
18
          zend_jit_traces[parent_num].code_size,
8486
18
          zend_jit_traces[parent_num].jmp_table_size,
8487
18
          exit_num,
8488
18
          handler);
8489
8490
18
        t->exit_counters = ZEND_JIT_EXIT_COUNTERS;
8491
18
        ZEND_JIT_EXIT_COUNTERS += t->exit_count;
8492
8493
18
        zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
8494
18
        ZEND_JIT_TRACE_NUM++;
8495
18
        zend_jit_traces[parent_num].exit_info[exit_num].flags |= ZEND_JIT_EXIT_JITED;
8496
8497
18
        ret = ZEND_JIT_TRACE_STOP_COMPILED;
8498
18
      } else if (t->exit_count >= ZEND_JIT_TRACE_MAX_EXITS ||
8499
0
                 ZEND_JIT_EXIT_COUNTERS + t->exit_count >= JIT_G(max_exit_counters)) {
8500
0
          if (t->stack_map) {
8501
0
          efree(t->stack_map);
8502
0
          t->stack_map = NULL;
8503
0
        }
8504
0
        if (t->constants) {
8505
0
          efree(t->constants);
8506
0
          t->constants = NULL;
8507
0
        }
8508
0
        ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
8509
0
      } else {
8510
0
        if (t->stack_map) {
8511
0
          efree(t->stack_map);
8512
0
          t->stack_map = NULL;
8513
0
        }
8514
0
        if (t->constants) {
8515
0
          efree(t->constants);
8516
0
          t->constants = NULL;
8517
0
        }
8518
0
        ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
8519
0
      }
8520
8521
18
exit:;
8522
18
    } zend_catch {
8523
0
      do_bailout = 1;
8524
18
    }  zend_end_try();
8525
8526
18
    zend_jit_protect();
8527
18
    SHM_PROTECT();
8528
18
  }
8529
8530
18
  zend_shared_alloc_unlock();
8531
8532
18
  if (do_bailout) {
8533
0
    zend_bailout();
8534
0
  }
8535
8536
18
  if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO) != 0
8537
0
   && ret == ZEND_JIT_TRACE_STOP_COMPILED
8538
0
   && t->exit_count > 0) {
8539
0
    zend_jit_dump_exit_info(t);
8540
0
  }
8541
8542
18
  return ret;
8543
18
}
8544
8545
int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint32_t parent_num, uint32_t exit_num)
8546
32
{
8547
32
  zend_jit_trace_stop stop;
8548
32
  int ret = 0;
8549
32
  uint32_t trace_num;
8550
32
  zend_jit_trace_rec trace_buffer[ZEND_JIT_TRACE_MAX_LENGTH];
8551
32
  uint32_t is_megamorphic = 0;
8552
32
  uint32_t polymorphism = 0;
8553
32
  uint32_t root;
8554
32
  int ret_depth = 0;
8555
8556
32
  trace_num = ZEND_JIT_TRACE_NUM;
8557
8558
  /* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
8559
32
  if (zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8560
0
    return 0;
8561
0
  }
8562
8563
32
  if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8564
0
    fprintf(stderr, "---- TRACE %d start (side trace %d/%d) %s%s%s() %s:%d\n",
8565
0
      trace_num, parent_num, exit_num,
8566
0
      EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8567
0
      EX(func)->op_array.scope ? "::" : "",
8568
0
      EX(func)->op_array.function_name ?
8569
0
        ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8570
0
      ZSTR_VAL(EX(func)->op_array.filename),
8571
0
      EX(opline)->lineno);
8572
0
  }
8573
8574
32
  if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8575
0
    stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8576
0
    goto abort;
8577
0
  }
8578
8579
32
  root = zend_jit_traces[parent_num].root;
8580
32
  if (zend_jit_traces[root].child_count >= JIT_G(max_side_traces)) {
8581
0
    stop = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
8582
0
    goto abort;
8583
0
  }
8584
8585
32
  if (JIT_G(max_polymorphic_calls) > 0) {
8586
32
    if ((zend_jit_traces[parent_num].exit_info[exit_num].flags & (ZEND_JIT_EXIT_METHOD_CALL|ZEND_JIT_EXIT_CLOSURE_CALL))
8587
32
     || ((zend_jit_traces[parent_num].exit_info[exit_num].flags & ZEND_JIT_EXIT_POLYMORPHISM)
8588
0
      && EX(call))) {
8589
0
      if (zend_jit_traces[parent_num].polymorphism >= JIT_G(max_polymorphic_calls) - 1) {
8590
0
        is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
8591
0
          (ZEND_JIT_EXIT_METHOD_CALL | ZEND_JIT_EXIT_CLOSURE_CALL | ZEND_JIT_EXIT_POLYMORPHISM);
8592
0
      } else if (!zend_jit_traces[parent_num].polymorphism) {
8593
0
        polymorphism = 1;
8594
0
      } else if (exit_num == 0) {
8595
0
        polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
8596
0
      }
8597
0
    }
8598
32
  }
8599
8600
  /* Check if this is a side trace of a root LOOP trace */
8601
32
  if ((zend_jit_traces[root].flags & ZEND_JIT_TRACE_LOOP)
8602
32
   && zend_jit_traces[root].op_array != &EX(func)->op_array) {
8603
32
    const zend_op_array *op_array = zend_jit_traces[root].op_array;
8604
32
    const zend_op *opline = zend_jit_traces[root].opline;
8605
32
    zend_jit_op_array_trace_extension *jit_extension =
8606
32
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8607
8608
32
    if (jit_extension->trace_info[opline - op_array->opcodes].trace_flags & ZEND_JIT_TRACE_START_LOOP) {
8609
32
      zend_execute_data *ex = execute_data;
8610
32
      int n = 0;
8611
32
      do {
8612
32
        ex = ex->prev_execute_data;
8613
32
        n++;
8614
32
      } while (ex && (!ex->func || zend_jit_traces[root].op_array != &ex->func->op_array));
8615
32
      if (ex && n <= ZEND_JIT_TRACE_MAX_RET_DEPTH) {
8616
0
        ret_depth = n;
8617
0
      }
8618
32
    }
8619
32
  }
8620
8621
32
  JIT_G(tracing) = 1;
8622
32
  stop = zend_jit_trace_execute(execute_data, EX(opline), trace_buffer, ZEND_JIT_TRACE_START_SIDE, is_megamorphic, ret_depth);
8623
32
  JIT_G(tracing) = 0;
8624
8625
32
  if (stop & ZEND_JIT_TRACE_HALT) {
8626
2
    ret = -1;
8627
2
  }
8628
32
  stop &= ~ZEND_JIT_TRACE_HALT;
8629
8630
32
  if (UNEXPECTED(trace_buffer->start != ZEND_JIT_TRACE_START_SIDE)) {
8631
0
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_START) {
8632
0
      const zend_op_array *op_array = trace_buffer[0].op_array;
8633
0
      const zend_op *opline = trace_buffer[1].opline;
8634
0
      zend_jit_op_array_trace_extension *jit_extension =
8635
0
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8636
0
      size_t offset = jit_extension->offset;
8637
8638
0
      fprintf(stderr, "---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8639
0
        trace_num,
8640
0
        zend_jit_trace_star_desc(ZEND_OP_TRACE_INFO(opline, offset)->trace_flags),
8641
0
        op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
8642
0
        op_array->scope ? "::" : "",
8643
0
        op_array->function_name ?
8644
0
          ZSTR_VAL(op_array->function_name) : "$main",
8645
0
        ZSTR_VAL(op_array->filename),
8646
0
        opline->lineno);
8647
0
    }
8648
0
  }
8649
8650
32
  if (UNEXPECTED(JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BYTECODE)) {
8651
0
    zend_jit_dump_trace(trace_buffer, NULL);
8652
0
  }
8653
8654
32
  if (ZEND_JIT_TRACE_STOP_OK(stop)) {
8655
18
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_STOP) {
8656
0
      if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8657
0
        uint32_t idx = trace_buffer[1].last;
8658
0
        uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->handler);;
8659
0
        fprintf(stderr, "---- TRACE %d stop (link to %d)\n",
8660
0
          trace_num,
8661
0
          link_to);
8662
0
      } else {
8663
0
        fprintf(stderr, "---- TRACE %d stop (%s)\n",
8664
0
          trace_num,
8665
0
          zend_jit_trace_stop_description[stop]);
8666
0
      }
8667
0
    }
8668
18
    if (EXPECTED(trace_buffer->start == ZEND_JIT_TRACE_START_SIDE)) {
8669
18
      stop = zend_jit_compile_side_trace(trace_buffer, parent_num, exit_num, polymorphism);
8670
18
    } else {
8671
0
      const zend_op_array *op_array = trace_buffer[0].op_array;
8672
0
      zend_jit_op_array_trace_extension *jit_extension =
8673
0
        (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8674
0
      const zend_op *opline = trace_buffer[1].opline;
8675
8676
0
      stop = zend_jit_compile_root_trace(trace_buffer, opline, jit_extension->offset);
8677
0
    }
8678
18
    if (EXPECTED(ZEND_JIT_TRACE_STOP_DONE(stop))) {
8679
18
      if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_COMPILED) {
8680
0
        fprintf(stderr, "---- TRACE %d %s\n",
8681
0
          trace_num,
8682
0
          zend_jit_trace_stop_description[stop]);
8683
0
      }
8684
18
    } else {
8685
0
      goto abort;
8686
0
    }
8687
18
  } else {
8688
14
abort:
8689
14
    if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_ABORT) {
8690
0
      fprintf(stderr, "---- TRACE %d abort (%s)\n",
8691
0
        trace_num,
8692
0
        zend_jit_trace_stop_description[stop]);
8693
0
    }
8694
14
    if (!ZEND_JIT_TRACE_STOP_MAY_RECOVER(stop)
8695
14
     || zend_jit_trace_exit_is_bad(parent_num, exit_num)) {
8696
0
      zend_jit_blacklist_trace_exit(parent_num, exit_num);
8697
0
      if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8698
0
        fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8699
0
          parent_num, exit_num);
8700
0
      }
8701
0
    }
8702
14
    if (ZEND_JIT_TRACE_STOP_REPEAT(stop)) {
8703
0
      execute_data = EG(current_execute_data);
8704
0
      return zend_jit_trace_hot_root(execute_data, EX(opline));
8705
0
    }
8706
14
  }
8707
8708
32
  if (JIT_G(debug) & (ZEND_JIT_DEBUG_TRACE_STOP|ZEND_JIT_DEBUG_TRACE_ABORT|ZEND_JIT_DEBUG_TRACE_COMPILED|ZEND_JIT_DEBUG_TRACE_BLACKLIST)) {
8709
0
    fprintf(stderr, "\n");
8710
0
  }
8711
8712
32
  return ret;
8713
32
}
8714
8715
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs)
8716
83
{
8717
83
  uint32_t trace_num = EG(jit_trace_num);
8718
83
  zend_execute_data *execute_data = EG(current_execute_data);
8719
83
  const zend_op *orig_opline = EX(opline);
8720
83
  const zend_op *opline;
8721
83
  zend_jit_trace_info *t = &zend_jit_traces[trace_num];
8722
83
  int repeat_last_opline = 0;
8723
8724
  /* Deoptimization of VM stack state */
8725
83
  uint32_t i;
8726
83
  uint32_t stack_size = t->exit_info[exit_num].stack_size;
8727
83
  zend_jit_trace_stack *stack = stack_size ? t->stack_map + t->exit_info[exit_num].stack_offset : NULL;
8728
8729
83
  if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_RESTORE_CALL) {
8730
1
    zend_execute_data *call = (zend_execute_data *)regs->gpr[ZREG_RX];
8731
1
    call->prev_execute_data = EX(call);
8732
1
    EX(call) = call;
8733
1
  }
8734
8735
178
  for (i = 0; i < stack_size; i++) {
8736
95
    if (STACK_FLAGS(stack, i) == ZREG_CONST) {
8737
0
      if (STACK_TYPE(stack, i) == IS_LONG) {
8738
0
        ZVAL_LONG(EX_VAR_NUM(i), (zend_long)t->constants[STACK_REF(stack, i)].i);
8739
0
      } else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
8740
0
        ZVAL_DOUBLE(EX_VAR_NUM(i), t->constants[STACK_REF(stack, i)].d);
8741
0
      } else {
8742
0
        ZEND_UNREACHABLE();
8743
0
      }
8744
95
    } else if (STACK_FLAGS(stack, i) == ZREG_TYPE_ONLY) {
8745
0
      uint32_t type = STACK_TYPE(stack, i);
8746
0
      if (type <= IS_DOUBLE) {
8747
0
        Z_TYPE_INFO_P(EX_VAR_NUM(i)) = type;
8748
0
      } else {
8749
0
        ZEND_UNREACHABLE();
8750
0
      }
8751
95
    } else if (STACK_FLAGS(stack, i) == ZREG_THIS) {
8752
0
      ZVAL_OBJ_COPY(EX_VAR_NUM(i), Z_OBJ(EX(This)));
8753
95
    } else if (STACK_FLAGS(stack, i) == ZREG_ZVAL_ADDREF) {
8754
0
      Z_TRY_ADDREF_P(EX_VAR_NUM(i));
8755
95
    } else if (STACK_FLAGS(stack, i) == ZREG_ZVAL_COPY) {
8756
0
      zval *val = (zval*)regs->gpr[STACK_REG(stack, i)];
8757
8758
0
      if (UNEXPECTED(Z_TYPE_P(val) == IS_UNDEF)) {
8759
        /* Undefined array index or property */
8760
0
        const zend_op *op = t->exit_info[exit_num].opline;
8761
0
        ZEND_ASSERT(op);
8762
0
        op--;
8763
0
        if (op->opcode == ZEND_FETCH_DIM_IS) {
8764
0
          ZVAL_NULL(EX_VAR_NUM(i));
8765
0
        } else if (op->opcode == ZEND_FETCH_OBJ_IS
8766
0
         && (Z_PROP_FLAG_P(val) & (IS_PROP_LAZY|IS_PROP_UNINIT)) == IS_PROP_UNINIT) {
8767
0
          ZVAL_NULL(EX_VAR_NUM(i));
8768
0
        } else {
8769
0
          ZEND_ASSERT(op->opcode == ZEND_FETCH_DIM_R || op->opcode == ZEND_FETCH_LIST_R || op->opcode == ZEND_FETCH_OBJ_R || op->opcode == ZEND_FETCH_OBJ_IS || op->opcode == ZEND_FETCH_DIM_FUNC_ARG || op->opcode == ZEND_FETCH_OBJ_FUNC_ARG);
8770
0
          repeat_last_opline = 1;
8771
0
        }
8772
0
      } else {
8773
0
        ZVAL_COPY(EX_VAR_NUM(i), val);
8774
0
      }
8775
95
    } else if (STACK_FLAGS(stack, i) & ZREG_SPILL_SLOT) {
8776
0
      ZEND_ASSERT(STACK_REG(stack, i) != ZREG_NONE);
8777
0
      uintptr_t ptr = (uintptr_t)regs->gpr[STACK_REG(stack, i)] + STACK_REF(stack, i);
8778
8779
0
      if (STACK_TYPE(stack, i) == IS_LONG) {
8780
0
        ZVAL_LONG(EX_VAR_NUM(i), *(zend_long*)ptr);
8781
0
      } else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
8782
0
        ZVAL_DOUBLE(EX_VAR_NUM(i), *(double*)ptr);
8783
0
      } else {
8784
0
        ZEND_UNREACHABLE();
8785
0
      }
8786
95
    } else if (STACK_REG(stack, i) != ZREG_NONE) {
8787
10
      if (STACK_TYPE(stack, i) == IS_LONG) {
8788
10
        zend_long val = regs->gpr[STACK_REG(stack, i)];
8789
10
        ZVAL_LONG(EX_VAR_NUM(i), val);
8790
10
      } else if (STACK_TYPE(stack, i) == IS_DOUBLE) {
8791
0
        double val = regs->fpr[STACK_REG(stack, i) - ZREG_FIRST_FPR];
8792
0
        ZVAL_DOUBLE(EX_VAR_NUM(i), val);
8793
0
      } else {
8794
0
        ZEND_UNREACHABLE();
8795
0
      }
8796
10
    }
8797
95
  }
8798
8799
83
  if (repeat_last_opline) {
8800
0
    EX(opline) = t->exit_info[exit_num].opline - 1;
8801
0
    if ((EX(opline)->op1_type & (IS_VAR|IS_TMP_VAR))
8802
0
     && !(t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1)
8803
0
     && EX(opline)->opcode != ZEND_FETCH_LIST_R) {
8804
0
      Z_TRY_ADDREF_P(EX_VAR(EX(opline)->op1.var));
8805
0
    }
8806
0
    return 1;
8807
0
  }
8808
8809
83
  opline = t->exit_info[exit_num].opline;
8810
8811
83
  if (opline) {
8812
83
    if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP2) {
8813
0
      ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8814
0
          || (opline-1)->opcode == ZEND_FETCH_DIM_IS
8815
0
          || (opline-1)->opcode == ZEND_FETCH_LIST_R
8816
0
          || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG);
8817
0
      EX(opline) = opline-1;
8818
0
      zval_ptr_dtor_nogc(EX_VAR((opline-1)->op2.var));
8819
0
    }
8820
83
    if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) {
8821
0
      ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R
8822
0
          || (opline-1)->opcode == ZEND_FETCH_DIM_IS
8823
0
          || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG
8824
0
          || (opline-1)->opcode == ZEND_FETCH_OBJ_R
8825
0
          || (opline-1)->opcode == ZEND_FETCH_OBJ_IS
8826
0
          || (opline-1)->opcode == ZEND_FETCH_OBJ_FUNC_ARG);
8827
0
      EX(opline) = opline-1;
8828
0
      zval_ptr_dtor_nogc(EX_VAR((opline-1)->op1.var));
8829
0
    }
8830
83
    if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_FREE_OP1|ZEND_JIT_EXIT_FREE_OP2|ZEND_JIT_EXIT_CHECK_EXCEPTION)) {
8831
0
      if (EG(exception)) {
8832
        /* EX(opline) was overridden in zend_jit_trace_exit_stub(),
8833
         * and may be wrong when IP is reused. */
8834
0
        EX(opline) = EG(exception_op);
8835
0
        return 0;
8836
0
      }
8837
0
    }
8838
83
    if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_METHOD_CALL) {
8839
0
      zend_jit_ref_snapshot *func_snapshot = &t->exit_info[exit_num].poly_func;
8840
0
      ZEND_ASSERT(func_snapshot->reg >= 0);
8841
8842
0
      zend_function *func;
8843
0
      if (IR_REG_SPILLED(func_snapshot->reg)) {
8844
0
        func = *(zend_function**)(regs->gpr[IR_REG_NUM(func_snapshot->reg)] + func_snapshot->offset);
8845
0
      } else {
8846
0
        func = (zend_function*)regs->gpr[func_snapshot->reg];
8847
0
      }
8848
0
      if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
8849
0
        zend_string_release_ex(func->common.function_name, 0);
8850
0
        zend_free_trampoline(func);
8851
0
        EX(opline) = opline;
8852
0
        return 1;
8853
0
      }
8854
0
    }
8855
8856
    /* Set VM opline to continue interpretation */
8857
83
    EX(opline) = opline;
8858
83
  }
8859
8860
83
  if (atomic_load(&EG(vm_interrupt)) || JIT_G(tracing)) {
8861
0
    return 1;
8862
  /* Lock-free check if the side trace was already JIT-ed or blacklist-ed in another process */
8863
83
  } else if (t->exit_info[exit_num].flags & (ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)) {
8864
0
    return 0;
8865
0
  }
8866
8867
83
  ZEND_ASSERT(EX(func)->type == ZEND_USER_FUNCTION);
8868
83
  ZEND_ASSERT(EX(opline) >= EX(func)->op_array.opcodes &&
8869
83
    EX(opline) < EX(func)->op_array.opcodes + EX(func)->op_array.last);
8870
8871
83
  if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT) {
8872
0
    fprintf(stderr, "     TRACE %d exit %d %s%s%s() %s:%d\n",
8873
0
      trace_num,
8874
0
      exit_num,
8875
0
      EX(func)->op_array.scope ? ZSTR_VAL(EX(func)->op_array.scope->name) : "",
8876
0
      EX(func)->op_array.scope ? "::" : "",
8877
0
      EX(func)->op_array.function_name ?
8878
0
        ZSTR_VAL(EX(func)->op_array.function_name) : "$main",
8879
0
      ZSTR_VAL(EX(func)->op_array.filename),
8880
0
      EX(opline)->lineno);
8881
0
  }
8882
8883
83
  if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_INVALIDATE) {
8884
0
    zend_jit_op_array_trace_extension *jit_extension;
8885
0
    uint32_t num = trace_num;
8886
8887
0
    while (t->root != num) {
8888
0
      num = t->root;
8889
0
      t = &zend_jit_traces[num];
8890
0
    }
8891
8892
0
    zend_shared_alloc_lock();
8893
8894
0
    jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(t->op_array);
8895
8896
    /* Checks under lock, just in case something has changed while we were waiting for the lock */
8897
0
    if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & (ZEND_JIT_TRACE_JITED|ZEND_JIT_TRACE_BLACKLISTED))) {
8898
      /* skip: not JIT-ed nor blacklisted */
8899
0
    } else if (ZEND_JIT_TRACE_NUM >= JIT_G(max_root_traces)) {
8900
      /* too many root traces, blacklist the root trace */
8901
0
      if (!(ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED)) {
8902
0
        SHM_UNPROTECT();
8903
0
        zend_jit_unprotect();
8904
8905
0
        ((zend_op*)(t->opline))->handler =
8906
0
          ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->orig_handler;
8907
8908
0
        ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &= ~ZEND_JIT_TRACE_JITED;
8909
0
        ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags |= ZEND_JIT_TRACE_BLACKLISTED;
8910
8911
0
        zend_jit_protect();
8912
0
        SHM_PROTECT();
8913
0
      }
8914
0
    } else {
8915
0
      SHM_UNPROTECT();
8916
0
      zend_jit_unprotect();
8917
8918
0
      if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) {
8919
0
        ((zend_op*)(t->opline))->handler = zend_jit_loop_trace_counter_handler;
8920
0
      } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) {
8921
0
        ((zend_op*)(t->opline))->handler = zend_jit_func_trace_counter_handler;
8922
0
      } else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) {
8923
0
        ((zend_op*)(t->opline))->handler = zend_jit_ret_trace_counter_handler;
8924
0
      }
8925
0
      ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &=
8926
0
        ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN;
8927
8928
0
      zend_jit_protect();
8929
0
      SHM_PROTECT();
8930
0
    }
8931
8932
0
    zend_shared_alloc_unlock();
8933
8934
0
    return 0;
8935
0
  }
8936
8937
83
  if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_TO_VM) {
8938
51
    if (zend_jit_trace_exit_is_bad(trace_num, exit_num)) {
8939
0
      zend_jit_blacklist_trace_exit(trace_num, exit_num);
8940
0
      if (JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_BLACKLIST) {
8941
0
        fprintf(stderr, "---- EXIT %d/%d blacklisted\n",
8942
0
          trace_num, exit_num);
8943
0
      }
8944
0
      return 0;
8945
0
    }
8946
51
  } else if (JIT_G(hot_side_exit) && zend_jit_trace_exit_is_hot(trace_num, exit_num)) {
8947
32
    return zend_jit_trace_hot_side(execute_data, trace_num, exit_num);
8948
32
  }
8949
8950
  /* Return 1 to call original handler instead of the same JIT-ed trace */
8951
51
  return (orig_opline == t->opline && EX(opline) == orig_opline);
8952
83
}
8953
8954
static zend_always_inline uint8_t zend_jit_trace_supported(const zend_op *opline)
8955
29.9k
{
8956
29.9k
  switch (opline->opcode) {
8957
0
    case ZEND_CATCH:
8958
0
    case ZEND_FAST_CALL:
8959
0
    case ZEND_FAST_RET:
8960
0
      return ZEND_JIT_TRACE_UNSUPPORTED;
8961
29.9k
    default:
8962
29.9k
      return ZEND_JIT_TRACE_SUPPORTED;
8963
29.9k
  }
8964
29.9k
}
8965
8966
static int zend_jit_restart_hot_trace_counters(zend_op_array *op_array)
8967
0
{
8968
0
  zend_jit_op_array_trace_extension *jit_extension;
8969
0
  uint32_t i;
8970
8971
0
  jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array);
8972
0
  for (i = 0; i < op_array->last; i++) {
8973
0
    jit_extension->trace_info[i].trace_flags &=
8974
0
      ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_UNSUPPORTED;
8975
0
    if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_LOOP) {
8976
0
      op_array->opcodes[i].handler = zend_jit_loop_trace_counter_handler;
8977
0
    } else if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_ENTER) {
8978
0
      op_array->opcodes[i].handler = zend_jit_func_trace_counter_handler;
8979
0
    } else {
8980
0
      op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
8981
0
    }
8982
0
  }
8983
0
  return SUCCESS;
8984
0
}
8985
8986
static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
8987
5.26k
{
8988
5.26k
  zend_op *opline;
8989
5.26k
  zend_jit_op_array_trace_extension *jit_extension;
8990
5.26k
  uint32_t i;
8991
8992
5.26k
  ZEND_ASSERT(sizeof(zend_op_trace_info) == sizeof(zend_op));
8993
8994
5.26k
  jit_extension = (zend_jit_op_array_trace_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_trace_extension) + (op_array->last - 1) * sizeof(zend_op_trace_info));
8995
5.26k
  if (!jit_extension) {
8996
0
    return FAILURE;
8997
0
  }
8998
5.26k
  memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
8999
5.26k
  jit_extension->func_info.flags = ZEND_FUNC_JIT_ON_HOT_TRACE;
9000
5.26k
  jit_extension->op_array = op_array;
9001
5.26k
  jit_extension->offset = (char*)jit_extension->trace_info - (char*)op_array->opcodes;
9002
35.2k
  for (i = 0; i < op_array->last; i++) {
9003
29.9k
    jit_extension->trace_info[i].orig_handler = op_array->opcodes[i].handler;
9004
29.9k
    jit_extension->trace_info[i].call_handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(&op_array->opcodes[i]);
9005
29.9k
    jit_extension->trace_info[i].counter = NULL;
9006
29.9k
    jit_extension->trace_info[i].trace_flags =
9007
29.9k
      zend_jit_trace_supported(&op_array->opcodes[i]);
9008
29.9k
  }
9009
5.26k
  ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
9010
9011
5.26k
  if (JIT_G(hot_loop)) {
9012
5.26k
    zend_cfg cfg;
9013
9014
5.26k
    ZEND_ASSERT(zend_jit_loop_trace_counter_handler != NULL);
9015
9016
5.26k
    if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
9017
0
      return FAILURE;
9018
0
    }
9019
9020
12.6k
    for (i = 0; i < cfg.blocks_count; i++) {
9021
7.35k
      if (cfg.blocks[i].flags & ZEND_BB_REACHABLE) {
9022
7.35k
        if (cfg.blocks[i].flags & ZEND_BB_LOOP_HEADER) {
9023
          /* loop header */
9024
105
          opline = op_array->opcodes + cfg.blocks[i].start;
9025
105
          if (!(ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_UNSUPPORTED)) {
9026
105
            opline->handler = zend_jit_loop_trace_counter_handler;
9027
105
            if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter) {
9028
105
              ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
9029
105
                &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
9030
105
              ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
9031
105
            }
9032
105
            ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
9033
105
              ZEND_JIT_TRACE_START_LOOP;
9034
105
          }
9035
105
        }
9036
7.35k
      }
9037
7.35k
    }
9038
5.26k
  }
9039
9040
5.26k
  if (JIT_G(hot_func)) {
9041
5.26k
    ZEND_ASSERT(zend_jit_func_trace_counter_handler != NULL);
9042
5.26k
    opline = op_array->opcodes;
9043
5.26k
    if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
9044
5.24k
      while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
9045
6
        opline++;
9046
6
      }
9047
5.24k
    }
9048
9049
5.26k
    if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags) {
9050
      /* function entry */
9051
5.21k
      opline->handler = zend_jit_func_trace_counter_handler;
9052
5.21k
      ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
9053
5.21k
        &zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
9054
5.21k
      ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
9055
5.21k
      ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags |=
9056
5.21k
        ZEND_JIT_TRACE_START_ENTER;
9057
5.21k
    }
9058
5.26k
  }
9059
9060
5.26k
  zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
9061
9062
5.26k
  return SUCCESS;
9063
5.26k
}
9064
9065
static void zend_jit_trace_init_caches(void)
9066
16
{
9067
16
  memset(ZEND_VOIDP(JIT_G(bad_root_cache_opline)), 0, sizeof(JIT_G(bad_root_cache_opline)));
9068
16
  memset(JIT_G(bad_root_cache_count), 0, sizeof(JIT_G(bad_root_cache_count)));
9069
16
  memset(JIT_G(bad_root_cache_stop), 0, sizeof(JIT_G(bad_root_cache_count)));
9070
16
  JIT_G(bad_root_slot) = 0;
9071
9072
16
  if (JIT_G(exit_counters)) {
9073
0
    memset(JIT_G(exit_counters), 0, JIT_G(max_exit_counters));
9074
0
  }
9075
16
}
9076
9077
static void zend_jit_trace_reset_caches(void)
9078
10.3k
{
9079
10.3k
  JIT_G(tracing) = 0;
9080
#ifdef ZTS
9081
  if (!JIT_G(exit_counters)) {
9082
    JIT_G(exit_counters) = calloc(JIT_G(max_exit_counters), 1);
9083
  }
9084
#endif
9085
10.3k
}
9086
9087
static void zend_jit_trace_free_caches(zend_jit_globals *jit_globals)
9088
0
{
9089
0
  if (jit_globals->exit_counters) {
9090
0
    free(jit_globals->exit_counters);
9091
0
  }
9092
0
}
9093
9094
static void zend_jit_trace_restart(void)
9095
0
{
9096
0
  ZEND_JIT_TRACE_NUM = 1;
9097
0
  ZEND_JIT_COUNTER_NUM = 0;
9098
0
  ZEND_JIT_EXIT_NUM = 0;
9099
0
  ZEND_JIT_EXIT_COUNTERS = 0;
9100
0
  ZCSG(jit_counters_stopped) = false;
9101
9102
0
  zend_jit_trace_init_caches();
9103
0
}