php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
zend_jit_vm_helpers.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 | Xinchen Hui <laruence@php.net> |
17 +----------------------------------------------------------------------+
18*/
19
20#include "Zend/zend_execute.h"
22#include "Zend/zend_vm.h"
23#include "Zend/zend_closures.h"
24#include "Zend/zend_constants.h"
25#include "Zend/zend_API.h"
26
27#include <ZendAccelerator.h>
30#include "zend_jit.h"
31
32#include "zend_jit_internal.h"
33
34#ifdef HAVE_GCC_GLOBAL_REGS
35# pragma GCC diagnostic ignored "-Wvolatile-register-var"
36# if defined(__x86_64__)
37register zend_execute_data* volatile execute_data __asm__("%r14");
38register const zend_op* volatile opline __asm__("%r15");
39# elif defined(i386)
40register zend_execute_data* volatile execute_data __asm__("%esi");
41register const zend_op* volatile opline __asm__("%edi");
42# elif defined(__aarch64__)
43register zend_execute_data* volatile execute_data __asm__("x27");
44register const zend_op* volatile opline __asm__("x28");
45# endif
46# pragma GCC diagnostic warning "-Wvolatile-register-var"
47#endif
48
50{
51 zend_execute_data *old_execute_data;
52
55 }
56
57 zend_vm_stack_free_extra_args_ex(call_info, execute_data);
62 }
64 zend_free_extra_named_params(EX(extra_named_params));
65 }
66
67 old_execute_data = execute_data;
69 zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
70
71 if (UNEXPECTED(EG(exception) != NULL)) {
72 const zend_op *old_opline = EX(opline);
74 if (old_opline->result_type != IS_UNDEF) {
75 zval_ptr_dtor(EX_VAR(old_opline->result.var));
76 }
77#ifndef HAVE_GCC_GLOBAL_REGS
78 return 2; // ZEND_VM_LEAVE
79#endif
80 } else {
81 EX(opline)++;
82#ifdef HAVE_GCC_GLOBAL_REGS
83 opline = EX(opline);
84#else
85 return 2; // ZEND_VM_LEAVE
86#endif
87 }
88}
89
91{
95 }
96 zend_vm_stack_free_extra_args_ex(call_info, execute_data);
97 }
99 zend_free_extra_named_params(EX(extra_named_params));
100 }
103 }
104 execute_data = EG(current_execute_data);
105#ifdef HAVE_GCC_GLOBAL_REGS
106 opline = zend_jit_halt_op;
107#else
108 return -1; // ZEND_VM_RETURN
109#endif
110}
111
122
123static void ZEND_FASTCALL zend_jit_copy_extra_args_helper_ex(bool skip_recv EXECUTE_DATA_DC)
124{
125 zend_op_array *op_array = &EX(func)->op_array;
126
127 if (EXPECTED(!(op_array->fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))) {
128 uint32_t first_extra_arg = op_array->num_args;
129 uint32_t num_args = EX_NUM_ARGS();
130 zval *end, *src, *dst;
131 uint32_t type_flags = 0;
132
133 if (skip_recv && EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) {
134 /* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
135#ifdef HAVE_GCC_GLOBAL_REGS
136 opline += first_extra_arg;
137#else
138 EX(opline) += first_extra_arg;
139#endif
140 }
141
142 /* move extra args into separate array after all CV and TMP vars */
143 end = EX_VAR_NUM(first_extra_arg - 1);
144 src = end + (num_args - first_extra_arg);
145 dst = src + (op_array->last_var + op_array->T - first_extra_arg);
146 if (EXPECTED(src != dst)) {
147 do {
148 type_flags |= Z_TYPE_INFO_P(src);
149 ZVAL_COPY_VALUE(dst, src);
150 ZVAL_UNDEF(src);
151 src--;
152 dst--;
153 } while (src != end);
154 if (type_flags & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) {
156 }
157 } else {
158 do {
159 if (Z_REFCOUNTED_P(src)) {
161 break;
162 }
163 src--;
164 } while (src != end);
165 }
166 }
167}
168
170{
171 zend_jit_copy_extra_args_helper_ex(true EXECUTE_DATA_CC);
172}
173
175{
176 zend_jit_copy_extra_args_helper_ex(false EXECUTE_DATA_CC);
177}
178
180{
182 zend_function *fbc = call->func;
183
185
186 if (EG(exception)) {
187#ifndef HAVE_GCC_GLOBAL_REGS
188 zend_execute_data *execute_data = EG(current_execute_data);
189#endif
190 const zend_op *opline = EG(opline_before_exception);
191 if (opline && RETURN_VALUE_USED(opline)) {
192 ZVAL_UNDEF(EX_VAR(opline->result.var));
193 }
194
195 zend_vm_stack_free_args(call);
196
198 OBJ_RELEASE(Z_OBJ(call->This));
199 }
200
201 zend_vm_stack_free_call_frame(call);
202 return 0;
203 }
204 return 1;
205}
206
208{
209 const zend_op *opline = EX(opline);
210 zval *result = EX_VAR(opline->result.var);
211 zval *dim;
212
213 if (opline->op2_type == IS_CONST) {
214 dim = RT_CONSTANT(opline, opline->op2);
215 } else {
216 dim = EX_VAR(opline->op2.var);
217 }
219 zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, Z_LVAL_P(dim));
221}
222
224{
225 const zend_op *opline = EX(opline);
226 zval *result = EX_VAR(opline->result.var);
227
228 zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, key);
230}
231
233{
234 const zend_op *opline = EX(opline);
235 zval *result = EX_VAR(opline->result.var);
236 zval *dim;
237 zend_ulong lval;
238
239 if (opline->op2_type == IS_CONST) {
240 dim = RT_CONSTANT(opline, opline->op2);
241 } else {
242 dim = EX_VAR(opline->op2.var);
243 }
245 if (ZEND_HANDLE_NUMERIC(Z_STR_P(dim), lval)) {
246 zend_error(E_WARNING, "Undefined array key " ZEND_LONG_FMT, lval);
247 } else {
248 zend_error(E_WARNING, "Undefined array key \"%s\"", Z_STRVAL_P(dim));
249 }
251}
252
262
264{
265 zend_jit_op_array_hot_extension *jit_extension =
267#ifndef HAVE_GCC_GLOBAL_REGS
268 const zend_op *opline = EX(opline);
269#endif
270
271 *(jit_extension->counter) -= ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func));
272
273 if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
274 *(jit_extension->counter) = ZEND_JIT_COUNTER_INIT;
277 } else {
278 zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
280 }
281}
282
284{
285 zend_jit_op_array_hot_extension *jit_extension =
287#ifndef HAVE_GCC_GLOBAL_REGS
288 const zend_op *opline = EX(opline);
289#endif
290
291 *(jit_extension->counter) -= ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop));
292
293 if (UNEXPECTED(*(jit_extension->counter) <= 0)) {
294 *(jit_extension->counter) = ZEND_JIT_COUNTER_INIT;
297 } else {
298 zend_vm_opcode_handler_t handler = (zend_vm_opcode_handler_t)jit_extension->orig_handlers[opline - EX(func)->op_array.opcodes];
300 }
301}
302
303static zend_always_inline zend_constant* _zend_quick_get_constant(
304 const zval *key, uint32_t flags, int check_defined_only)
305{
306#ifndef HAVE_GCC_GLOBAL_REGS
307 zend_execute_data *execute_data = EG(current_execute_data);
308#endif
309 const zend_op *opline = EX(opline);
310 zval *zv;
311 zend_constant *c = NULL;
312
313 /* null/true/false are resolved during compilation, so don't check for them here. */
314 zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
315 if (zv) {
316 c = (zend_constant*)Z_PTR_P(zv);
318 key++;
319 zv = zend_hash_find_known_hash(EG(zend_constants), Z_STR_P(key));
320 if (zv) {
321 c = (zend_constant*)Z_PTR_P(zv);
322 }
323 }
324
325 if (!c) {
326 if (!check_defined_only) {
327 zend_throw_error(NULL, "Undefined constant \"%s\"", Z_STRVAL_P(RT_CONSTANT(opline, opline->op2)));
328 ZVAL_UNDEF(EX_VAR(opline->result.var));
329 }
330 CACHE_PTR(opline->extended_value, ENCODE_SPECIAL_CACHE_NUM(zend_hash_num_elements(EG(zend_constants))));
331 return NULL;
332 }
333
334 if (!check_defined_only) {
336 zend_error(E_DEPRECATED, "Constant %s is deprecated", ZSTR_VAL(c->name));
337 if (EG(exception)) {
338 return NULL;
339 }
340 return c;
341 }
342 }
343
344 CACHE_PTR(opline->extended_value, c);
345 return c;
346}
347
349{
350 return _zend_quick_get_constant(key, flags, 0);
351}
352
354{
355 return _zend_quick_get_constant(key, 0, 1);
356}
357
358static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_trace_counter_helper(uint32_t cost ZEND_OPCODE_HANDLER_ARGS_DC)
359{
360 zend_jit_op_array_trace_extension *jit_extension =
362 size_t offset = jit_extension->offset;
363#ifndef HAVE_GCC_GLOBAL_REGS
364 const zend_op *opline = EX(opline);
365#endif
366
367 *(ZEND_OP_TRACE_INFO(opline, offset)->counter) -= cost;
368
369 if (UNEXPECTED(*(ZEND_OP_TRACE_INFO(opline, offset)->counter) <= 0)) {
370 *(ZEND_OP_TRACE_INFO(opline, offset)->counter) = ZEND_JIT_COUNTER_INIT;
372#ifdef HAVE_GCC_GLOBAL_REGS
373 opline = NULL;
374 return;
375#else
376 return -1;
377#endif
378 }
379#ifdef HAVE_GCC_GLOBAL_REGS
380 execute_data = EG(current_execute_data);
381 opline = execute_data ? EX(opline) : NULL;
382 return;
383#else
384 return 1;
385#endif
386 } else {
389 }
390}
391
397
399{
400 ZEND_OPCODE_TAIL_CALL_EX(zend_jit_trace_counter_helper,
401 ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return)));
402}
403
409
410#define TRACE_RECORD(_op, _info, _ptr) \
411 trace_buffer[idx].info = _op | (_info); \
412 trace_buffer[idx].ptr = _ptr; \
413 idx++; \
414 if (idx >= JIT_G(max_trace_length) - 2) { \
415 stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
416 break; \
417 }
418
419#define TRACE_RECORD_VM(_op, _ptr, _op1_type, _op2_type, _op3_type) \
420 trace_buffer[idx].op = _op; \
421 trace_buffer[idx].op1_type = _op1_type; \
422 trace_buffer[idx].op2_type = _op2_type; \
423 trace_buffer[idx].op3_type = _op3_type; \
424 trace_buffer[idx].ptr = _ptr; \
425 idx++; \
426 if (idx >= JIT_G(max_trace_length) - 2) { \
427 stop = ZEND_JIT_TRACE_STOP_TOO_LONG; \
428 break; \
429 }
430
431#define TRACE_START(_op, _start, _ptr1, _ptr2) \
432 trace_buffer[0].op = _op; \
433 trace_buffer[0].start = _start; \
434 trace_buffer[0].level = 0; \
435 trace_buffer[0].ptr = _ptr1; \
436 trace_buffer[1].last = 0; \
437 trace_buffer[1].ptr = _ptr2; \
438 idx = ZEND_JIT_TRACE_START_REC_SIZE;
439
440#define TRACE_END(_op, _stop, _ptr) \
441 trace_buffer[1].last = idx; \
442 trace_buffer[idx].op = _op; \
443 trace_buffer[idx].start = trace_buffer[idx].start; \
444 trace_buffer[idx].stop = trace_buffer[0].stop = _stop; \
445 trace_buffer[idx].level = trace_buffer[0].level = ret_level ? ret_level + 1 : 0; \
446 trace_buffer[idx].ptr = _ptr;
447
448static int zend_jit_trace_recursive_call_count(const zend_op_array *op_array, const zend_op_array **unrolled_calls, int ret_level, int level)
449{
450 int i;
451 int count = 0;
452
453 for (i = ret_level; i < level; i++) {
454 count += (unrolled_calls[i] == op_array);
455 }
456 return count;
457}
458
459static int zend_jit_trace_recursive_ret_count(const zend_op_array *op_array, const zend_op_array **unrolled_calls, int ret_level)
460{
461 int i;
462 int count = 0;
463
464 for (i = 0; i < ret_level; i++) {
465 count += (unrolled_calls[i] == op_array);
466 }
467 return count;
468}
469
470static int zend_jit_trace_has_recursive_ret(zend_execute_data *ex, const zend_op_array *orig_op_array, const zend_op *orig_opline, int ret_level)
471{
472 while (ex != NULL && ex->func != NULL && ret_level < ZEND_JIT_TRACE_MAX_RET_DEPTH) {
473 if (&ex->func->op_array == orig_op_array && ex->opline + 1 == orig_opline) {
474 return 1;
475 }
476 ex = ex->prev_execute_data;
477 ret_level++;
478 }
479 return 0;
480}
481
482static uint8_t zend_jit_trace_bad_stop_event(const zend_op *opline, int count)
483{
484 const zend_op **cache_opline = JIT_G(bad_root_cache_opline);
485 uint8_t *cache_count = JIT_G(bad_root_cache_count);
486 uint8_t *cache_stop = JIT_G(bad_root_cache_stop);
487 uint32_t i;
488
489 if (count < 0) {
490 count = 0;
491 }
492 for (i = 0; i < ZEND_JIT_TRACE_BAD_ROOT_SLOTS; i++) {
493 if (cache_opline[i] == opline) {
494 if (cache_count[i] >= count) {
495 return cache_stop[i];
496 }
497 break;
498 }
499 }
500 return 0;
501}
502
503#define ZEND_CALL_MEGAMORPHIC ZEND_CALL_JIT_RESERVED
504
505static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic, uint32_t init_level)
506{
507 zend_jit_trace_stop stop ZEND_ATTRIBUTE_UNUSED = ZEND_JIT_TRACE_STOP_ERROR;
508
509 do {
512
513 if (call->prev_execute_data) {
514 idx = zend_jit_trace_record_fake_init_call_ex(call->prev_execute_data, trace_buffer, idx, is_megamorphic, init_level + 1);
515 if (idx < 0) {
516 return idx;
517 }
518 }
519
520 func = call->func;
521 if (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE|ZEND_ACC_NEVER_CACHE)) {
522 /* TODO: Can we continue recording ??? */
523 return -1;
524 }
525 /* Function is a property hook. */
526 if (func->common.prop_info) {
527 /* TODO: Can we continue recording ??? */
528 return -1;
529 }
530 if (func->type == ZEND_INTERNAL_FUNCTION
531 && (func->op_array.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE))) {
532 return -1;
533 }
534 if (func->type == ZEND_USER_FUNCTION) {
535 jit_extension =
537 if (UNEXPECTED(!jit_extension && (func->op_array.fn_flags & ZEND_ACC_CLOSURE))
538 || (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE))
539 || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
540 return -1;
541 }
542 if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) {
543 func = (zend_function*)jit_extension->op_array;
544 }
545 }
546 if (is_megamorphic == ZEND_JIT_EXIT_POLYMORPHISM
547 /* TODO: use more accurate check ??? */
549 || func->common.scope)) {
550 func = NULL;
552 }
554 } while (0);
555 return idx;
556}
557
558static int zend_jit_trace_record_fake_init_call(zend_execute_data *call, zend_jit_trace_rec *trace_buffer, int idx, uint32_t is_megamorphic)
559{
560 return zend_jit_trace_record_fake_init_call_ex(call, trace_buffer, idx, is_megamorphic, 0);
561}
562
563static int zend_jit_trace_subtrace(zend_jit_trace_rec *trace_buffer, int start, int end, uint8_t event, const zend_op_array *op_array, const zend_op *opline)
564{
565 int idx;
566
567 TRACE_START(ZEND_JIT_TRACE_START, event, op_array, opline);
568 memmove(trace_buffer + idx, trace_buffer + start, (end - start) * sizeof(zend_jit_trace_rec));
569 return idx + (end - start);
570}
571
572/*
573 * Trace Linking Rules
574 * ===================
575 *
576 * flags
577 * +----------+----------+----------++----------+----------+----------+
578 * | || JIT |
579 * +----------+----------+----------++----------+----------+----------+
580 * start | LOOP | ENTER | RETURN || LOOP | ENTER | RETURN |
581 * +========+==========+==========+==========++==========+==========+==========+
582 * | LOOP | loop | | loop-ret || COMPILED | LINK | LINK |
583 * +--------+----------+----------+----------++----------+----------+----------+
584 * | ENTER |INNER_LOOP| rec-call | return || LINK | LINK | LINK |
585 * +--------+----------+----------+----------++----------+----------+----------+
586 * | RETURN |INNER_LOOP| | rec-ret || LINK | | LINK |
587 * +--------+----------+----------+----------++----------+----------+----------+
588 * | SIDE | unroll | | side-ret || LINK | LINK | LINK |
589 * +--------+----------+----------+----------++----------+----------+----------+
590 *
591 * loop: LOOP if "cycle" and level == 0, otherwise INNER_LOOP
592 * INNER_LOOP: abort recording and start new one (wait for loop)
593 * COMPILED: abort recording (wait while side exit creates outer loop)
594 * unroll: continue recording while unroll limit reached
595 * rec-call: RECURSIVE_CALL if "cycle" and level > N, otherwise continue
596 * loop-ret: LOOP_EXIT if level == 0, otherwise continue (wait for loop)
597 * return: RETURN if level == 0
598 * rec_ret: RECURSIVE_RET if "cycle" and ret_level > N, otherwise continue
599 * side_ret: RETURN if level == 0 && ret_level == ret_depth, otherwise continue
600 *
601 */
602
604 const zend_op *op,
605 zend_jit_trace_rec *trace_buffer,
606 uint8_t start,
607 uint32_t is_megamorphic,
608 int ret_depth)
609
610{
611#ifdef HAVE_GCC_GLOBAL_REGS
612 zend_execute_data *save_execute_data = execute_data;
613 const zend_op *save_opline = opline;
614#endif
615 const zend_op *orig_opline, *end_opline;
616 zend_jit_trace_stop stop = ZEND_JIT_TRACE_STOP_ERROR;
617 zend_jit_trace_stop halt = 0;
618 int level = 0;
619 int ret_level = 0;
621 const zend_op_array *op_array;
623 size_t offset;
624 int idx, count;
625 uint8_t trace_flags, op1_type, op2_type, op3_type;
626 zend_class_entry *ce1, *ce2;
627 const zend_op *link_to_enter_opline = NULL;
628 int backtrack_link_to_enter = -1;
629 int backtrack_recursion = -1;
630 int backtrack_ret_recursion = -1;
631 int backtrack_ret_recursion_level = 0;
632 int loop_unroll_limit = 0;
633 int last_loop = -1;
634 int last_loop_level = -1;
635 const zend_op *last_loop_opline = NULL;
637#ifdef HAVE_GCC_GLOBAL_REGS
639
641 opline = EX(opline) = op;
642#else
643 int rc;
645 const zend_op *opline = EX(opline);
646#endif
647 zend_execute_data *prev_call = EX(call);
648
649 orig_opline = opline;
650
651 op_array = &EX(func)->op_array;
652 jit_extension =
654 offset = jit_extension->offset;
655 if (!op_array->function_name
656 || (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
657 op_array = jit_extension->op_array;
658 }
659
660 TRACE_START(ZEND_JIT_TRACE_START, start, op_array, opline);
661
662 if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) {
663 /* Abort trace because of exception */
664 TRACE_END(ZEND_JIT_TRACE_END, ZEND_JIT_TRACE_STOP_EXCEPTION, opline);
665#ifdef HAVE_GCC_GLOBAL_REGS
666 execute_data = save_execute_data;
667 opline = save_opline;
668#endif
669 return ZEND_JIT_TRACE_STOP_EXCEPTION;
670 }
671
672 trace_flags = ZEND_OP_TRACE_INFO(opline, offset)->trace_flags;
673 if (trace_flags & ZEND_JIT_TRACE_UNSUPPORTED) {
674 TRACE_END(ZEND_JIT_TRACE_END, ZEND_JIT_TRACE_STOP_NOT_SUPPORTED, opline);
675#ifdef HAVE_GCC_GLOBAL_REGS
676 execute_data = save_execute_data;
677 opline = save_opline;
678#endif
679 return ZEND_JIT_TRACE_STOP_NOT_SUPPORTED;
680 }
681
682 if (prev_call) {
683 int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, is_megamorphic);
684 if (ret < 0) {
685 TRACE_END(ZEND_JIT_TRACE_END, ZEND_JIT_TRACE_STOP_BAD_FUNC, opline);
686#ifdef HAVE_GCC_GLOBAL_REGS
687 execute_data = save_execute_data;
688 opline = save_opline;
689#endif
690 return ZEND_JIT_TRACE_STOP_BAD_FUNC;
691 }
692 idx = ret;
693 }
694
695 while (1) {
696 ce1 = ce2 = NULL;
697 op1_type = op2_type = op3_type = IS_UNKNOWN;
698 if ((opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV))
699 && opline->opcode != ZEND_ROPE_ADD
700 && opline->opcode != ZEND_ROPE_END
701 && opline->opcode != ZEND_NEW
703 && opline->opcode != ZEND_INIT_STATIC_METHOD_CALL) {
704 zval *zv = EX_VAR(opline->op1.var);
705 op1_type = Z_TYPE_P(zv);
706 uint8_t flags = 0;
707
708 if (op1_type == IS_INDIRECT) {
709 zv = Z_INDIRECT_P(zv);
710 op1_type = Z_TYPE_P(zv);
712 }
713 if (op1_type == IS_REFERENCE) {
714 zv = Z_REFVAL_P(zv);
715 op1_type = Z_TYPE_P(zv);
717 }
718 if (Z_TYPE_P(zv) == IS_OBJECT) {
719 ce1 = Z_OBJCE_P(zv);
720 } else if (Z_TYPE_P(zv) == IS_ARRAY) {
721 if (HT_IS_PACKED(Z_ARRVAL_P(zv))) {
723 }
724 }
725 op1_type |= flags;
726 } else if (opline->op1_type == IS_UNUSED && (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
727 uint32_t op1_flags = ZEND_VM_OP1_FLAGS(zend_get_opcode_flags(opline->opcode));
728 if ((op1_flags & ZEND_VM_OP_MASK) == ZEND_VM_OP_THIS) {
729 op1_type = IS_OBJECT;
730 ce1 = Z_OBJCE(EX(This));
731 }
732 }
733 if (opline->op2_type & (IS_TMP_VAR|IS_VAR|IS_CV)
734 && opline->opcode != ZEND_INSTANCEOF
735 && opline->opcode != ZEND_UNSET_STATIC_PROP
737 && opline->opcode != ZEND_ASSIGN_STATIC_PROP
740 && opline->opcode != ZEND_PRE_INC_STATIC_PROP
742 && opline->opcode != ZEND_PRE_DEC_STATIC_PROP
744 && opline->opcode != ZEND_FETCH_STATIC_PROP_R
745 && opline->opcode != ZEND_FETCH_STATIC_PROP_W
750 && (opline->op2_type == IS_CV
751 || (opline->opcode != ZEND_FE_FETCH_R
752 && opline->opcode != ZEND_FE_FETCH_RW))) {
753 zval *zv = EX_VAR(opline->op2.var);
754 uint8_t flags = 0;
755
756 op2_type = Z_TYPE_P(zv);
757 if (op2_type == IS_INDIRECT) {
758 zv = Z_INDIRECT_P(zv);
759 op2_type = Z_TYPE_P(zv);
761 }
762 if (op2_type == IS_REFERENCE) {
763 zv = Z_REFVAL_P(zv);
764 op2_type = Z_TYPE_P(zv);
766 }
767 if (Z_TYPE_P(zv) == IS_OBJECT) {
768 ce2 = Z_OBJCE_P(zv);
769 }
770 op2_type |= flags;
771 }
772 if (opline->opcode == ZEND_ASSIGN_DIM ||
773 opline->opcode == ZEND_ASSIGN_OBJ ||
774 opline->opcode == ZEND_ASSIGN_STATIC_PROP ||
775 opline->opcode == ZEND_ASSIGN_DIM_OP ||
776 opline->opcode == ZEND_ASSIGN_OBJ_OP ||
778 opline->opcode == ZEND_ASSIGN_OBJ_REF ||
780 if ((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
781 zval *zv = EX_VAR((opline+1)->op1.var);
782 uint8_t flags = 0;
783
784 op3_type = Z_TYPE_P(zv);
785 if (op3_type == IS_INDIRECT) {
786 zv = Z_INDIRECT_P(zv);
787 op3_type = Z_TYPE_P(zv);
789 }
790 if (op3_type == IS_REFERENCE) {
791 zv = Z_REFVAL_P(zv);
792 op3_type = Z_TYPE_P(zv);
794 }
795 op3_type |= flags;
796 }
797 }
798
799 TRACE_RECORD_VM(ZEND_JIT_TRACE_VM, opline, op1_type, op2_type, op3_type);
800
801 if (ce1) {
803 }
804
805 if (ce2) {
807 }
808
809 switch (opline->opcode) {
810 case ZEND_FETCH_DIM_R:
811 case ZEND_FETCH_DIM_W:
818 case ZEND_ASSIGN_DIM:
820 case ZEND_UNSET_DIM:
822 if (opline->op1_type == IS_CONST) {
823 zval *arr = RT_CONSTANT(opline, opline->op1);
824 op1_type = Z_TYPE_P(arr);
825 }
826 if ((op1_type & IS_TRACE_TYPE_MASK) == IS_ARRAY
827 && opline->op2_type != IS_UNDEF) {
828 zval *arr, *dim, *val;
829 uint8_t val_type = IS_UNDEF;
830
831 if (opline->op2_type == IS_CONST) {
832 dim = RT_CONSTANT(opline, opline->op2);
833 } else {
834 dim = EX_VAR(opline->op2.var);
835 }
836
837 if (Z_TYPE_P(dim) == IS_LONG || Z_TYPE_P(dim) == IS_STRING) {
838 if (opline->op1_type == IS_CONST) {
839 arr = RT_CONSTANT(opline, opline->op1);
840 } else {
841 arr = EX_VAR(opline->op1.var);
842 }
843 if (Z_TYPE_P(arr) == IS_INDIRECT) {
844 arr = Z_INDIRECT_P(arr);
845 }
846 if (Z_TYPE_P(arr) == IS_REFERENCE) {
847 arr = Z_REFVAL_P(arr);
848 }
850 if (Z_TYPE_P(dim) == IS_LONG) {
852 } else /*if Z_TYPE_P(dim) == IS_STRING)*/ {
853 val = zend_symtable_find(Z_ARRVAL_P(arr), Z_STR_P(dim));
854 }
855 if (val) {
857 }
859 }
860 }
861 break;
862 case ZEND_FETCH_OBJ_R: {
863 if (opline->op2_type == IS_CONST) {
864 /* Remove the SIMPLE_GET flag to avoid inlining hooks. */
865 void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_REF);
866 uintptr_t prop_offset = (uintptr_t)CACHED_PTR_EX(cache_slot + 1);
867 if (IS_HOOKED_PROPERTY_OFFSET(prop_offset)) {
868 CACHE_PTR_EX(cache_slot + 1, (void*)((uintptr_t)CACHED_PTR_EX(cache_slot + 1) & ~ZEND_PROPERTY_HOOK_SIMPLE_GET_BIT)); \
869 }
870 }
872 }
873 case ZEND_FETCH_OBJ_W:
878 case ZEND_ASSIGN_OBJ:
881 case ZEND_UNSET_OBJ:
883 case ZEND_PRE_INC_OBJ:
884 case ZEND_PRE_DEC_OBJ:
887 if (opline->op1_type != IS_CONST
888 && opline->op2_type == IS_CONST
889 && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING
890 && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') {
891 zval *obj, *val;
892 zend_string *prop_name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
894
895 if (opline->op1_type == IS_UNUSED) {
896 obj = &EX(This);
897 } else {
898 obj = EX_VAR(opline->op1.var);
899 }
900 if (Z_TYPE_P(obj) != IS_OBJECT
901 || Z_OBJ_P(obj)->handlers != &std_object_handlers) {
902 break;
903 }
904 prop_info = zend_get_property_info(Z_OBJCE_P(obj), prop_name, 1);
905 if (prop_info
907 && !prop_info->hooks
908 && !(prop_info->flags & ZEND_ACC_STATIC)) {
909 val = OBJ_PROP(Z_OBJ_P(obj), prop_info->offset);
911 }
912 }
913 break;
914 default:
915 break;
916 }
917
918 if (opline->opcode == ZEND_DO_FCALL
919 || opline->opcode == ZEND_DO_ICALL
920 || opline->opcode == ZEND_DO_UCALL
921 || opline->opcode == ZEND_DO_FCALL_BY_NAME) {
923 stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
924 break;
925 }
926 if (EX(call)->func->type == ZEND_INTERNAL_FUNCTION) {
927 if (EX(call)->func->op_array.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) {
928 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
929 break;
930 }
932 }
933 } else if (opline->opcode == ZEND_INCLUDE_OR_EVAL
934 || opline->opcode == ZEND_CALLABLE_CONVERT) {
935 /* TODO: Support tracing JIT for ZEND_CALLABLE_CONVERT. */
936 stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
937 break;
938 }
939
941#ifdef HAVE_GCC_GLOBAL_REGS
942 handler();
943 if (UNEXPECTED(opline == zend_jit_halt_op)) {
944 stop = ZEND_JIT_TRACE_STOP_RETURN;
945 opline = NULL;
946 halt = ZEND_JIT_TRACE_HALT;
947 break;
948 }
950#else
952 if (rc != 0) {
953 if (rc < 0) {
954 stop = ZEND_JIT_TRACE_STOP_RETURN;
955 opline = NULL;
956 halt = ZEND_JIT_TRACE_HALT;
957 break;
958 } else if (execute_data == EG(current_execute_data)) {
959 /* return after interrupt handler */
960 rc = 0;
961 }
962 execute_data = EG(current_execute_data);
963 opline = EX(opline);
964#endif
965
966 op_array = &EX(func)->op_array;
967 jit_extension =
969 if (UNEXPECTED(!jit_extension)
970 || UNEXPECTED(!(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE))) {
971#ifdef HAVE_GCC_GLOBAL_REGS
972 if (execute_data->prev_execute_data != prev_execute_data) {
973#else
974 if (rc < 0) {
975#endif
976 stop = ZEND_JIT_TRACE_STOP_RETURN;
977 } else {
978 stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
979 }
980 break;
981 }
982 offset = jit_extension->offset;
983 if (!op_array->function_name
984 || (op_array->fn_flags & ZEND_ACC_CLOSURE)) {
985 op_array = jit_extension->op_array;
986 }
987
988#ifdef HAVE_GCC_GLOBAL_REGS
989 if (execute_data->prev_execute_data == prev_execute_data) {
990#else
991 if (rc == 0) {
992 /* pass */
993 } else if (rc == 1) {
994#endif
995 /* Enter into function */
996 prev_call = NULL;
997 if (level > ZEND_JIT_TRACE_MAX_CALL_DEPTH) {
998 stop = ZEND_JIT_TRACE_STOP_TOO_DEEP;
999 break;
1000 }
1001
1002 if (EX(func)->op_array.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
1003 /* TODO: Can we continue recording ??? */
1004 stop = ZEND_JIT_TRACE_STOP_TRAMPOLINE;
1005 break;
1006 }
1007
1008 if (EX(func)->op_array.prop_info) {
1009 /* TODO: Can we continue recording ??? */
1010 stop = ZEND_JIT_TRACE_STOP_PROP_HOOK_CALL;
1011 break;
1012 }
1013
1016 op_array);
1017
1018 count = zend_jit_trace_recursive_call_count(&EX(func)->op_array, unrolled_calls, ret_level, level);
1019
1020 if (opline == orig_opline) {
1021 if (count + 1 >= JIT_G(max_recursive_calls)) {
1022 stop = ZEND_JIT_TRACE_STOP_RECURSIVE_CALL;
1023 break;
1024 }
1025 backtrack_recursion = idx;
1026 } else if (count >= JIT_G(max_recursive_calls)) {
1027 stop = ZEND_JIT_TRACE_STOP_DEEP_RECURSION;
1028 break;
1029 }
1030
1031 unrolled_calls[ret_level + level] = &EX(func)->op_array;
1032 level++;
1033 } else {
1034 /* Return from function */
1035 prev_call = EX(call);
1036 if (level == 0) {
1038 && JIT_G(max_recursive_returns) > 0
1039 && execute_data->prev_execute_data
1040 && execute_data->prev_execute_data->func
1041 && execute_data->prev_execute_data->func->type == ZEND_USER_FUNCTION
1042 && zend_jit_trace_has_recursive_ret(execute_data, trace_buffer[0].op_array, orig_opline, ret_level)) {
1043 if (ret_level > ZEND_JIT_TRACE_MAX_RET_DEPTH) {
1044 stop = ZEND_JIT_TRACE_STOP_TOO_DEEP_RET;
1045 break;
1046 }
1047 TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, op_array);
1048 count = zend_jit_trace_recursive_ret_count(&EX(func)->op_array, unrolled_calls, ret_level);
1049 if (opline == orig_opline) {
1050 if (count + 1 >= JIT_G(max_recursive_returns)) {
1051 stop = ZEND_JIT_TRACE_STOP_RECURSIVE_RET;
1052 break;
1053 }
1054 backtrack_ret_recursion = idx;
1055 backtrack_ret_recursion_level = ret_level;
1056 } else if (count >= JIT_G(max_recursive_returns)) {
1057 stop = ZEND_JIT_TRACE_STOP_DEEP_RECURSION;
1058 break;
1059 }
1060
1061 unrolled_calls[ret_level] = &EX(func)->op_array;
1062 ret_level++;
1063 last_loop_opline = NULL;
1064
1065 if (prev_call) {
1066 int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, 0);
1067 if (ret < 0) {
1068 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
1069 break;
1070 }
1071 idx = ret;
1072 }
1073 } else if (start & ZEND_JIT_TRACE_START_LOOP
1074 && zend_jit_trace_bad_stop_event(orig_opline, JIT_G(blacklist_root_trace) - 1) !=
1075 ZEND_JIT_TRACE_STOP_LOOP_EXIT) {
1076 /* Fail to try close the loop.
1077 If this doesn't work terminate it. */
1078 stop = ZEND_JIT_TRACE_STOP_LOOP_EXIT;
1079 break;
1083 && zend_jit_trace_bad_stop_event(orig_opline, JIT_G(blacklist_root_trace) - 1) !=
1084 ZEND_JIT_TRACE_STOP_RECURSION_EXIT) {
1085 stop = ZEND_JIT_TRACE_STOP_RECURSION_EXIT;
1086 break;
1087 } else if ((start & ZEND_JIT_TRACE_START_SIDE)
1088 && ret_level < ret_depth) {
1089 TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, op_array);
1090 ret_level++;
1091 last_loop_opline = NULL;
1092
1093 if (prev_call) {
1094 int ret = zend_jit_trace_record_fake_init_call(prev_call, trace_buffer, idx, 0);
1095 if (ret < 0) {
1096 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
1097 break;
1098 }
1099 idx = ret;
1100 }
1101 } else {
1102 stop = ZEND_JIT_TRACE_STOP_RETURN;
1103 break;
1104 }
1105 } else {
1106 level--;
1107 if (level < last_loop_level) {
1108 last_loop_opline = NULL;
1109 }
1110 TRACE_RECORD(ZEND_JIT_TRACE_BACK, 0, op_array);
1111 }
1112 }
1113#ifdef HAVE_GCC_GLOBAL_REGS
1115#endif
1116 }
1117 if (EX(call) != prev_call) {
1118 if (EX(call)
1119 && EX(call)->prev_execute_data == prev_call) {
1121 zend_jit_op_array_trace_extension *jit_extension;
1122
1123 if (EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
1124 /* TODO: Can we continue recording ??? */
1125 stop = ZEND_JIT_TRACE_STOP_TRAMPOLINE;
1126 break;
1127 } else if (EX(call)->func->common.fn_flags & ZEND_ACC_NEVER_CACHE) {
1128 /* TODO: Can we continue recording ??? */
1129 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
1130 break;
1131 } else if (EX(call)->func->common.prop_info) {
1132 /* TODO: Can we continue recording ??? */
1133 stop = ZEND_JIT_TRACE_STOP_PROP_HOOK_CALL;
1134 break;
1135 }
1136 func = EX(call)->func;
1137 if (func->type == ZEND_INTERNAL_FUNCTION
1138 && (func->op_array.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE))) {
1139 stop = ZEND_JIT_TRACE_STOP_BAD_FUNC;
1140 break;
1141 }
1142 if (func->type == ZEND_USER_FUNCTION) {
1143 jit_extension =
1145 if (UNEXPECTED(!jit_extension && (func->op_array.fn_flags & ZEND_ACC_CLOSURE))
1146 || (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE))
1147 || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
1148 stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
1149 break;
1150 }
1151 if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) {
1152 func = (zend_function*)jit_extension->op_array;
1153 }
1154 }
1155
1156#ifndef HAVE_GCC_GLOBAL_REGS
1157 opline = EX(opline);
1158#endif
1159
1160 if (JIT_G(max_polymorphic_calls) == 0
1161 && zend_jit_may_be_polymorphic_call(opline - 1)) {
1162 func = NULL;
1163 } else if ((is_megamorphic == ZEND_JIT_EXIT_METHOD_CALL
1164 || is_megamorphic == ZEND_JIT_EXIT_CLOSURE_CALL)
1165 && trace_buffer[1].opline == opline - 1) {
1166 func = NULL;
1167 }
1168 if (!func) {
1170 }
1172 }
1173 prev_call = EX(call);
1174 }
1175
1176#ifndef HAVE_GCC_GLOBAL_REGS
1177 opline = EX(opline);
1178#endif
1179
1180 if (UNEXPECTED(opline->opcode == ZEND_HANDLE_EXCEPTION)) {
1181 /* Abort trace because of exception */
1182 stop = ZEND_JIT_TRACE_STOP_EXCEPTION;
1183 break;
1184 }
1185
1186 trace_flags = ZEND_OP_TRACE_INFO(opline, offset)->trace_flags;
1187 if (trace_flags) {
1188 if (trace_flags & ZEND_JIT_TRACE_JITED) {
1189 if (trace_flags & ZEND_JIT_TRACE_START_LOOP) {
1190 if ((start & ZEND_JIT_TRACE_START_LOOP) != 0
1191 && level + ret_level == 0
1192 && zend_jit_trace_bad_stop_event(orig_opline, JIT_G(blacklist_root_trace) - 1) !=
1193 ZEND_JIT_TRACE_STOP_COMPILED_LOOP) {
1194 /* Fail to try close outer loop through side exit.
1195 If this doesn't work just link. */
1196 stop = ZEND_JIT_TRACE_STOP_COMPILED_LOOP;
1197 break;
1198 } else {
1199 stop = ZEND_JIT_TRACE_STOP_LINK;
1200 break;
1201 }
1202 } else if (trace_flags & ZEND_JIT_TRACE_START_ENTER) {
1204 // TODO: We may try to inline function ???
1205 stop = ZEND_JIT_TRACE_STOP_LINK;
1206 break;
1207 }
1208 if (backtrack_link_to_enter < 0) {
1209 backtrack_link_to_enter = idx;
1210 link_to_enter_opline = opline;
1211 }
1212 } else {
1213 stop = ZEND_JIT_TRACE_STOP_LINK;
1214 break;
1215 }
1216 } else if (trace_flags & ZEND_JIT_TRACE_BLACKLISTED) {
1217 stop = ZEND_JIT_TRACE_STOP_BLACK_LIST;
1218 break;
1219 } else if (trace_flags & ZEND_JIT_TRACE_START_LOOP) {
1220 uint8_t bad_stop;
1221
1223 if (opline == orig_opline && level + ret_level == 0) {
1224 stop = ZEND_JIT_TRACE_STOP_LOOP;
1225 break;
1226 }
1227 }
1228
1230 || level + ret_level != 0) {
1231 /* First try creating a trace for inner loop.
1232 If this doesn't work try loop unroling. */
1233 bad_stop = zend_jit_trace_bad_stop_event(opline,
1234 JIT_G(blacklist_root_trace) / 2);
1235 if (bad_stop != ZEND_JIT_TRACE_STOP_INNER_LOOP
1236 && bad_stop != ZEND_JIT_TRACE_STOP_LOOP_EXIT) {
1238 || zend_jit_trace_bad_stop_event(orig_opline,
1239 JIT_G(blacklist_root_trace) / 2) != ZEND_JIT_TRACE_STOP_INNER_LOOP) {
1240 stop = ZEND_JIT_TRACE_STOP_INNER_LOOP;
1241 break;
1242 }
1243 }
1244 }
1245
1246 if (opline == last_loop_opline
1247 && level == last_loop_level) {
1248 idx = zend_jit_trace_subtrace(trace_buffer,
1249 last_loop, idx, ZEND_JIT_TRACE_START_LOOP, op_array, opline);
1251 stop = ZEND_JIT_TRACE_STOP_LOOP;
1252 ret_level = 0;
1253 break;
1254 } else if (loop_unroll_limit < JIT_G(max_loop_unrolls)) {
1255 last_loop = idx;
1256 last_loop_opline = opline;
1257 last_loop_level = level;
1258 loop_unroll_limit++;
1259 } else {
1260 stop = ZEND_JIT_TRACE_STOP_LOOP_UNROLL;
1261 break;
1262 }
1263 } else if (trace_flags & ZEND_JIT_TRACE_UNSUPPORTED) {
1264 TRACE_RECORD(ZEND_JIT_TRACE_VM, 0, opline);
1265 stop = ZEND_JIT_TRACE_STOP_NOT_SUPPORTED;
1266 break;
1267 }
1268 }
1269 }
1270
1271 end_opline = opline;
1272 if (!ZEND_JIT_TRACE_STOP_OK(stop)) {
1273 if (backtrack_recursion > 0) {
1274 idx = backtrack_recursion;
1275 stop = ZEND_JIT_TRACE_STOP_RECURSIVE_CALL;
1276 end_opline = orig_opline;
1277 } else if (backtrack_ret_recursion > 0) {
1278 idx = backtrack_ret_recursion;
1279 ret_level = backtrack_ret_recursion_level;
1280 stop = ZEND_JIT_TRACE_STOP_RECURSIVE_RET;
1281 end_opline = orig_opline;
1282 } else if (backtrack_link_to_enter > 0) {
1283 if (stop == ZEND_JIT_TRACE_STOP_DEEP_RECURSION
1284 && zend_jit_trace_bad_stop_event(orig_opline, JIT_G(blacklist_root_trace) / 2) ==
1285 ZEND_JIT_TRACE_STOP_DEEP_RECURSION) {
1286 idx = backtrack_link_to_enter;
1287 stop = ZEND_JIT_TRACE_STOP_LINK;
1288 end_opline = link_to_enter_opline;
1289 }
1290 }
1291 }
1292
1293 if (stop == ZEND_JIT_TRACE_STOP_LINK) {
1294 /* Shrink fake INIT_CALLs */
1295 while (trace_buffer[idx-1].op == ZEND_JIT_TRACE_INIT_CALL
1296 && (trace_buffer[idx-1].info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) {
1297 idx--;
1298 }
1299 }
1300
1301 TRACE_END(ZEND_JIT_TRACE_END, stop, end_opline);
1302
1303#ifdef HAVE_GCC_GLOBAL_REGS
1304 if (!halt) {
1305 EX(opline) = opline;
1306 }
1307#endif
1308
1309#ifdef HAVE_GCC_GLOBAL_REGS
1310 execute_data = save_execute_data;
1311 opline = save_opline;
1312#endif
1313
1314 return stop | halt;
1315}
bool exception
Definition assert.c:30
count(Countable|array $value, int $mode=COUNT_NORMAL)
zval * zv
Definition ffi.c:3975
zval * val
Definition ffi.c:4262
buf start
Definition ffi.c:4687
zend_long offset
#define NULL
Definition gdcache.h:45
#define memmove(a, b, c)
unsigned const char * end
Definition php_ffi.h:51
zend_stack handlers
Definition php_output.h:139
unsigned char key[REFLECTION_KEY_LEN]
zend_object * ex
zend_string * name
const zend_property_info * prop_info
uint32_t num_args
zend_string * function_name
uint32_t fn_flags
znode_op op1
uint8_t result_type
znode_op op2
znode_op result
uint8_t opcode
uint8_t op1_type
uint32_t extended_value
uint8_t op2_type
uint32_t var
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API ZEND_COLD void zend_error(int type, const char *format,...)
Definition zend.c:1666
struct _zval_struct zval
#define RETURN_VALUE_USED(opline)
Definition zend_cfg.h:113
uint32_t num_args
execute_data func
#define ZEND_CLOSURE_OBJECT(op_array)
#define ZEND_CALL_CLOSURE
struct _zend_op zend_op
#define EX_VAR_NUM(n)
#define IS_UNUSED
#define ZEND_ACC_FAKE_CLOSURE
#define IS_CONST
#define ZEND_ACC_HAS_TYPE_HINTS
#define ZEND_INTERNAL_FUNCTION
#define IS_VAR
#define EX_NUM_ARGS()
#define ZEND_CALL_TOP
#define EX(element)
#define ZEND_USER_FUNCTION
#define EX_CALL_INFO()
#define ZEND_CALL_HAS_SYMBOL_TABLE
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
struct _zend_op_array zend_op_array
#define OBJ_PROP(obj, offset)
struct _zend_property_info zend_property_info
#define ZEND_CALL_HAS_EXTRA_NAMED_PARAMS
#define ZEND_FETCH_REF
#define RT_CONSTANT(opline, node)
#define ZEND_ACC_STATIC
#define ZEND_CALL_INFO(call)
#define EX_VAR(n)
#define ZEND_CALL_DYNAMIC
#define ZEND_ADD_CALL_FLAG(call, flag)
#define ZEND_CALL_FREE_EXTRA_ARGS
#define IS_CV
#define IS_TMP_VAR
#define ZEND_CALL_RELEASE_THIS
#define IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE
#define ZEND_ACC_CLOSURE
#define ZEND_ACC_NEVER_CACHE
#define ZEND_CONSTANT_FLAGS(c)
struct _zend_constant zend_constant
#define CONST_DEPRECATED
#define E_WARNING
Definition zend_errors.h:24
#define E_DEPRECATED
Definition zend_errors.h:37
ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception)
ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named_params)
#define EXECUTE_DATA_CC
#define EXECUTE_DATA_D
ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table)
#define EXECUTE_DATA_DC
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_function(const zend_function *fbc)
#define OPLINE_D
#define CACHED_PTR_EX(slot)
#define CACHE_PTR_EX(slot, ptr)
#define ENCODE_SPECIAL_CACHE_NUM(num)
#define CACHE_PTR(num, ptr)
#define CACHE_ADDR(num)
union _zend_function zend_function
#define ZEND_FUNC_JIT_ON_HOT_TRACE
#define ZEND_FUNC_INFO(op_array)
#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
ZEND_API zval *ZEND_FASTCALL zend_hash_index_find(const HashTable *ht, zend_ulong h)
Definition zend_hash.c:2701
#define HT_IS_PACKED(ht)
Definition zend_hash.h:59
#define ZEND_HANDLE_NUMERIC(key, idx)
Definition zend_hash.h:420
struct _zend_jit_trace_rec zend_jit_trace_rec
Definition zend_jit.h:99
#define ZEND_JIT_TRACE_MAX_CALL_DEPTH
Definition zend_jit.h:93
#define ZEND_JIT_COUNTER_INIT
Definition zend_jit.h:52
#define ZEND_JIT_TRACE_BAD_ROOT_SLOTS
Definition zend_jit.h:97
#define JIT_G(v)
Definition zend_jit.h:151
#define ZEND_JIT_TRACE_MAX_RET_DEPTH
Definition zend_jit.h:94
void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend_op *opline)
#define ZEND_JIT_EXIT_CLOSURE_CALL
#define ZEND_OPCODE_RETURN()
#define ZEND_JIT_EXIT_METHOD_CALL
zend_ulong zend_jit_profile_counter
#define ZEND_JIT_TRACE_JITED
#define IS_TRACE_REFERENCE
#define ZEND_OPCODE_TAIL_CALL_EX(handler, arg)
@ ZEND_JIT_TRACE_HALT
#define IS_TRACE_PACKED
#define ZEND_OPCODE_TAIL_CALL(handler)
#define ZEND_JIT_TRACE_STOP_OK(ret)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC)
@ ZEND_JIT_TRACE_ENTER
@ ZEND_JIT_TRACE_VAL_INFO
@ ZEND_JIT_TRACE_OP2_TYPE
@ ZEND_JIT_TRACE_START
@ ZEND_JIT_TRACE_OP1_TYPE
@ ZEND_JIT_TRACE_END
@ ZEND_JIT_TRACE_DO_ICALL
@ ZEND_JIT_TRACE_VM
@ ZEND_JIT_TRACE_INIT_CALL
@ ZEND_JIT_TRACE_BACK
#define ZEND_JIT_TRACE_RETURN_VALUE_USED
int zend_jit_profile_counter_rid
#define ZEND_JIT_TRACE_START_SIDE
#define ZEND_JIT_TRACE_FAKE_INFO(level)
struct _zend_jit_op_array_trace_extension zend_jit_op_array_trace_extension
#define IS_TRACE_INDIRECT
const zend_op * zend_jit_halt_op
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC)
#define ZEND_JIT_TRACE_BLACKLISTED
ZEND_OPCODE_HANDLER_RET(ZEND_FASTCALL * zend_vm_opcode_handler_t)(ZEND_OPCODE_HANDLER_ARGS)
#define ZEND_JIT_TRACE_START_ENTER
#define ZEND_JIT_TRACE_UNSUPPORTED
#define ZEND_JIT_TRACE_START_LOOP
#define ZEND_OP_TRACE_INFO(opline, offset)
#define IS_TRACE_TYPE_MASK
struct _zend_jit_op_array_hot_extension zend_jit_op_array_hot_extension
#define ZEND_JIT_TRACE_START_RETURN
#define ZEND_JIT_EXIT_POLYMORPHISM
#define IS_UNKNOWN
#define ZEND_JIT_TRACE_FAKE_INIT_CALL
enum _zend_jit_trace_stop zend_jit_trace_stop
struct _zend_jit_op_array_extension zend_jit_op_array_extension
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
#define TRACE_RECORD(_op, _info, _ptr)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_func_helper(EXECUTE_DATA_D)
void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D)
zend_constant *ZEND_FASTCALL zend_jit_get_constant(const zval *key, uint32_t flags)
#define TRACE_RECORD_VM(_op, _ptr, _op1_type, _op2_type, _op3_type)
void ZEND_FASTCALL zend_jit_undefined_long_key(EXECUTE_DATA_D)
void ZEND_FASTCALL zend_jit_undefined_long_key_ex(zend_long key EXECUTE_DATA_DC)
bool ZEND_FASTCALL zend_jit_deprecated_helper(OPLINE_D)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(uint32_t call_info EXECUTE_DATA_DC)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, const zend_op *op, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphic, int ret_depth)
#define TRACE_START(_op, _start, _ptr1, _ptr2)
void ZEND_FASTCALL zend_jit_copy_extra_args_helper(EXECUTE_DATA_D)
void ZEND_FASTCALL zend_jit_copy_extra_args_helper_no_skip_recv(EXECUTE_DATA_D)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(uint32_t call_info EXECUTE_DATA_DC)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_ret_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
#define TRACE_END(_op, _stop, _ptr)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
#define ZEND_CALL_MEGAMORPHIC
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_HANDLER_ARGS)
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_func_trace_helper(ZEND_OPCODE_HANDLER_ARGS)
zend_constant *ZEND_FASTCALL zend_jit_check_constant(const zval *key)
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API zend_property_info * zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent)
#define ZEND_PROPERTY_HOOK_SIMPLE_GET_BIT
#define ZEND_WRONG_PROPERTY_INFO
#define IS_HOOKED_PROPERTY_OFFSET(offset)
#define OBJ_RELEASE(obj)
#define ZEND_ATTRIBUTE_UNUSED
#define ZEND_FALLTHROUGH
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_FASTCALL
#define ZEND_ASSERT(c)
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define ZVAL_UNDEF(z)
#define Z_REFVAL_P(zval_p)
#define Z_STRVAL_P(zval_p)
Definition zend_types.h:975
#define IS_UNDEF
Definition zend_types.h:600
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define IS_STRING
Definition zend_types.h:606
#define Z_REFCOUNTED_P(zval_p)
Definition zend_types.h:921
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define Z_TYPE_INFO_P(zval_p)
Definition zend_types.h:669
#define IS_TYPE_REFCOUNTED
Definition zend_types.h:793
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
#define Z_OBJCE_P(zval_p)
#define IS_OBJECT
Definition zend_types.h:608
#define IS_LONG
Definition zend_types.h:604
#define IS_REFERENCE
Definition zend_types.h:610
#define Z_INDIRECT_P(zval_p)
#define IS_INDIRECT
Definition zend_types.h:623
#define Z_TYPE_FLAGS_SHIFT
Definition zend_types.h:704
struct _zend_execute_data zend_execute_data
Definition zend_types.h:91
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define Z_OBJCE(zval)
#define Z_OBJ(zval)
Definition zend_types.h:989
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
uint32_t call_info
zval * return_value
call prev_execute_data
zend_property_info * prop_info
zval * dim
fbc internal_function handler(call, ret)
zend_function * fbc
bool result
op1
execute_data
zval * ret
zend_execute_data * call
#define ZEND_OPCODE_HANDLER_RET
#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU
#define ZEND_OPCODE_HANDLER_ARGS
#define ZEND_OPCODE_HANDLER_ARGS_DC
ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(uint8_t opcode)
#define ZEND_FETCH_STATIC_PROP_IS
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_UNSET_STATIC_PROP
#define ZEND_PRE_DEC_OBJ
#define ZEND_FETCH_OBJ_W
#define ZEND_NEW
#define ZEND_FE_FETCH_RW
#define ZEND_FETCH_LIST_R
#define ZEND_INCLUDE_OR_EVAL
#define ZEND_FE_FETCH_R
#define ZEND_VM_OP_THIS
#define ZEND_FETCH_LIST_W
#define ZEND_CALLABLE_CONVERT
#define ZEND_VM_OP1_FLAGS(flags)
#define ZEND_ASSIGN_DIM
#define ZEND_FETCH_OBJ_FUNC_ARG
#define ZEND_PRE_INC_OBJ
#define ZEND_FETCH_STATIC_PROP_R
#define ZEND_PRE_DEC_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_FETCH_DIM_FUNC_ARG
#define ZEND_POST_INC_STATIC_PROP
#define ZEND_HANDLE_EXCEPTION
#define ZEND_FETCH_STATIC_PROP_UNSET
#define ZEND_FETCH_OBJ_IS
#define ZEND_DO_UCALL
#define ZEND_INSTANCEOF
#define ZEND_FETCH_OBJ_UNSET
#define ZEND_ROPE_ADD
#define ZEND_POST_DEC_OBJ
#define ZEND_VM_OP_MASK
#define ZEND_ISSET_ISEMPTY_PROP_OBJ
#define ZEND_FETCH_STATIC_PROP_FUNC_ARG
#define ZEND_DO_FCALL
#define ZEND_UNSET_DIM
#define ZEND_ISSET_ISEMPTY_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_POST_DEC_STATIC_PROP
#define ZEND_UNSET_OBJ
#define ZEND_PRE_INC_STATIC_PROP
#define ZEND_ROPE_END
#define ZEND_DO_ICALL
#define ZEND_FETCH_OBJ_R
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_FETCH_DIM_W
#define ZEND_ASSIGN_OBJ
#define ZEND_FETCH_STATIC_PROP_W
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_FETCH_STATIC_PROP_RW
#define ZEND_FETCH_CLASS_CONSTANT
#define ZEND_FETCH_DIM_IS
#define ZEND_FETCH_OBJ_RW
#define ZEND_FETCH_DIM_UNSET
#define ZEND_POST_INC_OBJ
#define ZEND_FETCH_DIM_R
#define ZEND_DO_FCALL_BY_NAME
#define ZEND_INIT_STATIC_METHOD_CALL
#define ZEND_FETCH_DIM_RW