Revision: 10341
Author:   [email protected]
Date:     Wed Jun 15 12:44:51 2011
Log:      Fix handling of unlabeled break and continue in gflow.

This fixes issues:

http://code.google.com/p/google-web-toolkit/issues/detail?id=6272

http://code.google.com/p/google-web-toolkit/issues/detail?id=6429

(was issue 1453809)

Review at http://gwt-code-reviews.appspot.com/1447824

Review by: [email protected]
http://code.google.com/p/google-web-toolkit/source/detail?r=10341

Modified:
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java Fri Jul 16 08:33:21 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java Wed Jun 15 12:44:51 2011
@@ -452,6 +452,7 @@

     @Override
     public boolean visit(JDoStatement x, Context ctx) {
+      List<Exit> unlabeledExits = removeUnlabeledExits();
       pushNode(new CfgStatementNode<JStatement>(parent, x));
       int pos = nodes.size();

@@ -473,6 +474,7 @@
       addNormalExit(node, CfgConditionalNode.ELSE);

       popNode();
+      addExits(unlabeledExits);
       return false;
     }

@@ -486,6 +488,7 @@

     @Override
     public boolean visit(JForStatement x, Context ctx) {
+      List<Exit> unlabeledExits = removeUnlabeledExits();
       pushNode(new CfgStatementNode<JStatement>(parent, x));
       accept(x.getInitializers());

@@ -519,6 +522,7 @@
       }

       popNode();
+      addExits(unlabeledExits);
       return false;
     }

@@ -970,6 +974,7 @@

     @Override
     public boolean visit(JWhileStatement x, Context ctx) {
+      List<Exit> unlabeledExits = removeUnlabeledExits();
       pushNode(new CfgStatementNode<JStatement>(parent, x));
       int pos = nodes.size();
       accept(x.getTestExpr());
@@ -992,6 +997,7 @@
       addNormalExit(node, CfgConditionalNode.ELSE);

       popNode();
+      addExits(unlabeledExits);
       return false;
     }

@@ -1014,7 +1020,7 @@
     }

     /**
-     * Transform all brake exits into normal exits, thus making sure that
+     * Transform all break exits into normal exits, thus making sure that
      * next node will get edges from them.
      */
     private void addBreakExits(String label) {
@@ -1163,6 +1169,21 @@
       addExits(labeledBreaks);
       return breakExits;
     }
+
+    private List<Exit> removeUnlabeledExits() {
+      List<Exit> unlabeledExits = new ArrayList<Exit>();
+      Exit.Reason reasons[] = { Exit.Reason.BREAK, Exit.Reason.CONTINUE };
+      for (Exit.Reason reason : reasons) {
+ for (Iterator<Exit> i = currentExitsByReason.get(reason).iterator(); i.hasNext();) {
+          Exit exit = i.next();
+          if (exit.getLabel() == null) {
+            i.remove();
+            unlabeledExits.add(exit);
+          }
+        }
+      }
+      return unlabeledExits;
+    }
   }

   /**
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java Thu Apr 7 10:39:39 2011 +++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java Wed Jun 15 12:44:51 2011
@@ -261,6 +261,36 @@
        "return results;"
        );
   }
+
+  public void testComplexCode4() throws Exception {
+    addSnippetClassDecl("static boolean confirm() { return true; }");
+
+    optimize("int",
+       "int n = 0;",
+       "for (; ; ) {",
+       "  if (confirm()) {",
+       "    break;",
+       "  } else {",
+       "    for (int i = 0; i < 2; i++) {",
+       "      n = i;",
+       "    }",
+       "  }",
+       "}",
+       "return n;"
+   ).into(
+       "int n = 0;",
+       "for (; ; ) {",
+       "  if (confirm()) {",
+       "    break;",
+       "  } else {",
+       "    for (int i = 0; i < 2; i++) {",
+       "      n = i;",
+       "    }",
+       "  }",
+       "}",
+      "return n;"
+      );
+  }

   public void testImplicitConversion() throws Exception {
     optimize("long",
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java Fri Jul 16 08:33:21 2010 +++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java Wed Jun 15 12:44:51 2011
@@ -51,7 +51,7 @@
     addSnippetClassDecl("static class Foo { int i; int j; int k; }");
     addSnippetClassDecl("static Foo createFoo() {return null;}");
   }
-
+
   public void testConstantAssignment() throws Exception {
     assertCfg("void", "i = 1;").is(
         "BLOCK -> [*]",
@@ -260,6 +260,52 @@
         "END");
   }

+  public void testDoStatementBreakNoLabel() throws Exception {
+ assertCfg("void", "do { if (b1) { break; } else { do { j = 2; } while (b2); } } while (i == 1);").is(
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "1: BLOCK -> [*]",
+        "STMT -> [*]",
+        "READ(b1) -> [*]",
+        "COND (EntryPoint.b1) -> [THEN=*, ELSE=2]",
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "GOTO -> [4]",
+        "2: BLOCK -> [*]",
+        "STMT -> [*]",
+        "3: BLOCK -> [*]",
+        "STMT -> [*]",
+        "WRITE(j, 2) -> [*]",
+        "READ(b2) -> [*]",
+        "COND (EntryPoint.b2) -> [THEN=3, ELSE=*]",
+        "READ(i) -> [*]",
+        "COND (EntryPoint.i == 1) -> [THEN=1, ELSE=*]",
+        "4: END");
+  }
+
+  public void testDoStatementContinueNoLabel() throws Exception {
+ assertCfg("void", "do { if (b1) { continue; } else { do { j = 2; } while (b2); } } while (i == 1);").is(
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "1: BLOCK -> [*]",
+        "STMT -> [*]",
+        "READ(b1) -> [*]",
+        "COND (EntryPoint.b1) -> [THEN=*, ELSE=2]",
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "GOTO -> [1]",
+        "2: BLOCK -> [*]",
+        "STMT -> [*]",
+        "3: BLOCK -> [*]",
+        "STMT -> [*]",
+        "WRITE(j, 2) -> [*]",
+        "READ(b2) -> [*]",
+        "COND (EntryPoint.b2) -> [THEN=3, ELSE=*]",
+        "READ(i) -> [*]",
+        "COND (EntryPoint.i == 1) -> [THEN=1, ELSE=*]",
+        "END");
+  }
+
   public void testReturn1() throws Exception {
     assertCfg("void", "return;").is(
         "BLOCK -> [*]",
@@ -478,6 +524,29 @@
         "READWRITE(i, null) -> [1]",
         "3: END");
   }
+
+  public void testWhileBreakNoLabel2() throws Exception {
+ assertCfg("void", "while (b1) { if (b2) { break; } else { while (i < 10) { i++; } } }").is(
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "1: READ(b1) -> [*]",
+        "COND (EntryPoint.b1) -> [THEN=*, ELSE=4]",
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "READ(b2) -> [*]",
+        "COND (EntryPoint.b2) -> [THEN=*, ELSE=2]",
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "GOTO -> [4]",
+        "2: BLOCK -> [*]",
+        "STMT -> [*]",
+        "3: READ(i) -> [*]",
+        "COND (EntryPoint.i < 10) -> [THEN=*, ELSE=1]",
+        "BLOCK -> [*]",
+        "STMT -> [*]",
+        "READWRITE(i, null) -> [3]",
+        "4: END");
+  }

   public void testWhileBreakWithLabel1() throws Exception {
     assertCfg("void",
@@ -549,6 +618,29 @@
             "READWRITE(i, null) -> [1]",
             "3: END");
   }
+
+  public void testForBreakNoLabel() throws Exception {
+    assertCfg("void",
+        "for(int i = 0; i < 10; i++) { if (b2) { break; } i++; }").is(
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "STMT -> [*]",
+            "WRITE(i, 0) -> [*]",
+            "1: READ(i) -> [*]",
+            "COND (i < 10) -> [THEN=*, ELSE=3]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(b2) -> [*]",
+            "COND (EntryPoint.b2) -> [THEN=*, ELSE=2]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "GOTO -> [3]",
+            "2: STMT -> [*]",
+            "READWRITE(i, null) -> [*]",
+            "STMT -> [*]",
+            "READWRITE(i, null) -> [1]",
+            "3: END");
+  }

   public void testForContinueNoLabel() throws Exception {
     assertCfg("void",
@@ -572,7 +664,71 @@
             "READWRITE(i, null) -> [1]",
             "4: END");
   }
-
+
+  public void testForBreakNestedForWithLabel() throws Exception {
+    assertCfg("int",
+ "int j = 0; a: for(; ; ) { if (b2) { break a; } else { for (int i = 0; i < 1; i++) { j = i; } } } return j;").is(
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "WRITE(j, 0) -> [*]",
+            "STMT -> [*]",
+            "1: BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(b2) -> [*]",
+            "COND (EntryPoint.b2) -> [THEN=*, ELSE=2]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "GOTO -> [4]",
+            "2: BLOCK -> [*]",
+            "STMT -> [*]",
+            "STMT -> [*]",
+            "WRITE(i, 0) -> [*]",
+            "3: READ(i) -> [*]",
+            "COND (i < 1) -> [THEN=*, ELSE=1]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(i) -> [*]",
+            "WRITE(j, i) -> [*]",
+            "STMT -> [*]",
+            "READWRITE(i, null) -> [3]",
+            "4: STMT -> [*]",
+            "READ(j) -> [*]",
+            "GOTO -> [*]",
+            "END");
+  }
+
+  public void testForBreakNestedForNoLabel() throws Exception {
+    assertCfg("int",
+ "int j = 0; for(; ; ) { if (b2) { break; } else { for (int i = 0; i < 1; i++) { j = i; } } } return j;").is(
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "WRITE(j, 0) -> [*]",
+            "STMT -> [*]",
+            "1: BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(b2) -> [*]",
+            "COND (EntryPoint.b2) -> [THEN=*, ELSE=2]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "GOTO -> [4]",
+            "2: BLOCK -> [*]",
+            "STMT -> [*]",
+            "STMT -> [*]",
+            "WRITE(i, 0) -> [*]",
+            "3: READ(i) -> [*]",
+            "COND (i < 1) -> [THEN=*, ELSE=1]",
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(i) -> [*]",
+            "WRITE(j, i) -> [*]",
+            "STMT -> [*]",
+            "READWRITE(i, null) -> [3]",
+            "4: STMT -> [*]",
+            "READ(j) -> [*]",
+            "GOTO -> [*]",
+            "END");
+  }
+
   public void testCatchThrowException1() throws Exception {
     assertCfg("void",
         "try {",
@@ -1484,7 +1640,7 @@
         "READWRITE(k, null) -> [*]",
         "8: END");
   }
-
+
private CfgBuilderResult assertCfg(String returnType, String ...codeSnippet)
       throws UnableToCompleteException {
     JProgram program = compileSnippet(returnType,

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to