diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2015-12-22 15:35:17 +0300 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2015-12-22 15:35:17 +0300 |
| commit | 83cd8284693e0f0bd2cf9562886ea8238a07fe3c (patch) | |
| tree | 9ea27d11d2b62b416425703aa3d29467087c3f9e | |
| parent | 6607b6506a86dc646f2e6875bb73c39017661c4c (diff) | |
| download | php-git-83cd8284693e0f0bd2cf9562886ea8238a07fe3c.tar.gz | |
Make RC1/RCN inference more accurate (it's probably not 100% correct anyway)
| -rw-r--r-- | ext/opcache/Optimizer/zend_func_info.c | 4 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_inference.c | 108 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_inference.h | 8 |
3 files changed, 64 insertions, 56 deletions
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index e94282d68f..a8aec475fb 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -1239,7 +1239,9 @@ uint32_t zend_get_func_info(const zend_call_info *call_info, const zend_ssa *ssa if (call_info->callee_func->type == ZEND_INTERNAL_FUNCTION) { ret |= FUNC_MAY_WARN; } - if (call_info->callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) { + if (call_info->callee_func->common.fn_flags & ZEND_ACC_GENERATOR) { + ret = MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; + } else if (call_info->callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) { ret |= MAY_BE_REF; } else { ret |= MAY_BE_RC1 | MAY_BE_RCN; diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index ccbc14a930..ebaf058079 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -1978,18 +1978,24 @@ static int zend_infer_ranges(const zend_op_array *op_array, zend_ssa *ssa) /* {{ } /* }}} */ -#define UPDATE_SSA_TYPE(_type, var) \ +#define UPDATE_SSA_TYPE(_type, _var) \ do { \ uint32_t __type = (_type); \ + int __var = (_var); \ if (__type & MAY_BE_REF) { \ - __type |= MAY_BE_RC1 | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; \ + __type |= MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; \ } \ - if (var >= 0) { \ - if (ssa_var_info[var].type != __type) { \ - check_type_narrowing(op_array, ssa, worklist, \ - var, ssa_var_info[var].type, __type); \ - ssa_var_info[var].type = __type; \ - add_usages(op_array, ssa, worklist, var); \ + if (__var >= 0) { \ + if (ssa_vars[__var].var < op_array->last_var) { \ + if (__type & (MAY_BE_REF|MAY_BE_RCN)) { \ + __type |= MAY_BE_RC1 | MAY_BE_RCN; \ + } \ + } \ + if (ssa_var_info[__var].type != __type) { \ + check_type_narrowing(op_array, ssa, worklist, \ + __var, ssa_var_info[__var].type, __type); \ + ssa_var_info[__var].type = __type; \ + add_usages(op_array, ssa, worklist, __var); \ } \ /*zend_bitset_excl(worklist, var);*/ \ } \ @@ -2345,14 +2351,13 @@ static void zend_update_type_info(const zend_op_array *op_array, break; case ZEND_QM_ASSIGN: case ZEND_COALESCE: - if (opline->op1_type == IS_CV || opline->op1_type == IS_VAR) { - tmp = (MAY_BE_RCN | t1) & ~(MAY_BE_UNDEF|MAY_BE_REF); - } else { - tmp = (MAY_BE_RC1 | t1) & ~(MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_RCN); - } + tmp = t1 & ~(MAY_BE_UNDEF|MAY_BE_REF); if (t1 & MAY_BE_UNDEF) { tmp |= MAY_BE_NULL; } + if (opline->op1_type & (IS_CV|IS_VAR)) { + tmp |= MAY_BE_RCN; + } UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); if ((t1 & MAY_BE_OBJECT) && 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); @@ -2425,6 +2430,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); if ((orig & MAY_BE_OBJECT) && 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].op1_def); @@ -2505,6 +2513,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2557,6 +2568,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2601,6 +2615,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2646,6 +2663,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2690,6 +2710,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2741,6 +2764,9 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { tmp |= MAY_BE_ARRAY_KEY_STRING; } + if (!(orig & (MAY_BE_OBJECT|MAY_BE_REF))) { + orig &= ~MAY_BE_RCN; + } UPDATE_SSA_TYPE(orig, ssa_ops[i].op1_def); } } else { @@ -2853,12 +2879,15 @@ static void zend_update_type_info(const zend_op_array *op_array, break; case ZEND_ASSIGN_DIM: if (opline->op1_type == IS_CV) { - tmp = (t1 & (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)); + tmp = (t1 & (MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)); tmp &= ~MAY_BE_NULL; if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING)) { tmp |= MAY_BE_ARRAY; } - if (tmp & MAY_BE_RCN) { + if (t1 & MAY_BE_REF) { + tmp |= MAY_BE_REF; + } + if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) { tmp |= MAY_BE_RC1; } if (tmp & MAY_BE_ARRAY) { @@ -2901,9 +2930,7 @@ static void zend_update_type_info(const zend_op_array *op_array, tmp = OP1_INFO(); if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { - if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) { - tmp |= MAY_BE_RCN; - } + tmp |= MAY_BE_RCN; } } UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); @@ -2911,12 +2938,15 @@ static void zend_update_type_info(const zend_op_array *op_array, break; case ZEND_ASSIGN_OBJ: if (opline->op1_type == IS_CV) { - tmp = (t1 & (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)); + tmp = (t1 & (MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)); tmp &= ~MAY_BE_NULL; if (t1 & (MAY_BE_UNDEF | MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING)) { tmp |= MAY_BE_OBJECT; } - if (tmp & MAY_BE_RCN) { + if (t1 & MAY_BE_REF) { + tmp |= MAY_BE_REF; + } + if (t1 & (MAY_BE_RC1|MAY_BE_RCN)) { tmp |= MAY_BE_RC1; } UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); @@ -2937,9 +2967,7 @@ static void zend_update_type_info(const zend_op_array *op_array, tmp = OP1_INFO(); if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { - if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) { - tmp |= MAY_BE_RCN; - } + tmp |= MAY_BE_RCN; } } UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); @@ -2950,9 +2978,7 @@ static void zend_update_type_info(const zend_op_array *op_array, tmp = t2; if (tmp & (MAY_BE_ANY | MAY_BE_REF)) { if (tmp & MAY_BE_RC1) { - if (t2 & (MAY_BE_RC1|MAY_BE_RCN)) { - tmp |= MAY_BE_RCN; - } + tmp |= MAY_BE_RCN; } } UPDATE_SSA_TYPE(tmp, ssa_ops[i].op2_def); @@ -2964,43 +2990,23 @@ static void zend_update_type_info(const zend_op_array *op_array, if (t1 & MAY_BE_REF) { tmp |= MAY_BE_REF; } - if ((t1 & MAY_BE_RCN) && !(opline->op2_type & (IS_CV|IS_VAR))) { - tmp |= MAY_BE_RC1; - } - if ((t1 & MAY_BE_RCN) && (opline->op2_type & (IS_CV|IS_VAR))) { + if (t1 & (MAY_BE_RC1 | MAY_BE_RCN)) { if (t2 & MAY_BE_REF) { tmp |= MAY_BE_RC1; } if (t2 & MAY_BE_RC1) { tmp |= MAY_BE_RC1; - if (opline->op2_type == IS_CV) { + if (opline->op2_type & (IS_CV|IS_VAR)) { tmp |= MAY_BE_RCN; } } if (t2 & MAY_BE_RCN) { tmp |= MAY_BE_RCN; } - } - if ((t1 & MAY_BE_RC1) && !(opline->op2_type & (IS_CV|IS_VAR))) { - tmp |= MAY_BE_RC1; - } - if ((t1 & MAY_BE_RC1) && (opline->op2_type & (IS_CV|IS_VAR))) { - if (t2 & MAY_BE_REF) { - tmp |= MAY_BE_RC1; - } - if (t2 & MAY_BE_RC1) { - tmp |= MAY_BE_RC1; - if (opline->op2_type == IS_CV) { - tmp |= MAY_BE_RCN; - } - } - if (t2 & MAY_BE_RCN) { + if (RETURN_VALUE_USED(opline) && (tmp & MAY_BE_RC1)) { tmp |= MAY_BE_RCN; } } - 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) { tmp &= ~MAY_BE_LONG; @@ -3231,7 +3237,7 @@ static void zend_update_type_info(const zend_op_array *op_array, UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def); break; case ZEND_CLONE: - UPDATE_SSA_TYPE(MAY_BE_OBJECT, ssa_ops[i].result_def); + UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN|MAY_BE_OBJECT, ssa_ops[i].result_def); if ((t1 & MAY_BE_OBJECT) && 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); } else { @@ -3581,7 +3587,7 @@ static void zend_update_type_info(const zend_op_array *op_array, break; case ZEND_FETCH_CONSTANT: case ZEND_FETCH_CLASS_CONSTANT: - UPDATE_SSA_TYPE(MAY_BE_RC1|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_ops[i].result_def); break; case ZEND_STRLEN: tmp = MAY_BE_RC1|MAY_BE_LONG; diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h index 0ac01bfbe8..a9e1abd151 100644 --- a/ext/opcache/Optimizer/zend_inference.h +++ b/ext/opcache/Optimizer/zend_inference.h @@ -189,12 +189,12 @@ DEFINE_SSA_OP_RANGE_OVERFLOW(op2) static zend_always_inline uint32_t _const_op_type(const zval *zv) { if (Z_TYPE_P(zv) == IS_CONSTANT) { - return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY; + return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY; } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) { - return MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY; + return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY; } else if (Z_TYPE_P(zv) == IS_ARRAY) { HashTable *ht = Z_ARRVAL_P(zv); - uint32_t tmp = MAY_BE_ARRAY | MAY_BE_RC1; + uint32_t tmp = MAY_BE_ARRAY | MAY_BE_RC1 | MAY_BE_RCN; zend_string *str; zval *val; @@ -208,7 +208,7 @@ static zend_always_inline uint32_t _const_op_type(const zval *zv) { } ZEND_HASH_FOREACH_END(); return tmp; } else { - return (1 << Z_TYPE_P(zv)) | MAY_BE_RC1; + return (1 << Z_TYPE_P(zv)) | MAY_BE_RC1 | MAY_BE_RCN; } } |
