]> granicus.if.org Git - php/commitdiff
Improved reference dependencies analysis
authorDmitry Stogov <dmitry@zend.com>
Wed, 13 Sep 2017 15:18:51 +0000 (18:18 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 13 Sep 2017 15:18:51 +0000 (18:18 +0300)
ext/opcache/Optimizer/escape_analysis.c
ext/opcache/tests/opt/dce_007.phpt [new file with mode: 0644]

index 3c039913156ab5a34e10fbdb9b678ce41e37c93a..7ffdf7382026cd72c52819c4b1a2a3b865635f4f 100644 (file)
@@ -298,6 +298,17 @@ static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int va
                                        return 1; /* incorrect type */
                                }
                                break;
+                       case ZEND_INIT_ARRAY:
+                       case ZEND_ADD_ARRAY_ELEMENT:
+                               if (opline->extended_value & ZEND_ARRAY_ELEMENT_REF) {
+                                       return 1;
+                               }
+                               if (OP1_INFO() & MAY_BE_OBJECT) {
+                                       /* object aliasing */
+                                       return 1;
+                               }
+                               /* reference dependencies processed separately */
+                               break;
                        default:
                                return 1;
                }
@@ -307,9 +318,19 @@ static int is_escape_use(zend_op_array *op_array, zend_ssa *ssa, int use, int va
                switch (opline->opcode) {
                        case ZEND_ASSIGN_DIM:
                        case ZEND_ASSIGN_OBJ:
+                               if (OP1_INFO() & MAY_BE_OBJECT) {
+                                       /* object aliasing */
+                                       return 1;
+                               }
                                /* reference dependencies processed separately */
                                break;
                        case ZEND_ASSIGN:
+                               if (OP1_INFO() & MAY_BE_REF) {
+                                       return 1;
+                               }
+                               if (op->op1_def >= 0 && ssa->vars[op->op1_def].alias) {
+                                       return 1;
+                               }
                                if (opline->op2_type == IS_CV || opline->result_type != IS_UNUSED) {
                                        if (OP2_INFO() & MAY_BE_OBJECT) {
                                                /* object aliasing */
@@ -428,30 +449,40 @@ int zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array,
                                                FOREACH_USE(ssa->vars + i, use) {
                                                        zend_ssa_op *op = ssa->ops + use;
                                                        zend_op *opline = op_array->opcodes + use;
+                                                       int enclosing_root;
 
                                                        if ((opline->opcode == ZEND_ASSIGN_DIM ||
                                                             opline->opcode == ZEND_ASSIGN_OBJ) &&
                                                            op->op2_use == i &&
                                                            op->op1_use >= 0) {
-                                                               int root2 = ees[op->op1_use];
-
-                                                               if (ssa_vars[root2].escape_state == ESCAPE_STATE_UNKNOWN ||
-                                                                   ssa_vars[root2].escape_state > ssa_vars[root].escape_state) {
-                                                                   if (ssa_vars[root2].escape_state == ESCAPE_STATE_UNKNOWN) {
-                                                                               ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
-                                                                   } else {
-                                                                               ssa_vars[root].escape_state = ssa_vars[root2].escape_state;
-                                                                       }
-                                                                       if (ssa_vars[root].escape_state == ESCAPE_STATE_GLOBAL_ESCAPE) {
-                                                                               num_non_escaped--;
-                                                                               if (num_non_escaped == 0) {
-                                                                                       i = ssa_vars_count;
-                                                                                       changed = 0;
-                                                                               }
-                                                                               break;
+                                                               enclosing_root = ees[op->op1_use];
+                                                       } else if ((opline->opcode == ZEND_INIT_ARRAY ||
+                                                            opline->opcode == ZEND_ADD_ARRAY_ELEMENT) &&
+                                                           op->op1_use == i &&
+                                                           op->result_def >= 0) {
+                                                               enclosing_root = ees[op->result_def];
+                                                       } else {
+                                                               continue;
+                                                       }
+
+                                                       if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN ||
+                                                           ssa_vars[enclosing_root].escape_state > ssa_vars[root].escape_state) {
+                                                           if (ssa_vars[enclosing_root].escape_state == ESCAPE_STATE_UNKNOWN) {
+                                                                       ssa_vars[root].escape_state = ESCAPE_STATE_GLOBAL_ESCAPE;
+                                                           } else {
+                                                                       ssa_vars[root].escape_state = ssa_vars[enclosing_root].escape_state;
+                                                               }
+                                                               if (ssa_vars[root].escape_state == ESCAPE_STATE_GLOBAL_ESCAPE) {
+                                                                       num_non_escaped--;
+                                                                       if (num_non_escaped == 0) {
+                                                                               i = ssa_vars_count;
+                                                                               changed = 0;
                                                                        } else {
                                                                                changed = 1;
                                                                        }
+                                                                       break;
+                                                               } else {
+                                                                       changed = 1;
                                                                }
                                                        }
                                                } FOREACH_USE_END();
diff --git a/ext/opcache/tests/opt/dce_007.phpt b/ext/opcache/tests/opt/dce_007.phpt
new file mode 100644 (file)
index 0000000..de0ace5
--- /dev/null
@@ -0,0 +1,28 @@
+--TEST--
+DCE 007: Escaiping of enclosed arrays doesn't prevent removing of enclosing array
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.opt_debug_level=0x20000
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function esc($x) {
+        $a = [$x];
+        $b = [$a];
+        return $a;
+}
+--EXPECTF--
+$_main: ; (lines=1, args=0, vars=0, tmps=0)
+    ; (after optimizer)
+    ; %sdce_007.php:1-7
+L0:     RETURN int(1)
+
+esc: ; (lines=3, args=1, vars=2, tmps=0)
+    ; (after optimizer)
+    ; %sdce_007.php:2-6
+L0:     CV0($x) = RECV 1
+L1:     CV1($a) = INIT_ARRAY 1 (packed) CV0($x) NEXT
+L2:     RETURN CV1($a)