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