]> granicus.if.org Git - php/commitdiff
More accurate reference-counter inference
authorDmitry Stogov <dmitry@zend.com>
Mon, 6 Jul 2020 14:55:23 +0000 (17:55 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 6 Jul 2020 14:55:23 +0000 (17:55 +0300)
ext/opcache/Optimizer/zend_inference.c

index 0f79e92a9f8be297e15308aa3f9c625c03c6bd88..76cc15f2dab98322e5d2abcf1dbfc683642ec713 100644 (file)
@@ -3398,10 +3398,26 @@ static zend_always_inline int _zend_update_type_info(
                case ZEND_FETCH_OBJ_UNSET:
                case ZEND_FETCH_OBJ_FUNC_ARG:
                        if (ssa_op->result_def >= 0) {
-                               tmp = zend_fetch_prop_type(script,
-                                       zend_fetch_prop_info(op_array, ssa, opline, ssa_op), &ce);
+                               zend_property_info *prop_info = zend_fetch_prop_info(op_array, ssa, opline, ssa_op);
+
+                               tmp = zend_fetch_prop_type(script, prop_info, &ce);
                                if (opline->result_type != IS_TMP_VAR) {
                                        tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
+                               } else if (prop_info) {
+                                       /* FETCH_OBJ_R/IS for plain property increments reference counter,
+                                          so it can't be 1 */
+                                       tmp &= ~MAY_BE_RC1;
+                               } else {
+                                       zend_class_entry *ce = NULL;
+
+                                       if (opline->op1_type == IS_UNUSED) {
+                                               ce = op_array->scope;
+                                       } else if (ssa_op->op1_use >= 0 && !ssa->var_info[ssa_op->op1_use].is_instanceof) {
+                                               ce = ssa->var_info[ssa_op->op1_use].ce;
+                                       }
+                                       if (ce && !ce->create_object && !ce->__get) {
+                                               tmp &= ~MAY_BE_RC1;
+                                       }
                                }
                                UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
                                if (ce) {
@@ -3419,6 +3435,8 @@ static zend_always_inline int _zend_update_type_info(
                                zend_fetch_static_prop_info(script, op_array, ssa, opline), &ce);
                        if (opline->result_type != IS_TMP_VAR) {
                                tmp |= MAY_BE_REF | MAY_BE_INDIRECT;
+                       } else {
+                               tmp &= ~MAY_BE_RC1;
                        }
                        UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
                        if (ce) {
@@ -3523,7 +3541,11 @@ unknown_opcode:
                        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;
+                                       if (opline->opcode == ZEND_FETCH_R || opline->opcode == ZEND_FETCH_IS) {
+                                               tmp |= MAY_BE_RCN;
+                                       } else {
+                                               tmp |= MAY_BE_RC1 | MAY_BE_RCN;
+                                       }
                                } else {
                                        tmp |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN;
                                        switch (opline->opcode) {