Fixing handling of nested switch statements in gflow.
Added couple of toString methods which helped debugging the issue.
Review by: spoon@google.com
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7720 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/AnalysisSolver.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/AnalysisSolver.java
index 08c3eb7..c978395 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/AnalysisSolver.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/AnalysisSolver.java
@@ -83,8 +83,8 @@
if (debug) {
System.err.println("Applying transformation: " + transformation);
System.err.println("Replacing");
- System.err.println(graph);
- System.err.println("With");
+ System.err.println(node);
+ System.err.println("With graph:");
System.err.println(newSubgraph);
}
@@ -271,6 +271,12 @@
*/
private void iterate(G graph,
final IntegratedAnalysis<N, E, T, G, A> integratedAnalysis) {
+ if (debug) {
+ System.err.println("-----------------------------------------");
+ System.err.println("Iterate started on:");
+ System.err.println(graph);
+ System.err.println("-----------------------------------------");
+ }
final IntegratedFlowFunctionAdapter adapter =
new IntegratedFlowFunctionAdapter(integratedAnalysis);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
index bc55958..07d9f4f 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
@@ -610,12 +610,16 @@
accept(x.getExpr());
JSwitchStatement oldSwitchStatement = switchStatement;
+ // We don't want to mess with other case exits here
+ List<Exit> oldCaseElseExits = removeExits(Exit.Reason.CASE_ELSE);
+ List<Exit> oldCaseThenExits = removeExits(Exit.Reason.CASE_THEN);
+ List<Exit> oldBreakExits = removeExits(Exit.Reason.BREAK);
switchStatement = x;
int defaultPos = -1;
List<Exit> breakExits = new ArrayList<Exit>();
-
+
for (JStatement s : x.getBody().getStatements()) {
if (s instanceof JCaseStatement) {
if (((JCaseStatement) s).getExpr() != null) {
@@ -660,6 +664,9 @@
}
switchStatement = oldSwitchStatement;
+ addExits(oldCaseElseExits);
+ addExits(oldCaseThenExits);
+ addExits(oldBreakExits);
popNode();
return false;
}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/ConstantConditionTransformation.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/ConstantConditionTransformation.java
index a870c67..2519171 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/ConstantConditionTransformation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/ConstantConditionTransformation.java
@@ -111,4 +111,10 @@
return newSubgraph;
}
+
+ @Override
+ public String toString() {
+ return "ConstantConditionTransformation(node=" + node +
+ ", conditionValue=" + conditionValue + ")";
+ }
}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/FoldConstantsTransformation.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/FoldConstantsTransformation.java
index f3e3fbb..fd22b90 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/FoldConstantsTransformation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/constants/FoldConstantsTransformation.java
@@ -52,4 +52,10 @@
CfgNode<?> newNode = new CfgNopNode(node.getParent(), node.getJNode());
return CfgUtil.createSingleNodeReplacementGraph(graph, node, newNode);
}
+
+ @Override
+ public String toString() {
+ return "FoldConstantsTransformation(node=" + node +
+ ", assumptions=" + assumption + ")";
+ }
}
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/unreachable/DeleteNodeTransformation.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/unreachable/DeleteNodeTransformation.java
index 238ea9a..671b332 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/unreachable/DeleteNodeTransformation.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/unreachable/DeleteNodeTransformation.java
@@ -65,4 +65,9 @@
CfgNode<?> newNode = new CfgNopNode(node.getParent(), node.getJNode());
return CfgUtil.createSingleNodeReplacementGraph(graph, node, newNode);
}
+
+ @Override
+ public String toString() {
+ return "DeleteNodeTransformation(node=" + node + ")";
+ }
}
\ No newline at end of file
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
index d1bf20d..07ba206 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
@@ -231,5 +231,16 @@
"public class Exceptions { static boolean throwAssertionError() { throw new RuntimeException(); } }";
}
});
-}
+
+ sourceOracle.addOrReplace(new MockJavaResource("java.lang.String") {
+ @Override
+ protected CharSequence getContent() {
+ return "package java.lang;" +
+ "public class String {" +
+ " public int length() { return 0; }" +
+ " public char charAt(int pos) { return 0; }" +
+ "}";
+ }
+ });
+ }
}
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java
index bb9e0b0..48f0478 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/DataflowOptimizerTest.java
@@ -181,6 +181,121 @@
);
}
+ public void testComplexCode3() throws Exception {
+ addSnippetClassDecl("static final int SPLIT_LOOKING_FOR_COMMA = 0;");
+ addSnippetClassDecl("static final int SPLIT_IN_STRING = 1;");
+ addSnippetClassDecl("static final int SPLIT_IN_ESCAPE = 2;");
+ addSnippetClassDecl("static String getCsvString() { return null; }");
+
+ addSnippetClassDecl(
+ "static class JsArrayString {" +
+ " static JsArrayString createArray() { return null; }" +
+ " JsArrayString cast() { return this; }" +
+ " void push(String s) { }" +
+ "}");
+
+ addSnippetClassDecl(
+ "static class StringBuilder {" +
+ " void append(char c) { }" +
+ "}");
+
+ optimize("JsArrayString",
+ "int state;",
+ "String csvString = getCsvString();",
+ "JsArrayString results = JsArrayString.createArray().cast();",
+ "int index = 0;",
+ "StringBuilder field = new StringBuilder();",
+ "state = SPLIT_LOOKING_FOR_COMMA;",
+ "while (index < csvString.length()) {",
+ " char nextCharacter = csvString.charAt(index);",
+ " switch (state) {",
+ " case SPLIT_LOOKING_FOR_COMMA:",
+ " switch (nextCharacter) {",
+ " case ',':",
+ " results.push(field.toString());",
+ " field = new StringBuilder();",
+ " break;",
+ " case '\"':",
+ " state = SPLIT_IN_STRING;",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " break;",
+ " case SPLIT_IN_STRING:",
+ " switch (nextCharacter) {",
+ " case '\"':",
+ " state = SPLIT_LOOKING_FOR_COMMA;",
+ " break;",
+ " case '\\\\':",
+ " state = SPLIT_IN_ESCAPE;",
+ " field.append(nextCharacter);",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " break;",
+ " case SPLIT_IN_ESCAPE:",
+ " state = SPLIT_IN_STRING;",
+ " field.append(nextCharacter);",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " index++;",
+ "}",
+ "results.push(field.toString());",
+ "return results;"
+ ).into(
+ "int state;",
+ "String csvString = getCsvString();",
+ "JsArrayString results = JsArrayString.createArray().cast();",
+ "int index = 0;",
+ "StringBuilder field = new StringBuilder();",
+ "state = SPLIT_LOOKING_FOR_COMMA;",
+ "while (index < csvString.length()) {",
+ " char nextCharacter = csvString.charAt(index);",
+ " switch (state) {",
+ " case SPLIT_LOOKING_FOR_COMMA:",
+ " switch (nextCharacter) {",
+ " case ',':",
+ " results.push(field.toString());",
+ " field = new StringBuilder();",
+ " break;",
+ " case '\"':",
+ " state = SPLIT_IN_STRING;",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " break;",
+ " case SPLIT_IN_STRING:",
+ " switch (nextCharacter) {",
+ " case '\"':",
+ " state = SPLIT_LOOKING_FOR_COMMA;",
+ " break;",
+ " case '\\\\':",
+ " state = SPLIT_IN_ESCAPE;",
+ " field.append('\\\\');",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " break;",
+ " case SPLIT_IN_ESCAPE:",
+ " state = SPLIT_IN_STRING;",
+ " field.append(nextCharacter);",
+ " break;",
+ " default:",
+ " field.append(nextCharacter);",
+ " }",
+ " ++index;",
+ "}",
+ "results.push(field.toString());",
+ "return results;"
+ );
+ }
+
/* public void testInlineField1() throws Exception {
optimize("int",
"int i = staticFooInstance.i;",
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
index 13e438a..b96c079 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
@@ -1134,6 +1134,89 @@
);
}
+ public void testNestedSwitch() throws Exception {
+ assertCfg("void",
+ "switch(i) {",
+ " case 1: ",
+ " switch (j) {",
+ " case 0: k = 1; break;",
+ " case 1: k = 2; break;",
+ " }",
+ " break;",
+ " case 2: ",
+ " switch (j) {",
+ " case 0: k = 3; break;",
+ " case 1: k = 4; break;",
+ " }",
+ " break;",
+ " case 3: ",
+ " switch (j) {",
+ " case 0: k = 5; break;",
+ " case 1: k = 6; break;",
+ " }",
+ " break;",
+ "}"
+ ).is(
+ "BLOCK -> [*]",
+ "STMT -> [*]",
+ "READ(i) -> [*]",
+ "STMT -> [*]",
+ "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=3]",
+ "STMT -> [*]",
+ "READ(j) -> [*]",
+ "STMT -> [*]",
+ "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=1]",
+ "STMT -> [*]",
+ "WRITE(k, 1) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [2]",
+ "1: STMT -> [*]",
+ "COND (EntryPoint.j == 1) -> [THEN=*, ELSE=2]",
+ "STMT -> [*]",
+ "WRITE(k, 2) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [*]",
+ "2: STMT -> [*]",
+ "GOTO -> [9]",
+ "3: STMT -> [*]",
+ "COND (EntryPoint.i == 2) -> [THEN=*, ELSE=6]",
+ "STMT -> [*]",
+ "READ(j) -> [*]",
+ "STMT -> [*]",
+ "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=4]",
+ "STMT -> [*]",
+ "WRITE(k, 3) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [5]",
+ "4: STMT -> [*]",
+ "COND (EntryPoint.j == 1) -> [THEN=*, ELSE=5]",
+ "STMT -> [*]",
+ "WRITE(k, 4) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [*]",
+ "5: STMT -> [*]",
+ "GOTO -> [9]",
+ "6: STMT -> [*]",
+ "COND (EntryPoint.i == 3) -> [THEN=*, ELSE=9]",
+ "STMT -> [*]",
+ "READ(j) -> [*]",
+ "STMT -> [*]",
+ "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=7]",
+ "STMT -> [*]",
+ "WRITE(k, 5) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [8]",
+ "7: STMT -> [*]",
+ "COND (EntryPoint.j == 1) -> [THEN=*, ELSE=8]",
+ "STMT -> [*]",
+ "WRITE(k, 6) -> [*]",
+ "STMT -> [*]",
+ "GOTO -> [*]",
+ "8: STMT -> [*]",
+ "GOTO -> [*]",
+ "9: END"
+ );
+ }
public void testSwitchWithLoopAndBreak() throws Exception {
assertCfg("void",
"switch(i) {",