php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_jit.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
19#include "main/php.h"
20#include "main/SAPI.h"
21#include "php_version.h"
22#include <ZendAccelerator.h>
23#include "zend_shared_alloc.h"
24#include "Zend/zend_execute.h"
25#include "Zend/zend_vm.h"
27#include "Zend/zend_constants.h"
28#include "Zend/zend_closures.h"
29#include "Zend/zend_ini.h"
30#include "Zend/zend_observer.h"
31#include "zend_smart_str.h"
32#include "jit/zend_jit.h"
33
34#ifdef HAVE_JIT
35
37#include "Optimizer/zend_ssa.h"
40#include "Optimizer/zend_dump.h"
42
44
45#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
46#include <pthread.h>
47#endif
48
49#ifdef ZTS
50int jit_globals_id;
51#else
53#endif
54
55//#define CONTEXT_THREADED_JIT
56#define ZEND_JIT_USE_RC_INFERENCE
57
58#ifdef ZEND_JIT_USE_RC_INFERENCE
59# define ZEND_SSA_RC_INFERENCE_FLAG ZEND_SSA_RC_INFERENCE
60# define RC_MAY_BE_1(info) (((info) & (MAY_BE_RC1|MAY_BE_REF)) != 0)
61# define RC_MAY_BE_N(info) (((info) & (MAY_BE_RCN|MAY_BE_REF)) != 0)
62#else
63# define ZEND_SSA_RC_INFERENCE_FLAG 0
64# define RC_MAY_BE_1(info) 1
65# define RC_MAY_BE_N(info) 1
66#endif
67
68#define JIT_PREFIX "JIT$"
69#define JIT_STUB_PREFIX "JIT$$"
70#define TRACE_PREFIX "TRACE-"
71
72bool zend_jit_startup_ok = false;
73
76
78
80static int zend_jit_vm_kind = 0;
81#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
82static int zend_write_protect = 1;
83#endif
84
85static void *dasm_buf = NULL;
86static void *dasm_end = NULL;
87static void **dasm_ptr = NULL;
88
89static size_t dasm_size = 0;
90
91static zend_long jit_bisect_pos = 0;
92
93static const void *zend_jit_runtime_jit_handler = NULL;
94static const void *zend_jit_profile_jit_handler = NULL;
95static const void *zend_jit_func_hot_counter_handler = NULL;
96static const void *zend_jit_loop_hot_counter_handler = NULL;
97static const void *zend_jit_func_trace_counter_handler = NULL;
98static const void *zend_jit_ret_trace_counter_handler = NULL;
99static const void *zend_jit_loop_trace_counter_handler = NULL;
100
101static int ZEND_FASTCALL zend_runtime_jit(void);
102
103static int zend_jit_trace_op_len(const zend_op *opline);
104static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline);
105static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags);
106static const void *zend_jit_trace_get_exit_addr(uint32_t n);
107static void zend_jit_trace_add_code(const void *start, uint32_t size);
108static zend_string *zend_jit_func_name(const zend_op_array *op_array);
109
110static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info);
111static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info);
112
113static bool dominates(const zend_basic_block *blocks, int a, int b) {
114 while (blocks[b].level > blocks[a].level) {
115 b = blocks[b].idom;
116 }
117 return a == b;
118}
119
120static bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa *ssa, int var, int use)
121{
122 int next_use;
123
124 if (ssa->vars[var].phi_use_chain) {
125 zend_ssa_phi *phi = ssa->vars[var].phi_use_chain;
126 do {
127 if (!ssa->vars[phi->ssa_var].no_val) {
128 return 0;
129 }
130 phi = zend_ssa_next_use_phi(ssa, var, phi);
131 } while (phi);
132 }
133
134 if (ssa->cfg.blocks[ssa->cfg.map[use]].loop_header > 0
135 || (ssa->cfg.blocks[ssa->cfg.map[use]].flags & ZEND_BB_LOOP_HEADER)) {
136 int b = ssa->cfg.map[use];
137 int prev_use = ssa->vars[var].use_chain;
138 int def_block;
139
140 if (ssa->vars[var].definition >= 0) {
141 def_block =ssa->cfg.map[ssa->vars[var].definition];
142 } else {
144 def_block = ssa->vars[var].definition_phi->block;
145 }
146 if (dominates(ssa->cfg.blocks, def_block,
147 (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) ? b : ssa->cfg.blocks[b].loop_header)) {
148 return 0;
149 }
150
151 while (prev_use >= 0 && prev_use != use) {
152 if (b != ssa->cfg.map[prev_use]
153 && dominates(ssa->cfg.blocks, b, ssa->cfg.map[prev_use])
154 && !zend_ssa_is_no_val_use(op_array->opcodes + prev_use, ssa->ops + prev_use, var)) {
155 return 0;
156 }
157 prev_use = zend_ssa_next_use(ssa->ops, var, prev_use);
158 }
159 }
160
161 next_use = zend_ssa_next_use(ssa->ops, var, use);
162 if (next_use < 0) {
163 return 1;
164 } else if (zend_ssa_is_no_val_use(op_array->opcodes + next_use, ssa->ops + next_use, var)) {
165 return 1;
166 }
167 return 0;
168}
169
170static int zend_jit_is_constant_cmp_long_long(const zend_op *opline,
171 zend_ssa_range *op1_range,
172 zend_jit_addr op1_addr,
173 zend_ssa_range *op2_range,
174 zend_jit_addr op2_addr,
175 bool *result)
176{
177 zend_long op1_min;
178 zend_long op1_max;
179 zend_long op2_min;
180 zend_long op2_max;
181
182 if (op1_range) {
183 op1_min = op1_range->min;
184 op1_max = op1_range->max;
185 } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL) {
186 ZEND_ASSERT(Z_TYPE_P(Z_ZV(op1_addr)) == IS_LONG);
187 op1_min = op1_max = Z_LVAL_P(Z_ZV(op1_addr));
188 } else {
189 return 0;
190 }
191
192 if (op2_range) {
193 op2_min = op2_range->min;
194 op2_max = op2_range->max;
195 } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
196 ZEND_ASSERT(Z_TYPE_P(Z_ZV(op2_addr)) == IS_LONG);
197 op2_min = op2_max = Z_LVAL_P(Z_ZV(op2_addr));
198 } else {
199 return 0;
200 }
201
202 switch (opline->opcode) {
203 case ZEND_IS_EQUAL:
205 case ZEND_CASE:
206 case ZEND_CASE_STRICT:
207 if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
208 *result = 1;
209 return 1;
210 } else if (op1_max < op2_min || op1_min > op2_max) {
211 *result = 0;
212 return 1;
213 }
214 return 0;
217 if (op1_min == op1_max && op2_min == op2_max && op1_min == op2_min) {
218 *result = 0;
219 return 1;
220 } else if (op1_max < op2_min || op1_min > op2_max) {
221 *result = 1;
222 return 1;
223 }
224 return 0;
225 case ZEND_IS_SMALLER:
226 if (op1_max < op2_min) {
227 *result = 1;
228 return 1;
229 } else if (op1_min >= op2_max) {
230 *result = 0;
231 return 1;
232 }
233 return 0;
235 if (op1_max <= op2_min) {
236 *result = 1;
237 return 1;
238 } else if (op1_min > op2_max) {
239 *result = 0;
240 return 1;
241 }
242 return 0;
243 default:
245 }
246 return 0;
247}
248
249#define ADVANCE_SSA_OP(ssa_op, offset) \
250 do { \
251 if (ssa_op) ssa_op += offset; \
252 } while (0)
253
254static int zend_jit_needs_call_chain(zend_call_info *call_info, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, const zend_op *opline, int call_level, zend_jit_trace_rec *trace)
255{
256 int skip;
257
258 if (trace) {
259 zend_jit_trace_rec *p = trace;
260
261 ADVANCE_SSA_OP(ssa_op, 1);
262 while (1) {
263 if (p->op == ZEND_JIT_TRACE_VM) {
264 switch (p->opline->opcode) {
265 case ZEND_SEND_ARRAY:
266 case ZEND_SEND_USER:
267 case ZEND_SEND_UNPACK:
268 case ZEND_INIT_FCALL:
275 case ZEND_NEW:
277 case ZEND_FAST_CALL:
278 case ZEND_JMP:
279 case ZEND_JMPZ:
280 case ZEND_JMPNZ:
281 case ZEND_JMPZ_EX:
282 case ZEND_JMPNZ_EX:
283 case ZEND_FE_RESET_R:
284 case ZEND_FE_RESET_RW:
285 case ZEND_JMP_SET:
286 case ZEND_COALESCE:
287 case ZEND_JMP_NULL:
289 case ZEND_CATCH:
291 case ZEND_FE_FETCH_R:
292 case ZEND_FE_FETCH_RW:
295 return 1;
296 case ZEND_DO_ICALL:
297 case ZEND_DO_UCALL:
299 case ZEND_DO_FCALL:
301 return 0;
302 case ZEND_SEND_VAL:
303 case ZEND_SEND_VAR:
304 case ZEND_SEND_VAL_EX:
305 case ZEND_SEND_VAR_EX:
307 case ZEND_SEND_REF:
310 /* skip */
311 break;
312 default:
313 if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
314 return 1;
315 }
316 }
317 ADVANCE_SSA_OP(ssa_op, zend_jit_trace_op_len(opline));
318 } else if (p->op == ZEND_JIT_TRACE_ENTER ||
319 p->op == ZEND_JIT_TRACE_BACK ||
320 p->op == ZEND_JIT_TRACE_END) {
321 return 1;
322 }
323 p++;
324 }
325 }
326
327 if (!call_info) {
328 const zend_op *end = op_array->opcodes + op_array->last;
329
330 opline++;
331 ADVANCE_SSA_OP(ssa_op, 1);
332 skip = (call_level == 1);
333 while (opline != end) {
334 if (!skip) {
335 if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
336 return 1;
337 }
338 }
339 switch (opline->opcode) {
340 case ZEND_SEND_VAL:
341 case ZEND_SEND_VAR:
342 case ZEND_SEND_VAL_EX:
343 case ZEND_SEND_VAR_EX:
345 case ZEND_SEND_REF:
348 skip = 0;
349 break;
350 case ZEND_SEND_ARRAY:
351 case ZEND_SEND_USER:
352 case ZEND_SEND_UNPACK:
353 case ZEND_INIT_FCALL:
360 case ZEND_NEW:
362 case ZEND_FAST_CALL:
363 case ZEND_JMP:
364 case ZEND_JMPZ:
365 case ZEND_JMPNZ:
366 case ZEND_JMPZ_EX:
367 case ZEND_JMPNZ_EX:
368 case ZEND_FE_RESET_R:
369 case ZEND_FE_RESET_RW:
370 case ZEND_JMP_SET:
371 case ZEND_COALESCE:
372 case ZEND_JMP_NULL:
374 case ZEND_CATCH:
376 case ZEND_FE_FETCH_R:
377 case ZEND_FE_FETCH_RW:
380 return 1;
381 case ZEND_DO_ICALL:
382 case ZEND_DO_UCALL:
384 case ZEND_DO_FCALL:
386 end = opline;
387 if (end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
388 /* INIT_FCALL and DO_FCALL in different BasicBlocks */
389 return 1;
390 }
391 return 0;
392 }
393 opline++;
394 ADVANCE_SSA_OP(ssa_op, 1);
395 }
396
397 return 1;
398 } else {
399 const zend_op *end = call_info->caller_call_opline;
400
401 /* end may be null if an opcode like EXIT is part of the argument list. */
402 if (!end || end - op_array->opcodes >= ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len) {
403 /* INIT_FCALL and DO_FCALL in different BasicBlocks */
404 return 1;
405 }
406
407 opline++;
408 ADVANCE_SSA_OP(ssa_op, 1);
409 skip = (call_level == 1);
410 while (opline != end) {
411 if (skip) {
412 switch (opline->opcode) {
413 case ZEND_SEND_VAL:
414 case ZEND_SEND_VAR:
415 case ZEND_SEND_VAL_EX:
416 case ZEND_SEND_VAR_EX:
418 case ZEND_SEND_REF:
421 skip = 0;
422 break;
423 case ZEND_SEND_ARRAY:
424 case ZEND_SEND_USER:
425 case ZEND_SEND_UNPACK:
426 return 1;
427 }
428 } else {
429 if (zend_may_throw(opline, ssa_op, op_array, ssa)) {
430 return 1;
431 }
432 }
433 opline++;
434 ADVANCE_SSA_OP(ssa_op, 1);
435 }
436
437 return 0;
438 }
439}
440
441static uint32_t skip_valid_arguments(const zend_op_array *op_array, zend_ssa *ssa, const zend_call_info *call_info)
442{
443 uint32_t num_args = 0;
444 zend_function *func = call_info->callee_func;
445
446 /* It's okay to handle prototypes here, because they can only increase the accepted arguments.
447 * Anything legal for the parent method is also legal for the parent method. */
449 zend_arg_info *arg_info = func->op_array.arg_info + num_args;
450
451 if (ZEND_TYPE_IS_SET(arg_info->type)) {
452 if (ZEND_TYPE_IS_ONLY_MASK(arg_info->type)) {
453 zend_op *opline = call_info->arg_info[num_args].opline;
454 zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[opline - op_array->opcodes] : NULL;
455 uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type);
456 if ((OP1_INFO() & (MAY_BE_ANY|MAY_BE_UNDEF)) & ~type_mask) {
457 break;
458 }
459 } else {
460 break;
461 }
462 }
463 num_args++;
464 }
465 return num_args;
466}
467
468static uint32_t zend_ssa_cv_info(const zend_op_array *op_array, zend_ssa *ssa, uint32_t var)
469{
470 uint32_t j, info;
471
472 if (ssa->vars && ssa->var_info) {
473 info = ssa->var_info[var].type;
474 for (j = op_array->last_var; j < ssa->vars_count; j++) {
475 if (ssa->vars[j].var == var) {
476 info |= ssa->var_info[j].type;
477 }
478 }
479 } else {
482 }
483
484#ifdef ZEND_JIT_USE_RC_INFERENCE
485 /* Refcount may be increased by RETURN opcode */
486 if ((info & MAY_BE_RC1) && !(info & MAY_BE_RCN)) {
487 for (j = 0; j < ssa->cfg.blocks_count; j++) {
488 if ((ssa->cfg.blocks[j].flags & ZEND_BB_REACHABLE) &&
489 ssa->cfg.blocks[j].len > 0) {
490 const zend_op *opline = op_array->opcodes + ssa->cfg.blocks[j].start + ssa->cfg.blocks[j].len - 1;
491
492 if (opline->opcode == ZEND_RETURN) {
493 if (opline->op1_type == IS_CV && opline->op1.var == EX_NUM_TO_VAR(var)) {
494 info |= MAY_BE_RCN;
495 break;
496 }
497 }
498 }
499 }
500 }
501#endif
502
503 return info;
504}
505
506static bool zend_jit_may_avoid_refcounting(const zend_op *opline, uint32_t op1_info)
507{
508 switch (opline->opcode) {
510 if (!JIT_G(current_frame) ||
511 !JIT_G(current_frame)->call->func ||
512 !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
513 return 0;
514 }
515 /* break missing intentionally */
516 case ZEND_FETCH_OBJ_R:
518 if ((op1_info & MAY_BE_OBJECT)
519 && opline->op2_type == IS_CONST
520 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
521 && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
522 return 1;
523 }
524 break;
526 if (!JIT_G(current_frame) ||
527 !JIT_G(current_frame)->call->func ||
528 !TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) {
529 return 0;
530 }
531 /* break missing intentionally */
532 case ZEND_FETCH_DIM_R:
534 return 1;
536 if (!(opline->extended_value & ZEND_ISEMPTY)) {
537 return 1;
538 }
539 break;
540 }
541 return 0;
542}
543
544static bool zend_jit_is_persistent_constant(zval *key, uint32_t flags)
545{
546 zval *zv;
547 zend_constant *c = NULL;
548
549 /* null/true/false are resolved during compilation, so don't check for them here. */
550 zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
551 if (zv) {
552 c = (zend_constant*)Z_PTR_P(zv);
554 key++;
555 zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
556 if (zv) {
557 c = (zend_constant*)Z_PTR_P(zv);
558 }
559 }
560 return c && (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
561}
562
563static zend_property_info* zend_get_known_property_info(const zend_op_array *op_array, zend_class_entry *ce, zend_string *member, bool on_this, zend_string *filename)
564{
565 zend_property_info *info = NULL;
566
567 if ((on_this && (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) ||
568 !ce ||
569 !(ce->ce_flags & ZEND_ACC_LINKED) ||
570 (ce->ce_flags & ZEND_ACC_TRAIT) ||
571 ce->create_object) {
572 return NULL;
573 }
574
575 if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
576 if (ce->info.user.filename != filename) {
577 /* class declaration might be changed independently */
578 return NULL;
579 }
580
581 if (ce->parent) {
582 zend_class_entry *parent = ce->parent;
583
584 do {
585 if (parent->type == ZEND_INTERNAL_CLASS) {
586 break;
587 } else if (parent->info.user.filename != filename) {
588 /* some of parents class declarations might be changed independently */
589 /* TODO: this check may be not enough, because even
590 * in the same it's possible to conditionally define
591 * few classes with the same name, and "parent" may
592 * change from request to request.
593 */
594 return NULL;
595 }
596 parent = parent->parent;
597 } while (parent);
598 }
599 }
600
601 // TODO: Treat property hooks more precisely.
602 info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
603 if (info == NULL ||
605 (info->flags & ZEND_ACC_STATIC) ||
606 info->hooks) {
607 return NULL;
608 }
609
610 if (info->flags & ZEND_ACC_PUBLIC) {
611 return info;
612 } else if (on_this) {
613 if (ce == info->ce) {
614 if (ce == op_array->scope) {
615 return info;
616 } else {
617 return NULL;
618 }
619 } else if ((info->flags & ZEND_ACC_PROTECTED)
620 && instanceof_function_slow(ce, info->ce)) {
621 return info;
622 }
623 }
624
625 return NULL;
626}
627
628static bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *member, bool on_this, const zend_op_array *op_array)
629{
630 zend_property_info *info;
631
632 if (!ce || (ce->ce_flags & ZEND_ACC_TRAIT) || (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
633 return 1;
634 }
635
636 if (!(ce->ce_flags & ZEND_ACC_IMMUTABLE)) {
637 if (ce->info.user.filename != op_array->filename) {
638 /* class declaration might be changed independently */
639 return 1;
640 }
641 }
642
643 // TODO: Treat property hooks more precisely.
644 info = (zend_property_info*)zend_hash_find_ptr(&ce->properties_info, member);
645 if (info == NULL ||
647 (info->flags & ZEND_ACC_STATIC) ||
648 info->hooks) {
649 return 1;
650 }
651
652 if (!(info->flags & ZEND_ACC_PUBLIC) &&
653 (!on_this || info->ce != ce)) {
654 return 1;
655 }
656
657 return 0;
658}
659
660#define OP_RANGE(ssa_op, opN) \
661 (((opline->opN##_type & (IS_TMP_VAR|IS_VAR|IS_CV)) && \
662 ssa->var_info && \
663 (ssa_op)->opN##_use >= 0 && \
664 ssa->var_info[(ssa_op)->opN##_use].has_range) ? \
665 &ssa->var_info[(ssa_op)->opN##_use].range : NULL)
666
667#define OP1_RANGE() OP_RANGE(ssa_op, op1)
668#define OP2_RANGE() OP_RANGE(ssa_op, op2)
669#define OP1_DATA_RANGE() OP_RANGE(ssa_op + 1, op1)
670
671#include "jit/zend_jit_helpers.c"
672#include "Zend/zend_cpuinfo.h"
673
674#ifdef HAVE_GCC_GLOBAL_REGS
675# define GCC_GLOBAL_REGS 1
676#else
677# define GCC_GLOBAL_REGS 0
678#endif
679
680/* By default avoid JITing inline handlers if it does not seem profitable due to lack of
681 * type information. Disabling this option allows testing some JIT handlers in the
682 * presence of try/catch blocks, which prevent SSA construction. */
683#ifndef PROFITABILITY_CHECKS
684# define PROFITABILITY_CHECKS 1
685#endif
686
687#define BP_JIT_IS 6 /* Used for ISSET_ISEMPTY_DIM_OBJ. see BP_VAR_*defines in Zend/zend_compile.h */
688
689/* The generated code may contain tautological comparisons, ignore them. */
690#if defined(__clang__)
691# pragma clang diagnostic push
692# pragma clang diagnostic ignored "-Wtautological-compare"
693# pragma clang diagnostic ignored "-Wstring-compare"
694#endif
695
696#include "jit/zend_jit_ir.c"
697
698#if defined(__clang__)
699# pragma clang diagnostic pop
700#endif
701
702#ifdef _WIN32
703# include <Windows.h>
704#else
705# include <sys/mman.h>
706# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
707# define MAP_ANONYMOUS MAP_ANON
708# endif
709#endif
710
712{
713 zval stats;
714 array_init(&stats);
715 add_assoc_bool(&stats, "enabled", JIT_G(enabled));
716 add_assoc_bool(&stats, "on", JIT_G(on));
717 add_assoc_long(&stats, "kind", JIT_G(trigger));
718 add_assoc_long(&stats, "opt_level", JIT_G(opt_level));
719 add_assoc_long(&stats, "opt_flags", JIT_G(opt_flags));
720 if (dasm_buf) {
721 add_assoc_long(&stats, "buffer_size", (char*)dasm_end - (char*)dasm_buf);
722 add_assoc_long(&stats, "buffer_free", (char*)dasm_end - (char*)*dasm_ptr);
723 } else {
724 add_assoc_long(&stats, "buffer_size", 0);
725 add_assoc_long(&stats, "buffer_free", 0);
726 }
727 add_assoc_zval(ret, "jit", &stats);
728}
729
730static bool zend_jit_inc_call_level(uint8_t opcode)
731{
732 switch (opcode) {
733 case ZEND_INIT_FCALL:
741 case ZEND_NEW:
742 return true;
743 default:
744 return false;
745 }
746}
747
748static bool zend_jit_dec_call_level(uint8_t opcode)
749{
750 switch (opcode) {
751 case ZEND_DO_FCALL:
752 case ZEND_DO_ICALL:
753 case ZEND_DO_UCALL:
756 return true;
757 default:
758 return false;
759 }
760}
761
762static zend_string *zend_jit_func_name(const zend_op_array *op_array)
763{
764 smart_str buf = {0};
765
766 if (op_array->function_name) {
767 smart_str_appends(&buf, JIT_PREFIX);
768 if (op_array->scope) {
769 smart_str_appendl(&buf, ZSTR_VAL(op_array->scope->name), ZSTR_LEN(op_array->scope->name));
770 smart_str_appends(&buf, "::");
771 }
772 smart_str_appendl(&buf, ZSTR_VAL(op_array->function_name), ZSTR_LEN(op_array->function_name));
773 if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
774 smart_str_appends(&buf, ":");
775 smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
776 smart_str_appends(&buf, ":");
777 smart_str_append_long(&buf, op_array->line_start);
778 }
779 smart_str_0(&buf);
780 return buf.s;
781 } else if (op_array->filename) {
782 smart_str_appends(&buf, JIT_PREFIX);
783 smart_str_appendl(&buf, ZSTR_VAL(op_array->filename), ZSTR_LEN(op_array->filename));
784 smart_str_0(&buf);
785 return buf.s;
786 } else {
787 return NULL;
788 }
789}
790
791static int zend_may_overflow(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa)
792{
793 int res;
794 zend_long op1_min, op1_max, op2_min, op2_max;
795
796 if (!ssa->ops || !ssa->var_info) {
797 return 1;
798 }
799 switch (opline->opcode) {
800 case ZEND_PRE_INC:
801 case ZEND_POST_INC:
802 res = ssa_op->op1_def;
803 if (res < 0
804 || !ssa->var_info[res].has_range
805 || ssa->var_info[res].range.overflow) {
806 if (!OP1_HAS_RANGE()) {
807 return 1;
808 }
809 op1_max = OP1_MAX_RANGE();
810 if (op1_max == ZEND_LONG_MAX) {
811 return 1;
812 }
813 }
814 return 0;
815 case ZEND_PRE_DEC:
816 case ZEND_POST_DEC:
817 res = ssa_op->op1_def;
818 if (res < 0
819 || !ssa->var_info[res].has_range
820 || ssa->var_info[res].range.underflow) {
821 if (!OP1_HAS_RANGE()) {
822 return 1;
823 }
824 op1_min = OP1_MIN_RANGE();
825 if (op1_min == ZEND_LONG_MIN) {
826 return 1;
827 }
828 }
829 return 0;
830 case ZEND_ADD:
831 res = ssa_op->result_def;
832 if (res < 0
833 || !ssa->var_info[res].has_range
834 || ssa->var_info[res].range.underflow) {
835 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
836 return 1;
837 }
838 op1_min = OP1_MIN_RANGE();
839 op2_min = OP2_MIN_RANGE();
840 if (zend_add_will_overflow(op1_min, op2_min)) {
841 return 1;
842 }
843 }
844 if (res < 0
845 || !ssa->var_info[res].has_range
846 || ssa->var_info[res].range.overflow) {
847 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
848 return 1;
849 }
850 op1_max = OP1_MAX_RANGE();
851 op2_max = OP2_MAX_RANGE();
852 if (zend_add_will_overflow(op1_max, op2_max)) {
853 return 1;
854 }
855 }
856 return 0;
857 case ZEND_SUB:
858 res = ssa_op->result_def;
859 if (res < 0
860 || !ssa->var_info[res].has_range
861 || ssa->var_info[res].range.underflow) {
862 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
863 return 1;
864 }
865 op1_min = OP1_MIN_RANGE();
866 op2_max = OP2_MAX_RANGE();
867 if (zend_sub_will_overflow(op1_min, op2_max)) {
868 return 1;
869 }
870 }
871 if (res < 0
872 || !ssa->var_info[res].has_range
873 || ssa->var_info[res].range.overflow) {
874 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
875 return 1;
876 }
877 op1_max = OP1_MAX_RANGE();
878 op2_min = OP2_MIN_RANGE();
879 if (zend_sub_will_overflow(op1_max, op2_min)) {
880 return 1;
881 }
882 }
883 return 0;
884 case ZEND_MUL:
885 res = ssa_op->result_def;
886 return (res < 0 ||
887 !ssa->var_info[res].has_range ||
888 ssa->var_info[res].range.underflow ||
889 ssa->var_info[res].range.overflow);
890 case ZEND_ASSIGN_OP:
891 if (opline->extended_value == ZEND_ADD) {
892 res = ssa_op->op1_def;
893 if (res < 0
894 || !ssa->var_info[res].has_range
895 || ssa->var_info[res].range.underflow) {
896 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
897 return 1;
898 }
899 op1_min = OP1_MIN_RANGE();
900 op2_min = OP2_MIN_RANGE();
901 if (zend_add_will_overflow(op1_min, op2_min)) {
902 return 1;
903 }
904 }
905 if (res < 0
906 || !ssa->var_info[res].has_range
907 || ssa->var_info[res].range.overflow) {
908 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
909 return 1;
910 }
911 op1_max = OP1_MAX_RANGE();
912 op2_max = OP2_MAX_RANGE();
913 if (zend_add_will_overflow(op1_max, op2_max)) {
914 return 1;
915 }
916 }
917 return 0;
918 } else if (opline->extended_value == ZEND_SUB) {
919 res = ssa_op->op1_def;
920 if (res < 0
921 || !ssa->var_info[res].has_range
922 || ssa->var_info[res].range.underflow) {
923 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
924 return 1;
925 }
926 op1_min = OP1_MIN_RANGE();
927 op2_max = OP2_MAX_RANGE();
928 if (zend_sub_will_overflow(op1_min, op2_max)) {
929 return 1;
930 }
931 }
932 if (res < 0
933 || !ssa->var_info[res].has_range
934 || ssa->var_info[res].range.overflow) {
935 if (!OP1_HAS_RANGE() || !OP2_HAS_RANGE()) {
936 return 1;
937 }
938 op1_max = OP1_MAX_RANGE();
939 op2_min = OP2_MIN_RANGE();
940 if (zend_sub_will_overflow(op1_max, op2_min)) {
941 return 1;
942 }
943 }
944 return 0;
945 } else if (opline->extended_value == ZEND_MUL) {
946 res = ssa_op->op1_def;
947 return (res < 0 ||
948 !ssa->var_info[res].has_range ||
949 ssa->var_info[res].range.underflow ||
950 ssa->var_info[res].range.overflow);
951 }
953 default:
954 return 1;
955 }
956}
957
958static int zend_jit_build_cfg(const zend_op_array *op_array, zend_cfg *cfg)
959{
960 uint32_t flags;
961
963
964 zend_build_cfg(&CG(arena), op_array, flags, cfg);
965
966 /* Don't JIT huge functions. Apart from likely being detrimental due to the amount of
967 * generated code, some of our analysis is recursive and will stack overflow with many
968 * blocks. */
969 if (cfg->blocks_count > 100000) {
970 return FAILURE;
971 }
972
974
975 /* Compute Dominators Tree */
977
978 /* Identify reducible and irreducible loops */
979 zend_cfg_identify_loops(op_array, cfg);
980
981 return SUCCESS;
982}
983
984static int zend_jit_op_array_analyze1(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa)
985{
986 if (zend_jit_build_cfg(op_array, &ssa->cfg) != SUCCESS) {
987 return FAILURE;
988 }
989
990#if 0
991 /* TODO: debugger and profiler supports? */
992 if ((ssa->cfg.flags & ZEND_FUNC_HAS_EXTENDED_INFO)) {
993 return FAILURE;
994 }
995#endif
996
997 /* TODO: move this to zend_cfg.c ? */
998 if (!op_array->function_name) {
1000 }
1001
1002 if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
1003 && ssa->cfg.blocks
1004 && op_array->last_try_catch == 0
1005 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
1007 if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) {
1008 return FAILURE;
1009 }
1010
1011 zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa);
1012
1013 zend_ssa_find_false_dependencies(op_array, ssa);
1014
1015 zend_ssa_find_sccs(op_array, ssa);
1016 }
1017
1018 return SUCCESS;
1019}
1020
1021static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa, uint32_t optimization_level)
1022{
1023 if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC)
1024 && ssa->cfg.blocks
1025 && op_array->last_try_catch == 0
1026 && !(op_array->fn_flags & ZEND_ACC_GENERATOR)
1028 if (zend_ssa_inference(&CG(arena), op_array, script, ssa,
1029 optimization_level & ~ZEND_OPTIMIZER_NARROW_TO_DOUBLE) != SUCCESS) {
1030 return FAILURE;
1031 }
1032 }
1033
1034 return SUCCESS;
1035}
1036
1037static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array *op_array, zend_ssa *ssa)
1038{
1039 void *checkpoint;
1040 int candidates_count, i;
1041 zend_jit_reg_var *ra;
1042
1043 checkpoint = zend_arena_checkpoint(CG(arena));
1044 ra = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_reg_var));
1045 candidates_count = 0;
1046 for (i = 0; i < ssa->vars_count; i++) {
1047 if (zend_jit_may_be_in_reg(op_array, ssa, i)) {
1048 ra[i].ref = IR_NULL;
1049 candidates_count++;
1050 }
1051 }
1052 if (!candidates_count) {
1053 zend_arena_release(&CG(arena), checkpoint);
1054 return;
1055 }
1056
1057 if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) {
1058 /* Naive SSA resolution */
1059 for (i = 0; i < ssa->vars_count; i++) {
1060 if (ssa->vars[i].definition_phi && !ssa->vars[i].no_val) {
1061 zend_ssa_phi *phi = ssa->vars[i].definition_phi;
1062 int k, src;
1063
1064 if (phi->pi >= 0) {
1065 src = phi->sources[0];
1066 if (ra[i].ref) {
1067 if (!ra[src].ref) {
1068 ra[i].flags |= ZREG_LOAD;
1069 } else {
1070 ra[i].flags |= ZREG_PI;
1071 }
1072 } else if (ra[src].ref) {
1073 ra[src].flags |= ZREG_STORE;
1074 }
1075 } else {
1076 int need_move = 0;
1077
1078 for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
1079 src = phi->sources[k];
1080 if (src >= 0) {
1081 if (ssa->vars[src].definition_phi
1082 && ssa->vars[src].definition_phi->pi >= 0
1083 && phi->block == ssa->vars[src].definition_phi->block) {
1084 /* Skip zero-length interval for Pi variable */
1085 src = ssa->vars[src].definition_phi->sources[0];
1086 }
1087 if (ra[i].ref) {
1088 if (!ra[src].ref) {
1089 need_move = 1;
1090 }
1091 } else if (ra[src].ref) {
1092 need_move = 1;
1093 }
1094 }
1095 }
1096 if (need_move) {
1097 if (ra[i].ref) {
1098 ra[i].flags |= ZREG_LOAD;
1099 }
1100 for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) {
1101 src = phi->sources[k];
1102 if (src >= 0) {
1103 if (ssa->vars[src].definition_phi
1104 && ssa->vars[src].definition_phi->pi >= 0
1105 && phi->block == ssa->vars[src].definition_phi->block) {
1106 /* Skip zero-length interval for Pi variable */
1107 src = ssa->vars[src].definition_phi->sources[0];
1108 }
1109 if (ra[src].ref) {
1110 ra[src].flags |= ZREG_STORE;
1111 }
1112 }
1113 }
1114 } else {
1115 ra[i].flags |= ZREG_PHI;
1116 }
1117 }
1118 }
1119 }
1120
1121 /* Remove useless register allocation */
1122 for (i = 0; i < ssa->vars_count; i++) {
1123 if (ra[i].ref &&
1124 ((ra[i].flags & ZREG_LOAD) ||
1125 ((ra[i].flags & ZREG_STORE) && ssa->vars[i].definition >= 0)) &&
1126 ssa->vars[i].use_chain < 0) {
1127 bool may_remove = 1;
1128 zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1129
1130 while (phi) {
1131 if (ra[phi->ssa_var].ref &&
1132 !(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1133 may_remove = 0;
1134 break;
1135 }
1136 phi = zend_ssa_next_use_phi(ssa, i, phi);
1137 }
1138 if (may_remove) {
1139 ra[i].ref = IR_UNUSED;
1140 }
1141 }
1142 }
1143
1144 /* Remove intervals used once */
1145 for (i = 0; i < ssa->vars_count; i++) {
1146 if (ra[i].ref) {
1147 if (!(ra[i].flags & (ZREG_LOAD|ZREG_STORE))) {
1148 uint32_t var_num = ssa->vars[i].var;
1149 uint32_t op_num = ssa->vars[i].definition;
1150
1151 /* Check if a tempoary variable may be freed by exception handler */
1152 if (op_array->last_live_range
1153 && var_num >= op_array->last_var
1154 && ssa->vars[i].definition >= 0
1155 && ssa->ops[op_num].result_def == i) {
1156 const zend_live_range *range = op_array->live_range;
1157 int j;
1158
1159 op_num++;
1160 if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1161 op_num++;
1162 }
1163 for (j = 0; j < op_array->last_live_range; range++, j++) {
1164 if (range->start > op_num) {
1165 /* further blocks will not be relevant... */
1166 break;
1167 } else if (op_num < range->end && var_num == (range->var & ~ZEND_LIVE_MASK)) {
1168 /* check if opcodes in range may throw */
1169 do {
1170 if (zend_may_throw(op_array->opcodes + op_num, ssa->ops + op_num, op_array, ssa)) {
1171 ra[i].flags |= ZREG_STORE;
1172 break;
1173 }
1174 op_num++;
1175 if (op_array->opcodes[op_num].opcode == ZEND_OP_DATA) {
1176 op_num++;
1177 }
1178 } while (op_num < range->end);
1179 break;
1180 }
1181 }
1182 }
1183 }
1184 if ((ra[i].flags & ZREG_LOAD)
1185 && (ra[i].flags & ZREG_STORE)
1186 && (ssa->vars[i].use_chain < 0
1187 || zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) {
1188 bool may_remove = 1;
1189 zend_ssa_phi *phi = ssa->vars[i].phi_use_chain;
1190
1191 while (phi) {
1192 if (ra[phi->ssa_var].ref &&
1193 !(ra[phi->ssa_var].flags & ZREG_LOAD)) {
1194 may_remove = 0;
1195 break;
1196 }
1197 phi = zend_ssa_next_use_phi(ssa, i, phi);
1198 }
1199 if (may_remove) {
1200 ra[i].ref = IR_UNUSED;
1201 }
1202 }
1203 }
1204 }
1205 }
1206
1208 fprintf(stderr, "Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]");
1209 for (i = 0; i < ssa->vars_count; i++) {
1210 if (ra[i].ref) {
1211 fprintf(stderr, "#%d.", i);
1212 uint32_t var_num = ssa->vars[i].var;
1213 zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num);
1214 if (ra[i].flags & ZREG_LOAD) {
1215 fprintf(stderr, " load");
1216 }
1217 if (ra[i].flags & ZREG_STORE) {
1218 fprintf(stderr, " store");
1219 }
1220 fprintf(stderr, "\n");
1221 }
1222 }
1223 fprintf(stderr, "\n");
1224 }
1225
1226 ctx->ra = ra;
1227}
1228
1229static int zend_jit_compute_post_order(zend_cfg *cfg, int start, int *post_order)
1230{
1231 int count = 0;
1232 int b, n, *p;
1233 zend_basic_block *bb;
1234 zend_worklist worklist;
1235 ALLOCA_FLAG(use_heap)
1236
1237 ZEND_WORKLIST_ALLOCA(&worklist, cfg->blocks_count, use_heap);
1238 zend_worklist_push(&worklist, start);
1239
1240 while (zend_worklist_len(&worklist) != 0) {
1241next:
1242 b = zend_worklist_peek(&worklist);
1243 bb = &cfg->blocks[b];
1244 n = bb->successors_count;
1245 if (n > 0) {
1246 p = bb->successors;
1247 do {
1249 /* skip */
1250 } else if (zend_worklist_push(&worklist, *p)) {
1251 goto next;
1252 }
1253 p++;
1254 n--;
1255 } while (n > 0);
1256 }
1257 zend_worklist_pop(&worklist);
1258 post_order[count++] = b;
1259 }
1260 ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap);
1261 return count;
1262}
1263
1264static bool zend_jit_next_is_send_result(const zend_op *opline)
1265{
1266 if (opline->result_type == IS_TMP_VAR
1267 && (opline+1)->opcode == ZEND_SEND_VAL
1268 && (opline+1)->op1_type == IS_TMP_VAR
1269 && (opline+1)->op2_type != IS_CONST
1270 && (opline+1)->op1.var == opline->result.var) {
1271 return 1;
1272 }
1273 return 0;
1274}
1275
1276static bool zend_jit_supported_binary_op(uint8_t op, uint32_t op1_info, uint32_t op2_info)
1277{
1278 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1279 return false;
1280 }
1281 switch (op) {
1282 case ZEND_POW:
1283 case ZEND_DIV:
1284 // TODO: check for division by zero ???
1285 return false;
1286 case ZEND_ADD:
1287 case ZEND_SUB:
1288 case ZEND_MUL:
1289 return (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))
1290 && (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE));
1291 case ZEND_BW_OR:
1292 case ZEND_BW_AND:
1293 case ZEND_BW_XOR:
1294 case ZEND_SL:
1295 case ZEND_SR:
1296 case ZEND_MOD:
1297 return (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG);
1298 case ZEND_CONCAT:
1299 return (op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING);
1301 }
1302}
1303
1304static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *rt_opline)
1305{
1306 int b, i, end;
1307 zend_op *opline;
1308 zend_jit_ctx ctx;
1309 zend_jit_ctx *jit = &ctx;
1310 zend_jit_reg_var *ra = NULL;
1311 void *handler;
1312 int call_level = 0;
1313 void *checkpoint = NULL;
1314 bool recv_emitted = 0; /* emitted at least one RECV opcode */
1315 uint8_t smart_branch_opcode;
1316 uint32_t target_label, target_label2;
1317 uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_mem_info;
1318 zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
1319 zend_class_entry *ce = NULL;
1320 bool ce_is_instanceof;
1321 bool on_this;
1322
1323 ZEND_ASSERT(!(op_array->fn_flags & ZEND_ACC_CLOSURE) || !(op_array->scope));
1324
1325 if (JIT_G(bisect_limit)) {
1326 jit_bisect_pos++;
1327 if (jit_bisect_pos >= JIT_G(bisect_limit)) {
1328 if (jit_bisect_pos == JIT_G(bisect_limit)) {
1329 fprintf(stderr, "Not JITing %s%s%s in %s:%d and after due to jit_bisect_limit\n",
1330 op_array->scope ? ZSTR_VAL(op_array->scope->name) : "",
1331 op_array->scope ? "::" : "",
1332 op_array->function_name ? ZSTR_VAL(op_array->function_name) : "{main}",
1333 ZSTR_VAL(op_array->filename), op_array->line_start);
1334 }
1335 return FAILURE;
1336 }
1337 }
1338
1339 if (ssa->cfg.flags & ZEND_FUNC_IRREDUCIBLE) {
1340 /* We can't order blocks properly */
1341 return FAILURE;
1342 }
1343
1344 if (rt_opline) {
1345 /* Set BB_ENTRY flag to limit register usage across the OSR ENTRY point */
1346 ssa->cfg.blocks[ssa->cfg.map[rt_opline - op_array->opcodes]].flags |= ZEND_BB_ENTRY;
1347 }
1348
1349 zend_jit_start(&ctx, op_array, ssa);
1351 checkpoint = zend_arena_checkpoint(CG(arena));
1352 zend_jit_allocate_registers(&ctx, op_array, ssa);
1353 ra = ctx.ra;
1354 }
1355
1356 /* Process blocks in Reverse Post Order */
1357 int *sorted_blocks = alloca(sizeof(int) * ssa->cfg.blocks_count);
1358 int n = zend_jit_compute_post_order(&ssa->cfg, 0, sorted_blocks);
1359
1360 while (n > 0) {
1361 b = sorted_blocks[--n];
1362 if ((ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE) == 0) {
1363 continue;
1364 }
1365
1367 opline = op_array->opcodes + ssa->cfg.blocks[b].start;
1368 if (ssa->cfg.flags & ZEND_CFG_RECV_ENTRY) {
1369 if (opline->opcode == ZEND_RECV_INIT) {
1370 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1371 if (opline != op_array->opcodes && (opline-1)->opcode != ZEND_RECV_INIT) {
1372 zend_jit_recv_entry(&ctx, b);
1373 }
1374 } else {
1375 if (opline != op_array->opcodes && recv_emitted) {
1376 zend_jit_recv_entry(&ctx, b);
1377 }
1378 }
1379 recv_emitted = 1;
1380 } else if (opline->opcode == ZEND_RECV) {
1381 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
1382 /* skip */
1383 zend_jit_bb_start(&ctx, b);
1384 zend_jit_bb_end(&ctx, b);
1385 continue;
1386 } else if (recv_emitted) {
1387 zend_jit_recv_entry(&ctx, b);
1388 } else {
1389 recv_emitted = 1;
1390 }
1391 } else {
1392 if (recv_emitted) {
1393 zend_jit_recv_entry(&ctx, b);
1394 } else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
1395 ssa->cfg.blocks[b].len == 1 &&
1396 (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
1397 /* don't generate code for BB with single opcode */
1398 zend_jit_free_ctx(&ctx);
1399
1401 zend_arena_release(&CG(arena), checkpoint);
1402 }
1403 return SUCCESS;
1404 }
1405 }
1406 } else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE &&
1407 ssa->cfg.blocks[b].len == 1 &&
1408 (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) {
1409 /* don't generate code for BB with single opcode */
1410 zend_jit_free_ctx(&ctx);
1411
1413 zend_arena_release(&CG(arena), checkpoint);
1414 }
1415 return SUCCESS;
1416 }
1417 }
1418
1419 zend_jit_bb_start(&ctx, b);
1420
1421 if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ctx.ra) {
1422 zend_ssa_phi *phi = ssa->blocks[b].phis;
1423
1424 /* First try to insert IR Phi */
1425 while (phi) {
1426 zend_jit_reg_var *ival = &ctx.ra[phi->ssa_var];
1427
1428 if (ival->ref) {
1429 if (ival->flags & ZREG_PI) {
1430 zend_jit_gen_pi(jit, phi);
1431 } else if (ival->flags & ZREG_PHI) {
1432 zend_jit_gen_phi(jit, phi);
1433 }
1434 }
1435 phi = phi->next;
1436 }
1437 }
1438
1439 if (rt_opline
1440 && (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) == 0
1441 && rt_opline == op_array->opcodes + ssa->cfg.blocks[b].start) {
1442 zend_jit_osr_entry(&ctx, b); /* OSR (On-Stack-Replacement) Entry-Point */
1443 }
1444
1445 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
1446 if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW)
1447 && ssa->cfg.blocks[b].start != 0
1448 && (op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_NOP
1449 || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG
1450 || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING
1451 || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) {
1452 zend_jit_reset_last_valid_opline(&ctx);
1453 } else {
1454 zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
1455 }
1456 } else if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) {
1457 zend_jit_reset_last_valid_opline(&ctx);
1458 } else if (ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY) {
1459 zend_jit_reset_last_valid_opline(&ctx);
1460 } else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY)) {
1461 zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
1462 }
1463 if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) {
1464 zend_jit_check_timeout(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start, NULL);
1465 }
1466 if (!ssa->cfg.blocks[b].len) {
1467 zend_jit_bb_end(&ctx, b);
1468 continue;
1469 }
1470 if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ra) {
1471 zend_ssa_phi *phi = ssa->blocks[b].phis;
1472
1473 while (phi) {
1474 zend_jit_reg_var *ival = &ra[phi->ssa_var];
1475
1476 if (ival->ref) {
1477 if (ival->flags & ZREG_LOAD) {
1478 ZEND_ASSERT(ival->ref == IR_NULL);
1479
1480 if (!zend_jit_load_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var)) {
1481 goto jit_failure;
1482 }
1483 } else if (ival->flags & ZREG_STORE) {
1484 ZEND_ASSERT(ival->ref != IR_NULL);
1485
1486 if (!zend_jit_store_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, phi->ssa_var, 1)) {
1487 goto jit_failure;
1488 }
1489 }
1490 }
1491 phi = phi->next;
1492 }
1493 }
1494 end = ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1;
1495 for (i = ssa->cfg.blocks[b].start; i <= end; i++) {
1496 zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[i] : NULL;
1497 opline = op_array->opcodes + i;
1498 if (zend_jit_inc_call_level(opline->opcode)) {
1499 call_level++;
1500 }
1501
1502 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_INLINE) {
1503 switch (opline->opcode) {
1504 case ZEND_PRE_INC:
1505 case ZEND_PRE_DEC:
1506 case ZEND_POST_INC:
1507 case ZEND_POST_DEC:
1508 if (opline->op1_type != IS_CV) {
1509 break;
1510 }
1511 op1_info = OP1_INFO();
1512 if (!(op1_info & MAY_BE_LONG)) {
1513 break;
1514 }
1515 if (opline->result_type != IS_UNUSED) {
1516 res_use_info = -1;
1517
1518 if (opline->result_type == IS_CV
1519 && ssa->vars
1520 && ssa_op->result_use >= 0
1521 && !ssa->vars[ssa_op->result_use].no_val) {
1522 zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1523
1524 if (Z_MODE(res_use_addr) != IS_REG
1525 || Z_LOAD(res_use_addr)
1526 || Z_STORE(res_use_addr)) {
1527 res_use_info = RES_USE_INFO();
1528 }
1529 }
1530 res_info = RES_INFO();
1531 res_addr = RES_REG_ADDR();
1532 } else {
1533 res_use_info = -1;
1534 res_info = -1;
1535 res_addr = 0;
1536 }
1537 op1_def_info = OP1_DEF_INFO();
1538 if (!zend_jit_inc_dec(&ctx, opline,
1539 op1_info, OP1_REG_ADDR(),
1540 op1_def_info, OP1_DEF_REG_ADDR(),
1541 res_use_info, res_info,
1542 res_addr,
1543 (op1_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1544 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1545 goto jit_failure;
1546 }
1547 goto done;
1548 case ZEND_BW_OR:
1549 case ZEND_BW_AND:
1550 case ZEND_BW_XOR:
1551 case ZEND_SL:
1552 case ZEND_SR:
1553 case ZEND_MOD:
1554 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1555 break;
1556 }
1557 op1_info = OP1_INFO();
1558 op2_info = OP2_INFO();
1559 if (!(op1_info & MAY_BE_LONG)
1560 || !(op2_info & MAY_BE_LONG)) {
1561 break;
1562 }
1563 res_addr = RES_REG_ADDR();
1564 if (Z_MODE(res_addr) != IS_REG
1565 && (i + 1) <= end
1566 && zend_jit_next_is_send_result(opline)) {
1567 i++;
1568 res_use_info = -1;
1569 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1570 if (!zend_jit_reuse_ip(&ctx)) {
1571 goto jit_failure;
1572 }
1573 } else {
1574 res_use_info = -1;
1575
1576 if (opline->result_type == IS_CV
1577 && ssa->vars
1578 && ssa_op->result_use >= 0
1579 && !ssa->vars[ssa_op->result_use].no_val) {
1580 zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1581
1582 if (Z_MODE(res_use_addr) != IS_REG
1583 || Z_LOAD(res_use_addr)
1584 || Z_STORE(res_use_addr)) {
1585 res_use_info = RES_USE_INFO();
1586 }
1587 }
1588 }
1589 if (!zend_jit_long_math(&ctx, opline,
1590 op1_info, OP1_RANGE(), OP1_REG_ADDR(),
1591 op2_info, OP2_RANGE(), OP2_REG_ADDR(),
1592 res_use_info, RES_INFO(), res_addr,
1593 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1594 goto jit_failure;
1595 }
1596 goto done;
1597 case ZEND_ADD:
1598 case ZEND_SUB:
1599 case ZEND_MUL:
1600// case ZEND_DIV: // TODO: check for division by zero ???
1601 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1602 break;
1603 }
1604 op1_info = OP1_INFO();
1605 op2_info = OP2_INFO();
1606 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1607 break;
1608 }
1609 if (opline->opcode == ZEND_ADD &&
1610 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
1611 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1612 /* pass */
1613 } else if (!(op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) ||
1614 !(op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) {
1615 break;
1616 }
1617 res_addr = RES_REG_ADDR();
1618 if (Z_MODE(res_addr) != IS_REG
1619 && (i + 1) <= end
1620 && zend_jit_next_is_send_result(opline)) {
1621 i++;
1622 res_use_info = -1;
1623 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1624 if (!zend_jit_reuse_ip(&ctx)) {
1625 goto jit_failure;
1626 }
1627 } else {
1628 res_use_info = -1;
1629
1630 if (opline->result_type == IS_CV
1631 && ssa->vars
1632 && ssa_op->result_use >= 0
1633 && !ssa->vars[ssa_op->result_use].no_val) {
1634 zend_jit_addr res_use_addr = RES_USE_REG_ADDR();
1635
1636 if (Z_MODE(res_use_addr) != IS_REG
1637 || Z_LOAD(res_use_addr)
1638 || Z_STORE(res_use_addr)) {
1639 res_use_info = RES_USE_INFO();
1640 }
1641 }
1642 }
1643 res_info = RES_INFO();
1644 if (opline->opcode == ZEND_ADD &&
1645 (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY &&
1646 (op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) {
1647 if (!zend_jit_add_arrays(&ctx, opline, op1_info, OP1_REG_ADDR(), op2_info, OP2_REG_ADDR(), res_addr)) {
1648 goto jit_failure;
1649 }
1650 } else {
1651 if (!zend_jit_math(&ctx, opline,
1652 op1_info, OP1_REG_ADDR(),
1653 op2_info, OP2_REG_ADDR(),
1654 res_use_info, res_info, res_addr,
1655 (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1656 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1657 goto jit_failure;
1658 }
1659 }
1660 goto done;
1661 case ZEND_CONCAT:
1662 case ZEND_FAST_CONCAT:
1663 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1664 break;
1665 }
1666 op1_info = OP1_INFO();
1667 op2_info = OP2_INFO();
1668 if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) {
1669 break;
1670 }
1671 if (!(op1_info & MAY_BE_STRING) ||
1672 !(op2_info & MAY_BE_STRING)) {
1673 break;
1674 }
1675 res_addr = RES_REG_ADDR();
1676 if ((i + 1) <= end
1677 && zend_jit_next_is_send_result(opline)) {
1678 i++;
1679 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1680 if (!zend_jit_reuse_ip(&ctx)) {
1681 goto jit_failure;
1682 }
1683 }
1684 if (!zend_jit_concat(&ctx, opline,
1685 op1_info, op2_info, res_addr,
1686 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1687 goto jit_failure;
1688 }
1689 goto done;
1690 case ZEND_ASSIGN_OP:
1691 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1692 break;
1693 }
1694 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1695 break;
1696 }
1697 op1_info = OP1_INFO();
1698 op2_info = OP2_INFO();
1699 if (!zend_jit_supported_binary_op(
1700 opline->extended_value, op1_info, op2_info)) {
1701 break;
1702 }
1703 op1_addr = OP1_REG_ADDR();
1704 op1_mem_info = -1;
1705 if (Z_MODE(op1_addr) != IS_REG
1706 || Z_LOAD(op1_addr)
1707 || Z_STORE(op1_addr)) {
1708 op1_mem_info = op1_info;
1709 }
1710 op1_def_info = OP1_DEF_INFO();
1711 if (!zend_jit_assign_op(&ctx, opline,
1712 op1_info, op1_addr, OP1_RANGE(),
1713 op1_def_info, OP1_DEF_REG_ADDR(), op1_mem_info,
1714 op2_info, OP2_REG_ADDR(), OP2_RANGE(),
1715 (op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (op1_def_info & MAY_BE_DOUBLE) && zend_may_overflow(opline, ssa_op, op_array, ssa),
1716 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1717 goto jit_failure;
1718 }
1719 goto done;
1720 case ZEND_ASSIGN_DIM_OP:
1721 if (opline->op1_type != IS_CV || opline->result_type != IS_UNUSED) {
1722 break;
1723 }
1724 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1725 break;
1726 }
1727 if (!zend_jit_supported_binary_op(
1729 break;
1730 }
1731 if (!zend_jit_assign_dim_op(&ctx, opline,
1733 OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
1734 (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
1735 OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(), IS_UNKNOWN,
1736 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1737 goto jit_failure;
1738 }
1739 goto done;
1740 case ZEND_ASSIGN_DIM:
1741 if (opline->op1_type != IS_CV) {
1742 break;
1743 }
1744 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1745 break;
1746 }
1747 if (!zend_jit_assign_dim(&ctx, opline,
1749 OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
1750 (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : NULL,
1752 (ctx.ra && (ssa_op+1)->op1_def >= 0) ? OP1_DATA_DEF_REG_ADDR() : 0,
1753 (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
1754 IS_UNKNOWN,
1755 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1756 goto jit_failure;
1757 }
1758 goto done;
1759 case ZEND_PRE_INC_OBJ:
1760 case ZEND_PRE_DEC_OBJ:
1761 case ZEND_POST_INC_OBJ:
1762 case ZEND_POST_DEC_OBJ:
1763 if (opline->op2_type != IS_CONST
1764 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1765 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1766 break;
1767 }
1768 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1769 break;
1770 }
1771 ce = NULL;
1772 ce_is_instanceof = 0;
1773 on_this = 0;
1774 if (opline->op1_type == IS_UNUSED) {
1776 ce = op_array->scope;
1777 /* scope is NULL for closures. */
1778 if (ce) {
1779 ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
1780 }
1781 op1_addr = 0;
1782 on_this = 1;
1783 } else {
1784 op1_info = OP1_INFO();
1785 if (!(op1_info & MAY_BE_OBJECT)) {
1786 break;
1787 }
1788 op1_addr = OP1_REG_ADDR();
1789 if (ssa->var_info && ssa->ops) {
1790 zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1791 if (ssa_op->op1_use >= 0) {
1792 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1793 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1794 ce = op1_ssa->ce;
1795 ce_is_instanceof = op1_ssa->is_instanceof;
1796 }
1797 }
1798 }
1799 }
1800 if (!zend_jit_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
1801 op1_info, op1_addr,
1802 0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
1803 goto jit_failure;
1804 }
1805 goto done;
1806 case ZEND_ASSIGN_OBJ_OP:
1807 if (opline->result_type != IS_UNUSED) {
1808 break;
1809 }
1810 if (opline->op2_type != IS_CONST
1811 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1812 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1813 break;
1814 }
1815 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1816 break;
1817 }
1818 if (!zend_jit_supported_binary_op(
1820 break;
1821 }
1822 ce = NULL;
1823 ce_is_instanceof = 0;
1824 on_this = 0;
1825 if (opline->op1_type == IS_UNUSED) {
1827 ce = op_array->scope;
1828 /* scope is NULL for closures. */
1829 if (ce) {
1830 ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
1831 }
1832 op1_addr = 0;
1833 on_this = 1;
1834 } else {
1835 op1_info = OP1_INFO();
1836 if (!(op1_info & MAY_BE_OBJECT)) {
1837 break;
1838 }
1839 op1_addr = OP1_REG_ADDR();
1840 if (ssa->var_info && ssa->ops) {
1841 zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1842 if (ssa_op->op1_use >= 0) {
1843 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1844 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1845 ce = op1_ssa->ce;
1846 ce_is_instanceof = op1_ssa->is_instanceof;
1847 }
1848 }
1849 }
1850 }
1851 if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
1852 op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
1853 0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
1854 goto jit_failure;
1855 }
1856 goto done;
1857 case ZEND_ASSIGN_OBJ:
1858 if (opline->op2_type != IS_CONST
1859 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1860 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
1861 break;
1862 }
1863 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1864 break;
1865 }
1866 ce = NULL;
1867 ce_is_instanceof = 0;
1868 on_this = 0;
1869 if (opline->op1_type == IS_UNUSED) {
1871 ce = op_array->scope;
1872 /* scope is NULL for closures. */
1873 if (ce) {
1874 ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
1875 }
1876 op1_addr = 0;
1877 on_this = 1;
1878 } else {
1879 op1_info = OP1_INFO();
1880 if (!(op1_info & MAY_BE_OBJECT)) {
1881 break;
1882 }
1883 op1_addr = OP1_REG_ADDR();
1884 if (ssa->var_info && ssa->ops) {
1885 zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
1886 if (ssa_op->op1_use >= 0) {
1887 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
1888 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
1889 ce = op1_ssa->ce;
1890 ce_is_instanceof = op1_ssa->is_instanceof;
1891 }
1892 }
1893 }
1894 }
1895 if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
1896 op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
1897 (opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
1898 0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN,
1899 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1900 goto jit_failure;
1901 }
1902 goto done;
1903 case ZEND_ASSIGN:
1904 if (opline->op1_type != IS_CV) {
1905 break;
1906 }
1907 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
1908 break;
1909 }
1910 op2_addr = OP2_REG_ADDR();
1911 if (ra
1912 && ssa->ops[opline - op_array->opcodes].op2_def >= 0
1913 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op2_def].no_val) {
1914 op2_def_addr = OP2_DEF_REG_ADDR();
1915 } else {
1916 op2_def_addr = op2_addr;
1917 }
1918 op1_info = OP1_INFO();
1919 if (ra && ssa->vars[ssa_op->op1_use].no_val) {
1920 op1_info |= MAY_BE_UNDEF; // requres type assignment
1921 }
1922 if (opline->result_type == IS_UNUSED) {
1923 res_addr = 0;
1924 res_info = -1;
1925 } else {
1926 res_addr = RES_REG_ADDR();
1927 res_info = RES_INFO();
1928 if (Z_MODE(res_addr) != IS_REG
1929 && (i + 1) <= end
1930 && zend_jit_next_is_send_result(opline)
1931 && (!(op1_info & MAY_HAVE_DTOR) || !(op1_info & MAY_BE_RC1))) {
1932 i++;
1933 res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var);
1934 if (!zend_jit_reuse_ip(&ctx)) {
1935 goto jit_failure;
1936 }
1937 }
1938 }
1939 if (!zend_jit_assign(&ctx, opline,
1940 op1_info, OP1_REG_ADDR(),
1942 OP2_INFO(), op2_addr, op2_def_addr,
1943 res_info, res_addr,
1944 0,
1945 zend_may_throw(opline, ssa_op, op_array, ssa))) {
1946 goto jit_failure;
1947 }
1948 goto done;
1949 case ZEND_QM_ASSIGN:
1950 op1_addr = OP1_REG_ADDR();
1951 if (ra
1952 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
1953 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
1954 op1_def_addr = OP1_DEF_REG_ADDR();
1955 } else {
1956 op1_def_addr = op1_addr;
1957 }
1958 if (!zend_jit_qm_assign(&ctx, opline,
1959 OP1_INFO(), op1_addr, op1_def_addr,
1960 -1, RES_INFO(), RES_REG_ADDR())) {
1961 goto jit_failure;
1962 }
1963 goto done;
1964 case ZEND_INIT_FCALL:
1967 if (!zend_jit_init_fcall(&ctx, opline, b, op_array, ssa, ssa_op, call_level, NULL, 0)) {
1968 goto jit_failure;
1969 }
1970 goto done;
1971 case ZEND_SEND_VAL:
1972 case ZEND_SEND_VAL_EX:
1973 if (opline->op2_type == IS_CONST) {
1974 /* Named parameters not supported in JIT (yet) */
1975 break;
1976 }
1977 if (opline->opcode == ZEND_SEND_VAL_EX
1978 && opline->op2.num > MAX_ARG_FLAG_NUM) {
1979 break;
1980 }
1981 if (!zend_jit_send_val(&ctx, opline,
1982 OP1_INFO(), OP1_REG_ADDR())) {
1983 goto jit_failure;
1984 }
1985 goto done;
1986 case ZEND_SEND_REF:
1987 if (opline->op2_type == IS_CONST) {
1988 /* Named parameters not supported in JIT (yet) */
1989 break;
1990 }
1991 if (!zend_jit_send_ref(&ctx, opline, op_array,
1992 OP1_INFO(), 0)) {
1993 goto jit_failure;
1994 }
1995 goto done;
1996 case ZEND_SEND_VAR:
1997 case ZEND_SEND_VAR_EX:
2000 case ZEND_SEND_FUNC_ARG:
2001 if (opline->op2_type == IS_CONST) {
2002 /* Named parameters not supported in JIT (yet) */
2003 break;
2004 }
2005 if ((opline->opcode == ZEND_SEND_VAR_EX
2006 || opline->opcode == ZEND_SEND_VAR_NO_REF_EX)
2007 && opline->op2.num > MAX_ARG_FLAG_NUM) {
2008 break;
2009 }
2010 op1_addr = OP1_REG_ADDR();
2011 if (ra
2012 && ssa->ops[opline - op_array->opcodes].op1_def >= 0
2013 && !ssa->vars[ssa->ops[opline - op_array->opcodes].op1_def].no_val) {
2014 op1_def_addr = OP1_DEF_REG_ADDR();
2015 } else {
2016 op1_def_addr = op1_addr;
2017 }
2018 if (!zend_jit_send_var(&ctx, opline, op_array,
2019 OP1_INFO(), op1_addr, op1_def_addr)) {
2020 goto jit_failure;
2021 }
2022 goto done;
2024 if (opline->op2_type == IS_CONST) {
2025 /* Named parameters not supported in JIT (yet) */
2026 break;
2027 }
2028 if (opline->op2.num > MAX_ARG_FLAG_NUM) {
2029 break;
2030 }
2031 if (!zend_jit_check_func_arg(&ctx, opline)) {
2032 goto jit_failure;
2033 }
2034 goto done;
2036 if (!zend_jit_check_undef_args(&ctx, opline)) {
2037 goto jit_failure;
2038 }
2039 goto done;
2040 case ZEND_DO_UCALL:
2042 case ZEND_DO_ICALL:
2044 case ZEND_DO_FCALL:
2045 if (!zend_jit_do_fcall(&ctx, opline, op_array, ssa, call_level, b + 1, NULL)) {
2046 goto jit_failure;
2047 }
2048 goto done;
2049 case ZEND_IS_EQUAL:
2050 case ZEND_IS_NOT_EQUAL:
2051 case ZEND_IS_SMALLER:
2053 case ZEND_CASE: {
2054 res_addr = RES_REG_ADDR();
2055 if ((opline->result_type & IS_TMP_VAR)
2056 && (i + 1) <= end
2057 && ((opline+1)->opcode == ZEND_JMPZ
2058 || (opline+1)->opcode == ZEND_JMPNZ
2059 || (opline+1)->opcode == ZEND_JMPZ_EX
2060 || (opline+1)->opcode == ZEND_JMPNZ_EX)
2061 && (opline+1)->op1_type == IS_TMP_VAR
2062 && (opline+1)->op1.var == opline->result.var) {
2063 i++;
2064 smart_branch_opcode = (opline+1)->opcode;
2065 target_label = ssa->cfg.blocks[b].successors[0];
2066 target_label2 = ssa->cfg.blocks[b].successors[1];
2067 /* For EX variant write into the result of EX opcode. */
2068 if ((opline+1)->opcode == ZEND_JMPZ_EX
2069 || (opline+1)->opcode == ZEND_JMPNZ_EX) {
2070 res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def);
2071 }
2072 } else {
2073 smart_branch_opcode = 0;
2074 target_label = target_label2 = (uint32_t)-1;
2075 }
2076 if (!zend_jit_cmp(&ctx, opline,
2077 OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2078 OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
2079 res_addr,
2080 zend_may_throw(opline, ssa_op, op_array, ssa),
2081 smart_branch_opcode, target_label, target_label2,
2082 NULL, 0)) {
2083 goto jit_failure;
2084 }
2085 goto done;
2086 }
2087 case ZEND_IS_IDENTICAL:
2089 case ZEND_CASE_STRICT:
2090 res_addr = RES_REG_ADDR();
2091 if ((opline->result_type & IS_TMP_VAR)
2092 && (i + 1) <= end
2093 && ((opline+1)->opcode == ZEND_JMPZ
2094 || (opline+1)->opcode == ZEND_JMPZ_EX
2095 || (opline+1)->opcode == ZEND_JMPNZ_EX
2096 || (opline+1)->opcode == ZEND_JMPNZ)
2097 && (opline+1)->op1_type == IS_TMP_VAR
2098 && (opline+1)->op1.var == opline->result.var) {
2099 i++;
2100 smart_branch_opcode = (opline+1)->opcode;
2101 target_label = ssa->cfg.blocks[b].successors[0];
2102 target_label2 = ssa->cfg.blocks[b].successors[1];
2103 /* For EX variant write into the result of EX opcode. */
2104 if ((opline+1)->opcode == ZEND_JMPZ_EX
2105 || (opline+1)->opcode == ZEND_JMPNZ_EX) {
2106 res_addr = OP_REG_ADDR(opline + 1, ssa_op + 1, result_type, result, result_def);
2107 }
2108 } else {
2109 smart_branch_opcode = 0;
2110 target_label = target_label2 = (uint32_t)-1;
2111 }
2112 if (!zend_jit_identical(&ctx, opline,
2113 OP1_INFO(), OP1_RANGE(), OP1_REG_ADDR(),
2114 OP2_INFO(), OP2_RANGE(), OP2_REG_ADDR(),
2115 res_addr,
2116 zend_may_throw(opline, ssa_op, op_array, ssa),
2117 smart_branch_opcode, target_label, target_label2,
2118 NULL, 0)) {
2119 goto jit_failure;
2120 }
2121 goto done;
2122 case ZEND_DEFINED:
2123 if ((opline->result_type & IS_TMP_VAR)
2124 && (i + 1) <= end
2125 && ((opline+1)->opcode == ZEND_JMPZ
2126 || (opline+1)->opcode == ZEND_JMPNZ)
2127 && (opline+1)->op1_type == IS_TMP_VAR
2128 && (opline+1)->op1.var == opline->result.var) {
2129 i++;
2130 smart_branch_opcode = (opline+1)->opcode;
2131 target_label = ssa->cfg.blocks[b].successors[0];
2132 target_label2 = ssa->cfg.blocks[b].successors[1];
2133 } else {
2134 smart_branch_opcode = 0;
2135 target_label = target_label2 = (uint32_t)-1;
2136 }
2137 if (!zend_jit_defined(&ctx, opline, smart_branch_opcode, target_label, target_label2, NULL)) {
2138 goto jit_failure;
2139 }
2140 goto done;
2141 case ZEND_TYPE_CHECK:
2142 if (opline->extended_value == MAY_BE_RESOURCE) {
2143 // TODO: support for is_resource() ???
2144 break;
2145 }
2146 if ((opline->result_type & IS_TMP_VAR)
2147 && (i + 1) <= end
2148 && ((opline+1)->opcode == ZEND_JMPZ
2149 || (opline+1)->opcode == ZEND_JMPNZ)
2150 && (opline+1)->op1_type == IS_TMP_VAR
2151 && (opline+1)->op1.var == opline->result.var) {
2152 i++;
2153 smart_branch_opcode = (opline+1)->opcode;
2154 target_label = ssa->cfg.blocks[b].successors[0];
2155 target_label2 = ssa->cfg.blocks[b].successors[1];
2156 } else {
2157 smart_branch_opcode = 0;
2158 target_label = target_label2 = (uint32_t)-1;
2159 }
2160 if (!zend_jit_type_check(&ctx, opline, OP1_INFO(), smart_branch_opcode, target_label, target_label2, NULL)) {
2161 goto jit_failure;
2162 }
2163 goto done;
2164 case ZEND_RETURN:
2165 op1_info = OP1_INFO();
2166 if ((PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info))
2167 || op_array->type == ZEND_EVAL_CODE
2168 // TODO: support for top-level code
2169 || !op_array->function_name
2170 // TODO: support for IS_UNDEF ???
2171 || (op1_info & MAY_BE_UNDEF)) {
2172 if (!zend_jit_tail_handler(&ctx, opline)) {
2173 goto jit_failure;
2174 }
2175 } else {
2176 if (!zend_jit_return(&ctx, opline, op_array,
2177 op1_info, OP1_REG_ADDR())) {
2178 goto jit_failure;
2179 }
2180 }
2181 goto done;
2182 case ZEND_BOOL:
2183 case ZEND_BOOL_NOT:
2184 if (!zend_jit_bool_jmpznz(&ctx, opline,
2186 -1, -1,
2187 zend_may_throw(opline, ssa_op, op_array, ssa),
2188 opline->opcode, NULL)) {
2189 goto jit_failure;
2190 }
2191 goto done;
2192 case ZEND_JMPZ:
2193 case ZEND_JMPNZ:
2194 if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
2195 ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
2196 /* smart branch */
2197 if (!zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2198 goto jit_failure;
2199 }
2200 goto done;
2201 }
2203 case ZEND_JMPZ_EX:
2204 case ZEND_JMPNZ_EX:
2205 if (opline->result_type == IS_UNDEF) {
2206 res_addr = 0;
2207 } else {
2208 res_addr = RES_REG_ADDR();
2209 }
2210 if (!zend_jit_bool_jmpznz(&ctx, opline,
2211 OP1_INFO(), OP1_REG_ADDR(), res_addr,
2212 ssa->cfg.blocks[b].successors[0], ssa->cfg.blocks[b].successors[1],
2213 zend_may_throw(opline, ssa_op, op_array, ssa),
2214 opline->opcode, NULL)) {
2215 goto jit_failure;
2216 }
2217 goto done;
2219 if ((opline->extended_value & ZEND_ISEMPTY)) {
2220 // TODO: support for empty() ???
2221 break;
2222 }
2223 if ((opline->result_type & IS_TMP_VAR)
2224 && (i + 1) <= end
2225 && ((opline+1)->opcode == ZEND_JMPZ
2226 || (opline+1)->opcode == ZEND_JMPNZ)
2227 && (opline+1)->op1_type == IS_TMP_VAR
2228 && (opline+1)->op1.var == opline->result.var) {
2229 i++;
2230 smart_branch_opcode = (opline+1)->opcode;
2231 target_label = ssa->cfg.blocks[b].successors[0];
2232 target_label2 = ssa->cfg.blocks[b].successors[1];
2233 } else {
2234 smart_branch_opcode = 0;
2235 target_label = target_label2 = (uint32_t)-1;
2236 }
2237 if (!zend_jit_isset_isempty_cv(&ctx, opline,
2239 smart_branch_opcode, target_label, target_label2,
2240 NULL)) {
2241 goto jit_failure;
2242 }
2243 goto done;
2244 case ZEND_IN_ARRAY:
2245 if (opline->op1_type == IS_VAR || opline->op1_type == IS_TMP_VAR) {
2246 break;
2247 }
2248 op1_info = OP1_INFO();
2249 if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_STRING) {
2250 break;
2251 }
2252 if ((opline->result_type & IS_TMP_VAR)
2253 && (i + 1) <= end
2254 && ((opline+1)->opcode == ZEND_JMPZ
2255 || (opline+1)->opcode == ZEND_JMPNZ)
2256 && (opline+1)->op1_type == IS_TMP_VAR
2257 && (opline+1)->op1.var == opline->result.var) {
2258 i++;
2259 smart_branch_opcode = (opline+1)->opcode;
2260 target_label = ssa->cfg.blocks[b].successors[0];
2261 target_label2 = ssa->cfg.blocks[b].successors[1];
2262 } else {
2263 smart_branch_opcode = 0;
2264 target_label = target_label2 = (uint32_t)-1;
2265 }
2266 if (!zend_jit_in_array(&ctx, opline,
2267 op1_info, OP1_REG_ADDR(),
2268 smart_branch_opcode, target_label, target_label2,
2269 NULL)) {
2270 goto jit_failure;
2271 }
2272 goto done;
2273 case ZEND_FETCH_DIM_R:
2274 case ZEND_FETCH_DIM_IS:
2275 case ZEND_FETCH_LIST_R:
2276 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2277 break;
2278 }
2279 if (!zend_jit_fetch_dim_read(&ctx, opline, ssa, ssa_op,
2280 OP1_INFO(), OP1_REG_ADDR(), 0,
2281 OP2_INFO(), OP2_REG_ADDR(), OP2_RANGE(),
2283 goto jit_failure;
2284 }
2285 goto done;
2286 case ZEND_FETCH_DIM_W:
2287 case ZEND_FETCH_DIM_RW:
2288// case ZEND_FETCH_DIM_UNSET:
2289 case ZEND_FETCH_LIST_W:
2290 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2291 break;
2292 }
2293 if (opline->op1_type != IS_CV) {
2294 break;
2295 }
2296 if (!zend_jit_fetch_dim(&ctx, opline,
2298 OP2_INFO(), (opline->op2_type != IS_UNUSED) ? OP2_REG_ADDR() : 0,
2299 (opline->op2_type != IS_UNUSED) ? OP2_RANGE() : 0,
2301 goto jit_failure;
2302 }
2303 goto done;
2305 if ((opline->extended_value & ZEND_ISEMPTY)) {
2306 // TODO: support for empty() ???
2307 break;
2308 }
2309 if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2310 break;
2311 }
2312 if ((opline->result_type & IS_TMP_VAR)
2313 && (i + 1) <= end
2314 && ((opline+1)->opcode == ZEND_JMPZ
2315 || (opline+1)->opcode == ZEND_JMPNZ)
2316 && (opline+1)->op1_type == IS_TMP_VAR
2317 && (opline+1)->op1.var == opline->result.var) {
2318 i++;
2319 smart_branch_opcode = (opline+1)->opcode;
2320 target_label = ssa->cfg.blocks[b].successors[0];
2321 target_label2 = ssa->cfg.blocks[b].successors[1];
2322 } else {
2323 smart_branch_opcode = 0;
2324 target_label = target_label2 = (uint32_t)-1;
2325 }
2326 if (!zend_jit_isset_isempty_dim(&ctx, opline,
2327 OP1_INFO(), OP1_REG_ADDR(), 0,
2328 OP2_INFO(), OP2_REG_ADDR(), OP2_RANGE(), IS_UNKNOWN,
2329 zend_may_throw(opline, ssa_op, op_array, ssa),
2330 smart_branch_opcode, target_label, target_label2,
2331 NULL)) {
2332 goto jit_failure;
2333 }
2334 goto done;
2335 case ZEND_FETCH_OBJ_R:
2336 case ZEND_FETCH_OBJ_IS:
2337 case ZEND_FETCH_OBJ_W:
2338 ce = NULL;
2339 ce_is_instanceof = 0;
2340 on_this = 0;
2341 if (opline->op1_type == IS_UNUSED) {
2343 op1_addr = 0;
2344 ce = op_array->scope;
2345 /* scope is NULL for closures. */
2346 if (ce) {
2347 ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
2348 }
2349 on_this = 1;
2350 } else {
2351 op1_info = OP1_INFO();
2352 if (!(op1_info & MAY_BE_OBJECT)) {
2353 break;
2354 }
2355 op1_addr = OP1_REG_ADDR();
2356 if (ssa->var_info && ssa->ops) {
2357 zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
2358 if (ssa_op->op1_use >= 0) {
2359 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
2360 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
2361 ce = op1_ssa->ce;
2362 ce_is_instanceof = op1_ssa->is_instanceof;
2363 }
2364 }
2365 }
2366 }
2367 if (opline->op2_type != IS_CONST
2368 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2369 || Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
2370 break;
2371 }
2372 if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
2373 op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
2375 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2376 goto jit_failure;
2377 }
2378 goto done;
2379 case ZEND_BIND_GLOBAL:
2380 if (!ssa->ops || !ssa->var_info) {
2381 op1_info = MAY_BE_ANY|MAY_BE_REF;
2382 } else {
2383 op1_info = OP1_INFO();
2384 }
2385 if (!zend_jit_bind_global(&ctx, opline, op1_info)) {
2386 goto jit_failure;
2387 }
2388 goto done;
2389 case ZEND_RECV:
2390 if (!zend_jit_recv(&ctx, opline, op_array)) {
2391 goto jit_failure;
2392 }
2393 goto done;
2394 case ZEND_RECV_INIT:
2395 if (!zend_jit_recv_init(&ctx, opline, op_array,
2396 (opline + 1)->opcode != ZEND_RECV_INIT,
2397 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2398 goto jit_failure;
2399 }
2400 goto done;
2401 case ZEND_FREE:
2402 case ZEND_FE_FREE:
2403 if (!zend_jit_free(&ctx, opline, OP1_INFO(),
2404 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2405 goto jit_failure;
2406 }
2407 goto done;
2408 case ZEND_ECHO:
2409 op1_info = OP1_INFO();
2410 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2411 break;
2412 }
2413 if (!zend_jit_echo(&ctx, opline, op1_info)) {
2414 goto jit_failure;
2415 }
2416 goto done;
2417 case ZEND_STRLEN:
2418 op1_info = OP1_INFO();
2419 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2420 break;
2421 }
2422 if (!zend_jit_strlen(&ctx, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR())) {
2423 goto jit_failure;
2424 }
2425 goto done;
2426 case ZEND_COUNT:
2427 op1_info = OP1_INFO();
2428 if ((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_ARRAY) {
2429 break;
2430 }
2431 if (!zend_jit_count(&ctx, opline, op1_info, OP1_REG_ADDR(), RES_REG_ADDR(), zend_may_throw(opline, ssa_op, op_array, ssa))) {
2432 goto jit_failure;
2433 }
2434 goto done;
2435 case ZEND_FETCH_THIS:
2436 if (!zend_jit_fetch_this(&ctx, opline, op_array, 0)) {
2437 goto jit_failure;
2438 }
2439 goto done;
2440 case ZEND_SWITCH_LONG:
2441 case ZEND_SWITCH_STRING:
2442 case ZEND_MATCH:
2443 if (!zend_jit_switch(&ctx, opline, op_array, ssa, NULL, NULL)) {
2444 goto jit_failure;
2445 }
2446 goto done;
2448 if (opline->op1_type == IS_UNUSED) {
2449 /* Always throws */
2450 break;
2451 }
2452 if (opline->op1_type == IS_CONST) {
2453 /* TODO Different instruction format, has return value */
2454 break;
2455 }
2456 if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) {
2457 /* Not worth bothering with */
2458 break;
2459 }
2460 if (OP1_INFO() & MAY_BE_REF) {
2461 /* TODO May need reference unwrapping. */
2462 break;
2463 }
2464 if (!zend_jit_verify_return_type(&ctx, opline, op_array, OP1_INFO())) {
2465 goto jit_failure;
2466 }
2467 goto done;
2468 case ZEND_FE_RESET_R:
2469 op1_info = OP1_INFO();
2470 if ((op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) != MAY_BE_ARRAY) {
2471 break;
2472 }
2473 if (!zend_jit_fe_reset(&ctx, opline, op1_info)) {
2474 goto jit_failure;
2475 }
2476 goto done;
2477 case ZEND_FE_FETCH_R:
2478 op1_info = OP1_INFO();
2479 if ((op1_info & MAY_BE_ANY) != MAY_BE_ARRAY) {
2480 break;
2481 }
2482 if (!zend_jit_fe_fetch(&ctx, opline, op1_info, OP2_INFO(),
2483 ssa->cfg.blocks[b].successors[0], opline->opcode, NULL)) {
2484 goto jit_failure;
2485 }
2486 goto done;
2488 if (!zend_jit_fetch_constant(&ctx, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
2489 goto jit_failure;
2490 }
2491 goto done;
2492 case ZEND_JMP_FRAMELESS:
2493 if (!zend_jit_jmp_frameless(&ctx, opline, /* exit_addr */ NULL, /* guard */ 0)) {
2494 goto jit_failure;
2495 }
2496 goto done;
2498 if (opline->op2_type != IS_CONST
2499 || Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING) {
2500 break;
2501 }
2502 ce = NULL;
2503 ce_is_instanceof = 0;
2504 on_this = 0;
2505 if (opline->op1_type == IS_UNUSED) {
2507 op1_addr = 0;
2508 ce = op_array->scope;
2509 /* scope is NULL for closures. */
2510 if (ce) {
2511 ce_is_instanceof = !(ce->ce_flags & ZEND_ACC_FINAL);
2512 }
2513 on_this = 1;
2514 } else {
2515 op1_info = OP1_INFO();
2516 if (!(op1_info & MAY_BE_OBJECT)) {
2517 break;
2518 }
2519 op1_addr = OP1_REG_ADDR();
2520 if (ssa->var_info && ssa->ops) {
2521 zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
2522 if (ssa_op->op1_use >= 0) {
2523 zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
2524 if (op1_ssa->ce && !op1_ssa->ce->create_object) {
2525 ce = op1_ssa->ce;
2526 ce_is_instanceof = op1_ssa->is_instanceof;
2527 }
2528 }
2529 }
2530 }
2531 if (!zend_jit_init_method_call(&ctx, opline, b, op_array, ssa, ssa_op, call_level,
2532 op1_info, op1_addr, ce, ce_is_instanceof, on_this, 0, NULL,
2533 NULL, 0,
2534 -1, -1,
2535 0)) {
2536 goto jit_failure;
2537 }
2538 goto done;
2539 case ZEND_ROPE_INIT:
2540 case ZEND_ROPE_ADD:
2541 case ZEND_ROPE_END:
2542 op2_info = OP2_INFO();
2543 if ((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) != MAY_BE_STRING) {
2544 break;
2545 }
2546 if (!zend_jit_rope(&ctx, opline, op2_info)) {
2547 goto jit_failure;
2548 }
2549 goto done;
2551 jit_frameless_icall0(jit, opline);
2552 goto done;
2554 op1_info = OP1_INFO();
2555 jit_frameless_icall1(jit, opline, op1_info);
2556 goto done;
2558 op1_info = OP1_INFO();
2559 op2_info = OP2_INFO();
2560 jit_frameless_icall2(jit, opline, op1_info, op2_info);
2561 goto done;
2563 op1_info = OP1_INFO();
2564 op2_info = OP2_INFO();
2565 jit_frameless_icall3(jit, opline, op1_info, op2_info, OP1_DATA_INFO());
2566 goto done;
2567 default:
2568 break;
2569 }
2570 }
2571
2572 switch (opline->opcode) {
2573 case ZEND_RECV_INIT:
2574 case ZEND_BIND_GLOBAL:
2575 if (opline == op_array->opcodes ||
2576 opline->opcode != op_array->opcodes[i-1].opcode) {
2577 /* repeatable opcodes */
2578 if (!zend_jit_handler(&ctx, opline,
2579 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2580 goto jit_failure;
2581 }
2582 }
2583 zend_jit_set_last_valid_opline(&ctx, opline+1);
2584 break;
2585 case ZEND_NOP:
2586 case ZEND_OP_DATA:
2587 case ZEND_SWITCH_LONG:
2588 case ZEND_SWITCH_STRING:
2589 break;
2590 case ZEND_MATCH:
2591 /* We have to exit to the VM because the MATCH handler performs an N-way jump for
2592 * which we can't generate simple (opcache.jit=1201) JIT code. */
2593 if (!zend_jit_tail_handler(&ctx, opline)) {
2594 goto jit_failure;
2595 }
2596 break;
2597 case ZEND_JMP:
2598 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
2599 const zend_op *target = OP_JMP_ADDR(opline, opline->op1);
2600
2601 if (!zend_jit_set_ip(&ctx, target)) {
2602 goto jit_failure;
2603 }
2604 }
2605 break;
2606 case ZEND_CATCH:
2607 case ZEND_FAST_CALL:
2608 case ZEND_FAST_RET:
2611 case ZEND_RETURN_BY_REF:
2612 case ZEND_RETURN:
2613 case ZEND_MATCH_ERROR:
2614 /* switch through trampoline */
2615 case ZEND_YIELD:
2616 case ZEND_YIELD_FROM:
2617 case ZEND_THROW:
2619 if (!zend_jit_tail_handler(&ctx, opline)) {
2620 goto jit_failure;
2621 }
2622 /* THROW and EXIT may be used in the middle of BB */
2623 /* don't generate code for the rest of BB */
2624
2625 /* Skip current opline for call_level computation because it does not influence call_level.
2626 * Don't include last opline because end of loop already checks call level of last opline. */
2627 i++;
2628 for (; i < end; i++) {
2629 opline = op_array->opcodes + i;
2630 if (zend_jit_inc_call_level(opline->opcode)) {
2631 call_level++;
2632 } else if (zend_jit_dec_call_level(opline->opcode)) {
2633 call_level--;
2634 }
2635 }
2636 opline = op_array->opcodes + end;
2637 break;
2638 /* stackless execution */
2640 case ZEND_DO_FCALL:
2641 case ZEND_DO_UCALL:
2643 if (!zend_jit_call(&ctx, opline, b + 1)) {
2644 goto jit_failure;
2645 }
2646 break;
2647 case ZEND_JMPZ:
2648 case ZEND_JMPNZ:
2649 if (opline > op_array->opcodes + ssa->cfg.blocks[b].start &&
2650 ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) {
2651 /* smart branch */
2652 if (!zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2653 goto jit_failure;
2654 }
2655 goto done;
2656 }
2658 case ZEND_JMPZ_EX:
2659 case ZEND_JMPNZ_EX:
2660 case ZEND_JMP_SET:
2661 case ZEND_COALESCE:
2662 case ZEND_JMP_NULL:
2663 case ZEND_FE_RESET_R:
2664 case ZEND_FE_RESET_RW:
2665 case ZEND_ASSERT_CHECK:
2666 case ZEND_FE_FETCH_R:
2667 case ZEND_FE_FETCH_RW:
2669 case ZEND_JMP_FRAMELESS:
2670 if (!zend_jit_handler(&ctx, opline,
2671 zend_may_throw(opline, ssa_op, op_array, ssa)) ||
2672 !zend_jit_cond_jmp(&ctx, opline + 1, ssa->cfg.blocks[b].successors[0])) {
2673 goto jit_failure;
2674 }
2675 break;
2676 case ZEND_NEW:
2677 if (!zend_jit_handler(&ctx, opline, 1)) {
2678 return 0;
2679 }
2680 if (opline->extended_value == 0 && (opline+1)->opcode == ZEND_DO_FCALL) {
2681 zend_class_entry *ce = NULL;
2682
2683 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) {
2684 if (ssa->ops && ssa->var_info) {
2685 zend_ssa_var_info *res_ssa = &ssa->var_info[ssa->ops[opline - op_array->opcodes].result_def];
2686 if (res_ssa->ce && !res_ssa->is_instanceof) {
2687 ce = res_ssa->ce;
2688 }
2689 }
2690 } else {
2691 if (opline->op1_type == IS_CONST) {
2692 zval *zv = RT_CONSTANT(opline, opline->op1);
2693 if (Z_TYPE_P(zv) == IS_STRING) {
2694 zval *lc = zv + 1;
2695 ce = (zend_class_entry*)zend_hash_find_ptr(EG(class_table), Z_STR_P(lc));
2696 }
2697 }
2698 }
2699
2700 i++;
2701
2702 if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || ce->constructor) {
2703 const zend_op *next_opline = opline + 1;
2704
2705 ZEND_ASSERT(b + 1 == ssa->cfg.blocks[b].successors[0]);
2706 zend_jit_constructor(&ctx, next_opline, op_array, ssa, call_level, b + 1);
2707 }
2708
2709 /* We skip over the DO_FCALL, so decrement call_level ourselves. */
2710 call_level--;
2711 }
2712 break;
2713 case ZEND_FETCH_OBJ_R:
2714 if (!zend_jit_handler(&ctx, opline,
2715 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2716 goto jit_failure;
2717 }
2718
2719 /* Cache slot is only used for IS_CONST op2, so only that can result in hook fast path. */
2720 if (opline->op2_type == IS_CONST) {
2721 if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) {
2722 if (opline->op1_type == IS_UNUSED) {
2723 ce = op_array->scope;
2724 } else {
2725 ce = NULL;
2726 }
2727 }
2728
2729 if (!ce || !(ce->ce_flags & ZEND_ACC_FINAL) || ce->num_hooked_props > 0) {
2730 /* If a simple hook is called, exit to the VM. */
2731 ir_ref if_hook_enter = ir_IF(jit_CMP_IP(jit, IR_EQ, opline + 1));
2732 ir_IF_FALSE(if_hook_enter);
2733 if (GCC_GLOBAL_REGS) {
2734 ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
2735 } else {
2736 ir_RETURN(ir_CONST_I32(1)); /* ZEND_VM_ENTER */
2737 }
2738 ir_IF_TRUE(if_hook_enter);
2739 }
2740 }
2741
2742 break;
2743 default:
2744 if (!zend_jit_handler(&ctx, opline,
2745 zend_may_throw(opline, ssa_op, op_array, ssa))) {
2746 goto jit_failure;
2747 }
2748 if (i == end
2750 /* smart branch split across basic blocks */
2751 if (!zend_jit_set_cond(&ctx, opline + 2, opline->result.var)) {
2752 goto jit_failure;
2753 }
2754 }
2755 }
2756done:
2757 if (zend_jit_dec_call_level(opline->opcode)) {
2758 call_level--;
2759 }
2760 }
2761 zend_jit_bb_end(&ctx, b);
2762 }
2763
2764 if (jit->return_inputs) {
2765 zend_jit_common_return(jit);
2766
2767 bool left_frame = 0;
2768 if (op_array->last_var > 100) {
2769 /* To many CVs to unroll */
2770 if (!zend_jit_free_cvs(&ctx)) {
2771 goto jit_failure;
2772 }
2773 left_frame = 1;
2774 }
2775 if (!left_frame) {
2776 int j;
2777
2778 for (j = 0 ; j < op_array->last_var; j++) {
2779 uint32_t info = zend_ssa_cv_info(op_array, ssa, j);
2780
2782 if (!left_frame) {
2783 left_frame = 1;
2784 if (!zend_jit_leave_frame(&ctx)) {
2785 goto jit_failure;
2786 }
2787 }
2788 if (!zend_jit_free_cv(&ctx, info, j)) {
2789 goto jit_failure;
2790 }
2791 }
2792 }
2793 }
2794 if (!zend_jit_leave_func(&ctx, op_array, NULL, MAY_BE_ANY, left_frame,
2795 NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) {
2796 goto jit_failure;
2797 }
2798 }
2799
2800 handler = zend_jit_finish(&ctx);
2801 if (!handler) {
2802 goto jit_failure;
2803 }
2804 zend_jit_free_ctx(&ctx);
2805
2807 zend_arena_release(&CG(arena), checkpoint);
2808 }
2809 return SUCCESS;
2810
2811jit_failure:
2812 zend_jit_free_ctx(&ctx);
2814 zend_arena_release(&CG(arena), checkpoint);
2815 }
2816 return FAILURE;
2817}
2818
2819static void zend_jit_collect_calls(zend_op_array *op_array, zend_script *script)
2820{
2821 zend_func_info *func_info;
2822
2823 if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
2824 JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
2825 JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
2826 func_info = ZEND_FUNC_INFO(op_array);
2827 } else {
2828 func_info = zend_arena_calloc(&CG(arena), 1, sizeof(zend_func_info));
2829 ZEND_SET_FUNC_INFO(op_array, func_info);
2830 }
2831 zend_analyze_calls(&CG(arena), script, ZEND_CALL_TREE, op_array, func_info);
2832}
2833
2834static void zend_jit_cleanup_func_info(zend_op_array *op_array)
2835{
2836 zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
2837 zend_call_info *caller_info, *callee_info;
2838
2839 if (func_info) {
2840 caller_info = func_info->caller_info;
2841 callee_info = func_info->callee_info;
2842
2843 if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
2844 JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
2845 JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
2846 func_info->num = 0;
2847 func_info->flags &= ZEND_FUNC_JIT_ON_FIRST_EXEC
2851 memset(&func_info->ssa, 0, sizeof(zend_func_info) - offsetof(zend_func_info, ssa));
2852 } else {
2853 ZEND_SET_FUNC_INFO(op_array, NULL);
2854 }
2855
2856 while (caller_info) {
2857 if (caller_info->caller_op_array) {
2858 zend_jit_cleanup_func_info(caller_info->caller_op_array);
2859 }
2860 caller_info = caller_info->next_caller;
2861 }
2862 while (callee_info) {
2863 if (callee_info->callee_func && callee_info->callee_func->type == ZEND_USER_FUNCTION) {
2864 zend_jit_cleanup_func_info(&callee_info->callee_func->op_array);
2865 }
2866 callee_info = callee_info->next_callee;
2867 }
2868 }
2869}
2870
2871static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, const zend_op *rt_opline, uint8_t trigger)
2872{
2873 zend_ssa ssa;
2874 void *checkpoint;
2875 zend_func_info *func_info;
2876 uint8_t orig_trigger;
2877
2878 if (*dasm_ptr == dasm_end) {
2879 return FAILURE;
2880 }
2881
2882 orig_trigger = JIT_G(trigger);
2883 JIT_G(trigger) = trigger;
2884 checkpoint = zend_arena_checkpoint(CG(arena));
2885
2886 /* Build SSA */
2887 memset(&ssa, 0, sizeof(zend_ssa));
2888
2889 if (op_array->fn_flags & ZEND_ACC_CLOSURE) {
2890 if (trigger == ZEND_JIT_ON_FIRST_EXEC) {
2892 op_array = (zend_op_array*) jit_extension->op_array;
2893 } else if (trigger == ZEND_JIT_ON_HOT_COUNTERS) {
2895 op_array = (zend_op_array*) jit_extension->op_array;
2896 } else {
2897 ZEND_ASSERT(!op_array->scope);
2898 }
2899 }
2900
2901 if (zend_jit_op_array_analyze1(op_array, script, &ssa) != SUCCESS) {
2902 goto jit_failure;
2903 }
2904
2905 if (JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNCS) {
2906 zend_jit_collect_calls(op_array, script);
2907 func_info = ZEND_FUNC_INFO(op_array);
2908 func_info->call_map = zend_build_call_map(&CG(arena), func_info, op_array);
2909 if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
2910 zend_init_func_return_info(op_array, script, &func_info->return_info);
2911 }
2912 }
2913
2914 if (zend_jit_op_array_analyze2(op_array, script, &ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
2915 goto jit_failure;
2916 }
2917
2920 }
2921
2922 if (zend_jit(op_array, &ssa, rt_opline) != SUCCESS) {
2923 goto jit_failure;
2924 }
2925
2926 zend_jit_cleanup_func_info(op_array);
2927 zend_arena_release(&CG(arena), checkpoint);
2928 JIT_G(trigger) = orig_trigger;
2929 return SUCCESS;
2930
2931jit_failure:
2932 zend_jit_cleanup_func_info(op_array);
2933 zend_arena_release(&CG(arena), checkpoint);
2934 JIT_G(trigger) = orig_trigger;
2935 return FAILURE;
2936}
2937
2938/* Run-time JIT handler */
2939static int ZEND_FASTCALL zend_runtime_jit(void)
2940{
2941 zend_execute_data *execute_data = EG(current_execute_data);
2942 zend_op_array *op_array = &EX(func)->op_array;
2943 zend_op *opline = op_array->opcodes;
2944 zend_jit_op_array_extension *jit_extension;
2945 bool do_bailout = 0;
2946
2948
2949 if (ZEND_FUNC_INFO(op_array)) {
2950
2951 SHM_UNPROTECT();
2953
2954 zend_try {
2955 /* restore original opcode handlers */
2956 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2957 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
2958 opline++;
2959 }
2960 }
2961 jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
2962 opline->handler = jit_extension->orig_handler;
2963
2964 /* perform real JIT for this function */
2965 zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_FIRST_EXEC);
2966 } zend_catch {
2967 do_bailout = true;
2968 } zend_end_try();
2969
2971 SHM_PROTECT();
2972 }
2973
2975
2976 if (do_bailout) {
2977 zend_bailout();
2978 }
2979
2980 /* JIT-ed code is going to be called by VM */
2981 return 0;
2982}
2983
2984void zend_jit_check_funcs(HashTable *function_table, bool is_method) {
2985 zend_op *opline;
2987 zend_op_array *op_array;
2988 uintptr_t counter;
2989 zend_jit_op_array_extension *jit_extension;
2990
2991 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(function_table, func) {
2992 if (func->type == ZEND_INTERNAL_FUNCTION) {
2993 break;
2994 }
2995 op_array = &func->op_array;
2996 opline = op_array->opcodes;
2997 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
2998 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
2999 opline++;
3000 }
3001 }
3002 if (opline->handler == zend_jit_profile_jit_handler) {
3003 if (!RUN_TIME_CACHE(op_array)) {
3004 continue;
3005 }
3006 counter = (uintptr_t)ZEND_COUNTER_INFO(op_array);
3007 ZEND_COUNTER_INFO(op_array) = 0;
3008 jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
3009 opline->handler = jit_extension->orig_handler;
3010 if (((double)counter / (double)zend_jit_profile_counter) > JIT_G(prof_threshold)) {
3011 zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_PROF_REQUEST);
3012 }
3013 }
3015}
3016
3018{
3019 zend_op_array *op_array = &EX(func)->op_array;
3020 zend_jit_op_array_hot_extension *jit_extension;
3021 uint32_t i;
3022 bool do_bailout = 0;
3023
3025 jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
3026
3027 if (jit_extension) {
3028 SHM_UNPROTECT();
3030
3031 zend_try {
3032 for (i = 0; i < op_array->last; i++) {
3033 op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
3034 }
3035
3036#ifdef HAVE_GCC_GLOBAL_REGS
3037 EX(opline) = opline;
3038#endif
3039
3040 /* perform real JIT for this function */
3041 zend_real_jit_func(op_array, NULL, opline, ZEND_JIT_ON_HOT_COUNTERS);
3042 } zend_catch {
3043 do_bailout = 1;
3044 } zend_end_try();
3045
3047 SHM_PROTECT();
3048 }
3049
3051
3052 if (do_bailout) {
3053 zend_bailout();
3054 }
3055 /* JIT-ed code is going to be called by VM */
3056}
3057
3058static void zend_jit_setup_hot_counters_ex(zend_op_array *op_array, zend_cfg *cfg)
3059{
3060 if (JIT_G(hot_func)) {
3061 zend_op *opline = op_array->opcodes;
3062
3063 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3064 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3065 opline++;
3066 }
3067 }
3068
3069 opline->handler = (const void*)zend_jit_func_hot_counter_handler;
3070 }
3071
3072 if (JIT_G(hot_loop)) {
3073 uint32_t i;
3074
3075 for (i = 0; i < cfg->blocks_count; i++) {
3076 if ((cfg->blocks[i].flags & ZEND_BB_REACHABLE) &&
3077 (cfg->blocks[i].flags & ZEND_BB_LOOP_HEADER)) {
3078 op_array->opcodes[cfg->blocks[i].start].handler =
3079 (const void*)zend_jit_loop_hot_counter_handler;
3080 }
3081 }
3082 }
3083}
3084
3085static int zend_jit_restart_hot_counters(zend_op_array *op_array)
3086{
3087 zend_jit_op_array_hot_extension *jit_extension;
3088 zend_cfg cfg;
3089 uint32_t i;
3090
3091 jit_extension = (zend_jit_op_array_hot_extension*)ZEND_FUNC_INFO(op_array);
3092 for (i = 0; i < op_array->last; i++) {
3093 op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
3094 }
3095
3096 if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
3097 return FAILURE;
3098 }
3099
3100 zend_jit_setup_hot_counters_ex(op_array, &cfg);
3101
3102 return SUCCESS;
3103}
3104
3105static int zend_jit_setup_hot_counters(zend_op_array *op_array)
3106{
3107 zend_jit_op_array_hot_extension *jit_extension;
3108 zend_cfg cfg;
3109 uint32_t i;
3110
3111 ZEND_ASSERT(!JIT_G(hot_func) || zend_jit_func_hot_counter_handler != NULL);
3112 ZEND_ASSERT(!JIT_G(hot_loop) || zend_jit_loop_hot_counter_handler != NULL);
3113
3114 if (zend_jit_build_cfg(op_array, &cfg) != SUCCESS) {
3115 return FAILURE;
3116 }
3117
3118 jit_extension = (zend_jit_op_array_hot_extension*)zend_shared_alloc(sizeof(zend_jit_op_array_hot_extension) + (op_array->last - 1) * sizeof(void*));
3119 if (!jit_extension) {
3120 return FAILURE;
3121 }
3122 memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3124 jit_extension->op_array = op_array;
3126 for (i = 0; i < op_array->last; i++) {
3127 jit_extension->orig_handlers[i] = op_array->opcodes[i].handler;
3128 }
3129 ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3130
3131 zend_jit_setup_hot_counters_ex(op_array, &cfg);
3132
3133 zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3134
3135 return SUCCESS;
3136}
3137
3138#include "jit/zend_jit_trace.c"
3139
3140int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
3141{
3142 if (dasm_ptr == NULL) {
3143 return FAILURE;
3144 }
3145
3146 if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC) {
3147 zend_jit_op_array_extension *jit_extension;
3148 zend_op *opline = op_array->opcodes;
3149
3150 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3151 ZEND_SET_FUNC_INFO(op_array, NULL);
3152 zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
3153 return SUCCESS;
3154 }
3155
3156 /* Set run-time JIT handler */
3157 ZEND_ASSERT(zend_jit_runtime_jit_handler != NULL);
3158 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3159 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3160 opline++;
3161 }
3162 }
3164 if (!jit_extension) {
3165 return FAILURE;
3166 }
3167 memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3169 jit_extension->op_array = op_array;
3170 jit_extension->orig_handler = (void*)opline->handler;
3171 ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3172 opline->handler = (const void*)zend_jit_runtime_jit_handler;
3173 zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3174
3175 return SUCCESS;
3176 } else if (JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST) {
3177 zend_jit_op_array_extension *jit_extension;
3178 zend_op *opline = op_array->opcodes;
3179
3180 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
3181 ZEND_SET_FUNC_INFO(op_array, NULL);
3182 zend_error(E_WARNING, "Preloading is incompatible with first-exec and profile triggered JIT");
3183 return SUCCESS;
3184 }
3185
3186 ZEND_ASSERT(zend_jit_profile_jit_handler != NULL);
3187 if (op_array->function_name) {
3188 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3189 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3190 opline++;
3191 }
3192 }
3194 if (!jit_extension) {
3195 return FAILURE;
3196 }
3197 memset(&jit_extension->func_info, 0, sizeof(zend_func_info));
3199 jit_extension->op_array = op_array;
3200 jit_extension->orig_handler = (void*)opline->handler;
3201 ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
3202 opline->handler = (const void*)zend_jit_profile_jit_handler;
3203 zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
3204 }
3205
3206 return SUCCESS;
3207 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
3208 return zend_jit_setup_hot_counters(op_array);
3209 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3210 return zend_jit_setup_hot_trace_counters(op_array);
3211 } else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3212 return zend_real_jit_func(op_array, script, NULL, ZEND_JIT_ON_SCRIPT_LOAD);
3213 } else {
3215 }
3216 return FAILURE;
3217}
3218
3219int zend_jit_script(zend_script *script)
3220{
3221 void *checkpoint;
3222 zend_call_graph call_graph;
3223 zend_func_info *info;
3224 int i;
3225
3226 if (dasm_ptr == NULL || *dasm_ptr == dasm_end) {
3227 return FAILURE;
3228 }
3229
3230 checkpoint = zend_arena_checkpoint(CG(arena));
3231
3232 call_graph.op_arrays_count = 0;
3233 zend_build_call_graph(&CG(arena), script, &call_graph);
3234
3235 zend_analyze_call_graph(&CG(arena), script, &call_graph);
3236
3237 if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC ||
3238 JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST ||
3239 JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS ||
3240 JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3241 for (i = 0; i < call_graph.op_arrays_count; i++) {
3242 if (zend_jit_op_array(call_graph.op_arrays[i], script) != SUCCESS) {
3243 goto jit_failure;
3244 }
3245 }
3246 } else if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3247 for (i = 0; i < call_graph.op_arrays_count; i++) {
3248 info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3249 if (info) {
3250 if (zend_jit_op_array_analyze1(call_graph.op_arrays[i], script, &info->ssa) != SUCCESS) {
3251 goto jit_failure;
3252 }
3253 info->ssa.cfg.flags |= info->flags;
3254 info->flags = info->ssa.cfg.flags;
3255 }
3256 }
3257
3258 for (i = 0; i < call_graph.op_arrays_count; i++) {
3259 info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3260 if (info) {
3261 info->call_map = zend_build_call_map(&CG(arena), info, call_graph.op_arrays[i]);
3262 if (call_graph.op_arrays[i]->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
3263 zend_init_func_return_info(call_graph.op_arrays[i], script, &info->return_info);
3264 }
3265 }
3266 }
3267
3268 for (i = 0; i < call_graph.op_arrays_count; i++) {
3269 info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3270 if (info) {
3271 if (zend_jit_op_array_analyze2(call_graph.op_arrays[i], script, &info->ssa, ZCG(accel_directives).optimization_level) != SUCCESS) {
3272 goto jit_failure;
3273 }
3274 info->flags = info->ssa.cfg.flags;
3275 }
3276 }
3277
3278 for (i = 0; i < call_graph.op_arrays_count; i++) {
3279 info = ZEND_FUNC_INFO(call_graph.op_arrays[i]);
3280 if (info) {
3283 }
3284 if (zend_jit(call_graph.op_arrays[i], &info->ssa, NULL) != SUCCESS) {
3285 goto jit_failure;
3286 }
3287 }
3288 }
3289
3290 for (i = 0; i < call_graph.op_arrays_count; i++) {
3291 ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
3292 }
3293 } else {
3295 }
3296
3297 zend_arena_release(&CG(arena), checkpoint);
3298
3299 if (JIT_G(trigger) == ZEND_JIT_ON_FIRST_EXEC
3300 || JIT_G(trigger) == ZEND_JIT_ON_PROF_REQUEST
3301 || JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS
3302 || JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3303 zend_class_entry *ce;
3304 zend_op_array *op_array;
3305
3308 if (!ZEND_FUNC_INFO(op_array)) {
3309 void *jit_extension = zend_shared_alloc_get_xlat_entry(op_array->opcodes);
3310
3311 if (jit_extension) {
3312 ZEND_SET_FUNC_INFO(op_array, jit_extension);
3313 }
3314 }
3317 }
3318
3319 return SUCCESS;
3320
3321jit_failure:
3322 if (JIT_G(trigger) == ZEND_JIT_ON_SCRIPT_LOAD) {
3323 for (i = 0; i < call_graph.op_arrays_count; i++) {
3324 ZEND_SET_FUNC_INFO(call_graph.op_arrays[i], NULL);
3325 }
3326 }
3327 zend_arena_release(&CG(arena), checkpoint);
3328 return FAILURE;
3329}
3330
3331void zend_jit_unprotect(void)
3332{
3333#ifdef HAVE_MPROTECT
3335 int opts = PROT_READ | PROT_WRITE;
3336#ifdef ZTS
3337#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3338 if (zend_write_protect) {
3339 pthread_jit_write_protect_np(0);
3340 }
3341#endif
3342 opts |= PROT_EXEC;
3343#endif
3344 if (mprotect(dasm_buf, dasm_size, opts) != 0) {
3345 fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3346 }
3347 }
3348#elif defined(_WIN32)
3350 DWORD old, new;
3351#ifdef ZTS
3352 new = PAGE_EXECUTE_READWRITE;
3353#else
3354 new = PAGE_READWRITE;
3355#endif
3356 if (!VirtualProtect(dasm_buf, dasm_size, new, &old)) {
3357 DWORD err = GetLastError();
3359 fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3361 }
3362 }
3363#endif
3364}
3365
3366void zend_jit_protect(void)
3367{
3368#ifdef HAVE_MPROTECT
3370#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3371 if (zend_write_protect) {
3372 pthread_jit_write_protect_np(1);
3373 }
3374#endif
3375 if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3376 fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3377 }
3378 }
3379#elif defined(_WIN32)
3381 DWORD old;
3382
3383 if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3384 DWORD err = GetLastError();
3386 fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3388 }
3389 }
3390#endif
3391}
3392
3393static void zend_jit_init_handlers(void)
3394{
3395 if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
3396 zend_jit_runtime_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_runtime_jit];
3397 zend_jit_profile_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_profile_jit];
3398 zend_jit_func_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_hot_counter];
3399 zend_jit_loop_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_hot_counter];
3400 zend_jit_func_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_trace_counter];
3401 zend_jit_ret_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_ret_trace_counter];
3402 zend_jit_loop_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_trace_counter];
3403 } else {
3404 zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit;
3405 zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper;
3406 zend_jit_func_hot_counter_handler = (const void*)zend_jit_func_counter_helper;
3407 zend_jit_loop_hot_counter_handler = (const void*)zend_jit_loop_counter_helper;
3408 zend_jit_func_trace_counter_handler = (const void*)zend_jit_func_trace_helper;
3409 zend_jit_ret_trace_counter_handler = (const void*)zend_jit_ret_trace_helper;
3410 zend_jit_loop_trace_counter_handler = (const void*)zend_jit_loop_trace_helper;
3411 }
3412}
3413
3414static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
3415{
3416 memset(jit_globals, 0, sizeof(zend_jit_globals));
3417 zend_jit_trace_init_caches();
3418}
3419
3420#ifdef ZTS
3421static void zend_jit_globals_dtor(zend_jit_globals *jit_globals)
3422{
3423 zend_jit_trace_free_caches(jit_globals);
3424}
3425#endif
3426
3427static int zend_jit_parse_config_num(zend_long jit)
3428{
3429 if (jit == 0) {
3430 JIT_G(on) = 0;
3431 return SUCCESS;
3432 }
3433
3434 if (jit < 0) return FAILURE;
3435
3436 if (jit % 10 == 0 || jit % 10 > 5) return FAILURE;
3437 JIT_G(opt_level) = jit % 10;
3438
3439 jit /= 10;
3440 if (jit % 10 > 5 || jit % 10 == 4) return FAILURE;
3441 JIT_G(trigger) = jit % 10;
3442
3443 jit /= 10;
3444 if (jit % 10 > 2) return FAILURE;
3445 JIT_G(opt_flags) = jit % 10;
3446
3447 jit /= 10;
3448 if (jit % 10 > 1) return FAILURE;
3449 JIT_G(opt_flags) |= ((jit % 10) ? ZEND_JIT_CPU_AVX : 0);
3450
3451 if (jit / 10 != 0) return FAILURE;
3452
3453 JIT_G(on) = 1;
3454
3455 return SUCCESS;
3456}
3457
3458int zend_jit_config(zend_string *jit, int stage)
3459{
3460 if (stage != ZEND_INI_STAGE_STARTUP && !JIT_G(enabled)) {
3461 if (stage == ZEND_INI_STAGE_RUNTIME) {
3462 zend_error(E_WARNING, "Cannot change opcache.jit setting at run-time (JIT is disabled)");
3463 }
3464 return FAILURE;
3465 }
3466
3467 if (zend_string_equals_literal_ci(jit, "disable")) {
3468 JIT_G(enabled) = 0;
3469 JIT_G(on) = 0;
3470 return SUCCESS;
3471 } else if (ZSTR_LEN(jit) == 0
3473 || zend_string_equals_literal_ci(jit, "off")
3474 || zend_string_equals_literal_ci(jit, "no")
3475 || zend_string_equals_literal_ci(jit, "false")) {
3476 JIT_G(enabled) = 1;
3477 JIT_G(on) = 0;
3478 return SUCCESS;
3479 } else if (zend_string_equals_literal_ci(jit, "1")
3480 || zend_string_equals_literal_ci(jit, "on")
3481 || zend_string_equals_literal_ci(jit, "yes")
3482 || zend_string_equals_literal_ci(jit, "true")
3483 || zend_string_equals_literal_ci(jit, "tracing")) {
3484 JIT_G(enabled) = 1;
3485 JIT_G(on) = 1;
3486 JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_FUNCS;
3487 JIT_G(trigger) = ZEND_JIT_ON_HOT_TRACE;
3489 return SUCCESS;
3490 } else if (zend_string_equals_ci(jit, ZSTR_KNOWN(ZEND_STR_FUNCTION))) {
3491 JIT_G(enabled) = 1;
3492 JIT_G(on) = 1;
3493 JIT_G(opt_level) = ZEND_JIT_LEVEL_OPT_SCRIPT;
3494 JIT_G(trigger) = ZEND_JIT_ON_SCRIPT_LOAD;
3496 return SUCCESS;
3497 } else {
3498 char *end;
3499 zend_long num = ZEND_STRTOL(ZSTR_VAL(jit), &end, 10);
3500 if (end != ZSTR_VAL(jit) + ZSTR_LEN(jit) || zend_jit_parse_config_num(num) != SUCCESS) {
3501 goto failure;
3502 }
3503 JIT_G(enabled) = 1;
3504 return SUCCESS;
3505 }
3506
3507failure:
3508 zend_error(E_WARNING, "Invalid \"opcache.jit\" setting. Should be \"disable\", \"on\", \"off\", \"tracing\", \"function\" or 4-digit number");
3509 JIT_G(enabled) = 0;
3510 JIT_G(on) = 0;
3511 return FAILURE;
3512}
3513
3514int zend_jit_debug_config(zend_long old_val, zend_long new_val, int stage)
3515{
3516 if (stage != ZEND_INI_STAGE_STARTUP) {
3517 if (((old_val ^ new_val) & ZEND_JIT_DEBUG_PERSISTENT) != 0) {
3518 if (stage == ZEND_INI_STAGE_RUNTIME) {
3519 zend_error(E_WARNING, "Some opcache.jit_debug bits cannot be changed after startup");
3520 }
3521 return FAILURE;
3522 }
3523 }
3524 return SUCCESS;
3525}
3526
3527void zend_jit_init(void)
3528{
3529#ifdef ZTS
3530 jit_globals_id = ts_allocate_id(&jit_globals_id, sizeof(zend_jit_globals), (ts_allocate_ctor) zend_jit_globals_ctor, (ts_allocate_dtor) zend_jit_globals_dtor);
3531#else
3532 zend_jit_globals_ctor(&jit_globals);
3533#endif
3534}
3535
3536int zend_jit_check_support(void)
3537{
3538 int i;
3539
3540 zend_jit_vm_kind = zend_vm_kind();
3541 if (zend_jit_vm_kind != ZEND_VM_KIND_CALL &&
3542 zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) {
3543 zend_error(E_WARNING, "JIT is compatible only with CALL and HYBRID VM. JIT disabled.");
3544 JIT_G(enabled) = 0;
3545 JIT_G(on) = 0;
3546 return FAILURE;
3547 }
3548
3549 if (zend_execute_ex != execute_ex) {
3550 if (zend_dtrace_enabled) {
3551 zend_error(E_WARNING, "JIT is incompatible with DTrace. JIT disabled.");
3552 } else if (strcmp(sapi_module.name, "phpdbg") != 0) {
3553 zend_error(E_WARNING, "JIT is incompatible with third party extensions that override zend_execute_ex(). JIT disabled.");
3554 }
3555 JIT_G(enabled) = 0;
3556 JIT_G(on) = 0;
3557 return FAILURE;
3558 }
3559
3560 for (i = 0; i <= 256; i++) {
3561 switch (i) {
3562 /* JIT has no effect on these opcodes */
3563 case ZEND_BEGIN_SILENCE:
3564 case ZEND_END_SILENCE:
3565 break;
3566 default:
3568 zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
3569 JIT_G(enabled) = 0;
3570 JIT_G(on) = 0;
3571 return FAILURE;
3572 }
3573 }
3574 }
3575
3576#if defined(IR_TARGET_AARCH64)
3577 if (JIT_G(buffer_size) > 128*1024*1024) {
3578 zend_error(E_WARNING, "JIT on AArch64 doesn't support opcache.jit_buffer_size above 128M.");
3579 JIT_G(enabled) = 0;
3580 JIT_G(on) = 0;
3581 return FAILURE;
3582 }
3583#elif defined(IR_TARGET_X64)
3584 if (JIT_G(buffer_size) > 2 * Z_L(1024*1024*1024)) {
3585 zend_error(E_WARNING, "JIT on x86_64 doesn't support opcache.jit_buffer_size above 2G.");
3586 JIT_G(enabled) = 0;
3587 JIT_G(on) = 0;
3588 return FAILURE;
3589 }
3590#endif
3591
3592 return SUCCESS;
3593}
3594
3595void zend_jit_startup(void *buf, size_t size, bool reattached)
3596{
3599
3600#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3601 zend_write_protect = pthread_jit_write_protect_supported_np();
3602#endif
3603
3604 dasm_buf = buf;
3605 dasm_size = size;
3606 dasm_ptr = dasm_end = (void*)(((char*)dasm_buf) + size - sizeof(*dasm_ptr) * 2);
3607
3608#ifdef HAVE_MPROTECT
3609#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
3610 if (zend_write_protect) {
3611 pthread_jit_write_protect_np(1);
3612 }
3613#endif
3615 if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) {
3616 fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3617 }
3618 } else {
3619 if (mprotect(dasm_buf, dasm_size, PROT_READ | PROT_EXEC) != 0) {
3620 fprintf(stderr, "mprotect() failed [%d] %s\n", errno, strerror(errno));
3621 }
3622 }
3623#elif defined(_WIN32)
3625 DWORD old;
3626
3627 if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READWRITE, &old)) {
3628 DWORD err = GetLastError();
3630 fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3632 }
3633 } else {
3634 DWORD old;
3635
3636 if (!VirtualProtect(dasm_buf, dasm_size, PAGE_EXECUTE_READ, &old)) {
3637 DWORD err = GetLastError();
3639 fprintf(stderr, "VirtualProtect() failed [%u] %s\n", err, msg);
3641 }
3642 }
3643#endif
3644
3645 if (!reattached) {
3647 *dasm_ptr = dasm_buf;
3648#if defined(_WIN32)
3649 zend_jit_stub_handlers = dasm_buf;
3650 *dasm_ptr = (void**)*dasm_ptr + sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]);
3651#elif defined(IR_TARGET_AARCH64)
3652 zend_jit_stub_handlers = dasm_buf;
3653 *dasm_ptr = (void**)*dasm_ptr + (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2;
3654 memset(zend_jit_stub_handlers, 0, (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2 * sizeof(void*));
3655#endif
3656 *dasm_ptr = (void*)ZEND_MM_ALIGNED_SIZE_EX(((size_t)(*dasm_ptr)), 16);
3658 } else {
3659#if defined(_WIN32) || defined(IR_TARGET_AARCH64)
3660 zend_jit_stub_handlers = dasm_buf;
3661 zend_jit_init_handlers();
3662#endif
3663 }
3664
3666 zend_jit_setup(reattached);
3668 if (!reattached) {
3669 zend_jit_init_handlers();
3670 }
3671
3672 zend_jit_trace_startup(reattached);
3673
3675 /* save JIT buffer pos */
3676 dasm_ptr[1] = dasm_ptr[0];
3678}
3679
3680void zend_jit_shutdown(void)
3681{
3682 if (JIT_G(debug) & ZEND_JIT_DEBUG_SIZE && dasm_ptr != NULL) {
3683 fprintf(stderr, "\nJIT memory usage: %td\n", (ptrdiff_t)((char*)*dasm_ptr - (char*)dasm_buf));
3684 }
3685
3686 zend_jit_shutdown_ir();
3687
3688#ifdef ZTS
3689 ts_free_id(jit_globals_id);
3690#else
3691 zend_jit_trace_free_caches(&jit_globals);
3692#endif
3693}
3694
3695static void zend_jit_reset_counters(void)
3696{
3697 int i;
3698
3699 for (i = 0; i < ZEND_HOT_COUNTERS_COUNT; i++) {
3701 }
3702}
3703
3704void zend_jit_activate(void)
3705{
3706#ifdef ZTS
3707 if (!zend_jit_startup_ok) {
3708 JIT_G(enabled) = 0;
3709 JIT_G(on) = 0;
3710 return;
3711 }
3712#endif
3714 if (JIT_G(on)) {
3715 if (JIT_G(trigger) == ZEND_JIT_ON_HOT_COUNTERS) {
3716 zend_jit_reset_counters();
3717 } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
3718 zend_jit_reset_counters();
3719 zend_jit_trace_reset_caches();
3720 }
3721 }
3722}
3723
3724void zend_jit_deactivate(void)
3725{
3726 if (zend_jit_profile_counter && !CG(unclean_shutdown)) {
3727 zend_class_entry *ce;
3728
3730 SHM_UNPROTECT();
3732
3733 zend_jit_check_funcs(EG(function_table), 0);
3734 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(EG(class_table), ce) {
3735 if (ce->type == ZEND_INTERNAL_CLASS) {
3736 break;
3737 }
3738 zend_jit_check_funcs(&ce->function_table, 1);
3740
3742 SHM_PROTECT();
3744 }
3745
3747}
3748
3749static void zend_jit_restart_preloaded_op_array(zend_op_array *op_array)
3750{
3751 zend_func_info *func_info = ZEND_FUNC_INFO(op_array);
3752
3753 if (!func_info) {
3754 return;
3755 }
3756
3757 if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_TRACE) {
3758 zend_jit_restart_hot_trace_counters(op_array);
3759 } else if (func_info->flags & ZEND_FUNC_JIT_ON_HOT_COUNTERS) {
3760 zend_jit_restart_hot_counters(op_array);
3761#if 0
3762 // TODO: We have to restore handlers for some inner basic-blocks, but we didn't store them ???
3763 } else if (func_info->flags & (ZEND_FUNC_JIT_ON_FIRST_EXEC|ZEND_FUNC_JIT_ON_PROF_REQUEST)) {
3764 zend_op *opline = op_array->opcodes;
3765 zend_jit_op_array_extension *jit_extension =
3766 (zend_jit_op_array_extension*)func_info;
3767
3768 if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) {
3769 while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) {
3770 opline++;
3771 }
3772 }
3773 if (func_info->flags & ZEND_FUNC_JIT_ON_FIRST_EXEC) {
3774 opline->handler = (const void*)zend_jit_runtime_jit_handler;
3775 } else {
3776 opline->handler = (const void*)zend_jit_profile_jit_handler;
3777 }
3778#endif
3779 }
3780 if (op_array->num_dynamic_func_defs) {
3781 for (uint32_t i = 0; i < op_array->num_dynamic_func_defs; i++) {
3782 zend_jit_restart_preloaded_op_array(op_array->dynamic_func_defs[i]);
3783 }
3784 }
3785}
3786
3787static void zend_jit_restart_preloaded_script(zend_persistent_script *script)
3788{
3789 zend_class_entry *ce;
3790 zend_op_array *op_array;
3791
3792 zend_jit_restart_preloaded_op_array(&script->script.main_op_array);
3793
3794 ZEND_HASH_MAP_FOREACH_PTR(&script->script.function_table, op_array) {
3795 zend_jit_restart_preloaded_op_array(op_array);
3797
3800 if (op_array->type == ZEND_USER_FUNCTION) {
3801 zend_jit_restart_preloaded_op_array(op_array);
3802 }
3805}
3806
3807void zend_jit_restart(void)
3808{
3809 if (dasm_buf) {
3811
3812 /* restore JIT buffer pos */
3813 dasm_ptr[0] = dasm_ptr[1];
3814
3815 zend_jit_trace_restart();
3816
3817 if (ZCSG(preload_script)) {
3818 zend_jit_restart_preloaded_script(ZCSG(preload_script));
3819 if (ZCSG(saved_scripts)) {
3820 zend_persistent_script **p = ZCSG(saved_scripts);
3821
3822 while (*p) {
3823 zend_jit_restart_preloaded_script(*p);
3824 p++;
3825 }
3826 }
3827 }
3828
3830 }
3831}
3832
3833#endif /* HAVE_JIT */
SAPI_API sapi_module_struct sapi_module
Definition SAPI.c:65
#define ACCELERATOR_PRODUCT_NAME
#define ZCSG(element)
#define ZCG(v)
struct _zend_persistent_script zend_persistent_script
#define SHM_PROTECT()
#define SHM_UNPROTECT()
#define ZEND_EXT_API
fprintf($stream, string $format, mixed ... $values)
count(Countable|array $value, int $mode=COUNT_NORMAL)
zend_long ptrdiff_t
#define DWORD
Definition exif.c:1762
zval * zv
Definition ffi.c:3975
zend_long n
Definition ffi.c:4979
new_type size
Definition ffi.c:4365
zend_string * res
Definition ffi.c:4692
char * err
Definition ffi.c:3029
memset(ptr, 0, type->size)
buf start
Definition ffi.c:4687
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define NULL
Definition gdcache.h:45
#define SUCCESS
Definition hash_sha3.c:261
again j
#define IR_UNUSED
Definition ir.h:395
@ IR_VOID
Definition ir.h:151
#define IR_NULL
Definition ir.h:396
int32_t ir_ref
Definition ir.h:390
#define ir_IF_TRUE(_if)
Definition ir_builder.h:594
#define ir_IF(_condition)
Definition ir_builder.h:593
#define ir_TAILCALL(type, func)
Definition ir_builder.h:520
#define ir_IF_FALSE(_if)
Definition ir_builder.h:596
#define ir_LOAD_A(_addr)
Definition ir_builder.h:568
#define ir_RETURN(_val)
Definition ir_builder.h:607
#define ir_CONST_I32(_val)
Definition ir_builder.h:29
#define next(ls)
Definition minilua.c:2661
char * debug
Definition mysqlnd.h:298
char * arena
Definition php_bcmath.h:37
unsigned const char * end
Definition php_ffi.h:51
#define offsetof(STRUCTURE, FIELD)
unsigned char key[REFLECTION_KEY_LEN]
char * msg
Definition phpdbg.h:289
int mprotect(void *addr, size_t size, int protection)
Definition phpdbg_win.c:22
#define PROT_READ
Definition phpdbg_win.h:26
#define PROT_WRITE
Definition phpdbg_win.h:27
p
Definition session.c:1105
uint32_t start
Definition zend_cfg.h:45
uint32_t flags
Definition zend_cfg.h:44
zend_op_array ** op_arrays
zend_op_array * caller_op_array
zend_call_info * next_caller
zend_function * callee_func
zend_call_info * next_callee
uint32_t flags
Definition zend_cfg.h:90
uint32_t * map
Definition zend_cfg.h:89
int blocks_count
Definition zend_cfg.h:85
zend_basic_block * blocks
Definition zend_cfg.h:87
zend_object *(* create_object)(zend_class_entry *class_type)
Definition zend.h:195
struct _zend_class_entry::@126215362204241324314155352336150042254204116267::@166057154351252324007362117353350250255142166322 user
uint32_t num_hooked_props
Definition zend.h:207
HashTable properties_info
Definition zend.h:164
zend_string * filename
Definition zend.h:228
zend_string * name
Definition zend.h:149
union _zend_class_entry::@126215362204241324314155352336150042254204116267 info
uint32_t ce_flags
Definition zend.h:156
char type
Definition zend.h:148
zend_function * constructor
Definition zend.h:172
zend_class_entry * parent
Definition zend.h:152
HashTable function_table
Definition zend.h:163
zend_ssa_var_info return_info
zend_call_info ** call_map
zend_jit_reg_var * ra
ir_ref return_inputs
const zend_op_array * op_array
zend_op_array ** dynamic_func_defs
zend_string * filename
uint32_t line_start
zend_class_entry * scope
zend_op * opcodes
zend_live_range * live_range
zend_string * function_name
uint32_t fn_flags
uint32_t num_dynamic_func_defs
znode_op op1
uint8_t result_type
znode_op op2
znode_op result
uint8_t opcode
uint8_t op1_type
uint32_t extended_value
const void * handler
uint8_t op2_type
zend_function ** hooks
zend_class_entry * ce
HashTable function_table
HashTable class_table
zend_op_array main_op_array
zend_ssa_phi * phis
Definition zend_ssa.h:79
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
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
$obj a
Definition test.php:84
zend_op_array op_array
uint32_t var
uint32_t num
#define errno
PHP_WINUTIL_API char * php_win32_error_to_msg(HRESULT error)
Definition winutil.c:25
PHP_WINUTIL_API void php_win32_error_msg_free(char *msg)
Definition winutil.c:50
ZEND_API bool zend_dtrace_enabled
Definition zend.c:74
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
#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
#define array_init(arg)
Definition zend_API.h:537
#define ZEND_MM_ALIGNED_SIZE_EX(size, alignment)
Definition zend_alloc.h:37
struct _zval_struct zval
strcmp(string $string1, string $string2)
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)
ZEND_API void zend_build_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph)
ZEND_API void zend_analyze_call_graph(zend_arena **arena, zend_script *script, zend_call_graph *call_graph)
struct _zend_call_graph zend_call_graph
ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg)
Definition zend_cfg.c:273
ZEND_API void zend_cfg_build_predecessors(zend_arena **arena, zend_cfg *cfg)
Definition zend_cfg.c:595
ZEND_API void zend_cfg_compute_dominators_tree(const zend_op_array *op_array, zend_cfg *cfg)
Definition zend_cfg.c:676
ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg)
Definition zend_cfg.c:778
struct _zend_basic_block zend_basic_block
#define ZEND_BB_FINALLY
Definition zend_cfg.h:30
#define ZEND_BB_START
Definition zend_cfg.h:23
#define ZEND_CFG_RECV_ENTRY
Definition zend_cfg.h:99
#define ZEND_BB_FINALLY_END
Definition zend_cfg.h:31
#define ZEND_BB_REACHABLE
Definition zend_cfg.h:38
#define ZEND_CFG_NO_ENTRY_PREDECESSORS
Definition zend_cfg.h:98
#define ZEND_BB_EXIT
Definition zend_cfg.h:26
struct _zend_cfg zend_cfg
#define ZEND_CFG_STACKLESS
Definition zend_cfg.h:94
#define ZEND_BB_ENTRY
Definition zend_cfg.h:27
#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_BB_CATCH
Definition zend_cfg.h:29
#define ZEND_BB_RECV_ENTRY
Definition zend_cfg.h:33
#define ZEND_SSA_USE_CV_RESULTS
Definition zend_cfg.h:101
uint32_t num_args
execute_data func
#define ZEND_LIVE_MASK
struct _zend_op zend_op
#define IS_UNUSED
#define ZEND_ACC_FINAL
#define ZEND_ACC_IMMUTABLE
#define IS_CONST
#define ZEND_COMPILE_PRELOAD
#define ZEND_ACC_HAS_TYPE_HINTS
#define IS_SMART_BRANCH_JMPNZ
#define ZEND_INTERNAL_FUNCTION
#define IS_VAR
#define EX_NUM_TO_VAR(n)
#define ZEND_ACC_LINKED
#define ZEND_ACC_TRAIT_CLONE
#define RUN_TIME_CACHE(op_array)
#define IS_SMART_BRANCH_JMPZ
#define ZEND_EVAL_CODE
#define EX(element)
#define ZEND_USER_FUNCTION
#define ZEND_ACC_GENERATOR
struct _zend_op_array zend_op_array
struct _zend_property_info zend_property_info
#define ZEND_ACC_TRAIT
#define RT_CONSTANT(opline, node)
#define ZEND_ACC_STATIC
#define MAX_ARG_FLAG_NUM
#define ZEND_ACC_PUBLIC
#define ZEND_ACC_HAS_RETURN_TYPE
struct _zend_arg_info zend_arg_info
#define OP_JMP_ADDR(opline, node)
#define ZEND_ISEMPTY
#define IS_CV
#define IS_TMP_VAR
struct _zend_live_range zend_live_range
#define ZEND_INTERNAL_CLASS
#define IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE
#define ZEND_ACC_RETURN_REFERENCE
#define ZEND_ACC_PROTECTED
#define ZEND_ACC_CLOSURE
#define ZEND_CONSTANT_FLAGS(c)
#define CONST_PERSISTENT
struct _zend_constant zend_constant
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_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
#define E_WARNING
Definition zend_errors.h:24
ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
ZEND_API void(* zend_execute_ex)(zend_execute_data *execute_data)
ZEND_API void execute_ex(zend_execute_data *execute_data)
ZEND_API int zend_get_op_array_extension_handle(const char *module_name)
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_FUNC_JIT_ON_HOT_COUNTERS
#define ZEND_SET_FUNC_INFO(op_array, info)
#define ZEND_FUNC_IRREDUCIBLE
#define ZEND_FUNC_JIT_ON_FIRST_EXEC
#define CG(v)
#define EG(v)
ZEND_API zval *ZEND_FASTCALL zend_hash_find_known_hash(const HashTable *ht, const zend_string *key)
Definition zend_hash.c:2679
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1326
#define ZEND_HASH_MAP_REVERSE_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1334
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
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 void zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa)
ZEND_API void zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa)
ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
#define OP1_INFO()
#define OP2_MIN_RANGE()
#define OP1_MAX_RANGE()
#define OP2_HAS_RANGE()
#define OP1_MIN_RANGE()
#define OP2_MAX_RANGE()
#define OP1_DATA_INFO()
#define OP1_HAS_RANGE()
#define RES_INFO()
#define OP2_INFO()
#define RES_USE_INFO()
#define OP1_DEF_INFO()
#define MAY_HAVE_DTOR
#define ZEND_INI_STAGE_STARTUP
Definition zend_ini.h:227
#define ZEND_INI_STAGE_RUNTIME
Definition zend_ini.h:231
#define ZEND_JIT_LEVEL_INLINE
Definition zend_jit.h:34
struct _zend_jit_globals zend_jit_globals
#define ZEND_JIT_DEBUG_PERF_DUMP
Definition zend_jit.h:60
#define ZEND_JIT_LEVEL_OPT_SCRIPT
Definition zend_jit.h:37
struct _zend_jit_trace_rec zend_jit_trace_rec
Definition zend_jit.h:99
int zend_jit_script(zend_script *script)
void zend_jit_unprotect(void)
zend_jit_globals jit_globals
#define ZEND_JIT_ON_FIRST_EXEC
Definition zend_jit.h:40
#define ZEND_JIT_CPU_AVX
Definition zend_jit.h:48
int zend_jit_debug_config(zend_long old_val, zend_long new_val, int stage)
void zend_jit_activate(void)
#define ZEND_JIT_LEVEL_OPT_FUNC
Definition zend_jit.h:35
#define ZEND_JIT_ON_HOT_COUNTERS
Definition zend_jit.h:42
#define ZREG_PHI
Definition zend_jit.h:176
#define ZEND_JIT_DEBUG_PERSISTENT
Definition zend_jit.h:87
void zend_jit_protect(void)
void zend_jit_init(void)
#define ZEND_JIT_COUNTER_INIT
Definition zend_jit.h:52
#define ZEND_JIT_REG_ALLOC_LOCAL
Definition zend_jit.h:46
void zend_jit_deactivate(void)
bool zend_jit_startup_ok
#define ZEND_JIT_ON_SCRIPT_LOAD
Definition zend_jit.h:39
#define ZEND_JIT_ON_PROF_REQUEST
Definition zend_jit.h:41
#define ZEND_JIT_ON_HOT_TRACE
Definition zend_jit.h:44
#define ZEND_JIT_LEVEL_OPT_FUNCS
Definition zend_jit.h:36
int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
void zend_jit_shutdown(void)
#define ZEND_JIT_DEBUG_GDB
Definition zend_jit.h:63
#define ZREG_LOAD
Definition zend_jit.h:171
int zend_jit_check_support(void)
#define ZEND_JIT_REG_ALLOC_GLOBAL
Definition zend_jit.h:47
int zend_jit_config(zend_string *jit_options, int stage)
#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
void zend_jit_restart(void)
#define ZREG_PI
Definition zend_jit.h:175
#define ZEND_JIT_DEBUG_SSA
Definition zend_jit.h:55
ZEND_EXT_API void zend_jit_status(zval *ret)
void zend_jit_startup(void *jit_buffer, size_t size, bool reattached)
#define ZEND_JIT_DEBUG_SIZE
Definition zend_jit.h:64
void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
#define Z_LOAD(addr)
#define RES_USE_REG_ADDR()
#define RES_REG_ADDR()
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS)
zend_ulong zend_jit_profile_counter
uintptr_t zend_jit_addr
#define OP1_DEF_REG_ADDR()
#define TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame)
#define Z_MODE(addr)
#define OP1_DATA_DEF_REG_ADDR()
#define ZEND_ADDR_MEM_ZVAL(reg, offset)
#define OP2_REG_ADDR()
#define Z_STORE(addr)
@ ZEND_JIT_TRACE_ENTER
@ ZEND_JIT_TRACE_END
@ ZEND_JIT_TRACE_VM
@ ZEND_JIT_TRACE_BACK
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
int zend_jit_profile_counter_rid
const zend_op * zend_jit_halt_op
#define ZEND_COUNTER_INFO(op_array)
#define OP1_REG_ADDR()
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_ret_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
#define Z_ZV(addr)
#define IS_CONST_ZVAL
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
#define OP2_DEF_REG_ADDR()
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
#define IS_REG
struct _zend_jit_op_array_hot_extension zend_jit_op_array_hot_extension
#define OP1_DATA_REG_ADDR()
#define zend_jit_op_array_hash(op_array)
#define OP_REG_ADDR(opline, ssa_op, type, op, _ssa_op)
#define IS_UNKNOWN
#define ZEND_HOT_COUNTERS_COUNT
struct _zend_jit_op_array_extension zend_jit_op_array_extension
int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT]
#define ZREG_RX
Definition zend_jit_ir.c:58
struct _zend_jit_ctx zend_jit_ctx
struct _zend_jit_reg_var zend_jit_reg_var
int32_t zend_long
Definition zend_long.h:42
#define ZEND_LONG_MIN
Definition zend_long.h:46
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_STRTOL(s0, s1, base)
Definition zend_long.h:85
#define Z_L(i)
Definition zend_long.h:48
#define ZEND_LONG_MAX
Definition zend_long.h:45
struct _zend_string zend_string
#define IS_VALID_PROPERTY_OFFSET(offset)
ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce)
struct _zend_script zend_script
#define ZEND_OPTIMIZER_NARROW_TO_DOUBLE
#define ALLOCA_FLAG(name)
char * alloca()
#define ZEND_FALLTHROUGH
#define ZEND_FASTCALL
#define ZEND_ASSERT(c)
#define ZEND_UNREACHABLE()
#define EMPTY_SWITCH_DEFAULT_CASE()
struct _zend_class_entry zend_class_entry
void zend_shared_alloc_lock(void)
void * zend_shared_alloc_get_xlat_entry(const void *key_pointer)
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 zend_result zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa)
Definition zend_ssa.c:936
ZEND_API void zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa)
Definition zend_ssa.c:1084
struct _zend_ssa_range zend_ssa_range
struct _zend_ssa zend_ssa
struct _zend_ssa_phi zend_ssa_phi
Definition zend_ssa.h:62
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 ZSTR_KNOWN(idx)
#define zend_string_equals_ci(s1, s2)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define zend_string_equals_literal_ci(str, c)
#define MAY_BE_REF
#define MAY_BE_ARRAY_OF_ANY
#define MAY_BE_STRING
#define MAY_BE_RC1
#define MAY_BE_ARRAY_OF_REF
#define MAY_BE_UNDEF
#define MAY_BE_DOUBLE
#define MAY_BE_LONG
#define MAY_BE_ANY
#define MAY_BE_OBJECT
#define MAY_BE_ARRAY_KEY_ANY
#define MAY_BE_RESOURCE
#define MAY_BE_RCN
#define MAY_BE_ARRAY
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZEND_TYPE_PURE_MASK(t)
Definition zend_types.h:257
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
@ FAILURE
Definition zend_types.h:61
#define IS_LONG
Definition zend_types.h:604
#define ZEND_TYPE_IS_ONLY_MASK(t)
Definition zend_types.h:195
#define ZEND_TYPE_IS_SET(t)
Definition zend_types.h:166
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
ZEND_API int zend_vm_kind(void)
ZEND_API const zend_op * zend_get_halt_op(void)
uint32_t call_info
uint32_t arg_num
fbc internal_function handler(call, ret)
bool result
execute_data
zval * ret
zend_execute_data * call
#define ZEND_FE_FREE
#define ZEND_SL
#define ZEND_SEND_VAR_EX
#define ZEND_IS_IDENTICAL
#define ZEND_YIELD
#define ZEND_DECLARE_ANON_CLASS
#define ZEND_FETCH_CONSTANT
#define ZEND_FETCH_THIS
#define ZEND_SWITCH_LONG
#define ZEND_ASSIGN_DIM_OP
#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_THROW
#define ZEND_FE_FETCH_R
#define ZEND_GENERATOR_CREATE
#define ZEND_INIT_USER_CALL
#define ZEND_ROPE_INIT
#define ZEND_FRAMELESS_ICALL_0
#define ZEND_FETCH_LIST_W
#define ZEND_INIT_FCALL
#define ZEND_CALLABLE_CONVERT
#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_FETCH_DIM_FUNC_ARG
#define ZEND_JMP_SET
#define ZEND_POW
#define ZEND_SUB
#define ZEND_JMPZ_EX
#define ZEND_IS_SMALLER
#define ZEND_PRE_INC
#define ZEND_DEFINED
#define ZEND_FRAMELESS_ICALL_1
#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_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_CHECK_FUNC_ARG
#define ZEND_BW_OR
#define ZEND_RECV
#define ZEND_VM_KIND_HYBRID
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_END_SILENCE
#define ZEND_INIT_NS_FCALL_BY_NAME
#define ZEND_JMPNZ_EX
#define ZEND_DO_FCALL
#define ZEND_IN_ARRAY
#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_SEND_USER
#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_BIND_INIT_STATIC_OR_JMP
#define ZEND_BIND_GLOBAL
#define ZEND_BW_AND
#define ZEND_GENERATOR_RETURN
#define ZEND_FETCH_DIM_W
#define ZEND_BEGIN_SILENCE
#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
#define ZEND_ECHO
#define ZEND_SR
#define ZEND_COUNT
#define ZEND_FETCH_DIM_IS
#define ZEND_TYPE_CHECK
#define ZEND_VERIFY_NEVER_TYPE
#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_QM_ASSIGN
#define ZEND_MOD
#define ZEND_CATCH
#define ZEND_ADD
#define ZEND_COALESCE
#define ZEND_ASSIGN_OP
#define ZEND_FETCH_DIM_RW
#define ZEND_MATCH_ERROR
#define ZEND_VM_KIND_CALL
#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)