diff options
author | Dmitry Stogov <dmitry@zend.com> | 2020-03-13 22:11:07 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2020-03-13 22:11:07 +0300 |
commit | 4bf2d09edeb14467ba79551a08d84efdff314899 (patch) | |
tree | 87215edd7d7be61c95f8560c9d5a9a4e4eff0aa9 /ext/opcache/Optimizer/zend_inference.c | |
parent | d15012d5e851b7dcc3dac69393f932c9cd5ebc49 (diff) | |
download | php-git-4bf2d09edeb14467ba79551a08d84efdff314899.tar.gz |
Tracing JIT (it doesn't support register allocation yet)
Use opcache.jit=1255 to swith it on (the third digit 5 really matters)
Use opcache.jit_debug=0xff001 to see how it works and what code it generates
Diffstat (limited to 'ext/opcache/Optimizer/zend_inference.c')
-rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 517 |
1 files changed, 277 insertions, 240 deletions
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index e11c3cd9c7..2be19fcf8a 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1828,7 +1828,7 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) { #define UPDATE_SSA_TYPE(_type, _var) \ do { \ - uint32_t __type = (_type); \ + uint32_t __type = (_type) & ~MAY_BE_GUARD; \ int __var = (_var); \ if (__type & MAY_BE_REF) { \ __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; \ @@ -1848,12 +1848,19 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) { } \ } \ if (ssa_var_info[__var].type != __type) { \ - if (ssa_var_info[__var].type & ~__type) { \ - emit_type_narrowing_warning(op_array, ssa, __var); \ - return FAILURE; \ + if (update_worklist) { \ + if (ssa_var_info[__var].type & ~__type) { \ + emit_type_narrowing_warning(op_array, ssa, __var);\ + return FAILURE; \ + } \ + ssa_var_info[__var].type = __type; \ + add_usages(op_array, ssa, worklist, __var); \ + } else { \ + if (ssa_var_info[__var].type & ~__type) { \ + return FAILURE; \ + } \ + ssa_var_info[__var].type = __type; \ } \ - ssa_var_info[__var].type = __type; \ - add_usages(op_array, ssa, worklist, __var); \ } \ /*zend_bitset_excl(worklist, var);*/ \ } \ @@ -1866,7 +1873,9 @@ static uint32_t get_ssa_alias_types(zend_ssa_alias_kind alias) { ssa_var_info[var].is_instanceof != (_is_instanceof)) { \ ssa_var_info[var].ce = (_ce); \ ssa_var_info[var].is_instanceof = (_is_instanceof); \ - add_usages(op_array, ssa, worklist, var); \ + if (update_worklist) { \ + add_usages(op_array, ssa, worklist, var); \ + } \ } \ /*zend_bitset_excl(worklist, var);*/ \ } \ @@ -2207,7 +2216,7 @@ static zend_property_info *lookup_prop_info(zend_class_entry *ce, zend_string *n return NULL; } -static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int i) +static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op *ssa_op) { zend_property_info *prop_info = NULL; if (opline->op2_type == IS_CONST) { @@ -2215,8 +2224,8 @@ static zend_property_info *zend_fetch_prop_info(const zend_op_array *op_array, z if (opline->op1_type == IS_UNUSED) { ce = op_array->scope; - } else if (ssa->ops[i].op1_use >= 0) { - ce = ssa->var_info[ssa->ops[i].op1_use].ce; + } else if (ssa_op->op1_use >= 0) { + ce = ssa->var_info[ssa_op->op1_use].ce; } if (ce) { prop_info = lookup_prop_info(ce, @@ -2294,17 +2303,19 @@ static uint32_t zend_fetch_prop_type(const zend_script *script, zend_property_in return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN; } -static int zend_update_type_info(const zend_op_array *op_array, - zend_ssa *ssa, - const zend_script *script, - zend_bitset worklist, - int i, - zend_long optimization_level) +static zend_always_inline int _zend_update_type_info( + const zend_op_array *op_array, + zend_ssa *ssa, + const zend_script *script, + zend_bitset worklist, + zend_op *opline, + zend_ssa_op *ssa_op, + const zend_op **ssa_opcodes, + zend_long optimization_level, + zend_bool update_worklist) { uint32_t t1, t2; uint32_t tmp, orig; - zend_op *opline = op_array->opcodes + i; - zend_ssa_op *ssa_ops = ssa->ops; zend_ssa_var *ssa_vars = ssa->vars; zend_ssa_var_info *ssa_var_info = ssa->var_info; zend_class_entry *ce; @@ -2312,11 +2323,11 @@ static int zend_update_type_info(const zend_op_array *op_array, if (opline->opcode == ZEND_OP_DATA) { opline--; - i--; + ssa_op--; } - t1 = OP1_INFO(); - t2 = OP2_INFO(); + t1 = OP1_INFO_EX(); + t2 = OP2_INFO_EX(); /* If one of the operands cannot have any type, this means the operand derives from * unreachable code. Propagate the empty result early, so that that the following @@ -2324,14 +2335,14 @@ static int zend_update_type_info(const zend_op_array *op_array, if (!(t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS)) || !(t2 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_CLASS))) { tmp = 0; - if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ssa_op->result_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } - if (ssa_ops[i].op1_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + if (ssa_op->op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - if (ssa_ops[i].op2_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); + if (ssa_op->op2_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->op2_def); } return 1; } @@ -2349,8 +2360,8 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_SL: case ZEND_SR: case ZEND_CONCAT: - tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_ops[i].result_def, optimization_level); - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_op->result_def, optimization_level); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_BW_NOT: tmp = 0; @@ -2366,10 +2377,10 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_OBJECT | MAY_BE_RC1; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_BEGIN_SILENCE: - UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def); break; case ZEND_BOOL_NOT: case ZEND_BOOL_XOR: @@ -2392,10 +2403,10 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_ASSERT_CHECK: case ZEND_IN_ARRAY: case ZEND_ARRAY_KEY_EXISTS: - UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def); break; case ZEND_CAST: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = t1; if ((t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) && (opline->op1_type == IS_CV) && @@ -2407,8 +2418,8 @@ static int zend_update_type_info(const zend_op_array *op_array, opline->extended_value == IS_STRING) { tmp |= MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } tmp = 1 << opline->extended_value; if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { @@ -2435,19 +2446,19 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= ((t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT) | ((t1 & MAY_BE_ANY)? MAY_BE_ARRAY_KEY_LONG : 0); } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_QM_ASSIGN: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_COPY_TMP: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = t1; if ((t1 & (MAY_BE_RC1|MAY_BE_REF)) && (opline->op1_type == IS_CV)) { tmp |= MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } tmp = t1 & ~(MAY_BE_UNDEF|MAY_BE_REF); if (t1 & MAY_BE_UNDEF) { @@ -2467,8 +2478,8 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp &= ~MAY_BE_FALSE; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def); break; case ZEND_ASSIGN_OP: case ZEND_ASSIGN_DIM_OP: @@ -2479,21 +2490,21 @@ static int zend_update_type_info(const zend_op_array *op_array, orig = 0; tmp = 0; if (opline->opcode == ZEND_ASSIGN_OBJ_OP) { - prop_info = zend_fetch_prop_info(op_array, ssa, opline, i); + prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op); orig = t1; t1 = zend_fetch_prop_type(script, prop_info, &ce); - t2 = OP1_DATA_INFO(); + t2 = OP1_DATA_INFO_EX(); } else if (opline->opcode == ZEND_ASSIGN_DIM_OP) { if (t1 & MAY_BE_ARRAY_OF_REF) { tmp |= MAY_BE_REF; } orig = t1; t1 = zend_array_element_type(t1, 1, 0); - t2 = OP1_DATA_INFO(); + t2 = OP1_DATA_INFO_EX(); } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP_OP) { prop_info = zend_fetch_static_prop_info(script, op_array, ssa, opline); t1 = zend_fetch_prop_type(script, prop_info, &ce); - t2 = OP1_DATA_INFO(); + t2 = OP1_DATA_INFO_EX(); } else { if (t1 & MAY_BE_REF) { tmp |= MAY_BE_REF; @@ -2501,7 +2512,7 @@ static int zend_update_type_info(const zend_op_array *op_array, } tmp |= binary_op_result_type( - ssa, opline->extended_value, t1, t2, ssa_ops[i].op1_def, optimization_level); + ssa, opline->extended_value, t1, t2, ssa_op->op1_def, optimization_level); if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) { tmp |= MAY_BE_RC1; } @@ -2511,9 +2522,9 @@ static int zend_update_type_info(const zend_op_array *op_array, if (opline->opcode == ZEND_ASSIGN_DIM_OP) { if (opline->op1_type == IS_CV) { - orig = assign_dim_result_type(orig, OP2_INFO(), tmp, opline->op2_type); - UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + orig = assign_dim_result_type(orig, OP2_INFO_EX(), tmp, opline->op2_type); + UPDATE_SSA_TYPE(orig, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } } else if (opline->opcode == ZEND_ASSIGN_OBJ_OP) { if (opline->op1_type == IS_CV) { @@ -2526,15 +2537,15 @@ static int zend_update_type_info(const zend_op_array *op_array, orig |= (MAY_BE_RC1|MAY_BE_RCN); } } - UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(orig, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } } else if (opline->opcode == ZEND_ASSIGN_STATIC_PROP) { /* Nothing to do */ } else { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { ce = NULL; if (opline->opcode == ZEND_ASSIGN_DIM_OP) { if (opline->op2_type == IS_UNUSED) { @@ -2569,9 +2580,9 @@ static int zend_update_type_info(const zend_op_array *op_array, } } tmp &= ~MAY_BE_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } } break; @@ -2584,18 +2595,18 @@ static int zend_update_type_info(const zend_op_array *op_array, } if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) { tmp |= MAY_BE_RC1; - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp |= MAY_BE_RCN; } } if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) { - if (!ssa_var_info[ssa_ops[i].op1_use].has_range || + if (!ssa_var_info[ssa_op->op1_use].has_range || (opline->opcode == ZEND_PRE_DEC && - (ssa_var_info[ssa_ops[i].op1_use].range.underflow || - ssa_var_info[ssa_ops[i].op1_use].range.min == ZEND_LONG_MIN)) || + (ssa_var_info[ssa_op->op1_use].range.underflow || + ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) || (opline->opcode == ZEND_PRE_INC && - (ssa_var_info[ssa_ops[i].op1_use].range.overflow || - ssa_var_info[ssa_ops[i].op1_use].range.max == ZEND_LONG_MAX))) { + (ssa_var_info[ssa_op->op1_use].range.overflow || + ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) { /* may overflow */ tmp |= MAY_BE_LONG | MAY_BE_DOUBLE; } else { @@ -2620,16 +2631,16 @@ static int zend_update_type_info(const zend_op_array *op_array, } tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY); } - if (ssa_ops[i].op1_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + if (ssa_op->op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ssa_op->result_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_POST_INC: case ZEND_POST_DEC: - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = 0; if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) { tmp |= MAY_BE_RC1|MAY_BE_RCN; @@ -2638,7 +2649,7 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t1 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } tmp = 0; if (t1 & MAY_BE_REF) { @@ -2648,13 +2659,13 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_RC1; } if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) { - if (!ssa_var_info[ssa_ops[i].op1_use].has_range || + if (!ssa_var_info[ssa_op->op1_use].has_range || (opline->opcode == ZEND_POST_DEC && - (ssa_var_info[ssa_ops[i].op1_use].range.underflow || - ssa_var_info[ssa_ops[i].op1_use].range.min == ZEND_LONG_MIN)) || + (ssa_var_info[ssa_op->op1_use].range.underflow || + ssa_var_info[ssa_op->op1_use].range.min == ZEND_LONG_MIN)) || (opline->opcode == ZEND_POST_INC && - (ssa_var_info[ssa_ops[i].op1_use].range.overflow || - ssa_var_info[ssa_ops[i].op1_use].range.max == ZEND_LONG_MAX))) { + (ssa_var_info[ssa_op->op1_use].range.overflow || + ssa_var_info[ssa_op->op1_use].range.max == ZEND_LONG_MAX))) { /* may overflow */ tmp |= MAY_BE_LONG | MAY_BE_DOUBLE; } else { @@ -2679,23 +2690,23 @@ static int zend_update_type_info(const zend_op_array *op_array, } tmp |= t1 & (MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_RESOURCE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ARRAY_KEY_ANY); } - if (ssa_ops[i].op1_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + if (ssa_op->op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_ASSIGN_DIM: if (opline->op1_type == IS_CV) { - tmp = assign_dim_result_type(t1, t2, OP1_DATA_INFO(), opline->op2_type); - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + tmp = assign_dim_result_type(t1, t2, OP1_DATA_INFO_EX(), opline->op2_type); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = 0; if (t1 & MAY_BE_STRING) { tmp |= MAY_BE_STRING; } if (t1 & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_STRING)) { - tmp |= (OP1_DATA_INFO() & (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF)); + tmp |= (OP1_DATA_INFO_EX() & (MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF)); if (opline->op2_type == IS_UNUSED) { /* When appending to an array and the LONG_MAX key is already used @@ -2716,18 +2727,18 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t1 & MAY_BE_OBJECT) { tmp |= MAY_BE_REF; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } - if ((opline+1)->op1_type == IS_CV && ssa_ops[i+1].op1_def >= 0) { + if ((opline+1)->op1_type == IS_CV && (ssa_op+1)->op1_def >= 0) { opline++; - i++; - tmp = OP1_INFO(); + ssa_op++; + tmp = OP1_INFO_EX(); if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_ASSIGN_OBJ: @@ -2740,28 +2751,28 @@ static int zend_update_type_info(const zend_op_array *op_array, if (tmp & MAY_BE_OBJECT) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { // TODO: If there is no __set we might do better tmp = zend_fetch_prop_type(script, - zend_fetch_prop_info(op_array, ssa, opline, i), &ce); - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } } if ((opline+1)->op1_type == IS_CV) { opline++; - i++; - tmp = OP1_INFO(); + ssa_op++; + tmp = OP1_INFO_EX(); if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_PRE_INC_OBJ: @@ -2777,24 +2788,24 @@ static int zend_update_type_info(const zend_op_array *op_array, if (tmp & MAY_BE_OBJECT) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { // TODO: ??? tmp = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_ASSIGN: - if (opline->op2_type == IS_CV && ssa_ops[i].op2_def >= 0) { + if (opline->op2_type == IS_CV && ssa_op->op2_def >= 0) { tmp = t2; if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op2_def); } tmp = t2 & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN); if (t2 & MAY_BE_UNDEF) { @@ -2813,17 +2824,17 @@ static int zend_update_type_info(const zend_op_array *op_array, if (RETURN_VALUE_USED(opline) && (tmp & MAY_BE_RC1)) { tmp |= MAY_BE_RCN; } - if (ssa_ops[i].op1_def >= 0) { - if (ssa_var_info[ssa_ops[i].op1_def].use_as_double) { + if (ssa_op->op1_def >= 0) { + if (ssa_var_info[ssa_op->op1_def].use_as_double) { tmp &= ~MAY_BE_LONG; tmp |= MAY_BE_DOUBLE; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op2_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp & ~MAY_BE_REF, ssa_ops[i].result_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op2_use, ssa_ops[i].result_def); + if (ssa_op->result_def >= 0) { + UPDATE_SSA_TYPE(tmp & ~MAY_BE_REF, ssa_op->result_def); + COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def); } break; case ZEND_ASSIGN_REF: @@ -2833,7 +2844,7 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t2 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op2_def); } if (opline->op2_type == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION) { tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF; @@ -2843,9 +2854,9 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t2 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + if (ssa_op->result_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_ASSIGN_OBJ_REF: @@ -2858,11 +2869,11 @@ static int zend_update_type_info(const zend_op_array *op_array, if (tmp & MAY_BE_OBJECT) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - t2 = OP1_DATA_INFO(); + t2 = OP1_DATA_INFO_EX(); if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION)) { tmp = (MAY_BE_REF | MAY_BE_RCN | MAY_BE_RC1 | t2) & ~MAY_BE_UNDEF; } else { @@ -2871,30 +2882,30 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t2 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } - if (ssa_ops[i].result_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + if (ssa_op->result_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } if ((opline+1)->op1_type == IS_CV) { opline++; - i++; + ssa_op++; tmp = (MAY_BE_REF | t2) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN); if (t2 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_ASSIGN_STATIC_PROP_REF: if ((opline+1)->op1_type == IS_CV) { opline++; - i++; - UPDATE_SSA_TYPE(MAY_BE_REF, ssa_ops[i].op1_def); + ssa_op++; + UPDATE_SSA_TYPE(MAY_BE_REF, ssa_op->op1_def); } break; case ZEND_BIND_GLOBAL: tmp = MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); break; case ZEND_BIND_STATIC: tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF @@ -2902,20 +2913,20 @@ static int zend_update_type_info(const zend_op_array *op_array, if (opline->extended_value & ZEND_BIND_IMPLICIT) { tmp |= MAY_BE_UNDEF; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); break; case ZEND_SEND_VAR: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = t1; if ((t1 & (MAY_BE_RC1|MAY_BE_REF)) && (opline->op1_type == IS_CV)) { tmp |= MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } break; case ZEND_BIND_LEXICAL: - if (ssa_ops[i].op2_def >= 0) { + if (ssa_op->op2_def >= 0) { if (opline->extended_value & ZEND_BIND_REF) { tmp = t2 | MAY_BE_REF; } else { @@ -2924,12 +2935,12 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op2_use, ssa_ops[i].op2_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op2_def); + COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->op2_def); } break; case ZEND_YIELD: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { if (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE) { tmp = t1 | MAY_BE_REF; } else { @@ -2938,30 +2949,30 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_RC1 | MAY_BE_RCN; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_SEND_VAR_EX: case ZEND_SEND_FUNC_ARG: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = (t1 & MAY_BE_UNDEF)|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_SEND_REF: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_SEND_UNPACK: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = t1; if (t1 & MAY_BE_ARRAY) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; @@ -2973,14 +2984,14 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t1 & MAY_BE_OBJECT) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_FAST_CONCAT: case ZEND_ROPE_INIT: case ZEND_ROPE_ADD: case ZEND_ROPE_END: - UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def); break; case ZEND_RECV: case ZEND_RECV_INIT: @@ -3008,8 +3019,8 @@ static int zend_update_type_info(const zend_op_array *op_array, } #if 0 /* We won't receive unused arguments */ - if (ssa_vars[ssa_ops[i].result_def].use_chain < 0 && - ssa_vars[ssa_ops[i].result_def].phi_use_chain == NULL && + if (ssa_vars[ssa_op->result_def].use_chain < 0 && + ssa_vars[ssa_op->result_def].phi_use_chain == NULL && op_array->arg_info && opline->op1.num <= op_array->num_args && op_array->arg_info[opline->op1.num-1].class_name == NULL && @@ -3017,81 +3028,81 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp = MAY_BE_UNDEF|MAY_BE_RCN; } #endif - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (func_info && (int)opline->op1.num-1 < func_info->num_args && func_info->arg_info[opline->op1.num-1].info.ce) { UPDATE_SSA_OBJ_TYPE( func_info->arg_info[opline->op1.num-1].info.ce, func_info->arg_info[opline->op1.num-1].info.is_instanceof, - ssa_ops[i].result_def); + ssa_op->result_def); } else if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } break; } case ZEND_DECLARE_ANON_CLASS: - UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def); if (script && (ce = zend_hash_find_ptr(&script->class_table, Z_STR_P(CRT_CONSTANT(opline->op1)))) != NULL) { - UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def); } break; case ZEND_FETCH_CLASS: - UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_CLASS, ssa_op->result_def); if (opline->op2_type == IS_UNUSED) { switch (opline->op1.num & ZEND_FETCH_CLASS_MASK) { case ZEND_FETCH_CLASS_SELF: if (op_array->scope) { - UPDATE_SSA_OBJ_TYPE(op_array->scope, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(op_array->scope, 0, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } break; case ZEND_FETCH_CLASS_PARENT: if (op_array->scope && op_array->scope->parent && (op_array->scope->ce_flags & ZEND_ACC_LINKED)) { - UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(op_array->scope->parent, 0, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } break; case ZEND_FETCH_CLASS_STATIC: default: - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); break; } } else if (opline->op2_type == IS_CONST) { zval *zv = CRT_CONSTANT(opline->op2); if (Z_TYPE_P(zv) == IS_STRING) { ce = get_class_entry(script, Z_STR_P(zv+1)); - UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } } else { - COPY_SSA_OBJ_TYPE(ssa_ops[i].op2_use, ssa_ops[i].result_def); + COPY_SSA_OBJ_TYPE(ssa_op->op2_use, ssa_op->result_def); } break; case ZEND_NEW: tmp = MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT; if (opline->op1_type == IS_CONST && (ce = get_class_entry(script, Z_STR_P(CRT_CONSTANT(opline->op1)+1))) != NULL) { - UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_ops[i].result_def); - } else if ((t1 & MAY_BE_CLASS) && ssa_ops[i].op1_use >= 0 && ssa_var_info[ssa_ops[i].op1_use].ce) { - UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_ops[i].op1_use].ce, ssa_var_info[ssa_ops[i].op1_use].is_instanceof, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 0, ssa_op->result_def); + } else if ((t1 & MAY_BE_CLASS) && ssa_op->op1_use >= 0 && ssa_var_info[ssa_op->op1_use].ce) { + UPDATE_SSA_OBJ_TYPE(ssa_var_info[ssa_op->op1_use].ce, ssa_var_info[ssa_op->op1_use].is_instanceof, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_CLONE: - UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_ops[i].result_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def); break; case ZEND_INIT_ARRAY: case ZEND_ADD_ARRAY_ELEMENT: - if (opline->op1_type == IS_CV && ssa_ops[i].op1_def >= 0) { + if (opline->op1_type == IS_CV && ssa_op->op1_def >= 0) { if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) { tmp = (MAY_BE_REF | t1) & ~(MAY_BE_UNDEF|MAY_BE_RC1|MAY_BE_RCN); if (t1 & MAY_BE_UNDEF) { @@ -3110,12 +3121,12 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = MAY_BE_RC1|MAY_BE_ARRAY; - if (ssa_ops[i].result_use >= 0) { - tmp |= ssa_var_info[ssa_ops[i].result_use].type; + if (ssa_op->result_use >= 0) { + tmp |= ssa_var_info[ssa_op->result_use].type; } if (opline->op1_type != IS_UNUSED) { tmp |= (t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT; @@ -3143,11 +3154,11 @@ static int zend_update_type_info(const zend_op_array *op_array, } } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_ADD_ARRAY_UNPACK: - tmp = ssa_var_info[ssa_ops[i].result_use].type; + tmp = ssa_var_info[ssa_op->result_use].type; ZEND_ASSERT(tmp & MAY_BE_ARRAY); /* Ignore string keys as they will throw. */ if (t1 & MAY_BE_ARRAY_KEY_LONG) { @@ -3156,7 +3167,7 @@ static int zend_update_type_info(const zend_op_array *op_array, if (t1 & MAY_BE_OBJECT) { tmp |= MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_UNSET_CV: tmp = MAY_BE_UNDEF; @@ -3164,18 +3175,18 @@ static int zend_update_type_info(const zend_op_array *op_array, /* In global scope, we know nothing */ tmp |= MAY_BE_REF; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); break; case ZEND_UNSET_DIM: case ZEND_UNSET_OBJ: - if (ssa_ops[i].op1_def >= 0) { - UPDATE_SSA_TYPE(t1, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + if (ssa_op->op1_def >= 0) { + UPDATE_SSA_TYPE(t1, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = t1; if (opline->opcode == ZEND_FE_RESET_RW) { tmp |= MAY_BE_REF; @@ -3184,8 +3195,8 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } if (opline->opcode == ZEND_FE_RESET_RW) { //??? @@ -3193,8 +3204,8 @@ static int zend_update_type_info(const zend_op_array *op_array, } else { tmp = MAY_BE_RC1 | MAY_BE_RCN | (t1 & (MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF)); } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->result_def); break; case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: @@ -3221,9 +3232,9 @@ static int zend_update_type_info(const zend_op_array *op_array, } } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); - if (ssa_ops[i].result_def >= 0) { - tmp = (ssa_ops[i].result_use >= 0) ? RES_USE_INFO() : 0; + UPDATE_SSA_TYPE(tmp, ssa_op->op2_def); + if (ssa_op->result_def >= 0) { + tmp = (ssa_op->result_use >= 0) ? RES_USE_INFO_EX() : 0; if (t1 & MAY_BE_OBJECT) { tmp |= MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; } @@ -3235,7 +3246,7 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp |= MAY_BE_STRING | MAY_BE_RCN; } } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; case ZEND_FETCH_DIM_R: @@ -3246,7 +3257,7 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_DIM_FUNC_ARG: case ZEND_FETCH_LIST_R: case ZEND_FETCH_LIST_W: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { uint32_t key_type = 0; tmp = t1 & ~(MAY_BE_RC1|MAY_BE_RCN); if (opline->opcode == ZEND_FETCH_DIM_W || @@ -3297,10 +3308,18 @@ static int zend_update_type_info(const zend_op_array *op_array, || opline->opcode == ZEND_FETCH_DIM_W || opline->opcode == ZEND_FETCH_DIM_FUNC_ARG || opline->opcode == ZEND_FETCH_LIST_W) { - j = ssa_vars[ssa_ops[i].result_def].use_chain; + j = ssa_vars[ssa_op->result_def].use_chain; while (j >= 0) { - ZEND_ASSERT(j == i + 1 && "Use must be in next opline"); - switch (op_array->opcodes[j].opcode) { + zend_uchar opcode; + + if (!ssa_opcodes) { + ZEND_ASSERT(j == (opline - op_array->opcodes) + 1 && "Use must be in next opline"); + opcode = op_array->opcodes[j].opcode; + } else { + ZEND_ASSERT(ssa_opcodes[j] == opline + 1 && "Use must be in next opline"); + opcode = ssa_opcodes[j]->opcode; + } + switch (opcode) { case ZEND_FETCH_DIM_W: case ZEND_FETCH_DIM_RW: case ZEND_FETCH_DIM_FUNC_ARG: @@ -3354,18 +3373,18 @@ static int zend_update_type_info(const zend_op_array *op_array, break; EMPTY_SWITCH_DEFAULT_CASE() } - j = zend_ssa_next_use(ssa_ops, ssa_ops[i].result_def, j); + j = zend_ssa_next_use(ssa->ops, ssa_op->result_def, j); ZEND_ASSERT(j < 0 && "There should only be one use"); } } if ((tmp & MAY_BE_ARRAY) && (tmp & MAY_BE_ARRAY_KEY_ANY)) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } else { /* invalid key type */ tmp = (tmp & (MAY_BE_RC1|MAY_BE_RCN)) | (t1 & ~(MAY_BE_RC1|MAY_BE_RCN)); - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - COPY_SSA_OBJ_TYPE(ssa_ops[i].op1_use, ssa_ops[i].op1_def); + COPY_SSA_OBJ_TYPE(ssa_op->op1_use, ssa_op->op1_def); } /* FETCH_LIST on a string behaves like FETCH_R on null */ tmp = zend_array_element_type( @@ -3375,11 +3394,11 @@ static int zend_update_type_info(const zend_op_array *op_array, if (opline->opcode == ZEND_FETCH_DIM_IS && (t1 & MAY_BE_STRING)) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_FETCH_THIS: - UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_ops[i].result_def); - UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(op_array->scope, 1, ssa_op->result_def); + UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_op->result_def); break; case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_IS: @@ -3387,15 +3406,15 @@ static int zend_update_type_info(const zend_op_array *op_array, case ZEND_FETCH_OBJ_W: case ZEND_FETCH_OBJ_UNSET: case ZEND_FETCH_OBJ_FUNC_ARG: - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = zend_fetch_prop_type(script, - zend_fetch_prop_info(op_array, ssa, opline, i), &ce); + zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce); if (opline->result_type != IS_TMP_VAR) { tmp |= MAY_BE_REF; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } } break; @@ -3410,16 +3429,16 @@ static int zend_update_type_info(const zend_op_array *op_array, if (opline->result_type != IS_TMP_VAR) { tmp |= MAY_BE_REF; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } break; case ZEND_DO_FCALL: case ZEND_DO_ICALL: case ZEND_DO_UCALL: case ZEND_DO_FCALL_BY_NAME: - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { zend_func_info *func_info = ZEND_FUNC_INFO(op_array); zend_call_info *call_info; @@ -3431,46 +3450,46 @@ static int zend_update_type_info(const zend_op_array *op_array, goto unknown_opcode; } tmp = zend_get_func_info(call_info, ssa); - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (call_info->callee_func->type == ZEND_USER_FUNCTION) { func_info = ZEND_FUNC_INFO(&call_info->callee_func->op_array); if (func_info) { UPDATE_SSA_OBJ_TYPE( func_info->return_info.ce, func_info->return_info.is_instanceof, - ssa_ops[i].result_def); + ssa_op->result_def); } } } break; case ZEND_FETCH_CONSTANT: case ZEND_FETCH_CLASS_CONSTANT: - UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING|MAY_BE_RESOURCE|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY, ssa_op->result_def); break; case ZEND_STRLEN: tmp = MAY_BE_LONG; if (t1 & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_STRING))) { tmp |= MAY_BE_NULL; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); break; case ZEND_COUNT: case ZEND_FUNC_NUM_ARGS: - UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def); break; case ZEND_FUNC_GET_ARGS: - UPDATE_SSA_TYPE(MAY_BE_RC1| MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_RC1| MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY, ssa_op->result_def); break; case ZEND_GET_CLASS: case ZEND_GET_CALLED_CLASS: - UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_RCN, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_RCN, ssa_op->result_def); break; case ZEND_GET_TYPE: - UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_STRING|MAY_BE_RC1|MAY_BE_RCN, ssa_op->result_def); break; case ZEND_TYPE_CHECK: case ZEND_DEFINED: - UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_FALSE|MAY_BE_TRUE, ssa_op->result_def); break; case ZEND_VERIFY_RETURN_TYPE: if (t1 & MAY_BE_REF) { @@ -3481,26 +3500,26 @@ static int zend_update_type_info(const zend_op_array *op_array, tmp = zend_fetch_arg_info_type(script, ret_info, &ce); } if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].op1_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->op1_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].op1_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->op1_def); } } else { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); if (ce) { - UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(ce, 1, ssa_op->result_def); } else { - UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_ops[i].result_def); + UPDATE_SSA_OBJ_TYPE(NULL, 0, ssa_op->result_def); } } break; case ZEND_MAKE_REF: tmp = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); - if (ssa_ops[i].op1_def >= 0) { - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); + if (ssa_op->op1_def >= 0) { + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } break; case ZEND_CATCH: @@ -3510,18 +3529,18 @@ static int zend_update_type_info(const zend_op_array *op_array, break; default: unknown_opcode: - if (ssa_ops[i].op1_def >= 0) { + if (ssa_op->op1_def >= 0) { tmp = MAY_BE_ANY | MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } - if (ssa_ops[i].result_def >= 0) { + if (ssa_op->result_def >= 0) { tmp = MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; if (opline->result_type == IS_TMP_VAR) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; } else { tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN; } - UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(tmp, ssa_op->result_def); } break; } @@ -3529,6 +3548,18 @@ unknown_opcode: return SUCCESS; } +int 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) +{ + return _zend_update_type_info(op_array, ssa, script, NULL, opline, ssa_op, ssa_opcodes, optimization_level, 0); +} + static uint32_t get_class_entry_rank(zend_class_entry *ce) { uint32_t rank = 0; if (ce->ce_flags & ZEND_ACC_LINKED) { @@ -3583,6 +3614,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script int ssa_vars_count = ssa->vars_count; int i, j; uint32_t tmp, worklist_len = zend_bitset_len(ssa_vars_count); + zend_bool update_worklist = 1; while (!zend_bitset_empty(worklist, worklist_len)) { j = zend_bitset_first(worklist, worklist_len); @@ -3645,7 +3677,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script } } else if (ssa_vars[j].definition >= 0) { i = ssa_vars[j].definition; - if (zend_update_type_info(op_array, ssa, script, worklist, i, optimization_level) == FAILURE) { + if (_zend_update_type_info(op_array, ssa, script, worklist, op_array->opcodes + i, ssa->ops + i, NULL, optimization_level, 1) == FAILURE) { return FAILURE; } } @@ -4220,10 +4252,10 @@ void zend_inference_check_recursive_dependencies(zend_op_array *op_array) free_alloca(worklist, use_heap); } -int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa) +int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa) { - uint32_t t1 = OP1_INFO(); - uint32_t t2 = OP2_INFO(); + uint32_t t1 = OP1_INFO_EX(); + uint32_t t2 = OP2_INFO_EX(); if (opline->op1_type == IS_CV) { if (t1 & MAY_BE_UNDEF) { @@ -4331,7 +4363,7 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss return 0; case ZEND_BIND_GLOBAL: if ((opline+1)->opcode == ZEND_BIND_GLOBAL) { - return zend_may_throw(opline + 1, op_array, ssa); + return zend_may_throw_ex(opline + 1, ssa_op + 1, op_array, ssa); } return 0; case ZEND_ADD: @@ -4343,8 +4375,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); case ZEND_DIV: case ZEND_MOD: - if (!OP2_HAS_RANGE() || - (OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) { + if (!OP2_HAS_RANGE_EX() || + (OP2_MIN_RANGE_EX() <= 0 && OP2_MAX_RANGE_EX() >= 0)) { /* Division by zero */ return 1; } @@ -4358,8 +4390,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss case ZEND_SR: return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - !OP2_HAS_RANGE() || - OP2_MIN_RANGE() < 0; + !OP2_HAS_RANGE_EX() || + OP2_MIN_RANGE_EX() < 0; case ZEND_CONCAT: case ZEND_FAST_CONCAT: return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) || @@ -4411,8 +4443,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)); } else if (opline->extended_value == ZEND_DIV || opline->extended_value == ZEND_MOD) { - if (!OP2_HAS_RANGE() || - (OP2_MIN_RANGE() <= 0 && OP2_MAX_RANGE() >= 0)) { + if (!OP2_HAS_RANGE_EX() || + (OP2_MIN_RANGE_EX() <= 0 && OP2_MAX_RANGE_EX() >= 0)) { /* Division by zero */ return 1; } @@ -4427,8 +4459,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss opline->extended_value == ZEND_SR) { return (t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || (t2 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT)) || - !OP2_HAS_RANGE() || - OP2_MIN_RANGE() < 0; + !OP2_HAS_RANGE_EX() || + OP2_MIN_RANGE_EX() < 0; } else if (opline->extended_value == ZEND_CONCAT) { return (t1 & (MAY_BE_ARRAY|MAY_BE_OBJECT)) || (t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)); @@ -4452,7 +4484,7 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)); case ZEND_ASSIGN_DIM: if ((opline+1)->op1_type == IS_CV) { - if (_ssa_op1_info(op_array, ssa, opline+1) & MAY_BE_UNDEF) { + if (_ssa_op1_info_ex(op_array, ssa, opline+1, ssa_op+1) & MAY_BE_UNDEF) { return 1; } } @@ -4462,8 +4494,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss if (t1 & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_OBJECT))) { return 1; } - if (ssa->ops[opline - op_array->opcodes].op1_use) { - zend_ssa_var_info *var_info = ssa->var_info + ssa->ops[opline - op_array->opcodes].op1_use; + if (ssa_op->op1_use) { + zend_ssa_var_info *var_info = ssa->var_info + ssa_op->op1_use; zend_class_entry *ce = var_info->ce; if (var_info->is_instanceof || @@ -4555,3 +4587,8 @@ int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ss return 1; } } + +int zend_may_throw(const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa) +{ + return zend_may_throw_ex(opline, &ssa->ops[opline - op_array->opcodes], op_array, ssa); +} |