Coverage Report

Created: 2026-09-14 06:25

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