21static const void **zend_jit_exit_groups =
NULL;
23#define ZEND_JIT_COUNTER_NUM zend_jit_traces[0].root
24#define ZEND_JIT_TRACE_NUM zend_jit_traces[0].id
25#define ZEND_JIT_EXIT_NUM zend_jit_traces[0].exit_count
26#define ZEND_JIT_EXIT_COUNTERS zend_jit_traces[0].exit_counters
28#define ZEND_JIT_TRACE_STOP_DESCRIPTION(name, description) \
31static const char * zend_jit_trace_stop_description[] = {
49static void zend_jit_trace_startup(
bool reattached)
53 if (!zend_jit_traces) {
57 if (!zend_jit_exit_groups) {
64 ZCSG(jit_traces) = zend_jit_traces;
65 ZCSG(jit_exit_groups) = zend_jit_exit_groups;
66 ZCSG(jit_counters_stopped) =
false;
68 zend_jit_traces =
ZCSG(jit_traces);
69 if (!zend_jit_traces) {
72 zend_jit_exit_groups =
ZCSG(jit_exit_groups);
73 if (!zend_jit_exit_groups) {
78 memset(&dummy_op_array, 0,
sizeof(dummy_op_array));
81 JIT_G(exit_counters) = calloc(
JIT_G(max_exit_counters), 1);
87static const void *zend_jit_trace_allocate_exit_point(uint32_t
n)
89 const void *group =
NULL;
104 ((
const char*)group +
108static const void *zend_jit_trace_get_exit_addr(uint32_t
n)
111 return zend_jit_trace_allocate_exit_point(
n);
118static uint32_t zend_jit_exit_point_by_addr(
const void *
addr)
123 for (i = 0; i <
n; i++) {
124 if ((
char*)
addr >= (
char*)zend_jit_exit_groups[i]
133static uint32_t zend_jit_trace_get_exit_point(
const zend_op *to_opline, uint32_t
flags)
138 uint32_t stack_offset = (uint32_t)-1;
142 if (delayed_call_chain) {
146 if (
JIT_G(current_frame)) {
147 op_array = &
JIT_G(current_frame)->func->op_array;
148 stack_size = op_array->
last_var + op_array->
T;
150 stack =
JIT_G(current_frame)->stack;
159 }
while (stack_size);
167 if (to_opline !=
NULL
188 if (stack_size != 0 && stack_offset == (uint32_t)-1) {
208static void zend_jit_trace_add_code(
const void *
start, uint32_t
size)
223static uint32_t zend_jit_find_trace(
const void *
addr)
228 if (zend_jit_traces[i].code_start ==
addr) {
239 smart_str_appends(&
buf, TRACE_PREFIX);
241 smart_str_appendc(&
buf,
'$');
243 if (op_array->
scope) {
245 smart_str_appends(&
buf,
"::");
253 smart_str_appendc(&
buf,
'$');
358 return zend_jit_trace_type_to_info_ex(
type, -1);
367 }
else if (ssa->
vars) {
390#define ADD_OP_GUARD(_ssa_var, _op_type) do { \
391 if (_ssa_var >= 0 && _op_type != IS_UNKNOWN) { \
392 zend_jit_trace_add_op_guard(tssa, _ssa_var, _op_type); \
396#define CHECK_OP_TRACE_TYPE(_var, _ssa_var, op_info, op_type) do { \
397 if (op_type != IS_UNKNOWN) { \
398 if ((op_info & MAY_BE_GUARD) != 0) { \
399 if (!zend_jit_type_guard(&ctx, opline, _var, op_type)) { \
402 if (ssa->vars[_ssa_var].alias != NO_ALIAS) { \
403 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), IS_UNKNOWN, 1); \
404 op_info = zend_jit_trace_type_to_info(op_type); \
406 SET_STACK_TYPE(stack, EX_VAR_TO_NUM(_var), op_type, 1); \
407 op_info &= ~MAY_BE_GUARD; \
408 ssa->var_info[_ssa_var].type &= op_info; \
414#define ADD_OP1_TRACE_GUARD() \
415 ADD_OP_GUARD(tssa->ops[idx].op1_use, op1_type)
416#define ADD_OP2_TRACE_GUARD() \
417 ADD_OP_GUARD(tssa->ops[idx].op2_use, op2_type)
418#define ADD_OP1_DATA_TRACE_GUARD() \
419 ADD_OP_GUARD(tssa->ops[idx+1].op1_use, op3_type)
421#define CHECK_OP1_TRACE_TYPE() \
422 CHECK_OP_TRACE_TYPE(opline->op1.var, ssa_op->op1_use, op1_info, op1_type)
423#define CHECK_OP2_TRACE_TYPE() \
424 CHECK_OP_TRACE_TYPE(opline->op2.var, ssa_op->op2_use, op2_info, op2_type)
425#define CHECK_OP1_DATA_TRACE_TYPE() \
426 CHECK_OP_TRACE_TYPE((opline+1)->op1.var, (ssa_op+1)->op1_use, op1_data_info, op3_type)
432 }
else if (op_array) {
485 &&
JIT_G(current_frame)
536 if (zend_jit_op_array_analyze1(op_array, script, ssa) !=
SUCCESS) {
548 if (zend_jit_op_array_analyze2(op_array, script, ssa, 0) !=
SUCCESS) {
564 void *checkpoint = zend_arena_checkpoint(
CG(
arena));
566 if (zend_jit_build_cfg(op_array, &cfg) ==
SUCCESS) {
577 zend_arena_release(&
CG(
arena), checkpoint);
655 set_size = zend_bitset_len(op_array->
last_var + op_array->
T);
658 def = use + set_size;
666 len = zend_jit_trace_op_len(opline);
690 zend_bitset_intersection(use, def, set_size);
695 vars_count = op_array->
last_var + op_array->
T;
697 for (k = 0; k < vars_count; k++) {
698 if (zend_bitset_in(use, k)) {
705 phi->sources[1] = -1;
709 phi->ssa_var = ssa_vars_count;
724 return ssa_vars_count;
735 for(i = 0; i <
count; i++) {
742 phi->sources[1] = -1;
746 phi->ssa_var = ssa_vars_count;
757 return ssa_vars_count;
774 phi->sources[1] = -1;
778 phi->ssa_var = ssa_vars_count;
784 return ssa_vars_count;
798 if (opline >= op_array->
opcodes && opline < op_array->opcodes + op_array->
last) {
806static int zend_jit_trace_copy_ssa_var_info(
const zend_op_array *op_array,
813 int var, use, def, src;
817 uint32_t b = ssa->
cfg.
map[tssa_opcodes[0] - op_array->
opcodes];
821 && !zend_jit_trace_is_false_loop(op_array, ssa, tssa_opcodes, tssa)) {
842 while (bb->
idom >= 0) {
885 op = ssa->
ops + (tssa_opcodes[def] - op_array->
opcodes);
888 }
else if (tssa->
ops[def].
op2_def == ssa_var) {
908 op = ssa->
ops + (tssa_opcodes[use] - op_array->
opcodes);
922 uint32_t op_num = opline - op_array->
opcodes;
923 uint32_t b = ssa->
cfg.
map[op_num];
928 while (op_num > bb->
start) {
930 op = ssa->
ops + op_num;
1004 op = ssa->
ops + (tssa_opcodes[def] - op_array->
opcodes);
1009 }
else if (tssa->
ops[def].
op2_def == ssa_var) {
1026 zend_jit_trace_propagate_range(op_array, tssa_opcodes, tssa, ssa_var);
1052 op = ssa->
ops + (tssa_opcodes[def] - op_array->
opcodes);
1055 }
else if (tssa->
ops[def].
op2_def == ssa_var) {
1067 if (instanceof_function(tssa->
var_info[ssa_var].
ce, info->
ce)) {
1069 }
else if (instanceof_function(info->
ce, tssa->
var_info[ssa_var].
ce)) {
1163 while (opline > op_array->
opcodes) {
1165 if (zend_jit_inc_call_level(opline->
opcode)) {
1166 if (call_level == 0) {
1170 }
else if (zend_jit_dec_call_level(opline->
opcode)) {
1179static int is_checked_guard(
const zend_ssa *tssa,
const zend_op **ssa_opcodes, uint32_t var, uint32_t phi_var)
1187 const zend_op *opline = ssa_opcodes[idx];
1224 const zend_op *opline = ssa_opcodes[idx];
1281static const zend_op _nop_opcode = {0};
1293 int i,
v, idx,
len, ssa_ops_count, vars_count, ssa_vars_count;
1296 uint32_t optimization_level = 0;
1297 int call_level, level, num_op_arrays, used_stack, max_used_stack;
1298 size_t frame_size, stack_top, stack_size, stack_bottom;
1309 stack_top = stack_size = zend_jit_trace_frame_size(op_array);
1317 op_arrays[num_op_arrays++] = op_array;
1319 ssa = zend_jit_trace_build_ssa(op_array, script);
1325 switch (opline->
opcode) {
1346 ssa_ops_count += zend_jit_trace_op_len(
p->opline);
1349 stack_top += zend_jit_trace_frame_size(
p->op_array);
1350 if (stack_top > stack_size) {
1351 stack_size = stack_top;
1363 frame_size = zend_jit_trace_frame_size(
p->op_array);
1364 if (call_level == 0) {
1365 if (stack_top + frame_size > stack_size) {
1366 stack_size = stack_top + frame_size;
1370 stack_top -= frame_size;
1373 op_array =
p->op_array;
1374 if (call_level == 0) {
1375 stack_top += zend_jit_trace_frame_size(op_array);
1376 if (stack_top > stack_size) {
1377 stack_size = stack_top;
1390 *num_op_arrays_ptr = num_op_arrays;
1394 op_arrays[num_op_arrays++] = op_array;
1396 ssa = zend_jit_trace_build_ssa(op_array, script);
1400 stack_bottom += zend_jit_trace_frame_size(
p->op_array);
1408 *num_op_arrays_ptr = num_op_arrays;
1412 op_arrays[num_op_arrays++] = op_array;
1414 ssa = zend_jit_trace_build_ssa(op_array, script);
1417 stack_top -= zend_jit_trace_frame_size(op_array);
1420 op_array =
p->op_array;
1425 *num_op_arrays_ptr = num_op_arrays;
1437 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1438 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1439 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1475 ssa_opcodes = zend_arena_calloc(&
CG(
arena), ssa_ops_count + 1,
sizeof(
zend_op*));
1476 ((
zend_tssa*)tssa)->tssa_opcodes = ssa_opcodes;
1477 ssa_opcodes[ssa_ops_count] = &_nop_opcode;
1481 ssa_vars_count = op_array->
last_var;
1483 ssa_vars_count = op_array->
last_var + op_array->
T;
1485 stack =
frame->stack;
1486 for (i = 0; i < ssa_vars_count; i++) {
1490 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1493 ssa_vars_count = zend_jit_trace_add_phis(trace_buffer, ssa_vars_count, tssa, stack);
1494 }
else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
1495 ssa_vars_count = zend_jit_trace_add_call_phis(trace_buffer, ssa_vars_count, tssa, stack);
1496 }
else if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1497 ssa_vars_count = zend_jit_trace_add_ret_phis(trace_buffer, ssa_vars_count, tssa, stack);
1506 ssa_opcodes[idx] = opline;
1507 ssa_vars_count =
zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (
int*)stack);
1509 len = zend_jit_trace_op_len(
p->opline);
1512 ssa_opcodes[idx] = opline;
1514 ssa_vars_count =
zend_ssa_rename_op(op_array, opline, idx, build_flags, ssa_vars_count, ssa_ops, (
int*)stack);
1520 frame = zend_jit_trace_call_frame(
frame, op_array);
1521 stack =
frame->stack;
1522 op_array =
p->op_array;
1528 for (i = 0; i < op_array->
last_var; i++) {
1532 op_array =
p->op_array;
1533 frame = zend_jit_trace_ret_frame(
frame, op_array);
1534 stack =
frame->stack;
1540 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
1557 vars_count = op_array->
last_var + op_array->
T;
1560 while (i < vars_count) {
1561 ssa_vars[i].
var = i;
1562 ssa_vars[i].
scc = -1;
1567 while (i < tssa->vars_count) {
1568 ssa_vars[i].
var = -1;
1569 ssa_vars[i].
scc = -1;
1575 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1576 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1577 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1592 idx = (ssa_ops_count - 1);
1595 opline = ssa_opcodes[idx];
1626 opline = trace_buffer[1].
opline;
1635 while (i < op_array->last_var) {
1638 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i,
NULL)) {
1645 ssa_vars[i].
alias = zend_jit_var_may_alias(op_array, ssa, i);
1647 if (op_array->
arg_info && i < trace_buffer[1].opline - op_array->
opcodes) {
1655 ssa_var_info[i].
type = tmp;
1656 ssa_var_info[i].
ce = ce;
1667 ssa_vars[i].
alias = zend_jit_var_may_alias(op_array, ssa, i);
1669 if (ssa_vars[i].alias ==
NO_ALIAS) {
1678 int parent_vars_count = 0;
1683 parent_vars_count =
MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
1685 if (parent_vars_count) {
1687 zend_jit_traces[parent_trace].stack_map +
1688 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
1691 while (i < op_array->last_var + op_array->
T) {
1693 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, i, opline)) {
1694 if (ssa->
vars && i < ssa->vars_count) {
1697 ssa_vars[i].
alias = zend_jit_var_may_alias(op_array, ssa, i);
1699 if (i < op_array->last_var) {
1705 if (i < parent_vars_count) {
1707 uint8_t op_type =
STACK_TYPE(parent_stack, i);
1710 ssa_var_info[i].
type &= zend_jit_trace_type_to_info(op_type);
1711 if (!ssa_var_info[i].
type
1723 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
1724 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
1725 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
1731 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, phi->
ssa_var,
NULL)) {
1740 top = zend_jit_trace_call_frame(
frame, op_array);
1743 frame->used_stack = 0;
1744 memset(&return_value_info, 0,
sizeof(return_value_info));
1746 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
1747 max_used_stack = used_stack = 0;
1749 max_used_stack = used_stack = -1;
1758 uint8_t orig_op1_type, orig_op2_type, op1_type, op2_type, op3_type;
1765 op1_type = orig_op1_type =
p->op1_type;
1766 op2_type = orig_op2_type =
p->op2_type;
1767 op3_type =
p->op3_type;
1794 switch (opline->
opcode) {
1817 && !zend_jit_supported_binary_op(
1824 if ((opline+1)->op1_type ==
IS_CV
1825 && (opline+1)->
op1.var == opline->
op1.
var) {
1890 && (opline+1)->op1_type ==
IS_CV
1891 && (opline+1)->op1.var == opline->
op1.
var) {
1973 || !
frame->call->func
2108 &&
frame->call->func
2110 && opline->
op2.
num <=
frame->call->func->op_array.num_args) {
2123 arg_info = &
frame->call->func->op_array.arg_info[opline->
op2.
num - 1];
2155 return_value_info = ssa_var_info[ssa_ops[idx].
op1_use];
2171 || !
frame->call->func) {
2189 || !
frame->call->func
2222 max_used_stack = used_stack = -1;
2246 len = zend_jit_trace_op_len(opline);
2249 if (ssa_ops[idx].op1_def >= 0) {
2250 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2252 if (ssa_ops[idx].op2_def >= 0) {
2253 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2255 if (ssa_ops[idx].result_def >= 0) {
2256 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2259 if (ssa_ops[idx+1].op1_def >= 0) {
2260 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2262 if (ssa_ops[idx+1].op2_def >= 0) {
2263 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2265 if (ssa_ops[idx+1].result_def >= 0) {
2266 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2270 if (ssa_ops[idx].op1_def >= 0) {
2272 if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].
type &
MAY_BE_REF)) {
2273 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2276 if (ssa_ops[idx].op2_def >= 0) {
2278 if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].
type &
MAY_BE_REF)) {
2279 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2282 if (ssa_ops[idx].result_def >= 0) {
2284 if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].
type &
MAY_BE_REF)) {
2285 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2289 if (ssa_ops[idx+1].op1_def >= 0) {
2290 ssa_vars[ssa_ops[idx+1].op1_def].
alias = zend_jit_var_may_alias(op_array, ssa,
EX_VAR_TO_NUM((opline+1)->
op1.var));
2291 if (ssa_ops[idx+1].op1_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op1_use].
type &
MAY_BE_REF)) {
2292 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op1_def);
2295 if (ssa_ops[idx+1].op2_def >= 0) {
2296 ssa_vars[ssa_ops[idx+1].op2_def].
alias = zend_jit_var_may_alias(op_array, ssa,
EX_VAR_TO_NUM((opline+1)->
op2.var));
2297 if (ssa_ops[idx+1].op2_use < 0 || !(ssa_var_info[ssa_ops[idx+1].op2_use].
type &
MAY_BE_REF)) {
2298 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].op2_def);
2301 if (ssa_ops[idx+1].result_def >= 0) {
2302 ssa_vars[ssa_ops[idx+1].result_def].
alias = zend_jit_var_may_alias(op_array, ssa,
EX_VAR_TO_NUM((opline+1)->
result.var));
2303 if (ssa_ops[idx+1].result_use < 0 || !(ssa_var_info[ssa_ops[idx+1].result_use].
type &
MAY_BE_REF)) {
2304 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx+1].result_def);
2312 ssa_var_info[ssa_ops[idx].result_def].
type = _const_op_type(
RT_CONSTANT(opline, opline->
op2));
2315 if (ssa_ops[idx].op2_use >= 0 && ssa_ops[idx].op2_def >= 0) {
2316 ssa_var_info[ssa_ops[idx].op2_def] = ssa_var_info[ssa_ops[idx].op2_use];
2324 && ssa_ops[idx].op1_def >= 0
2340 if (ssa_ops[idx].op1_def >= 0) {
2344 &&
frame->call->func
2346 ssa_var_info[ssa_ops[idx].op1_def] = ssa_var_info[ssa_ops[idx].op1_use];
2352 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2355 if (ssa_ops[idx].op2_def >= 0) {
2358 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2361 if (ssa_ops[idx].result_def >= 0) {
2362 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2371 if (ssa_ops[idx].op1_def >= 0) {
2372 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2374 if (ssa_ops[idx].op2_def >= 0) {
2375 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2377 if (ssa_ops[idx].result_def >= 0) {
2378 zend_jit_trace_copy_ssa_var_range(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2381 if (ssa_ops[idx].op1_def >= 0) {
2383 if (ssa_ops[idx].op1_use < 0 || !(ssa_var_info[ssa_ops[idx].op1_use].
type &
MAY_BE_REF)) {
2384 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2387 if (ssa_ops[idx].op2_def >= 0) {
2389 if (ssa_ops[idx].op2_use < 0 || !(ssa_var_info[ssa_ops[idx].op2_use].
type &
MAY_BE_REF)) {
2390 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2393 if (ssa_ops[idx].result_def >= 0) {
2395 if (ssa_ops[idx].result_use < 0 || !(ssa_var_info[ssa_ops[idx].result_use].
type &
MAY_BE_REF)) {
2396 zend_jit_trace_propagate_range(op_array, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2403 ssa_var_info[ssa_ops[idx].result_def].
type = _const_op_type(
RT_CONSTANT(opline, opline->
op2));
2413 if (ssa_ops[idx].op1_def >= 0) {
2414 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op1_def);
2416 if (ssa_ops[idx].op2_def >= 0) {
2417 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].op2_def);
2419 if (ssa_ops[idx].result_def >= 0) {
2420 zend_jit_trace_restrict_ssa_var_info(op_array, ssa, ssa_opcodes, tssa, ssa_ops[idx].result_def);
2428 op_array =
p->op_array;
2438 call->used_stack = 0;
2439 top = zend_jit_trace_call_frame(
top, op_array);
2451 while (i < op_array->last_var) {
2452 ssa_vars[
v].
var = i;
2455 && zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa,
v,
NULL)) {
2458 ssa_vars[
v].
alias = zend_jit_var_may_alias(op_array, ssa, i);
2467 ssa_var_info[
v].
type = tmp;
2468 ssa_var_info[
v].
ce = ce;
2479 ssa_vars[
v].
alias = zend_jit_var_may_alias(op_array, ssa, i);
2496 op_array =
p->op_array;
2503 while (i < op_array->last_var) {
2504 ssa_vars[
v].
var = i;
2506 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa,
v,
NULL)) {
2512 while (i < op_array->last_var + op_array->
T) {
2513 ssa_vars[
v].
var = i;
2515 || !zend_jit_trace_copy_ssa_var_info(op_array, ssa, ssa_opcodes, tssa,
v,
NULL)) {
2521 if (return_value_info.
type != 0) {
2528 && q->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)) {
2536 memset(&return_value_info, 0,
sizeof(return_value_info));
2540 if (return_value_info.
type != 0) {
2542 const zend_op *opline = (
p+1)->opline - 1;
2549 memset(&return_value_info, 0,
sizeof(return_value_info));
2555 if (used_stack > 0) {
2556 used_stack -=
frame->used_stack;
2561 max_used_stack = used_stack = -1;
2562 frame = zend_jit_trace_ret_frame(
frame, op_array);
2565 frame->used_stack = 0;
2572 call->used_stack = 0;
2574 top = zend_jit_trace_call_frame(
top,
p->op_array);
2576 for (i = 0; i <
p->op_array->last_var +
p->op_array->T; i++) {
2583 max_used_stack = used_stack = -1;
2585 const zend_op *opline = (
p-1)->opline;
2587 switch (opline->
opcode) {
2598 used_stack +=
frame->used_stack;
2599 if (used_stack > max_used_stack) {
2600 max_used_stack = used_stack;
2604 max_used_stack = used_stack = -1;
2616 && ssa_ops[idx-1].result_def >= 0
2630 ssa_var_info[ssa_ops[idx-1].result_def].
type &= ret_type;
2638 ((
zend_tssa*)tssa)->used_stack = max_used_stack;
2640 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2641 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2642 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2664 || is_checked_guard(tssa, ssa_opcodes, phi->
sources[1], phi->
ssa_var)) {
2693 && is_checked_guard(tssa, ssa_opcodes, phi->
sources[1], phi->
ssa_var)) {
2733 fprintf(stderr,
"---- TRACE %d TSSA start (side trace %d/%d) %s%s%s() %s:%d\n",
2742 trace_buffer[1].opline->lineno);
2744 fprintf(stderr,
"---- TRACE %d TSSA start (%s) %s%s%s() %s:%d\n",
2746 zend_jit_trace_star_desc(trace_buffer->start),
2752 trace_buffer[1].opline->lineno);
2754 zend_jit_dump_trace(trace_buffer, tssa);
2755 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LINK) {
2756 uint32_t idx = trace_buffer[1].
last;
2757 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->
handler);
2758 fprintf(stderr,
"---- TRACE %d TSSA stop (link to %d)\n",
2762 fprintf(stderr,
"---- TRACE %d TSSA stop (%s)\n",
2764 zend_jit_trace_stop_description[trace_buffer->stop]);
2771#define RA_HAS_IVAL(var) (ra[var].ref != 0)
2772#define RA_IVAL_FLAGS(var) ra[var].flags
2773#define RA_IVAL_START(var, line) do {ra[var].ref = IR_NULL;} while (0)
2774#define RA_IVAL_END(var, line)
2775#define RA_IVAL_CLOSE(var, line)
2776#define RA_IVAL_DEL(var) do {ra[var].ref = IR_UNUSED;} while (0)
2777#define RA_HAS_REG(var) (ra[var].ref != 0)
2778#define RA_REG_FLAGS(var) ra[var].flags
2779#define RA_REG_START(var, line) do {ra[var].ref = IR_NULL;} while (0)
2780#define RA_REG_DEL(var) do {ra[var].ref = IR_UNUSED;} while (0)
2791 }
else if (use_chain >= 0 && !zend_ssa_is_no_val_use(ssa_opcodes[use_chain], ssa->
ops + use_chain, var)) {
2793 }
else if (op_array_ssa->
vars) {
2794 uint32_t use = ssa_opcodes[
line] - op_array->
opcodes;
2797 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->
ops[use].
op1_use, use)) {
2801 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->
ops[use].
op2_use, use)) {
2805 if (zend_ssa_is_last_use(op_array, op_array_ssa, op_array_ssa->
ops[use].
result_use, use)) {
2820 int i,
j, idx,
count, level;
2826 uint32_t parent_vars_count = parent_trace ?
2827 zend_jit_traces[parent_trace].exit_info[exit_num].stack_size : 0;
2829 zend_jit_traces[parent_trace].stack_map +
2830 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset :
NULL;
2831 checkpoint = zend_arena_checkpoint(
CG(
arena));
2843 stack =
frame->stack;
2854 vars_op_array[i] = op_array;
2859 && zend_jit_var_supports_reg(ssa, i)) {
2861 if (i < parent_vars_count
2884 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
2885 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
2886 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
2891 vars_op_array[phi->
ssa_var] = op_array;
2894 && zend_jit_var_supports_reg(ssa, phi->
ssa_var)) {
2910 bool support_opline;
2913 zend_jit_opline_supports_reg(op_array, ssa, opline, ssa_op,
p);
2926 if (!support_opline) {
2929 }
else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->
op1_use)) {
2932 ssa, ssa_opcodes, op_array, op_array_ssa);
2958 if (!support_opline) {
2961 }
else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->
op2_use)) {
2964 ssa, ssa_opcodes, op_array, op_array_ssa);
2974 if (!support_opline) {
2977 }
else if (!zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->
result_use)) {
2980 ssa, ssa_opcodes, op_array, op_array_ssa);
2997 if (support_opline) {
3002 && zend_jit_var_supports_reg(ssa, ssa_op->
result_def)) {
3016 vars_op_array[ssa_op->
result_def] = op_array;
3026 && zend_jit_var_supports_reg(ssa, ssa_op->
op1_def)
3032 vars_op_array[ssa_op->
op1_def] = op_array;
3040 && zend_jit_var_supports_reg(ssa, ssa_op->
op2_def)
3042 vars_op_array[ssa_op->
op2_def] = op_array;
3048 len = zend_jit_trace_op_len(opline);
3049 switch (opline->
opcode) {
3064 && !zend_ssa_is_no_val_use(opline, ssa_op, ssa_op->
op1_use)) {
3065 if (support_opline) {
3068 ssa, ssa_opcodes, op_array, op_array_ssa);
3084 && zend_jit_var_supports_reg(ssa, ssa_op->
op1_def)
3086 vars_op_array[ssa_op->
op1_def] = op_array;
3139 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
3147 frame = zend_jit_trace_call_frame(
frame, op_array);
3148 frame->prev = prev_frame;
3150 stack =
frame->stack;
3151 op_array =
p->op_array;
3156 for (i = 0; i < op_array->
last_var; i++) {
3158 vars_op_array[
j] = op_array;
3161 && zend_jit_var_supports_reg(ssa,
j)) {
3168 for (i = op_array->
last_var; i < op_array->last_var + op_array->
T; i++) {
3174 for (i = 0; i < op_array->
last_var; i++) {
3177 op_array =
p->op_array;
3181 frame = zend_jit_trace_ret_frame(
frame, op_array);
3182 stack =
frame->stack;
3188 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
3190 vars_op_array[
j] = op_array;
3193 && zend_jit_var_supports_reg(ssa,
j)
3209 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3210 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3211 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3223 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
3224 for (i = 0; i < op_array->
last_var; i++) {
3252 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
3253 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
3254 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
3278 if (zend_jit_var_supports_reg(ssa, use)) {
3297 }
else if (
p->stop == ZEND_JIT_TRACE_STOP_LINK
3298 ||
p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
3299 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
3309 zend_arena_release(&
CG(
arena), checkpoint);
3318 uint32_t var_num = ssa->
vars[i].
var;
3319 zend_dump_var(vars_op_array[i], (var_num < vars_op_array[i]->last_var ?
IS_CV : 0), var_num);
3338 zend_arena_release(&
CG(
arena), checkpoint);
3370static void zend_jit_trace_setup_ret_counter(
const zend_op *opline,
size_t offset)
3382 next_opline->
handler = (
const void*)zend_jit_ret_trace_counter_handler;
3400 opline = ssa_opcodes[use];
3405 if (!
JIT_G(current_frame)
3431 && (opline+1)->op1_type ==
IS_CV
3432 && (opline+1)->op1.var == opline->
op1.
var) {
3436 if (!zend_jit_supported_binary_op(
3454static int zend_jit_trace_stack_needs_deoptimization(
zend_jit_trace_stack *stack, uint32_t stack_size)
3458 for (i = 0; i < stack_size; i++) {
3468static int zend_jit_trace_exit_needs_deoptimization(uint32_t trace_num, uint32_t exit_num)
3470 const zend_op *opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
3471 uint32_t
flags = zend_jit_traces[trace_num].exit_info[exit_num].flags;
3472 uint32_t stack_size;
3479 stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
3480 stack = zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset;
3481 return zend_jit_trace_stack_needs_deoptimization(stack, stack_size);
3484static int zend_jit_trace_deoptimization(
3488 int parent_vars_count,
3492 bool polymorphic_side_trace)
3501 for (i = 0; i < parent_vars_count; i++) {
3502 int8_t reg =
STACK_REG(parent_stack, i);
3508 if (!zend_jit_store_const_long(jit, i,
3513 if (!zend_jit_store_const_double(jit, i,
3514 constants[
STACK_REF(parent_stack, i)].d)) {
3522 if (jit->
ra && jit->
ra[i].
ref) {
3529 if (!zend_jit_store_type(jit, i,
type)) {
3536 if (polymorphic_side_trace) {
3546 zend_jit_zval_try_addref(jit, dst);
3557 if (!zend_jit_store_spill_slot(jit, 1 <<
type, i, reg,
STACK_REF(parent_stack, i),
3562 if (jit->
ra && jit->
ra[i].
ref) {
3580 if (!zend_jit_store_reg(jit, 1 <<
type, i, reg,
3586 if (jit->
ra && jit->
ra[i].
ref) {
3602 int8_t reg =
STACK_REG(parent_stack, check2);
3606 if (!zend_jit_escape_if_undef(jit, check2,
flags, opline, reg)) {
3609 if (!zend_jit_restore_zval(jit,
EX_NUM_TO_VAR(check2), reg)) {
3615 if (!zend_jit_save_call_chain(jit, -1)) {
3621 const zend_op *op = opline - 1;
3623 if (!zend_jit_free_op(jit, op, -1, op->
op2.
var)) {
3629 const zend_op *op = opline - 1;
3631 if (!zend_jit_free_op(jit, op, -1, op->
op1.
var)) {
3637 zend_jit_check_exception(jit);
3641 jit->
poly_func_ref = zend_jit_deopt_rload_spilled(jit, IR_ADDR,
3643 jit->
poly_this_ref = zend_jit_deopt_rload_spilled(jit, IR_ADDR,
3646 if (!polymorphic_side_trace) {
3667 zend_long op1_min, op1_max, op2_min, op2_max;
3679 switch (opline->
opcode) {
3685 if (!exit_if_true) {
3688 zend_jit_trace_set_var_range(
3690 MAX(op1_min, op2_min),
3691 MIN(op1_max, op2_max));
3694 zend_jit_trace_set_var_range(
3696 MAX(op2_min, op1_min),
3697 MIN(op2_max, op1_max));
3705 zend_jit_trace_set_var_range(
3707 MAX(op1_min, op2_min),
3708 MIN(op1_max, op2_max));
3711 zend_jit_trace_set_var_range(
3713 MAX(op2_min, op1_min),
3714 MIN(op2_max, op1_max));
3719 if (!exit_if_true) {
3722 zend_jit_trace_set_var_range(
3725 MIN(op1_max, op2_max));
3728 zend_jit_trace_set_var_range(
3730 MAX(op2_min, op1_min),
3736 zend_jit_trace_set_var_range(
3742 zend_jit_trace_set_var_range(
3750 if (!exit_if_true) {
3753 zend_jit_trace_set_var_range(
3759 zend_jit_trace_set_var_range(
3767 zend_jit_trace_set_var_range(
3769 MAX(op1_min, op2_min),
3773 zend_jit_trace_set_var_range(
3776 MIN(op2_max, op1_max));
3785 uint8_t prev_opcode;
3791 if ((ssa_op-1)->op1_def == ssa_op->
op2_use) {
3793 opline = ssa_opcodes[ssa_op - ssa->
ops];
3794 prev_opcode = opline->
opcode;
3801 }
else if ((ssa_op-1)->result_def == ssa_op->
op2_use) {
3803 opline = ssa_opcodes[ssa_op - ssa->
ops];
3804 prev_opcode = opline->
opcode;
3816 if ((ssa_op-1)->op1_def == ssa_op->
op1_use) {
3818 opline = ssa_opcodes[ssa_op - ssa->
ops];
3819 prev_opcode = opline->
opcode;
3826 }
else if ((ssa_op-1)->result_def == ssa_op->
op1_use) {
3828 opline = ssa_opcodes[ssa_op - ssa->
ops];
3829 prev_opcode = opline->
opcode;
3839 prev_opcode = ssa_opcodes[prev_ssa_op - ssa->
ops]->
opcode;
3842 && prev_ssa_op != ssa->
ops
3844 && prev_ssa_op->
op1_use == (prev_ssa_op-1)->result_def) {
3846 prev_opcode = ssa_opcodes[prev_ssa_op - ssa->
ops]->
opcode;
3876static bool zend_jit_trace_next_is_send_result(
const zend_op *opline,
3882 && (
p+1)->opline == opline + 1
3887 &&
frame->call->func
3890 && (opline+1)->op2_type !=
IS_CONST
3891 && (opline+1)->op1.var == opline->
result.
var) {
3894 uint8_t res_type = (
p+1)->op1_type;
3897 zend_jit_trace_send_type(opline+1,
frame->call, res_type);
3905static int zend_jit_find_ssa_var(
const zend_op_array *op_array,
3907 uint32_t opline_num,
3910 int ssa_var,
j, b = ssa->
cfg.
map[opline_num];
3918 ssa_op = ssa->
ops + opline_num;
3920 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3924 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3928 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3931 if (opline_num == bb->
start) {
3939 if (phi->
var == var_num) {
3956 zend_worklist_push(&worklist, b);
3959 while (zend_worklist_len(&worklist) != 0) {
3960 b = zend_worklist_pop(&worklist);
3963 opline_num = bb->
start + bb->
len - 1;
3965 ssa_op = ssa->
ops + opline_num;
3967 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3971 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3975 if (ssa_var >= 0 && ssa->
vars[ssa_var].
var == var_num) {
3978 if (opline_num == bb->
start) {
3987 if (phi->
var == var_num) {
3997 zend_worklist_push(&worklist, b);
4007static bool zend_jit_trace_must_store_type(
const zend_op_array *op_array,
4009 uint32_t opline_num,
4014 int ssa_var = zend_jit_find_ssa_var(op_array, ssa, opline_num, var_num);
4025static bool zend_jit_trace_may_throw(
const zend_op *opline,
4034 switch (opline->
opcode) {
4052static const void *zend_jit_trace(
zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
4066 int num_op_arrays = 0;
4069 uint8_t smart_branch_opcode;
4070 const void *exit_addr;
4071 uint32_t op1_info, op1_def_info, op2_info, res_info, res_use_info, op1_data_info, op1_mem_info;
4072 bool send_result = 0;
4073 bool skip_comparison;
4074 zend_jit_addr op1_addr, op1_def_addr, op2_addr, op2_def_addr, res_addr;
4076 bool ce_is_instanceof;
4078 bool delayed_fetch_this = 0;
4079 bool avoid_refcounting = 0;
4080 bool polymorphic_side_trace =
4087 const zend_op *opline, *orig_opline;
4090 int peek_checked_stack;
4091 uint32_t frame_flags = 0;
4093 JIT_G(current_trace) = trace_buffer;
4095 checkpoint = zend_arena_checkpoint(
CG(
arena));
4097 ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays);
4103 ssa_opcodes = ((
zend_tssa*)ssa)->tssa_opcodes;
4106 opline = trace_buffer[1].
opline;
4107 name = zend_jit_trace_name(op_array, opline->
lineno);
4109 parent_trace ? &zend_jit_traces[parent_trace] :
NULL, exit_num);
4115 ctx.
ra = ra = zend_jit_trace_allocate_registers(trace_buffer, ssa, parent_trace, exit_num);
4120 op_array =
p->op_array;
4122 top = zend_jit_trace_call_frame(
frame, op_array);
4124 frame->used_stack = checked_stack = peek_checked_stack = 0;
4125 stack =
frame->stack;
4126 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
4130 opline =
p[1].opline;
4137 if (!parent_trace) {
4138 zend_jit_set_last_valid_opline(&ctx, opline);
4139 zend_jit_track_last_valid_opline(&ctx);
4141 if (zend_jit_traces[parent_trace].exit_info[exit_num].opline ==
NULL) {
4142 zend_jit_trace_opline_guard(&ctx, opline);
4144 zend_jit_reset_last_valid_opline(&ctx);
4150 int parent_vars_count = 0;
4152 int used_stack = ((
zend_tssa*)ssa)->used_stack;
4154 if (used_stack > 0) {
4155 peek_checked_stack = used_stack;
4156 if (!zend_jit_stack_check(&ctx, opline, used_stack)) {
4162 parent_vars_count =
MIN(zend_jit_traces[parent_trace].exit_info[exit_num].stack_size,
4164 if (parent_vars_count) {
4166 zend_jit_traces[parent_trace].stack_map +
4167 zend_jit_traces[parent_trace].exit_info[exit_num].stack_offset;
4173 last_var += op_array->
T;
4176 for (i = 0; i < last_var; i++) {
4179 if (!(info &
MAY_BE_GUARD) && has_concrete_type(info)) {
4180 uint8_t
type, mem_type;
4182 type = concrete_type(info);
4183 if (i < parent_vars_count
4195 }
else if (i < parent_vars_count
4201 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4202 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4203 || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4209 if (!zend_jit_type_guard(&ctx, opline,
EX_NUM_TO_VAR(i), concrete_type(info))) {
4224 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4225 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4226 || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET
4233 if (!zend_jit_packed_guard(&ctx, opline,
EX_NUM_TO_VAR(i), info)) {
4243 if (!zend_jit_trace_deoptimization(&ctx,
4244 &zend_jit_traces[parent_trace].exit_info[exit_num],
4245 parent_stack, parent_vars_count, ssa, stack,
4246 zend_jit_traces[parent_trace].constants,
4247 polymorphic_side_trace)) {
4253 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4254 && trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4255 for (i = 0; i < last_var; i++) {
4266 if (!zend_jit_type_guard(&ctx, opline,
EX_NUM_TO_VAR(i), op_type)) {
4272 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP) {
4273 if (!zend_jit_load_var(&ctx, ssa->
var_info[i].
type, i, i)) {
4285 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
4286 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
4287 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
4298 zend_jit_trace_gen_phi(&ctx, phi);
4311 if (!zend_jit_type_guard(&ctx, opline,
EX_NUM_TO_VAR(phi->
var), concrete_type(info))) {
4354 uint8_t op1_type =
p->op1_type;
4355 uint8_t op2_type =
p->op2_type;
4356 uint8_t op3_type =
p->op3_type;
4357 uint8_t orig_op1_type = op1_type;
4358 uint8_t orig_op2_type = op2_type;
4394 if (zend_jit_inc_call_level(opline->
opcode)) {
4395 frame->call_level++;
4399 switch (opline->
opcode) {
4413 res_use_info = zend_jit_trace_type_to_info(
4427 && !has_concrete_type(op1_def_info)) {
4430 if (!zend_jit_inc_dec(&ctx, opline,
4433 res_use_info, res_info,
4478 && zend_jit_trace_next_is_send_result(opline,
p,
frame)) {
4482 if (!zend_jit_reuse_ip(&ctx)) {
4486 res_use_info = zend_jit_trace_type_to_info(
4493 if (!zend_jit_long_math(&ctx, opline,
4496 res_use_info, res_info, res_addr,
4524 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4538 if (!zend_jit_fetch_reference(&ctx, opline, orig_op2_type, &op2_info, &op2_addr,
4550 && zend_jit_trace_next_is_send_result(opline,
p,
frame)) {
4554 if (!zend_jit_reuse_ip(&ctx)) {
4558 res_use_info = zend_jit_trace_type_to_info(
4568 if (!zend_jit_add_arrays(&ctx, opline, op1_info, op1_addr, op2_info, op2_addr, res_addr)) {
4582 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
4584 if (!zend_jit_math(&ctx, opline,
4587 res_use_info, res_info, res_addr,
4594 && has_concrete_type(op1_info)
4596 && has_concrete_type(op2_info)
4616 if (zend_jit_trace_next_is_send_result(opline,
p,
frame)) {
4619 if (!zend_jit_reuse_ip(&ctx)) {
4623 if (!zend_jit_concat(&ctx, opline,
4624 op1_info, op2_info, res_addr,
4637 if (!zend_jit_supported_binary_op(
4645 op1_mem_info = op1_info;
4647 op1_mem_info = zend_jit_trace_type_to_info(
4652 && !has_concrete_type(op1_def_info)) {
4655 if (!zend_jit_assign_op(&ctx, opline,
4656 op1_info, op1_addr, OP1_RANGE(),
4664 && has_concrete_type(op1_info)
4665 && has_concrete_type(op2_info)) {
4676 if (!zend_jit_supported_binary_op(
4681 && (opline+1)->op1_type ==
IS_CV
4682 && (opline+1)->op1.var == opline->
op1.
var) {
4691 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4701 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4717 if (!zend_jit_assign_dim_op(&ctx, opline,
4718 op1_info, op1_def_info, op1_addr,
4722 zend_jit_trace_may_throw(opline, ssa_op, op_array, ssa,
4723 op1_info, op2_info, op1_data_info,
val_type))) {
4737 ce_is_instanceof = 0;
4738 on_this = delayed_fetch_this = 0;
4742 ce = op_array->
scope;
4762 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4770 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4793 if (delayed_fetch_this) {
4797 }
else if (op_array_ssa->
ops
4798 && op_array_ssa->
vars
4804 if (!zend_jit_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
4806 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4821 && (opline+1)->op1_type ==
IS_CV
4822 && (opline+1)->op1.var == opline->
op1.
var) {
4826 if (!zend_jit_supported_binary_op(
4831 ce_is_instanceof = 0;
4832 on_this = delayed_fetch_this = 0;
4836 ce = op_array->
scope;
4856 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4864 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4887 if (delayed_fetch_this) {
4891 }
else if (op_array_ssa->
ops
4892 && op_array_ssa->
vars
4900 if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
4902 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4914 ce_is_instanceof = 0;
4915 on_this = delayed_fetch_this = 0;
4919 ce = op_array->
scope;
4939 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
4947 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
4970 if (delayed_fetch_this) {
4974 }
else if (op_array_ssa->
ops
4975 && op_array_ssa->
vars
4983 if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
4986 op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
4991 if ((opline+1)->op1_type ==
IS_CV
4992 && (ssa_op+1)->op1_def >= 0
5001 && (opline+1)->op1_type ==
IS_CV
5002 && (opline+1)->op1.var == opline->
op1.
var) {
5010 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
5020 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5035 if (!zend_jit_assign_dim(&ctx, opline,
5046 if ((opline+1)->op1_type ==
IS_CV
5047 && (ssa_op+1)->op1_def >= 0
5061 op2_def_addr = op2_addr;
5071 if (!zend_jit_scalar_type_guard(&ctx, opline, opline->
op1.
var)) {
5089 if (!zend_jit_guard_reference(&ctx, opline, &op1_addr, &ref_addr,
5103 && zend_jit_trace_next_is_send_result(opline,
p,
frame)) {
5106 if (!zend_jit_reuse_ip(&ctx)) {
5111 op1_def_addr = op1_addr;
5114 if (!zend_jit_noref_guard(&ctx, opline, op1_addr)) {
5128 && zend_jit_trace_next_is_send_result(opline,
p,
frame)) {
5131 if (!zend_jit_reuse_ip(&ctx)) {
5136 if (!zend_jit_assign(&ctx, opline,
5138 op1_def_info, op1_def_addr,
5139 op2_info, op2_addr, op2_def_addr,
5154 if (!zend_jit_store_type(&ctx, var_num,
type)) {
5174 op1_def_addr = op1_addr;
5181 res_use_info = zend_jit_trace_type_to_info(
5193 if (!zend_jit_qm_assign(&ctx, opline,
5194 op1_info, op1_addr, op1_def_addr,
5195 res_use_info, res_info, res_addr)) {
5207 if (!zend_jit_store_type(&ctx, var_num,
type)) {
5223 if (!zend_jit_init_fcall(&ctx, opline, op_array_ssa->
cfg.
map ? op_array_ssa->
cfg.
map[opline - op_array->
opcodes] : -1, op_array, ssa, ssa_op,
frame->call_level,
p + 1, peek_checked_stack - checked_stack)) {
5239 if (!zend_jit_send_val(&ctx, opline,
5250 zend_jit_trace_send_type(opline,
frame->call, op1_type);
5260 if (!zend_jit_send_ref(&ctx, opline, op_array,
5285 op1_def_addr = op1_addr;
5291 if (!zend_jit_send_var(&ctx, opline, op_array,
5292 op1_info, op1_addr, op1_def_addr)) {
5304 if (!zend_jit_store_type(&ctx, var_num,
type)) {
5325 zend_jit_trace_send_type(opline,
frame->call, op1_type);
5330 if (!
JIT_G(current_frame)
5341 if (!zend_jit_check_func_arg(&ctx, opline)) {
5346 if (
JIT_G(current_frame)
5350 if (!zend_jit_check_undef_args(&ctx, opline)) {
5358 if (!zend_jit_do_fcall(&ctx, opline, op_array, op_array_ssa,
frame->call_level, -1,
p + 1)) {
5370 ssa_op != ssa->
ops &&
5373 zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5377 bool exit_if_true = 0;
5378 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5379 uint32_t exit_point;
5382 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5384 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5385 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5390 if (!zend_jit_cmp(&ctx, opline,
5395 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5398 zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5400 smart_branch_opcode = 0;
5402 if (!zend_jit_cmp(&ctx, opline,
5407 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5418 ssa_op != ssa->
ops &&
5421 zend_jit_may_skip_comparison(opline, ssa_op, ssa, ssa_opcodes, op_array);
5425 bool exit_if_true = 0;
5426 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5427 uint32_t exit_point;
5430 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5432 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5433 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5438 exit_if_true = !exit_if_true;
5441 if (!zend_jit_identical(&ctx, opline,
5446 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5449 zend_jit_trace_update_condition_ranges(opline, ssa_op, op_array, ssa, exit_if_true);
5451 smart_branch_opcode = 0;
5453 if (!zend_jit_identical(&ctx, opline,
5458 smart_branch_opcode, -1, -1, exit_addr, skip_comparison)) {
5465 bool exit_if_true = 0;
5466 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5467 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5469 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5475 smart_branch_opcode = 0;
5478 if (!zend_jit_defined(&ctx, opline, smart_branch_opcode, -1, -1, exit_addr)) {
5490 bool exit_if_true = 0;
5491 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5492 uint32_t exit_point;
5495 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5497 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5498 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5504 smart_branch_opcode = 0;
5507 if (!zend_jit_type_check(&ctx, opline, op1_info, smart_branch_opcode, -1, -1, exit_addr)) {
5517 res_type = op1_type;
5527 if (!zend_jit_trace_handler(&ctx, op_array, opline,
zend_may_throw(opline, ssa_op, op_array, ssa),
p + 1)) {
5533 bool left_frame = 0;
5535 if (!zend_jit_return(&ctx, opline, op_array,
5541 if (!zend_jit_free_cvs(&ctx)) {
5551 info = zend_ssa_cv_info(op_array, op_array_ssa,
j);
5553 info = zend_jit_trace_type_to_info_ex(
type, info);
5557 if (
JIT_G(current_frame)
5567 if (!zend_jit_leave_frame(&ctx)) {
5571 if (!zend_jit_free_cv(&ctx, info,
j)) {
5582 if (!zend_jit_leave_func(&ctx, op_array, opline, op1_info, left_frame,
5593 if (!zend_jit_bool_jmpznz(&ctx, opline,
5609 uint32_t exit_point;
5622 exit_opline = opline + 1;
5623 }
else if ((
p+1)->opline == opline + 1) {
5625 smart_branch_opcode = opline->
opcode;
5631 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5634 && has_concrete_type(op1_info)
5635 && concrete_type(op1_info) <=
IS_TRUE) {
5642 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5644 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5649 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5650 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5663 if (!zend_jit_bool_jmpznz(&ctx, opline,
5667 smart_branch_opcode, exit_addr)) {
5675 uint32_t exit_point;
5681 exit_opline = opline + 1;
5682 }
else if ((
p+1)->opline == opline + 1) {
5689 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5690 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5694 if (!zend_jit_jmp_frameless(&ctx, opline, exit_addr, guard)) {
5707 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5719 bool exit_if_true = 0;
5720 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5721 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5723 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5729 smart_branch_opcode = 0;
5732 if (!zend_jit_isset_isempty_cv(&ctx, opline,
5734 smart_branch_opcode, -1, -1, exit_addr)) {
5749 bool exit_if_true = 0;
5750 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5751 uint32_t exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5753 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5759 smart_branch_opcode = 0;
5762 if (!zend_jit_in_array(&ctx, opline,
5764 smart_branch_opcode, -1, -1, exit_addr)) {
5769 if (!
JIT_G(current_frame)
5783 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5823 if (!zend_jit_fetch_dim_read(&ctx, opline, ssa, ssa_op,
5824 op1_info, op1_addr, avoid_refcounting,
5847 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
5857 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5871 if (!zend_jit_fetch_dim(&ctx, opline,
5894 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
5908 bool exit_if_true = 0;
5909 const zend_op *exit_opline = zend_jit_trace_get_exit_opline(
p + 1, opline + 1, &exit_if_true);
5910 uint32_t exit_point;
5911 int32_t old_ref = 0;
5912 uint8_t old_flags = 0;
5919 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
5927 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5930 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
5932 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
5941 smart_branch_opcode = 0;
5961 if (!zend_jit_isset_isempty_dim(&ctx, opline,
5962 op1_info, op1_addr, avoid_refcounting,
5965 smart_branch_opcode, -1, -1,
5971 if (!
JIT_G(current_frame)
5981 on_this = delayed_fetch_this = 0;
5982 avoid_refcounting = 0;
5989 ce_is_instanceof = 0;
5993 ce = op_array->
scope;
6011 if (!zend_jit_fetch_indirect_var(&ctx, opline, orig_op1_type,
6019 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6046 if (delayed_fetch_this) {
6050 }
else if (op_array_ssa->
ops
6051 && op_array_ssa->
vars
6057 if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
6058 op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
6059 on_this, delayed_fetch_this, avoid_refcounting, op1_ce,
6066 orig_opline = opline;
6067 orig_ssa_op = ssa_op;
6077 if (!zend_jit_bind_global(&ctx, opline, op1_info)) {
6087 opline = orig_opline;
6088 ssa_op = orig_ssa_op;
6091 if (!zend_jit_recv(&ctx, opline, op_array)) {
6096 orig_opline = opline;
6097 orig_ssa_op = ssa_op;
6099 if (!zend_jit_recv_init(&ctx, opline, op_array,
6111 opline = orig_opline;
6112 ssa_op = orig_ssa_op;
6117 if (!zend_jit_free(&ctx, opline, op1_info,
6128 if (!zend_jit_echo(&ctx, opline, op1_info)) {
6136 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6150 if (!zend_jit_strlen(&ctx, opline, op1_info, op1_addr,
RES_REG_ADDR())) {
6158 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6177 delayed_fetch_this = 0;
6179 if (zend_jit_may_delay_fetch_this(op_array, ssa, ssa_opcodes, ssa_op)) {
6181 delayed_fetch_this = 1;
6184 if (!zend_jit_fetch_this(&ctx, opline, op_array, delayed_fetch_this)) {
6191 if (!zend_jit_switch(&ctx, opline, op_array, op_array_ssa,
p+1, &zend_jit_traces[
ZEND_JIT_TRACE_NUM])) {
6214 if (!zend_jit_verify_return_type(&ctx, opline, op_array, op1_info)) {
6224 if (!zend_jit_fe_reset(&ctx, opline, op1_info)) {
6236 uint32_t exit_point;
6238 if ((
p+1)->opline == exit_opline) {
6240 exit_opline = opline;
6242 }
else if ((
p+1)->opline == opline + 1) {
6248 exit_point = zend_jit_trace_get_exit_point(exit_opline, 0);
6249 exit_addr = zend_jit_trace_get_exit_addr(exit_point);
6256 if (!zend_jit_fe_fetch(&ctx, opline, op1_info,
OP2_INFO(),
6257 -1, smart_branch_opcode, exit_addr)) {
6262 if (!zend_jit_fetch_constant(&ctx, opline, op_array, ssa, ssa_op,
RES_REG_ADDR())) {
6271 on_this = delayed_fetch_this = 0;
6273 ce_is_instanceof = 0;
6276 ce = op_array->
scope;
6286 if (polymorphic_side_trace) {
6290 if (!zend_jit_fetch_reference(&ctx, opline, orig_op1_type, &op1_info, &op1_addr,
6313 if (delayed_fetch_this) {
6317 }
else if (op_array_ssa->
ops
6318 && op_array_ssa->
vars
6325 if (!zend_jit_init_method_call(&ctx, opline,
6327 op_array, ssa, ssa_op,
frame->call_level,
6328 op1_info, op1_addr, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
6329 p + 1, peek_checked_stack - checked_stack,
6332 polymorphic_side_trace)) {
6343 if (!zend_jit_init_closure_call(&ctx, opline, op_array_ssa->
cfg.
map ? op_array_ssa->
cfg.
map[opline - op_array->
opcodes] : -1, op_array, ssa, ssa_op,
frame->call_level,
p + 1, peek_checked_stack - checked_stack)) {
6349 if (
JIT_G(current_frame)
6362 if (!zend_jit_rope(&ctx, opline, op2_info)) {
6367 jit_frameless_icall0(jit, opline);
6371 jit_frameless_icall1(jit, opline, op1_info);
6376 jit_frameless_icall2(jit, opline, op1_info, op2_info);
6381 jit_frameless_icall3(jit, opline, op1_info, op2_info,
OP1_DATA_INFO());
6398 if (!zend_jit_trace_handler(&ctx, op_array, opline,
6406 if (zend_jit_may_be_polymorphic_call(opline) ||
6407 zend_jit_may_be_modified((
p+1)->
func, op_array)) {
6408 if (!zend_jit_init_fcall_guard(&ctx, 0, (
p+1)->
func, opline+1)) {
6416 polymorphic_side_trace = 0;
6417 if (zend_jit_dec_call_level(opline->
opcode)) {
6418 frame->call_level--;
6422 zend_jit_trace_cleanup_stack(&ctx, stack, opline, ssa_op, ssa, ssa_opcodes);
6480 }
else if ((
p+1)->opline != (opline + 1)) {
6492 uint32_t op_num = opline - op_array->
opcodes;
6496 op_num += zend_jit_trace_op_len(opline);
6498 if (range->start > op_num) {
6503 bool store_type = 0;
6504 const zend_ssa_op *next_ssa_op = ssa_op + zend_jit_trace_op_len(opline);
6513 if (op_num >= range->end || op_num < range->
start) {
6520 next_ssa_op += zend_jit_trace_op_len(q->
opline);
6526 if (!zend_jit_store_type(&ctx, var_num,
type)) {
6542 && delayed_fetch_this) {
6675 switch (opline->
opcode) {
6764 ssa_op += zend_jit_trace_op_len(opline);
6785 frame->call_opline = opline;
6788 if (opline > op_array->
opcodes) {
6789 const zend_op *prev_opline = opline - 1;
6798 &&
p->op_array->num_args
6804 && !zend_jit_trace_opline_guard(&ctx, (
p+1)->opline)) {
6835 stack =
frame->stack;
6839 for (i = 0; i < op_array->
last_var; i++,
j++) {
6866 checked_stack =
frame->old_checked_stack;
6867 peek_checked_stack =
frame->old_peek_checked_stack;
6869 stack =
frame->stack;
6872 frame = zend_jit_trace_ret_frame(
frame, op_array);
6874 frame->used_stack = checked_stack = peek_checked_stack = 0;
6875 stack =
frame->stack;
6879 for (i = 0; i < op_array->
last_var + op_array->
T; i++,
j++) {
6890 for (i = 0; i < op_array->
last_var + op_array->
T; i++,
j++) {
6900 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
6909 const zend_op *opline = (
p+1)->opline - 1;
6918 const zend_op *init_opline = zend_jit_trace_find_init_fcall_op(
p, op_array);
6941 && (ssa_op-1)->op1_use >=0
6944 || (
p->func && (!
p->func->common.scope || (
p->func->common.fn_flags &
ZEND_ACC_STATIC))))
6946 || (
p->func && (!
p->func->common.scope || (
p->func->common.fn_flags &
ZEND_ACC_STATIC))))
6953 &&
p->func &&
p->func->common.scope && !(
p->func->common.fn_flags &
ZEND_ACC_STATIC))) {
6958 top = zend_jit_trace_call_frame(
top,
p->op_array);
6966 while (i < p->op_array->
num_args) {
6971 while (i < p->op_array->
last_var) {
6980 while (i < p->op_array->
last_var +
p->op_array->T) {
6985 for (i = 0; i <
p->op_array->last_var +
p->op_array->T; i++) {
6991 for (i = 0; i <
p->op_array->num_args; i++) {
7002 if (
call_info->caller_init_opline == init_opline
7018 && !zend_jit_may_be_polymorphic_call(init_opline)
7019 && !zend_jit_may_be_modified(
p->func, op_array)) {
7033 if (!zend_jit_init_fcall_guard(&ctx,
7040 call->old_checked_stack = checked_stack;
7041 call->old_peek_checked_stack = peek_checked_stack;
7043 frame->call_level++;
7044 call->used_stack = checked_stack = peek_checked_stack = 0;
7051 switch (init_opline->
opcode) {
7061 checked_stack +=
call->used_stack;
7062 if (checked_stack > peek_checked_stack) {
7063 peek_checked_stack = checked_stack;
7067 checked_stack = peek_checked_stack = 0;
7073 checked_stack =
call->old_checked_stack;
7074 peek_checked_stack =
call->old_peek_checked_stack;
7087 if (!parent_trace && zend_jit_trace_uses_initial_ip(&ctx)) {
7091 if (
p->stop == ZEND_JIT_TRACE_STOP_LOOP
7092 ||
p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7093 ||
p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7111 if (
p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7113 && !zend_jit_set_ip(&ctx,
p->opline)) {
7118 if (
p->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7122 const void *timeout_exit_addr =
NULL;
7126 if (trace_buffer->stop != ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7129 && zend_jit_trace_stack_needs_deoptimization(stack, op_array->
last_var + op_array->
T))) {
7131 uint32_t exit_point = zend_jit_trace_get_exit_point(trace_buffer[1].opline,
ZEND_JIT_EXIT_TO_VM);
7133 timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7134 if (!timeout_exit_addr) {
7138 timeout_exit_addr = zend_jit_stub_handlers[jit_stub_interrupt_handler];
7142 zend_jit_trace_end_loop(&ctx, jit->
trace_loop_ref, timeout_exit_addr);
7144 }
else if (
p->stop == ZEND_JIT_TRACE_STOP_LINK
7145 ||
p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
7153 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
7162 }
else if (i < op_array->last_var
7165 && zend_jit_trace_must_store_type(op_array, op_array_ssa, opline - op_array->
opcodes, i,
type)) {
7166 if (!zend_jit_store_type(jit, i,
type)) {
7174 if (
p->stop == ZEND_JIT_TRACE_STOP_LINK) {
7175 const void *timeout_exit_addr =
NULL;
7177 t->
link = zend_jit_find_trace(
p->opline->handler);
7188 && !zend_jit_set_ip(&ctx,
p->opline)) {
7191 if (!parent_trace && zend_jit_trace_uses_initial_ip(&ctx)) {
7196 && zend_jit_traces[parent_trace].root == t->
link) {
7198 uint32_t exit_point;
7200 for (i = 0; i < op_array->
last_var + op_array->
T; i++) {
7204 timeout_exit_addr = zend_jit_trace_get_exit_addr(exit_point);
7205 if (!timeout_exit_addr) {
7209 timeout_exit_addr = zend_jit_stub_handlers[jit_stub_interrupt_handler];
7212 zend_jit_trace_link_to_root(&ctx, &zend_jit_traces[t->
link], timeout_exit_addr);
7214 zend_jit_trace_return(&ctx, 0,
NULL);
7216 }
else if (
p->stop == ZEND_JIT_TRACE_STOP_RETURN) {
7217 zend_jit_trace_return(&ctx, 0,
NULL);
7227 handler = zend_jit_finish(&ctx);
7230 if (
p->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL) {
7233 rec_op_array = op_array = trace_buffer->
op_array;
7241 if (
p->op_array == rec_op_array) {
7242 zend_jit_trace_setup_ret_counter(opline, jit_extension->
offset);
7244 op_array =
p->op_array;
7248 op_array =
p->op_array;
7255 }
else if (
p->stop == ZEND_JIT_TRACE_STOP_LINK
7256 ||
p->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
7264 zend_jit_trace_setup_ret_counter(opline, jit_extension->
offset);
7266 if (
JIT_G(current_frame)
7270 if (
frame->call_opline) {
7271 op_array = &
frame->func->op_array;
7274 zend_jit_trace_setup_ret_counter(
frame->call_opline, jit_extension->
offset);
7283 zend_jit_free_ctx(&ctx);
7286 zend_string_release(
name);
7291 while (num_op_arrays > 0) {
7292 op_array = op_arrays[--num_op_arrays];
7304 zend_arena_release(&
CG(
arena), checkpoint);
7312static zend_string *zend_jit_trace_escape_name(uint32_t trace_num, uint32_t exit_num)
7316 smart_str_appends(&
buf,
" ESCAPE-");
7318 smart_str_appendc(&
buf,
'-');
7324static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
7331 uint32_t stack_size;
7333 bool original_handler = 0;
7335 if (!zend_jit_trace_exit_needs_deoptimization(trace_num, exit_num)) {
7336 return zend_jit_stub_handlers[jit_stub_trace_escape];
7339 name = zend_jit_trace_escape_name(trace_num, exit_num);
7341 if (!zend_jit_deoptimizer_start(&ctx,
name, trace_num, exit_num)) {
7342 zend_string_release(
name);
7346 checkpoint = zend_arena_checkpoint(
CG(
arena));;
7349 stack_size = zend_jit_traces[trace_num].exit_info[exit_num].stack_size;
7350 stack = zend_jit_traces[trace_num].exit_info[exit_num].stack_size ?
7351 zend_jit_traces[trace_num].stack_map + zend_jit_traces[trace_num].exit_info[exit_num].stack_offset :
7354 if (!zend_jit_trace_deoptimization(&ctx,
7355 &zend_jit_traces[trace_num].exit_info[exit_num],
7357 zend_jit_traces[trace_num].constants,
7362 opline = zend_jit_traces[trace_num].exit_info[exit_num].opline;
7364 if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) {
7370 original_handler = 1;
7373 zend_jit_set_ip_ex(&ctx, opline, original_handler);
7376 zend_jit_trace_return(&ctx, original_handler, opline);
7378 handler = zend_jit_finish(&ctx);
7381 zend_jit_free_ctx(&ctx);
7382 zend_string_release(
name);
7383 zend_arena_release(&
CG(
arena), checkpoint);
7391 uint8_t orig_trigger;
7394 bool do_bailout = 0;
7400 ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
7402 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
7432 orig_trigger =
JIT_G(trigger);
7435 handler = zend_jit_trace(trace_buffer, 0, 0);
7437 JIT_G(trigger) = orig_trigger;
7448 if (!shared_exit_info) {
7457 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7460 memcpy(shared_exit_info, exit_info,
7467 if (!shared_stack_map) {
7474 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7486 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
7502 ret = ZEND_JIT_TRACE_STOP_COMPILED;
7513 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
7523 ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
7542 &&
ret == ZEND_JIT_TRACE_STOP_COMPILED
7544 zend_jit_dump_exit_info(t);
7551static void zend_jit_stop_hot_trace_counters(
zend_op_array *op_array)
7557 for (i = 0; i < op_array->
last; i++) {
7571static void zend_jit_stop_persistent_op_array(
zend_op_array *op_array)
7578 zend_jit_stop_hot_trace_counters(op_array);
7591 zend_jit_stop_persistent_op_array(op_array);
7597 zend_jit_stop_persistent_op_array(op_array);
7604static void zend_jit_stop_counter_handlers(
void)
7606 if (
ZCSG(jit_counters_stopped)) {
7613 if (!
ZCSG(jit_counters_stopped)) {
7614 ZCSG(jit_counters_stopped) =
true;
7615 for (uint32_t i = 0; i <
ZCSG(
hash).max_num_entries; i++) {
7617 for (cache_entry =
ZCSG(
hash).hash_table[i]; cache_entry; cache_entry = cache_entry->
next) {
7619 if (cache_entry->
indirect)
continue;
7621 zend_jit_stop_persistent_script(script);
7629static void zend_jit_blacklist_root_trace(
const zend_op *opline,
size_t offset)
7659 zend_jit_stop_persistent_op_array(op_array);
7669 const zend_op **cache_opline =
JIT_G(bad_root_cache_opline);
7670 uint8_t *cache_count =
JIT_G(bad_root_cache_count);
7671 uint8_t *cache_stop =
JIT_G(bad_root_cache_stop);
7672 uint32_t cache_slot =
JIT_G(bad_root_slot);
7676 if (cache_opline[i] == opline) {
7677 if (cache_count[i] >=
JIT_G(blacklist_root_trace) - 1) {
7678 cache_opline[i] =
NULL;
7684 random() % ZEND_JIT_TRACE_COUNTER_MAX;
7688 cache_stop[i] = stop;
7694 cache_opline[i] = opline;
7696 cache_stop[i] = stop;
7698 JIT_G(bad_root_slot) = cache_slot;
7707 uint32_t level = 1 + trace_buffer[0].level;
7708 int idx,
len, i,
v, vars_count, call_level;
7711 op_array =
p->op_array;
7720 vars_count = op_array->
last_var + op_array->
T;
7722 for (i = 0; i < vars_count; i++) {
7724 fprintf(stderr,
" %*c;", level,
' ');
7729 if (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
7730 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
7731 || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) {
7751 uint8_t op1_type, op2_type, op3_type;
7755 (
int)(opline - op_array->
opcodes),
7759 op1_type =
p->op1_type;
7760 op2_type =
p->op2_type;
7761 op3_type =
p->op3_type;
7770 fprintf(stderr,
" op1(%sobject of class %s)", ref,
7783 fprintf(stderr,
" op2(%sobject of class %s)", ref,
7820 len = zend_jit_trace_op_len(opline);
7824 (
int)(opline - op_array->
opcodes),
7832 op_array =
p->op_array;
7833 fprintf(stderr,
" %*c>enter %s%s%s\n",
7836 op_array->
scope ?
"::" :
"",
7845 for (i = 0; i < vars_count; i++,
v++) {
7847 fprintf(stderr,
" %*c;", level,
' ');
7854 op_array =
p->op_array;
7856 fprintf(stderr,
" %*c<back %s%s%s\n",
7859 op_array->
scope ?
"::" :
"",
7864 if (call_level == 0) {
7866 vars_count = op_array->
last_var + op_array->
T;
7867 for (i = 0; i < vars_count; i++,
v++) {
7869 fprintf(stderr,
" %*c;", level,
' ');
7882 (
p->func &&
p->func->common.scope) ?
ZSTR_VAL(
p->func->common.scope->name) :
"",
7883 (
p->func &&
p->func->common.scope) ?
"::" :
"",
7884 p->func ?
ZSTR_VAL(
p->func->common.function_name) :
"???");
7886 fprintf(stderr,
" %*c>skip\n",
7891 fprintf(stderr,
" %*c>call %s%s%s\n",
7893 p->func->common.scope ?
ZSTR_VAL(
p->func->common.scope->name) :
"",
7894 p->func->common.scope ?
"::" :
"",
7895 ZSTR_VAL(
p->func->common.function_name));
7897 fprintf(stderr,
" %*c>skip\n",
7912 fprintf(stderr,
"%s", zend_reg_name(rs->
reg));
7922 fprintf(stderr,
"---- TRACE %d exit info\n", t->
id);
7928 fprintf(stderr,
" exit_%d:", i);
7964 for (
j = 0;
j < stack_size;
j++) {
7984 fprintf(stderr,
"(type_only)");
7988 fprintf(stderr,
"(zval_try_addref)");
8009 fprintf(stderr,
":unknown(zval_try_addref)");
8037 orig_opline = opline;
8038 op_array = &
EX(
func)->op_array;
8042 EX(opline) = opline;
8049 if (
JIT_G(tracing)) {
8055 fprintf(stderr,
"---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8067 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8068 zend_jit_stop_counter_handlers();
8082 if (
UNEXPECTED(trace_buffer[1].opline != orig_opline)) {
8083 orig_opline = trace_buffer[1].
opline;
8094 fprintf(stderr,
"---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8098 op_array->
scope ?
"::" :
"",
8107 zend_jit_dump_trace(trace_buffer,
NULL);
8112 if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8113 uint32_t idx = trace_buffer[1].
last;
8114 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->
handler);
8115 fprintf(stderr,
"---- TRACE %d stop (link to %d)\n",
8119 fprintf(stderr,
"---- TRACE %d stop (%s)\n",
8121 zend_jit_trace_stop_description[stop]);
8124 stop = zend_jit_compile_root_trace(trace_buffer, orig_opline,
offset);
8127 fprintf(stderr,
"---- TRACE %d %s\n",
8129 zend_jit_trace_stop_description[stop]);
8137 fprintf(stderr,
"---- TRACE %d abort (%s)\n",
8139 zend_jit_trace_stop_description[stop]);
8142 || zend_jit_trace_is_bad_root(orig_opline, stop,
offset)) {
8144 fprintf(stderr,
"---- TRACE %d blacklisted\n",
8147 zend_jit_blacklist_root_trace(orig_opline,
offset);
8151 opline =
EX(opline);
8163static void zend_jit_blacklist_trace_exit(uint32_t trace_num, uint32_t exit_num)
8166 bool do_bailout = 0;
8175 handler = zend_jit_trace_exit_to_vm(trace_num, exit_num);
8178 zend_jit_link_side_trace(
8179 zend_jit_traces[trace_num].code_start,
8180 zend_jit_traces[trace_num].code_size,
8181 zend_jit_traces[trace_num].jmp_table_size,
8201static bool zend_jit_trace_exit_is_bad(uint32_t trace_num, uint32_t exit_num)
8203 uint8_t *counter =
JIT_G(exit_counters) +
8204 zend_jit_traces[trace_num].exit_counters + exit_num;
8206 if (*counter + 1 >=
JIT_G(hot_side_exit) +
JIT_G(blacklist_side_trace)) {
8213static bool zend_jit_trace_exit_is_hot(uint32_t trace_num, uint32_t exit_num)
8215 uint8_t *counter =
JIT_G(exit_counters) +
8216 zend_jit_traces[trace_num].exit_counters + exit_num;
8218 if (*counter + 1 >=
JIT_G(hot_side_exit)) {
8229 uint8_t orig_trigger;
8232 bool do_bailout = 0;
8238 ret = ZEND_JIT_TRACE_STOP_ALREADY_DONE;
8240 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8241 }
else if (zend_jit_traces[zend_jit_traces[parent_num].root].child_count >=
JIT_G(max_side_traces)) {
8242 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
8251 t->
root = zend_jit_traces[parent_num].root;
8266 orig_trigger =
JIT_G(trigger);
8269 handler = zend_jit_trace(trace_buffer, parent_num, exit_num);
8271 JIT_G(trigger) = orig_trigger;
8282 if (!shared_exit_info) {
8291 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8294 memcpy(shared_exit_info, exit_info,
8301 if (!shared_stack_map) {
8308 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8320 ret = ZEND_JIT_TRACE_STOP_NO_SHM;
8328 zend_jit_link_side_trace(
8329 zend_jit_traces[parent_num].code_start,
8330 zend_jit_traces[parent_num].code_size,
8331 zend_jit_traces[parent_num].jmp_table_size,
8338 zend_jit_traces[zend_jit_traces[parent_num].root].child_count++;
8342 ret = ZEND_JIT_TRACE_STOP_COMPILED;
8353 ret = ZEND_JIT_TRACE_STOP_TOO_MANY_EXITS;
8363 ret = ZEND_JIT_TRACE_STOP_COMPILER_ERROR;
8382 &&
ret == ZEND_JIT_TRACE_STOP_COMPILED
8384 zend_jit_dump_exit_info(t);
8396 uint32_t is_megamorphic = 0;
8397 uint32_t polymorphism = 0;
8409 fprintf(stderr,
"---- TRACE %d start (side trace %d/%d) %s%s%s() %s:%d\n",
8410 trace_num, parent_num, exit_num,
8416 EX(opline)->lineno);
8420 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_TRACES;
8424 root = zend_jit_traces[parent_num].root;
8425 if (zend_jit_traces[root].child_count >=
JIT_G(max_side_traces)) {
8426 stop = ZEND_JIT_TRACE_STOP_TOO_MANY_CHILDREN;
8430 if (
JIT_G(max_polymorphic_calls) > 0) {
8434 if (zend_jit_traces[parent_num].polymorphism >=
JIT_G(max_polymorphic_calls) - 1) {
8435 is_megamorphic = zend_jit_traces[parent_num].exit_info[exit_num].flags &
8437 }
else if (!zend_jit_traces[parent_num].polymorphism) {
8439 }
else if (exit_num == 0) {
8440 polymorphism = zend_jit_traces[parent_num].polymorphism + 1;
8447 && zend_jit_traces[root].op_array != &
EX(
func)->op_array) {
8448 const zend_op_array *op_array = zend_jit_traces[root].op_array;
8449 const zend_op *opline = zend_jit_traces[root].opline;
8457 ex =
ex->prev_execute_data;
8459 }
while (
ex && zend_jit_traces[root].op_array != &
ex->func->op_array);
8483 fprintf(stderr,
"---- TRACE %d start (%s) %s%s%s() %s:%d\n",
8487 op_array->
scope ?
"::" :
"",
8496 zend_jit_dump_trace(trace_buffer,
NULL);
8501 if (stop == ZEND_JIT_TRACE_STOP_LINK) {
8502 uint32_t idx = trace_buffer[1].
last;
8503 uint32_t link_to = zend_jit_find_trace(trace_buffer[idx].opline->
handler);;
8504 fprintf(stderr,
"---- TRACE %d stop (link to %d)\n",
8508 fprintf(stderr,
"---- TRACE %d stop (%s)\n",
8510 zend_jit_trace_stop_description[stop]);
8514 stop = zend_jit_compile_side_trace(trace_buffer, parent_num, exit_num, polymorphism);
8521 stop = zend_jit_compile_root_trace(trace_buffer, opline, jit_extension->
offset);
8525 fprintf(stderr,
"---- TRACE %d %s\n",
8527 zend_jit_trace_stop_description[stop]);
8535 fprintf(stderr,
"---- TRACE %d abort (%s)\n",
8537 zend_jit_trace_stop_description[stop]);
8540 || zend_jit_trace_exit_is_bad(parent_num, exit_num)) {
8541 zend_jit_blacklist_trace_exit(parent_num, exit_num);
8543 fprintf(stderr,
"---- EXIT %d/%d blacklisted\n",
8544 parent_num, exit_num);
8562 uint32_t trace_num =
EG(jit_trace_num);
8564 const zend_op *orig_opline =
EX(opline);
8567 int repeat_last_opline = 0;
8580 for (i = 0; i < stack_size; i++) {
8615 repeat_last_opline = 1;
8636 double val = regs->fpr[
STACK_REG(stack, i) - ZREG_FIRST_FPR];
8644 if (repeat_last_opline) {
8662 EX(opline) = opline-1;
8663 zval_ptr_dtor_nogc(
EX_VAR((opline-1)->
op2.var));
8672 EX(opline) = opline-1;
8673 zval_ptr_dtor_nogc(
EX_VAR((opline-1)->
op1.var));
8679 if (GCC_GLOBAL_REGS) {
8680 EX(opline) =
EG(exception_op);
8698 EX(opline) = opline;
8704 EX(opline) = opline;
8707 if (zend_atomic_bool_load_ex(&
EG(vm_interrupt)) ||
JIT_G(tracing)) {
8719 fprintf(stderr,
" TRACE %d exit %d %s%s%s() %s:%d\n",
8727 EX(opline)->lineno);
8732 uint32_t num = trace_num;
8734 while (t->
root != num) {
8736 t = &zend_jit_traces[num];
8766 ((
zend_op*)(t->
opline))->handler = (
const void*)zend_jit_loop_trace_counter_handler;
8768 ((
zend_op*)(t->
opline))->handler = (
const void*)zend_jit_func_trace_counter_handler;
8770 ((
zend_op*)(t->
opline))->handler = (
const void*)zend_jit_ret_trace_counter_handler;
8785 if (zend_jit_trace_exit_is_bad(trace_num, exit_num)) {
8786 zend_jit_blacklist_trace_exit(trace_num, exit_num);
8788 fprintf(stderr,
"---- EXIT %d/%d blacklisted\n",
8789 trace_num, exit_num);
8793 }
else if (
JIT_G(hot_side_exit) && zend_jit_trace_exit_is_hot(trace_num, exit_num)) {
8798 return (orig_opline == t->
opline &&
EX(opline) == orig_opline);
8803 switch (opline->
opcode) {
8813static int zend_jit_restart_hot_trace_counters(
zend_op_array *op_array)
8819 for (i = 0; i < op_array->
last; i++) {
8823 op_array->
opcodes[i].
handler = (
const void*)zend_jit_loop_trace_counter_handler;
8825 op_array->
opcodes[i].
handler = (
const void*)zend_jit_func_trace_counter_handler;
8833static int zend_jit_setup_hot_trace_counters(
zend_op_array *op_array)
8842 if (!jit_extension) {
8847 jit_extension->
op_array = op_array;
8849 for (i = 0; i < op_array->
last; i++) {
8854 zend_jit_trace_supported(&op_array->
opcodes[i]);
8858 if (
JIT_G(hot_loop)) {
8863 if (zend_jit_build_cfg(op_array, &cfg) !=
SUCCESS) {
8873 opline->
handler = (
const void*)zend_jit_loop_trace_counter_handler;
8887 if (
JIT_G(hot_func)) {
8898 opline->
handler = (
const void*)zend_jit_func_trace_counter_handler;
8912static void zend_jit_trace_init_caches(
void)
8915 memset(
JIT_G(bad_root_cache_count), 0,
sizeof(
JIT_G(bad_root_cache_count)));
8916 memset(
JIT_G(bad_root_cache_stop), 0,
sizeof(
JIT_G(bad_root_cache_count)));
8917 JIT_G(bad_root_slot) = 0;
8919 if (
JIT_G(exit_counters)) {
8924static void zend_jit_trace_reset_caches(
void)
8928 if (!
JIT_G(exit_counters)) {
8929 JIT_G(exit_counters) = calloc(
JIT_G(max_exit_counters), 1);
8941static void zend_jit_trace_restart(
void)
8947 ZCSG(jit_counters_stopped) =
false;
8949 zend_jit_trace_init_caches();
struct _zend_persistent_script zend_persistent_script
fprintf($stream, string $format, mixed ... $values)
prev(array|object &$array)
count(Countable|array $value, int $mode=COUNT_NORMAL)
assert(mixed $assertion, Throwable|string|null $description=null)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
hash(string $algo, string $data, bool $binary=false, array $options=[])
#define IR_REG_SPILLED(r)
unsigned const char * end
#define offsetof(STRUCTURE, FIELD)
zend_accel_hash_entry * next
int successors_storage[2]
zend_basic_block * blocks
zend_object *(* create_object)(zend_class_entry *class_type)
zend_ssa_var_info return_info
zend_call_info * callee_info
zend_call_info ** call_map
zend_jit_trace_info * trace
const zend_op_array * current_op_array
zend_op_trace_info trace_info[1]
const zend_op_array * op_array
zend_jit_ref_snapshot poly_this
const zend_op_array * op_array
zend_jit_ref_snapshot poly_func
zend_jit_exit_const * constants
const zend_op_array * op_array
zend_jit_trace_exit_info * exit_info
zend_jit_trace_stack * stack_map
const zend_op_array * op_array
zend_live_range * live_range
zend_string * function_name
zend_op_array main_op_array
zend_ssa_phi * definition_phi
zend_ssa_phi * phi_use_chain
zend_ssa_var_info * var_info
const zend_op ** tssa_opcodes
const void * call_handler
const void * orig_handler
ZEND_API const char * zend_get_type_by_const(int type)
ZEND_NORETURN void zend_accel_error_noreturn(int type, const char *format,...)
struct _zend_accel_hash_entry zend_accel_hash_entry
#define ZEND_MM_ALIGNED_SIZE(size)
#define erealloc(ptr, size)
#define ZEND_BITSET_ELM_SIZE
#define ZEND_BITSET_ALLOCA(n, use_heap)
exit(string|int $status=0)
ZEND_API zend_call_info ** zend_build_call_map(zend_arena **arena, zend_func_info *info, const zend_op_array *op_array)
ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32_t build_flags, zend_op_array *op_array, zend_func_info *func_info)
struct _zend_basic_block zend_basic_block
#define ZEND_BB_REACHABLE
struct _zend_cfg zend_cfg
#define RETURN_VALUE_USED(opline)
#define ZEND_SSA_RC_INFERENCE
#define ZEND_BB_LOOP_HEADER
#define ZEND_SSA_USE_CV_RESULTS
ZEND_API zend_class_entry * zend_ce_closure
zend_string_release_ex(func->internal_function.function_name, 0)
#define ARG_MUST_BE_SENT_BY_REF(zf, arg_num)
#define ZEND_ACC_IMMUTABLE
#define ZEND_FETCH_GLOBAL_LOCK
#define ZEND_ACC_HAS_TYPE_HINTS
#define IS_SMART_BRANCH_JMPNZ
#define ZEND_INTERNAL_FUNCTION
#define ZEND_ACC_DONE_PASS_TWO
#define ZEND_CALL_FRAME_SLOT
#define ZEND_ACC_TRAIT_CLONE
#define IS_SMART_BRANCH_JMPZ
#define ZEND_ARG_SEND_MODE(arg_info)
#define ZEND_USER_FUNCTION
#define ZEND_ACC_CALL_VIA_TRAMPOLINE
struct _zend_op_array zend_op_array
struct _zend_internal_arg_info zend_internal_arg_info
#define RT_CONSTANT(opline, node)
#define ZEND_ACC_HAS_RETURN_TYPE
struct _zend_arg_info zend_arg_info
#define OP_JMP_ADDR(opline, node)
#define ZEND_FETCH_GLOBAL
#define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num)
struct _zend_live_range zend_live_range
#define ZEND_ACC_RETURN_REFERENCE
#define ZEND_OFFSET_TO_OPLINE(base, offset)
ZEND_API void zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def)
ZEND_API void zend_dump_op(const zend_op_array *op_array, const zend_basic_block *b, const zend_op *opline, uint32_t dump_flags, const zend_ssa *ssa, const zend_ssa_op *ssa_op)
ZEND_API void zend_dump_var(const zend_op_array *op_array, uint8_t var_type, uint32_t var_num)
ZEND_API void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int ssa_var_num, uint8_t var_type, uint32_t var_num, uint32_t dump_flags)
ZEND_API void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, const char *msg, const void *data)
#define ZEND_DUMP_HIDE_UNREACHABLE
#define ZEND_DUMP_RC_INFERENCE
ZEND_API const zend_internal_function zend_pass_function
union _zend_function zend_function
#define ZEND_FUNC_JIT_ON_PROF_REQUEST
#define ZEND_FUNC_JIT_ON_HOT_TRACE
struct _zend_call_info zend_call_info
#define ZEND_FUNC_INDIRECT_VAR_ACCESS
#define ZEND_FUNC_INFO(op_array)
struct _zend_func_info zend_func_info
#define ZEND_FUNC_JIT_ON_HOT_COUNTERS
#define ZEND_SET_FUNC_INFO(op_array, info)
#define ZEND_FUNC_JIT_ON_FIRST_EXEC
#define ZEND_HASH_FOREACH_PTR(ht, _ptr)
#define ZEND_HASH_FOREACH_END()
ZEND_API bool zend_inference_propagate_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, int var, zend_ssa_range *tmp)
ZEND_API void zend_init_func_return_info(const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
ZEND_API bool zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa)
ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, const zend_ssa *ssa, uint32_t t1, uint32_t t2)
ZEND_API zend_result zend_update_type_info(const zend_op_array *op_array, zend_ssa *ssa, const zend_script *script, zend_op *opline, zend_ssa_op *ssa_op, const zend_op **ssa_opcodes, zend_long optimization_level)
ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, const zend_arg_info *arg_info, zend_class_entry **pce)
#define MAY_BE_PACKED_GUARD
#define ZEND_JIT_LEVEL_INLINE
#define ZEND_JIT_DEBUG_TRACE_BLACKLIST
struct _zend_jit_globals zend_jit_globals
#define ZEND_JIT_DEBUG_TRACE_COMPILED
struct _zend_jit_trace_rec zend_jit_trace_rec
#define ZEND_JIT_DEBUG_TRACE_EXIT_INFO
void zend_jit_unprotect(void)
zend_jit_globals jit_globals
struct _zend_jit_trace_stack_frame zend_jit_trace_stack_frame
#define ZEND_JIT_TRACE_MAX_LENGTH
#define ZEND_JIT_DEBUG_TRACE_TSSA
#define ZEND_JIT_DEBUG_TRACE_EXIT
#define ZEND_JIT_LEVEL_OPT_FUNC
#define ZEND_JIT_DEBUG_TRACE_START
void zend_jit_protect(void)
#define ZEND_JIT_TRACE_MAX_FUNCS
#define ZEND_JIT_REG_ALLOC_LOCAL
#define ZEND_JIT_ON_HOT_TRACE
#define ZEND_JIT_LEVEL_OPT_FUNCS
#define ZEND_JIT_REG_ALLOC_GLOBAL
#define ZEND_JIT_DEBUG_TRACE_STOP
#define ZEND_JIT_TRACE_BAD_ROOT_SLOTS
#define ZEND_JIT_TRACE_MAX_EXITS
#define ZEND_JIT_DEBUG_REG_ALLOC
#define ZEND_JIT_DEBUG_TRACE_ABORT
#define ZEND_JIT_DEBUG_TRACE_BYTECODE
#define ZEND_JIT_TRACE_MAX_RET_DEPTH
#define ZEND_JIT_DEBUG_SSA
#define TRACE_FRAME_IS_UNKNOWN_RETURN(frame)
#define ZEND_JIT_EXIT_CHECK_EXCEPTION
#define TRACE_FRAME_SET_ALWAYS_RELEASE_THIS(frame)
#define ZEND_JIT_EXIT_CLOSURE_CALL
#define TRACE_FRAME_SET_THIS_CHECKED(frame)
#define ZEND_JIT_TRACE_STOP(_)
#define ZEND_JIT_EXIT_METHOD_CALL
#define TRACE_FRAME_MASK_UNKNOWN_RETURN
#define TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(frame)
#define ZEND_JIT_TRACE_MAX_SSA_VAR
#define ZEND_JIT_TRACE_START_MASK
#define ZEND_JIT_TRACE_JITED
#define ZEND_JIT_TRACE_GET_FIRST_SSA_VAR(_info)
struct _zend_jit_trace_exit_info zend_jit_trace_exit_info
#define ZEND_JIT_TRACE_FAKE_LEVEL(info)
#define ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(_info, var)
#define STACK_FLAGS(_stack, _slot)
#define IS_TRACE_REFERENCE
#define OP1_DEF_REG_ADDR()
#define TRACE_FRAME_IS_LAST_SEND_BY_VAL(frame)
#define ZEND_JIT_TRACE_STOP_MAY_RECOVER(ret)
#define ZEND_JIT_TRACE_START_REC_SIZE
#define TRACE_FRAME_SET_LAST_SEND_BY_VAL(frame)
#define ZEND_JIT_TRACE_SUPPORTED
struct _zend_jit_trace_info zend_jit_trace_info
#define TRACE_FRAME_SET_RETURN_VALUE_UNUSED(frame)
#define OP1_DATA_DEF_REG_ADDR()
#define ZEND_ADDR_MEM_ZVAL(reg, offset)
#define TRACE_FRAME_SET_RETURN_SSA_VAR(frame, var)
#define TRACE_FRAME_SET_NO_NEED_RELEASE_THIS(frame)
#define CLEAR_STACK_REF(_stack, _slot)
#define STACK_VAR(_stack, _slot)
#define ZEND_JIT_TRACE_STOP_OK(ret)
struct _zend_jit_ref_snapshot zend_jit_ref_snapshot
@ ZEND_JIT_TRACE_VAL_INFO
@ ZEND_JIT_TRACE_OP2_TYPE
@ ZEND_JIT_TRACE_OP1_TYPE
@ ZEND_JIT_TRACE_DO_ICALL
@ ZEND_JIT_TRACE_INIT_CALL
#define ZEND_JIT_TRACE_RETURN_VALUE_USED
zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *execute_data, const zend_op *opline, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphc, int ret_depth)
#define ZEND_JIT_TRACE_START_SIDE
#define ZEND_JIT_TRACE_STOP_REPEAT(ret)
#define TRACE_FRAME_IS_THIS_CHECKED(frame)
struct _zend_jit_op_array_trace_extension zend_jit_op_array_trace_extension
#define TRACE_FRAME_MAX_NUM_ARGS
#define STACK_REG(_stack, _slot)
#define TRACE_FRAME_MASK_NESTED
#define SET_STACK_REG_EX(_stack, _slot, _reg, _flags)
#define STACK_TYPE(_stack, _slot)
#define ZEND_JIT_EXIT_TO_VM
#define TRACE_FRAME_IS_RETURN_VALUE_USED(frame)
#define IS_TRACE_INDIRECT
#define TRACE_FRAME_SET_RETURN_VALUE_USED(frame)
#define RESET_STACK_MEM_TYPE(_stack, _slot)
#define ZEND_JIT_TRACE_BLACKLISTED
#define TRACE_FRAME_INIT(frame, _func, _flags, num_args)
#define STACK_REF(_stack, _slot)
union _zend_jit_exit_const zend_jit_exit_const
#define ZEND_JIT_TRACE_START_ENTER
#define ZEND_JIT_TRACE_UNSUPPORTED
#define SET_STACK_INFO(_stack, _slot, _info)
#define ZEND_JIT_EXIT_JITED
#define ZEND_JIT_TRACE_START_LOOP
#define ZEND_JIT_TRACE_CHECK_INTERRUPT
#define ZEND_OP_TRACE_INFO(opline, offset)
#define OP2_DEF_REG_ADDR()
struct _zend_jit_trace_stack zend_jit_trace_stack
#define TRACE_FRAME_NUM_ARGS(frame)
#define SET_STACK_REG(_stack, _slot, _reg)
#define SET_STACK_VAR(_stack, _slot, _ssa_var)
#define ZEND_JIT_EXIT_FREE_OP1
#define ZEND_JIT_TRACE_USES_INITIAL_IP
#define STACK_MEM_TYPE(_stack, _slot)
#define TRACE_FRAME_RETURN_SSA_VAR(frame)
#define ZEND_JIT_EXIT_RESTORE_CALL
#define TRACE_FRAME_SET_LAST_SEND_UNKNOWN(frame)
#define OP1_DATA_REG_ADDR()
#define ZEND_JIT_TRACE_START_RETURN
#define ZEND_JIT_TRACE_LOOP
#define ZEND_JIT_EXIT_POLYMORPHISM
#define STACK_INFO(_stack, _slot)
#define ZEND_JIT_TRACE_STOP_DONE(ret)
#define ZEND_JIT_TRACE_FAKE_INIT_CALL
#define SET_STACK_REF_EX(_stack, _slot, _ref, _flags)
#define SET_STACK_REF(_stack, _slot, _ref)
enum _zend_jit_trace_stop zend_jit_trace_stop
#define ZEND_JIT_EXIT_FREE_OP2
#define ZEND_HOT_COUNTERS_COUNT
#define ZEND_JIT_EXIT_INVALIDATE
#define TRACE_FRAME_SET_CLOSURE_CALL(frame)
#define TRACE_FRAME_SET_LAST_SEND_BY_REF(frame)
union _zend_op_trace_info zend_op_trace_info
#define SET_STACK_TYPE(_stack, _slot, _type, _set_mem_type)
int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT]
#define ZEND_JIT_EXIT_BLACKLISTED
struct _zend_jit_ctx zend_jit_ctx
#define ZEND_JIT_EXIT_POINTS_SPACING
struct _zend_jit_reg_var zend_jit_reg_var
struct _zend_jit_registers_buf zend_jit_registers_buf
#define ZEND_JIT_EXIT_POINTS_PER_GROUP
#define RA_IVAL_CLOSE(var, line)
#define RA_REG_START(var, line)
ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array)
#define CHECK_OP1_DATA_TRACE_TYPE()
#define ZEND_JIT_TRACE_NUM
int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs)
#define RA_REG_FLAGS(var)
#define CHECK_OP2_TRACE_TYPE()
#define ZEND_JIT_TRACE_STOP_DESCRIPTION(name, description)
#define ADD_OP2_TRACE_GUARD()
#define ZEND_JIT_EXIT_COUNTERS
#define ADD_OP1_DATA_TRACE_GUARD()
#define RA_IVAL_START(var, line)
#define RA_IVAL_FLAGS(var)
#define ZEND_JIT_EXIT_NUM
int ZEND_FASTCALL zend_jit_trace_hot_side(zend_execute_data *execute_data, uint32_t parent_num, uint32_t exit_num)
#define RA_IVAL_END(var, line)
struct _zend_tssa zend_tssa
#define ADD_OP1_TRACE_GUARD()
#define ZEND_JIT_COUNTER_NUM
int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline)
#define CHECK_OP1_TRACE_TYPE()
struct _zend_string zend_string
#define zend_free_trampoline(func)
struct _zend_script zend_script
#define ALLOCA_FLAG(name)
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_UNREACHABLE()
#define free_alloca(p, use_heap)
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
void zend_shared_alloc_lock(void)
void zend_shared_alloc_unlock(void)
void zend_shared_alloc_register_xlat_entry(const void *key_pointer, const void *value)
void * zend_shared_alloc(size_t size)
ZEND_API int zend_ssa_rename_op(const zend_op_array *op_array, const zend_op *opline, uint32_t k, uint32_t build_flags, int ssa_vars_count, zend_ssa_op *ssa_ops, int *var)
struct _zend_ssa_range zend_ssa_range
struct _zend_ssa_block zend_ssa_block
enum _zend_ssa_alias_kind zend_ssa_alias_kind
struct _zend_ssa zend_ssa
struct _zend_ssa_var zend_ssa_var
struct _zend_ssa_phi zend_ssa_phi
@ HTTP_RESPONSE_HEADER_ALIAS
struct _zend_ssa_op zend_ssa_op
struct _zend_ssa_var_info zend_ssa_var_info
#define zend_string_equals_literal(str, literal)
#define MAY_BE_ARRAY_OF_ANY
#define MAY_BE_ARRAY_PACKED
#define MAY_BE_ARRAY_OF_ARRAY
#define MAY_BE_ARRAY_STRING_HASH
#define MAY_BE_ARRAY_OF_OBJECT
#define MAY_BE_ARRAY_OF_REF
#define MAY_BE_PACKED_ONLY(t)
#define MAY_BE_ARRAY_OF_RESOURCE
#define MAY_BE_ARRAY_KEY_ANY
#define MAY_BE_ARRAY_NUMERIC_HASH
#define Z_TRY_ADDREF_P(pz)
#define Z_STRVAL_P(zval_p)
#define Z_REFCOUNTED_P(zval_p)
#define Z_TYPE_INFO_P(zval_p)
#define ZEND_TYPE_FULL_MASK(t)
#define ZEND_TYPE_IS_SET(t)
#define ZVAL_DOUBLE(z, d)
struct _zend_execute_data zend_execute_data
ZEND_API const void *ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *op)
fbc internal_function handler(call, ret)
gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno, $opcode, $extra_spec=null, &$switch_labels=array())
#define ZEND_IS_IDENTICAL
#define ZEND_FETCH_CONSTANT
#define ZEND_ASSIGN_DIM_OP
#define ZEND_ASSIGN_STATIC_PROP_REF
#define ZEND_ISSET_ISEMPTY_CV
#define ZEND_VERIFY_RETURN_TYPE
#define ZEND_FETCH_LIST_R
#define ZEND_INCLUDE_OR_EVAL
#define ZEND_GENERATOR_CREATE
#define ZEND_INIT_USER_CALL
#define ZEND_FRAMELESS_ICALL_0
#define ZEND_FETCH_LIST_W
#define ZEND_ASSERT_CHECK
#define ZEND_RETURN_BY_REF
#define ZEND_SWITCH_STRING
#define ZEND_FETCH_OBJ_FUNC_ARG
#define ZEND_ASSIGN_STATIC_PROP_OP
#define ZEND_FETCH_DIM_FUNC_ARG
#define ZEND_EXT_FCALL_BEGIN
#define ZEND_FRAMELESS_ICALL_1
#define ZEND_IS_NOT_EQUAL
#define ZEND_IS_NOT_IDENTICAL
#define ZEND_FETCH_OBJ_IS
#define ZEND_POST_DEC_OBJ
#define ZEND_CHECK_FUNC_ARG
#define ZEND_ISSET_ISEMPTY_PROP_OBJ
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_INIT_NS_FCALL_BY_NAME
#define ZEND_ISSET_ISEMPTY_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_IS_SMALLER_OR_EQUAL
#define ZEND_INIT_FCALL_BY_NAME
#define ZEND_FRAMELESS_ICALL_2
#define ZEND_SEND_VAR_NO_REF_EX
#define ZEND_BIND_LEXICAL
#define ZEND_SEND_FUNC_ARG
#define ZEND_CHECK_UNDEF_ARGS
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_ISSET_ISEMPTY_VAR
#define ZEND_BIND_INIT_STATIC_OR_JMP
#define ZEND_GENERATOR_RETURN
#define ZEND_ARRAY_KEY_EXISTS
#define ZEND_JMP_FRAMELESS
#define ZEND_INIT_DYNAMIC_CALL
#define ZEND_INIT_PARENT_PROPERTY_HOOK_CALL
#define ZEND_ASSIGN_OBJ_OP
#define ZEND_ASSIGN_OBJ_REF
#define ZEND_FETCH_DIM_IS
#define ZEND_SEND_VAR_NO_REF
#define ZEND_POST_INC_OBJ
#define ZEND_DO_FCALL_BY_NAME
#define ZEND_INIT_METHOD_CALL
#define ZEND_INIT_STATIC_METHOD_CALL
#define ZEND_FETCH_FUNC_ARG
#define ZEND_FETCH_DIM_RW
#define ZEND_WORKLIST_ALLOCA(w, _len, use_heap)
struct _zend_worklist zend_worklist
#define ZEND_WORKLIST_FREE_ALLOCA(w, use_heap)