]> granicus.if.org Git - php/commitdiff
Make RC1/RCN inference more accurate (it's probably not 100% correct anyway)
authorDmitry Stogov <dmitry@zend.com>
Tue, 22 Dec 2015 12:35:17 +0000 (15:35 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 22 Dec 2015 12:35:17 +0000 (15:35 +0300)
ext/opcache/Optimizer/zend_func_info.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_inference.h

index e94282d68f6545ea5d44d483d63033f49fa9c4c8..a8aec475fb39931c2559a917665ecbdc5895d4e6 100644 (file)
@@ -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;
index ccbc14a930dc08f6566941c86d32e1dd63bec4a0..ebaf05807985d9f8b20debf2058d600f8d85a456 100644 (file)
@@ -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;
index 0ac01bfbe8a92fb348f6958f0c6a096045a02896..a9e1abd1510e2e1db2711d175f132c00d23919b8 100644 (file)
@@ -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;
        }
 }