47#define RANGE_WARMUP_PASSES 16
51#define LOG_SSA_RANGE(...) fprintf(stderr, __VA_ARGS__)
53#define LOG_SSA_RANGE(...)
58#define LOG_NEG_RANGE(...) fprintf(stderr, __VA_ARGS__)
60#define LOG_NEG_RANGE(...)
64#define WHILE_WORKLIST(worklist, len, i) do { \
68 ZEND_BITSET_FOREACH(worklist, len, i) { \
69 zend_bitset_excl(worklist, i); \
72#define WHILE_WORKLIST_END() \
73 } ZEND_BITSET_FOREACH_END(); \
77#define CHECK_SCC_VAR(var2) \
79 if (!ssa->vars[var2].no_val) { \
80 if (ssa->vars[var2].scc < 0) { \
81 zend_ssa_check_scc_var(op_array, ssa, var2, index, stack); \
83 if (ssa->vars[var2].scc < ssa->vars[var].scc) { \
84 ssa->vars[var].scc = ssa->vars[var2].scc; \
90#define CHECK_SCC_ENTRY(var2) \
92 if (ssa->vars[var2].scc != ssa->vars[var].scc) { \
93 ssa->vars[var2].scc_entry = 1; \
97#define ADD_SCC_VAR(_var) \
99 if (ssa->vars[_var].scc == scc && \
100 !(ssa->var_info[_var].type & MAY_BE_REF)) { \
101 zend_bitset_incl(worklist, _var); \
105#define ADD_SCC_VAR_1(_var) \
107 if (ssa->vars[_var].scc == scc && \
108 !(ssa->var_info[_var].type & MAY_BE_REF) && \
109 !zend_bitset_in(visited, _var)) { \
110 zend_bitset_incl(worklist, _var); \
114#define FOR_EACH_DEFINED_VAR(line, MACRO) \
116 if (ssa->ops[line].op1_def >= 0) { \
117 MACRO(ssa->ops[line].op1_def); \
119 if (ssa->ops[line].op2_def >= 0) { \
120 MACRO(ssa->ops[line].op2_def); \
122 if (ssa->ops[line].result_def >= 0) { \
123 MACRO(ssa->ops[line].result_def); \
125 if (op_array->opcodes[line].opcode == ZEND_OP_DATA) { \
126 if (ssa->ops[line-1].op1_def >= 0) { \
127 MACRO(ssa->ops[line-1].op1_def); \
129 if (ssa->ops[line-1].op2_def >= 0) { \
130 MACRO(ssa->ops[line-1].op2_def); \
132 if (ssa->ops[line-1].result_def >= 0) { \
133 MACRO(ssa->ops[line-1].result_def); \
135 } else if ((uint32_t)line+1 < op_array->last && \
136 op_array->opcodes[line+1].opcode == ZEND_OP_DATA) { \
137 if (ssa->ops[line+1].op1_def >= 0) { \
138 MACRO(ssa->ops[line+1].op1_def); \
140 if (ssa->ops[line+1].op2_def >= 0) { \
141 MACRO(ssa->ops[line+1].op2_def); \
143 if (ssa->ops[line+1].result_def >= 0) { \
144 MACRO(ssa->ops[line+1].result_def); \
150#define FOR_EACH_VAR_USAGE(_var, MACRO) \
152 zend_ssa_phi *p = ssa->vars[_var].phi_use_chain; \
153 int use = ssa->vars[_var].use_chain; \
155 FOR_EACH_DEFINED_VAR(use, MACRO); \
156 use = zend_ssa_next_use(ssa->ops, _var, use); \
158 p = ssa->vars[_var].phi_use_chain; \
161 p = zend_ssa_next_use_phi(ssa, _var, p); \
195 p =
p->sym_use_chain;
201 while (stack->
len > 0) {
202 int var2 = zend_worklist_stack_peek(stack);
206 zend_worklist_stack_pop(stack);
214 zend_worklist_stack_push(stack, var);
232 zend_ssa_check_scc_var(op_array, ssa,
j, &index, &stack);
274 switch (iterator->
state) {
275 case 0:
goto state_0;
276 case 1: use = iterator->
use;
goto state_1;
277 case 2: use = iterator->
use;
goto state_2;
278 case 3: use = iterator->
use;
goto state_3;
279 case 4: use = iterator->
use;
goto state_4;
280 case 5: use = iterator->
use;
goto state_5;
281 case 6: use = iterator->
use;
goto state_6;
282 case 7: use = iterator->
use;
goto state_7;
283 case 8: use = iterator->
use;
goto state_8;
284 case 9: phi = iterator->
phi;
goto state_9;
286 case 10: phi = iterator->
phi;
goto state_10;
288 case 11:
goto state_11;
331 }
else if ((uint32_t)use+1 < op_array->
last &&
352 use = zend_ssa_next_use(ssa->
ops, var, use);
364 phi = zend_ssa_next_use_phi(ssa, var, phi);
373 iterator->
state = 10;
382 iterator->
state = 11;
391 zend_worklist_stack_push(vstack, var);
392 iterators[var].
state = 0;
393 iterators[var].
last = -1;
398 while (vstack->
len > 0) {
399 var = zend_worklist_stack_peek(vstack);
403 if (iterators[var].
last >= 0) {
405 var2 = iterators[var].
last;
411 var2 = zend_scc_next(op_array, ssa, var, iterators + var);
412 iterators[var].
last = var2;
422 zend_worklist_stack_pop(vstack);
425 while (stack->
len > 0) {
426 int var2 = zend_worklist_stack_peek(stack);
430 zend_worklist_stack_pop(stack);
437 zend_worklist_stack_push(stack, var);
461 zend_ssa_check_scc_var(op_array, ssa,
j, &index, &stack, &vstack, iterators);
507 for (i = 0; i < ssa_vars_count; i++) {
511 if (!zend_ssa_is_no_val_use(&op_array->
opcodes[use], &ssa->
ops[use], i)) {
513 zend_bitset_incl(worklist, i);
516 use = zend_ssa_next_use(ssa_ops, i, use);
521 if (ssa_vars[i].definition_phi) {
525 if (ssa_vars[
p->sources[0]].
no_val) {
526 ssa_vars[
p->sources[0]].
no_val = 0;
527 zend_bitset_incl(worklist,
p->sources[0]);
534 zend_bitset_incl(worklist,
p->sources[
j]);
558 }
else if (
a & ~c & m) {
577 temp = (b - m) | (m - 1);
582 temp = (d - m) | (m - 1);
623 temp = (b | ~m) | (m - 1);
628 }
else if (~b & d & m) {
629 temp = (d | ~m) | (m - 1);
655 int x = ((
a < 0) ? 8 : 0) |
664 tmp->
min = minOR(
a, b, c, d);
665 tmp->
max = maxOR(
a, b, c, d);
668 tmp->
min = minOR(
a, b, c, -1);
669 tmp->
max = maxOR(
a, b, 0, d);
672 tmp->
min = minOR(
a, -1, c, d);
673 tmp->
max = maxOR(0, b, c, d);
677 tmp->
max = maxOR(0, b, 0, d);
703 int x = ((
a < 0) ? 8 : 0) |
712 tmp->
min = minAND(
a, b, c, d);
713 tmp->
max = maxAND(
a, b, c, d);
724 tmp->
min = minAND(
a, -1, c, -1);
728 tmp->
min = minAND(
a, -1, c, d);
729 tmp->
max = maxAND(0, b, c, d);
732 tmp->
min = minAND(
a, b, c, -1);
733 tmp->
max = maxAND(
a, b, 0, d);
738static inline bool zend_abs_range(
748 }
else if (
max <= 0) {
786static bool zend_inference_calc_binary_op_range(
800 zend_add_will_overflow(op1_min, op2_min)) {
804 tmp->
min = op1_min + op2_min;
808 zend_add_will_overflow(op1_max, op2_max)) {
812 tmp->
max = op1_max + op2_max;
825 zend_sub_will_overflow(op1_min, op2_max)) {
829 tmp->
min = op1_min - op2_max;
833 zend_sub_will_overflow(op1_max, op2_min)) {
837 tmp->
max = op1_max - op2_min;
845 zend_long t1_overflow, t2_overflow, t3_overflow, t4_overflow;
862 t1_overflow || t2_overflow || t3_overflow || t4_overflow
887 (op2_min <= 0 && op2_max >= 0) ||
896 float_div(op1_min, op2_min, &
t1, &t1_);
897 float_div(op1_min, op2_max, &
t2, &t2_);
898 float_div(op1_max, op2_min, &
t3, &t3_);
899 float_div(op1_max, op2_max, &
t4, &t4_);
922 if (!zend_abs_range(op2_min, op2_max, &op2_abs_min, &op2_abs_max)) {
926 if (op2_abs_max == 0) {
930 if (op2_abs_min == 0) {
936 tmp->
min = op1_max < op2_abs_min ? op1_min : 0;
937 tmp->
max =
MIN(op1_max, op2_abs_max - 1);
938 }
else if (op1_max <= 0) {
939 tmp->
min =
MAX(op1_min, -op2_abs_max + 1);
940 tmp->
max = op1_min > -op2_abs_min ? op1_max : 0;
942 tmp->
min =
MAX(op1_min, -op2_abs_max + 1);
943 tmp->
max =
MIN(op1_max, op2_abs_max - 1);
971 if (shift_left_overflows(op1_min, op2_max)
972 || shift_left_overflows(op1_max, op2_max)) {
976 t1 = safe_shift_left(op1_min, op2_min);
977 t2 = safe_shift_left(op1_min, op2_max);
978 t3 = safe_shift_left(op1_max, op2_min);
979 t4 = safe_shift_left(op1_max, op2_max);
1017 t1 = op1_min >> op2_min;
1018 t2 = op1_min >> op2_max;
1019 t3 = op1_max >> op2_min;
1020 t4 = op1_max >> op2_max;
1040 zend_ssa_range_or(op1_min, op1_max, op2_min, op2_max, tmp);
1058 zend_ssa_range_and(op1_min, op1_max, op2_min, op2_max, tmp);
1085 if (
p->pi >= 0 &&
p->has_range_constraint) {
1088 int src1 =
p->sources[0];
1095 &&
p->constraint.range.min_ssa_var < 0
1096 &&
p->constraint.range.max_ssa_var < 0
1101 switch (opline->
opcode) {
1109 &&
p->sources[1] == var
1123 &&
p->sources[1] == var
1132 }
else if (narrowing) {
1188 }
else if (narrowing) {
1233 }
else if (narrowing) {
1241 return (tmp->
min <= tmp->
max);
1256 switch (opline->
opcode) {
1268 return zend_inference_calc_binary_op_range(
1269 op_array, ssa, opline, ssa_op, opline->
opcode, tmp);
1283 tmp->
min = ~op1_max;
1284 tmp->
max = ~op1_min;
1466 if ((ssa_op+1)->op1_def == var) {
1482 return zend_inference_calc_binary_op_range(
1483 op_array, ssa, opline, ssa_op,
1526#if SIZEOF_ZEND_LONG == 4
1554 if (!func_info || !func_info->call_map) {
1564 if (func_info && func_info->return_info.has_range) {
1565 *tmp = func_info->return_info.range;
1613 LOG_SSA_RANGE(
" change range (init SCC %2d) %2d [%s%ld..%ld%s]\n", ssa->
vars[var].
scc, var, (underflow?
"-- ":
""),
min,
max, (overflow?
" ++":
""));
1640 var_info->
range = *r;
1648 if (zend_inference_calc_range(op_array, ssa, var, 1, 0, &tmp)) {
1649 if (zend_inference_widening_meet(&ssa->
var_info[var], &tmp)) {
1685 var_info->
range = *r;
1693 if (zend_inference_calc_range(op_array, ssa, var, 0, 1, &tmp)) {
1694 if (zend_inference_narrowing_meet(&ssa->
var_info[var], &tmp)) {
1703# define CHECK_INNER_CYCLE(var2) \
1705 if (ssa->vars[var2].scc == ssa->vars[var].scc && \
1706 !ssa->vars[var2].scc_entry && \
1707 !zend_bitset_in(visited, var2) && \
1708 zend_check_inner_cycles(op_array, ssa, worklist, visited, var2)) { \
1715 if (zend_bitset_in(worklist, var)) {
1718 zend_bitset_incl(worklist, var);
1720 zend_bitset_incl(visited, var);
1725static void zend_infer_ranges_warmup(
const zend_op_array *op_array,
zend_ssa *ssa,
const int *scc_var,
const int *next_scc_var,
int scc)
1727 int worklist_len = zend_bitset_len(ssa->
vars_count);
1734 int has_inner_cycles = 0;
1740 if (!zend_bitset_in(visited,
j) &&
1741 zend_check_inner_cycles(op_array, ssa, worklist, visited,
j)) {
1742 has_inner_cycles = 1;
1745 j = next_scc_var[
j];
1756 zend_bitset_incl(worklist,
j);
1758 j = next_scc_var[
j];
1764 if (zend_inference_calc_range(op_array, ssa,
j, 0, 0, &tmp)) {
1766 if (!has_inner_cycles &&
1812 if (zend_inference_narrowing_meet(&ssa->
var_info[
j], &tmp)) {
1814 zend_bitset_incl(visited,
j);
1825 int worklist_len = zend_bitset_len(ssa->
vars_count);
1837 sizeof(
int) * ssa->
sccs, use_heap);
1844 memset(scc_var, -1,
sizeof(
int) * ssa->
sccs);
1847 next_scc_var[
j] = scc_var[ssa->
vars[
j].
scc];
1852 for (scc = 0; scc < ssa->
sccs; scc++) {
1854 if (next_scc_var[
j] < 0) {
1858 }
else if (zend_inference_calc_range(op_array, ssa,
j, 0, 1, &tmp)) {
1869 zend_bitset_incl(worklist,
j);
1871 j = next_scc_var[
j];
1874#if RANGE_WARMUP_PASSES > 0
1875 zend_infer_ranges_warmup(op_array, ssa, scc_var, next_scc_var, scc);
1879 zend_bitset_incl(worklist,
j);
1881 j = next_scc_var[
j];
1887 if (zend_ssa_range_widening(op_array, ssa,
j, scc)) {
1893 for (
j = scc_var[scc];
j >= 0;
j = next_scc_var[
j]) {
1903 if (zend_ssa_range_widening(op_array, ssa,
j, scc)) {
1909 for (
j = scc_var[scc];
j >= 0;
j = next_scc_var[
j]) {
1914 zend_ssa_range_narrowing(op_array, ssa,
j, scc);
1916 zend_bitset_incl(worklist,
j);
1921 if (zend_ssa_range_narrowing(op_array, ssa,
j, scc)) {
1928 p =
p->sym_use_chain;
1948#define UPDATE_SSA_TYPE(_type, _var) \
1950 uint32_t __type = (_type) & ~MAY_BE_GUARD; \
1951 int __var = (_var); \
1952 if (__type & MAY_BE_REF) { \
1953 __type |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; \
1956 zend_ssa_var *__ssa_var = &ssa_vars[__var]; \
1957 if (__ssa_var->var < op_array->num_args) { \
1958 if (__type & MAY_BE_RC1) { \
1960 __type |= MAY_BE_RCN; \
1963 if (__ssa_var->var < op_array->last_var) { \
1964 if (__type & (MAY_BE_REF|MAY_BE_RCN)) { \
1965 __type |= MAY_BE_RC1 | MAY_BE_RCN; \
1967 if ((__type & MAY_BE_RC1) && (__type & MAY_BE_STRING)) {\
1969 __type |= MAY_BE_RCN; \
1971 if ((__type & MAY_BE_RC1) && (__type & MAY_BE_OBJECT)) {\
1973 __type |= MAY_BE_RCN; \
1975 if (__ssa_var->alias) { \
1976 __type |= get_ssa_alias_types(__ssa_var->alias); \
1979 if (ssa_var_info[__var].type != __type) { \
1980 ZEND_ASSERT(ssa_opcodes != NULL || \
1981 __ssa_var->var >= op_array->last_var || \
1982 (ssa_var_info[__var].type & MAY_BE_REF) \
1983 == (__type & MAY_BE_REF)); \
1984 if (ssa_var_info[__var].type & ~__type) { \
1985 emit_type_narrowing_warning(op_array, ssa, __var); \
1988 ssa_var_info[__var].type = __type; \
1989 if (update_worklist) { \
1990 add_usages(op_array, ssa, worklist, __var); \
1997#define UPDATE_SSA_OBJ_TYPE(_ce, _is_instanceof, var) \
2000 zend_class_entry *__ce = (_ce); \
2001 bool __is_instanceof = (_is_instanceof); \
2002 if (__ce && (__ce->ce_flags & ZEND_ACC_FINAL)) { \
2003 __is_instanceof = false; \
2005 if (ssa_var_info[var].ce != __ce || \
2006 ssa_var_info[var].is_instanceof != __is_instanceof) { \
2007 ssa_var_info[var].ce = __ce; \
2008 ssa_var_info[var].is_instanceof = __is_instanceof; \
2009 if (update_worklist) { \
2010 add_usages(op_array, ssa, worklist, var); \
2017#define COPY_SSA_OBJ_TYPE(from_var, to_var) do { \
2018 if ((from_var) >= 0 && (ssa_var_info[(from_var)].type & MAY_BE_OBJECT) \
2019 && ssa_var_info[(from_var)].ce && !(ssa_var_info[(to_var)].type & MAY_BE_REF)) { \
2020 UPDATE_SSA_OBJ_TYPE(ssa_var_info[(from_var)].ce, \
2021 ssa_var_info[(from_var)].is_instanceof, (to_var)); \
2023 UPDATE_SSA_OBJ_TYPE(NULL, 0, (to_var)); \
2032 zend_bitset_incl(worklist,
p->ssa_var);
2033 p = zend_ssa_next_use_phi(ssa, var,
p);
2041 op = ssa->
ops + use;
2046 zend_bitset_incl(worklist, op->
op1_def);
2049 zend_bitset_incl(worklist, op->
op2_def);
2057 zend_bitset_incl(worklist, op->
op1_def);
2060 zend_bitset_incl(worklist, op->
op2_def);
2062 }
else if (use + 1 < op_array->
last
2069 zend_bitset_incl(worklist, op->
op1_def);
2072 zend_bitset_incl(worklist, op->
op2_def);
2075 use = zend_ssa_next_use(ssa->
ops, var, use);
2085 uint32_t lineno = def_opline ? def_opline->
lineno : 0;
2088 "Narrowing occurred during type inference of %s. Please file a bug report on https://github.com/php/php-src/issues", def_op_name);
2090 ZEND_ASSERT(0 &&
"Narrowing during type inference");
2107 if (zend_hash_num_elements(
ht) == 0) {
2189static uint32_t assign_dim_array_result_type(
2190 uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) {
2234static uint32_t assign_dim_result_type(
2235 uint32_t arr_type, uint32_t dim_type, uint32_t value_type, uint8_t dim_op_type) {
2249 tmp |= assign_dim_array_result_type(arr_type, dim_type, value_type, dim_op_type);
2255static uint32_t binary_op_result_type(
2256 zend_ssa *ssa, uint8_t opcode, uint32_t
t1, uint32_t
t2,
int result_var,
2274 if (result_var < 0 ||
2301 if (result_var < 0 ||
2354static uint32_t zend_convert_type_declaration_mask(uint32_t type_mask) {
2355 uint32_t result_mask = type_mask &
MAY_BE_ANY;
2403 return zend_convert_type(script, arg_info->
type, pce);
2415 EG(fake_scope) = prev_scope;
2440 ce = op_array->
scope;
2441 }
else if (ssa_op->
op1_use >= 0) {
2463 switch (fetch_type) {
2468 ce = op_array->
scope;
2501 return zend_convert_type(script,
prop_info->type, pce);
2513 if (use_op == ssa_op + 1) {
2532 bool update_worklist)
2576 if ((ssa_op+1)->op1_def >= 0 && !(ssa_var_info[(ssa_op+1)->op1_def].
type &
MAY_BE_REF)) {
2583 switch (opline->
opcode) {
2596 tmp = binary_op_result_type(ssa, opline->
opcode,
t1,
t2, ssa_op->
result_def, optimization_level);
2749 prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
2761 prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline);
2770 tmp |= binary_op_result_type(
2824 t1 = zend_fetch_prop_type(script,
prop_info, &ce);
2843 t1 = zend_fetch_prop_type(script,
prop_info, &ce);
2883 if (!ssa_var_info[ssa_op->
op1_use].has_range ||
2885 (ssa_var_info[ssa_op->
op1_use].range.underflow ||
2888 (ssa_var_info[ssa_op->
op1_use].range.overflow ||
2945 if (!ssa_var_info[ssa_op->
op1_use].has_range ||
2947 (ssa_var_info[ssa_op->
op1_use].range.underflow ||
2950 (ssa_var_info[ssa_op->
op1_use].range.overflow ||
3012 if ((ssa_op+1)->op1_def >= 0) {
3032 || ssa_var_info[ssa_op->
op1_use].is_instanceof);
3039 tmp = zend_fetch_prop_type(script,
3040 zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce);
3046 if ((ssa_op+1)->op1_def >= 0) {
3061 if ((ssa_op+1)->op1_def >= 0) {
3112 if (ssa_var_info[ssa_op->
op1_def].use_as_double) {
3187 if ((opline+1)->op1_type ==
IS_CV) {
3201 if ((opline+1)->op1_type ==
IS_CV) {
3343 if (op_array->
scope) {
3386 if (!ssa_var_info[ssa_op->
result_def].is_instanceof) {
3442 tmp |= assign_dim_array_result_type(arr_type,
t2,
t1, opline->
op2_type);
3637 if (
j != (opline - op_array->
opcodes) + 1) {
3644 if (ssa_opcodes[
j] != opline + 1) {
3649 opcode = ssa_opcodes[
j]->
opcode;
3783 tmp |= zend_fetch_prop_type(script,
prop_info, &ce);
3794 ce = op_array->
scope;
3803 && !result_may_be_separated(ssa, ssa_op)) {
3824 tmp = zend_fetch_prop_type(script,
3825 zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
3834 if (!result_may_be_separated(ssa, ssa_op)) {
3867 if (next_ssa_op->
op1_def >= 0) {
3886 if (!func_info || !func_info->call_map) {
3887 goto unknown_opcode;
3891 goto unknown_opcode;
3895 bool ce_is_instanceof;
3944 if (
t1 & expected_type_mask) {
3972 uint32_t extra_types =
t1 & ~tmp;
4021 tmp = zend_fetch_prop_type(script,
prop_info, &prop_ce);
4024 goto unknown_opcode;
4041#ifdef ZEND_DEBUG_TYPE_INFERENCE
4043 switch (opline->
opcode) {
4085 switch (opline->
opcode) {
4123 return _zend_update_type_info(op_array, ssa, script,
NULL, opline, ssa_op, ssa_opcodes, optimization_level, 0);
4140 uint32_t rank1, rank2;
4148 rank1 = get_class_entry_rank(ce1);
4149 rank2 = get_class_entry_rank(ce2);
4151 while (rank1 != rank2) {
4152 if (rank1 > rank2) {
4161 while (ce1 != ce2) {
4180 return instanceof_function(ce1, ce2);
4190 uint32_t tmp, worklist_len = zend_bitset_len(ssa_vars_count);
4191 bool update_worklist = 1;
4194 while (!zend_bitset_empty(worklist, worklist_len)) {
4195 j = zend_bitset_first(worklist, worklist_len);
4196 zend_bitset_excl(worklist,
j);
4197 if (ssa_vars[
j].definition_phi) {
4202 tmp = get_ssa_var_info(ssa,
p->sources[0]);
4204 if (!
p->has_range_constraint) {
4212 ce = constraint->
ce;
4214 }
else if (is_instanceof && safe_instanceof(constraint->
ce, ce)) {
4215 ce = constraint->
ce;
4231 int is_instanceof = 0;
4236 tmp |= get_ssa_var_info(ssa,
p->sources[i]);
4243 info = &ssa_var_info[
p->sources[i]];
4251 ce = join_class_entries(ce, info->
ce, &is_instanceof);
4257 }
else if (ssa_vars[
j].definition >= 0) {
4259 if (_zend_update_type_info(op_array, ssa, script, worklist, op_array->
opcodes + i, ssa->
ops + i,
NULL, optimization_level, 1) ==
FAILURE) {
4267static bool is_narrowable_instr(
zend_op *opline) {
4272static bool is_effective_op1_double_cast(
zend_op *opline,
zval *
op2) {
4278static bool is_effective_op2_double_cast(
zend_op *opline,
zval *
op1) {
4305static bool can_convert_to_double(
4313 if (zend_bitset_in(visited, var_num)) {
4316 zend_bitset_incl(visited, var_num);
4318 for (use = var->
use_chain; use >= 0; use = zend_ssa_next_use(ssa->
ops, var_num, use)) {
4322 if (zend_ssa_is_no_val_use(opline, ssa_op, var_num)) {
4326 if (!is_narrowable_instr(opline)) {
4349 zval orig_op1, orig_op2, orig_result;
4351 zval dval_op1, dval_op2, dval_result;
4355 if (ssa_op->
op1_use == var_num) {
4368 if (ssa_op->
op2_use == var_num) {
4383 }
else if (is_effective_op1_double_cast(opline, &orig_op2)) {
4391 }
else if (is_effective_op2_double_cast(opline, &orig_op1)) {
4397 uint8_t opcode = opline->
opcode;
4404 if (opcode ==
ZEND_DIV && zval_get_double(&orig_op2) == 0.0) {
4411 if (zval_get_double(&orig_result) !=
Z_DVAL(dval_result)) {
4416 if (!can_convert_to_double(op_array, ssa, ssa_op->
result_def, &orig_result, visited)) {
4422 for (phi = var->
phi_use_chain; phi; phi = zend_ssa_next_use_phi(ssa, var_num, phi)) {
4429 if (!can_convert_to_double(op_array, ssa, phi->
ssa_var,
value, visited)) {
4439 uint32_t bitset_len = zend_bitset_len(ssa->
vars_count);
4447 worklist = visited + bitset_len;
4449 zend_bitset_clear(worklist, bitset_len);
4462 zend_bitset_clear(visited, bitset_len);
4463 if (can_convert_to_double(op_array, ssa,
v,
value, visited)) {
4471 zend_bitset_union(worklist, visited, bitset_len);
4481 if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) ==
FAILURE) {
4490static bool is_recursive_tail_call(
const zend_op_array *op_array,
4513 zend_class_entry **ce,
bool *ce_is_instanceof,
bool use_tentative_return_info) {
4520 *ce_is_instanceof = ce !=
NULL;
4525 *ce_is_instanceof =
false;
4533 *ce_is_instanceof = 0;
4544 bool is_instanceof =
false;
4547 ret->is_instanceof = is_instanceof;
4548 ret->range = tmp_range;
4552static void zend_func_return_info(
const zend_op_array *op_array,
4566 int tmp_is_instanceof = -1;
4568 int arg_is_instanceof;
4570 int tmp_has_range = -1;
4575 ret->is_instanceof = 0;
4576 ret->range = tmp_range;
4587 for (
j = 0;
j < blocks_count;
j++) {
4598 if (is_recursive_tail_call(op_array, opline)) {
4623 arg_is_instanceof = 0;
4626 if (tmp_is_instanceof < 0) {
4628 tmp_is_instanceof = arg_is_instanceof;
4629 }
else if (arg_ce && arg_ce == tmp_ce) {
4630 if (tmp_is_instanceof != arg_is_instanceof) {
4631 tmp_is_instanceof = 1;
4635 tmp_is_instanceof = 0;
4642 if (tmp_has_range < 0) {
4648 }
else if (tmp_has_range) {
4661 if (tmp_has_range < 0) {
4664 }
else if (tmp_has_range) {
4679 }
else if (!widening) {
4694 if (tmp_is_instanceof < 0) {
4695 tmp_is_instanceof = 0;
4698 if (tmp_has_range < 0) {
4702 ret->is_instanceof = tmp_is_instanceof;
4705 ret->range = tmp_range;
4706 ret->has_range = tmp_has_range;
4720 for (
j = op_array->
last_var;
j < ssa_vars_count;
j++) {
4721 zend_bitset_incl(worklist,
j);
4724 if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) ==
FAILURE) {
4731 zend_type_narrowing(op_array, script, ssa, optimization_level);
4735 zend_func_return_info(op_array, script, 1, 0, &
ZEND_FUNC_INFO(op_array)->return_info);
4747 uint32_t worklist_len = zend_bitset_len(ssa->
vars_count);
4755 for (var = 0; var < ssa->
vars_count; var++) {
4758 opline = op_array->
opcodes + def;
4760 switch (opline->
opcode) {
4772 switch (opline->
opcode) {
4799 switch ((opline-1)->opcode) {
4811 switch (opline->
opcode) {
4826 zend_bitset_incl(worklist, var);
4828 zend_bitset_incl(worklist, var);
4830 zend_bitset_incl(worklist, var);
4843 zend_bitset_incl(worklist,
p->ssa_var);
4845 p = zend_ssa_next_use_phi(ssa, var,
p);
4860 zend_bitset_incl(worklist, op->
op1_def);
4865 zend_bitset_incl(worklist, op->
op2_def);
4891 for (i = 0; i < op_array->
last_var; i++) {
4896 for (i = 0; i < op_array->
last_var; i++) {
4900 ssa_var_info[i].
type |= get_ssa_alias_types(ssa->
vars[i].
alias);
4904 for (i = op_array->
last_var; i < ssa->vars_count; i++) {
4905 ssa_var_info[i].
type = 0;
4909 zend_mark_cv_references(op_array, script, ssa);
4911 zend_infer_ranges(op_array, ssa);
4913 if (zend_infer_types(op_array, script, ssa, optimization_level) ==
FAILURE) {
4925 switch (opline->
opcode) {
4953 switch (opline->
opcode) {
4981 switch (opline->
opcode) {
4994 switch (opline->
opcode) {
5006 switch (opline->
opcode) {
5186 if ((opline+1)->op1_type ==
IS_CV) {
5200 if ((opline+1)->op1_type ==
IS_CV) {
fprintf($stream, string $format, mixed ... $values)
memset(ptr, 0, type->size)
zend_basic_block * blocks
zend_object *(* create_object)(zend_class_entry *class_type)
HashTable properties_info
zend_function * constructor
zend_class_entry * parent
const zend_object_handlers * default_object_handlers
zend_call_info ** call_map
zend_object_write_property_t write_property
zend_object_get_property_ptr_ptr_t get_property_ptr_ptr
zend_object_read_property_t read_property
zend_object_get_constructor_t get_constructor
zend_string * function_name
zend_ssa_phi * sym_use_chain
bool has_range_constraint
zend_ssa_pi_constraint constraint
zend_ssa_negative_lat negative
zend_ssa_phi * sym_use_chain
zend_ssa_phi * definition_phi
zend_ssa_phi * phi_use_chain
zend_ssa_var_info * var_info
zend_ssa_range_constraint range
ZEND_API ZEND_COLD void zend_error_at(int type, zend_string *filename, uint32_t lineno, const char *format,...)
#define ZEND_MM_ALIGNED_SIZE(size)
struct _zend_arena zend_arena
#define ZEND_BITSET_FOREACH_END()
#define ZEND_BITSET_ALLOCA(n, use_heap)
#define ZEND_BITSET_FOREACH(set, len, bit)
struct _zend_basic_block zend_basic_block
#define ZEND_BB_REACHABLE
#define RETURN_VALUE_USED(opline)
#define CRT_CONSTANT(node)
ZEND_API zend_class_entry * zend_ce_closure
zend_string_release_ex(func->internal_function.function_name, 0)
#define ZEND_FETCH_CLASS_SELF
#define ZEND_SHORT_CIRCUITING_CHAIN_EXPR
#define ZEND_FETCH_CLASS_MASK
#define ZEND_ACC_HAS_TYPE_HINTS
#define ZEND_SHORT_CIRCUITING_CHAIN_EMPTY
#define ZEND_ACC_TRAIT_CLONE
#define ZEND_ARG_SEND_MODE(arg_info)
ZEND_API binary_op_type get_binary_op(int opcode)
#define ZEND_USER_FUNCTION
#define ZEND_ACC_GENERATOR
struct _zend_op_array zend_op_array
struct _zend_class_constant zend_class_constant
struct _zend_property_info zend_property_info
#define ZEND_BIND_IMPLICIT
#define ZEND_FETCH_CLASS_STATIC
#define ZEND_FETCH_DIM_WRITE
#define ZEND_ARG_TYPE_IS_TENTATIVE(arg_info)
#define ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES
#define ZEND_FETCH_CLASS_PARENT
#define ZEND_ARRAY_ELEMENT_REF
#define ZEND_ACC_HAS_RETURN_TYPE
struct _zend_arg_info zend_arg_info
#define ZEND_FETCH_OBJ_FLAGS
#define ZEND_ACC_VARIADIC
#define ZEND_ACC_RETURN_REFERENCE
#define ZEND_RETURNS_FUNCTION
#define ZEND_SHORT_CIRCUITING_CHAIN_MASK
#define ZEND_SHORT_CIRCUITING_CHAIN_ISSET
ZEND_API void(ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data)
union _zend_function zend_function
ZEND_API uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa, zend_class_entry **ce, bool *ce_is_instanceof)
struct _zend_call_info zend_call_info
#define ZEND_FUNC_INFO(op_array)
struct _zend_func_info zend_func_info
ZEND_API zend_class_entry * zend_ce_generator
#define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val)
#define ZEND_HASH_FOREACH_END()
#define ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(ht, _key, _val)
ZEND_API uint32_t zend_array_element_type(uint32_t t1, uint8_t op_type, int write, int insert)
uint32_t zend_get_return_info_from_signature_only(const zend_function *func, const zend_script *script, zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info)
#define LOG_NEG_RANGE(...)
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)
#define ADD_SCC_VAR(_var)
#define UPDATE_SSA_OBJ_TYPE(_ce, _is_instanceof, var)
#define CHECK_SCC_ENTRY(var2)
struct _zend_scc_iterator zend_scc_iterator
ZEND_API void zend_init_func_return_info(const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret)
#define CHECK_SCC_VAR(var2)
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)
#define UPDATE_SSA_TYPE(_type, _var)
#define ADD_SCC_VAR_1(_var)
#define COPY_SSA_OBJ_TYPE(from_var, to_var)
#define RANGE_WARMUP_PASSES
ZEND_API void zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa)
#define WHILE_WORKLIST(worklist, len, i)
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)
#define WHILE_WORKLIST_END()
ZEND_API void zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa)
ZEND_API uint32_t ZEND_FASTCALL zend_array_type_info(const zval *zv)
ZEND_API uint32_t zend_fetch_arg_info_type(const zend_script *script, const zend_arg_info *arg_info, zend_class_entry **pce)
ZEND_API zend_result zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
#define FOR_EACH_VAR_USAGE(_var, MACRO)
#define LOG_SSA_RANGE(...)
#define OP2_RANGE_OVERFLOW()
#define OP2_RANGE_UNDERFLOW()
#define OP1_RANGE_OVERFLOW()
#define OP1_RANGE_UNDERFLOW()
struct _zend_string zend_string
#define ZEND_SIGNED_MULTIPLY_LONG(a, b, lval, dval, usedval)
ZEND_API zval * zend_std_get_property_ptr_ptr(zend_object *zobj, zend_string *name, int type, void **cache_slot)
ZEND_API zval * zend_std_write_property(zend_object *zobj, zend_string *name, zval *value, void **cache_slot)
ZEND_API zend_property_info * zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent)
ZEND_API zval * zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv)
ZEND_API zend_function * zend_std_get_constructor(zend_object *zobj)
#define ZEND_WRONG_PROPERTY_INFO
const zend_class_constant * zend_fetch_class_const_info(const zend_script *script, const zend_op_array *op_array, const zend_op *opline, bool *is_prototype)
zend_class_entry * zend_optimizer_get_class_entry_from_op1(const zend_script *script, const zend_op_array *op_array, const zend_op *opline)
zend_class_entry * zend_optimizer_get_class_entry(const zend_script *script, const zend_op_array *op_array, zend_string *lcname)
struct _zend_script zend_script
#define ZEND_OPTIMIZER_IGNORE_OVERLOADING
#define ZEND_OPTIMIZER_NARROW_TO_DOUBLE
#define ALLOCA_FLAG(name)
#define EXPECTED(condition)
#define do_alloca(p, use_heap)
#define zend_always_inline
#define ZEND_UNREACHABLE()
#define free_alloca(p, use_heap)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_ssa_range zend_ssa_range
#define FOREACH_USE_END()
struct _zend_ssa_type_constraint zend_ssa_type_constraint
enum _zend_ssa_alias_kind zend_ssa_alias_kind
struct _zend_ssa zend_ssa
struct _zend_ssa_var zend_ssa_var
#define FOREACH_USE(var, use)
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
struct _zend_ssa_range_constraint zend_ssa_range_constraint
#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_DOUBLE
#define MAY_BE_ARRAY_SHIFT
#define MAY_BE_ARRAY_KEY_STRING
#define MAY_BE_ARRAY_OF_NULL
#define MAY_BE_ARRAY_OF_REF
#define MAY_BE_ARRAY_EMPTY
#define MAY_BE_ARRAY_OF_RESOURCE
#define MAY_BE_ARRAY_OF_LONG
#define MAY_BE_HASH_ONLY(t)
#define MAY_BE_ARRAY_KEY_LONG
#define MAY_BE_ARRAY_KEY_ANY
#define MAY_BE_ARRAY_NUMERIC_HASH
#define MAY_BE_ARRAY_OF_STRING
#define ZEND_TYPE_PURE_MASK(t)
#define ZEND_TYPE_NAME(t)
#define Z_ISUNDEF_P(zval_p)
#define Z_ARRVAL_P(zval_p)
#define Z_REFCOUNTED_P(zval_p)
struct _zend_array HashTable
#define ZEND_TYPE_HAS_NAME(t)
#define ZEND_TYPE_IS_SET(t)
#define ZVAL_DOUBLE(z, d)
ZEND_RESULT_CODE zend_result
#define ZEND_TYPE_PURE_MASK_WITHOUT_NULL(t)
#define ZVAL_COPY_VALUE(z, v)
#define ZEND_TYPE_IS_COMPLEX(t)
zend_property_info * prop_info
ZEND_API const char *ZEND_FASTCALL zend_get_opcode_name(uint8_t opcode)
#define ZEND_FETCH_STATIC_PROP_IS
#define ZEND_IS_IDENTICAL
#define ZEND_DECLARE_ANON_CLASS
#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_FUNC_NUM_ARGS
#define ZEND_FRAMELESS_ICALL_0
#define ZEND_FETCH_LIST_W
#define ZEND_CALLABLE_CONVERT
#define ZEND_ASSERT_CHECK
#define ZEND_RETURN_BY_REF
#define ZEND_SWITCH_STRING
#define ZEND_GET_CALLED_CLASS
#define ZEND_FETCH_OBJ_FUNC_ARG
#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_FETCH_GLOBALS
#define ZEND_FRAMELESS_ICALL_1
#define ZEND_POST_INC_STATIC_PROP
#define ZEND_IS_NOT_EQUAL
#define ZEND_FETCH_STATIC_PROP_UNSET
#define ZEND_IS_NOT_IDENTICAL
#define ZEND_FETCH_OBJ_IS
#define ZEND_FETCH_OBJ_UNSET
#define ZEND_POST_DEC_OBJ
#define ZEND_CHECK_FUNC_ARG
#define ZEND_ISSET_ISEMPTY_PROP_OBJ
#define ZEND_FETCH_STATIC_PROP_FUNC_ARG
#define ZEND_FRAMELESS_ICALL_3
#define ZEND_ADD_ARRAY_ELEMENT
#define ZEND_ISSET_ISEMPTY_STATIC_PROP
#define ZEND_ASSIGN_STATIC_PROP
#define ZEND_IS_SMALLER_OR_EQUAL
#define ZEND_POST_DEC_STATIC_PROP
#define ZEND_PRE_INC_STATIC_PROP
#define ZEND_FRAMELESS_ICALL_2
#define ZEND_SEND_VAR_NO_REF_EX
#define ZEND_BIND_LEXICAL
#define ZEND_DECLARE_LAMBDA_FUNCTION
#define ZEND_SEND_FUNC_ARG
#define ZEND_ISSET_ISEMPTY_DIM_OBJ
#define ZEND_ISSET_ISEMPTY_VAR
#define ZEND_BIND_INIT_STATIC_OR_JMP
#define ZEND_ADD_ARRAY_UNPACK
#define ZEND_BEGIN_SILENCE
#define ZEND_FUNC_GET_ARGS
#define ZEND_ARRAY_KEY_EXISTS
#define ZEND_JMP_FRAMELESS
#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_RECV_VARIADIC
#define ZEND_FETCH_DIM_IS
#define ZEND_FETCH_OBJ_RW
#define ZEND_FETCH_DIM_UNSET
#define ZEND_SEND_VAR_NO_REF
#define ZEND_POST_INC_OBJ
#define ZEND_DO_FCALL_BY_NAME
#define ZEND_ISSET_ISEMPTY_THIS
#define ZEND_FETCH_FUNC_ARG
#define ZEND_FETCH_CLASS_NAME
#define ZEND_FETCH_DIM_RW
struct _zend_worklist_stack zend_worklist_stack
#define ZEND_WORKLIST_STACK_FREE_ALLOCA(s, use_heap)
#define ZEND_WORKLIST_STACK_ALLOCA(s, _len, use_heap)