summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2015-12-22 15:35:17 +0300
committerDmitry Stogov <dmitry@zend.com>2015-12-22 15:35:17 +0300
commit83cd8284693e0f0bd2cf9562886ea8238a07fe3c (patch)
tree9ea27d11d2b62b416425703aa3d29467087c3f9e
parent6607b6506a86dc646f2e6875bb73c39017661c4c (diff)
downloadphp-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.c4
-rw-r--r--ext/opcache/Optimizer/zend_inference.c108
-rw-r--r--ext/opcache/Optimizer/zend_inference.h8
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;
}
}