Coverage Report

Created: 2026-06-02 06:40

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