CFG: Always jumping to first case statement git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7934 8db76d5a-ed1c-0410-87a9-c151d255dfc7
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 07d9f4f..8be2b1b 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
@@ -606,7 +606,6 @@ @Override public boolean visit(JSwitchStatement x, Context ctx) { pushNode(new CfgStatementNode<JStatement>(parent, x)); - // TODO: Add statement node accept(x.getExpr()); JSwitchStatement oldSwitchStatement = switchStatement; @@ -615,15 +614,26 @@ List<Exit> oldCaseThenExits = removeExits(Exit.Reason.CASE_THEN); List<Exit> oldBreakExits = removeExits(Exit.Reason.BREAK); switchStatement = x; + + // Goto to the first non-default node. + CfgSwitchGotoNode gotoNode = addNode(new CfgSwitchGotoNode(parent, x)); + Exit gotoExit = Exit.createNormal(gotoNode, null); int defaultPos = -1; List<Exit> breakExits = new ArrayList<Exit>(); - for (JStatement s : x.getBody().getStatements()) { + List<JStatement> statements = x.getBody().getStatements(); + + for (JStatement s : statements) { if (s instanceof JCaseStatement) { if (((JCaseStatement) s).getExpr() != null) { // case label + if (gotoExit != null) { + // This is first non-default case. + addExit(gotoExit); + gotoExit = null; + } List<Exit> elseExits = removeExits(Exit.Reason.CASE_ELSE); for (Exit e : elseExits) { addNormalExit(e.getNode(), e.role); @@ -642,6 +652,16 @@ breakExits.addAll(removeExits(Exit.Reason.BREAK)); } + if (gotoExit != null) { + // Happens when there are no case statements. + if (defaultPos >= 0) { + addEdge(gotoExit, nodes.get(defaultPos)); + } else { + addExit(gotoExit); + } + gotoExit = null; + } + List<Exit> thenExits = removeExits(Exit.Reason.CASE_THEN); for (Exit e : thenExits) { addNormalExit(e.getNode(), e.role);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgSwitchGotoNode.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgSwitchGotoNode.java new file mode 100644 index 0000000..a37724d --- /dev/null +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgSwitchGotoNode.java
@@ -0,0 +1,37 @@ +/* + * Copyright 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.google.gwt.dev.jjs.impl.gflow.cfg; + +import com.google.gwt.dev.jjs.ast.JSwitchStatement; + +/** + * Goto to first switch case statement. + */ +public class CfgSwitchGotoNode extends CfgGotoNode<JSwitchStatement> { + public CfgSwitchGotoNode(CfgNode<?> parent, JSwitchStatement node) { + super(parent, node); + } + + @Override + public void accept(CfgVisitor visitor) { + visitor.visitSwitchGotoNode(this); + } + + @Override + protected CfgNode<?> cloneImpl() { + return new CfgSwitchGotoNode(getParent(), getJNode()); + } +}
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgVisitor.java index 8c6287b..6a2aa7e 100644 --- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgVisitor.java +++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgVisitor.java
@@ -105,6 +105,10 @@ visitSimpleNode(node); } + public void visitSwitchGotoNode(CfgSwitchGotoNode node) { + visitGotoNode(node); + } + public void visitThrowNode(CfgThrowNode node) { visitNode(node); }
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 b96c079..82c0b37 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
@@ -1105,6 +1105,7 @@ "BLOCK -> [*]", "STMT -> [*]", "READ(i) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=1]", "STMT -> [*]", @@ -1134,6 +1135,63 @@ ); } + public void testSwitch_FirstDefault() throws Exception { + assertCfg("void", + "switch(i) {", + " default: j = 1; return;", + " case 1: j = 2; return;", + "}" + ).is( + "BLOCK -> [*]", + "STMT -> [*]", + "READ(i) -> [*]", + "GOTO -> [2]", + "1: STMT -> [*]", + "STMT -> [*]", + "WRITE(j, 1) -> [*]", + "STMT -> [*]", + "GOTO -> [3]", + "2: STMT -> [*]", + "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=1]", + "STMT -> [*]", + "WRITE(j, 2) -> [*]", + "STMT -> [*]", + "GOTO -> [*]", + "3: END" + ); + } + + public void testSwitch_Empty() throws Exception { + assertCfg("void", + "switch(i) {", + "}" + ).is( + "BLOCK -> [*]", + "STMT -> [*]", + "READ(i) -> [*]", + "GOTO -> [*]", + "END" + ); + } + + public void testSwitch_OnlyDefault() throws Exception { + assertCfg("void", + "switch(i) {", + " default: j = 0; return;", + "}" + ).is( + "BLOCK -> [*]", + "STMT -> [*]", + "READ(i) -> [*]", + "GOTO -> [*]", + "STMT -> [*]", + "STMT -> [*]", + "WRITE(j, 0) -> [*]", + "STMT -> [*]", + "GOTO -> [*]", + "END" + ); + } public void testNestedSwitch() throws Exception { assertCfg("void", "switch(i) {", @@ -1160,10 +1218,12 @@ "BLOCK -> [*]", "STMT -> [*]", "READ(i) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=3]", "STMT -> [*]", "READ(j) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=1]", "STMT -> [*]", @@ -1182,6 +1242,7 @@ "COND (EntryPoint.i == 2) -> [THEN=*, ELSE=6]", "STMT -> [*]", "READ(j) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=4]", "STMT -> [*]", @@ -1200,6 +1261,7 @@ "COND (EntryPoint.i == 3) -> [THEN=*, ELSE=9]", "STMT -> [*]", "READ(j) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.j == 0) -> [THEN=*, ELSE=7]", "STMT -> [*]", @@ -1231,6 +1293,7 @@ "BLOCK -> [*]", "STMT -> [*]", "READ(i) -> [*]", + "GOTO -> [*]", "STMT -> [*]", "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=1]", "STMT -> [*]",