Index: sdk/lib/_internal/compiler/implementation/ssa/builder.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/ssa/builder.dart (revision 26117) |
+++ sdk/lib/_internal/compiler/implementation/ssa/builder.dart (working copy) |
@@ -4670,16 +4670,14 @@ |
// TODO(ngeoffray): Handle switch-instruction in bailout code. |
work.allowSpeculativeOptimization = false; |
- // Then build a switch structure. |
HBasicBlock expressionStart = openNewBlock(); |
HInstruction expression = buildExpression(); |
if (switchCases.isEmpty) { |
return; |
} |
- HBasicBlock expressionEnd = current; |
HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); |
- HBasicBlock expressionBlock = close(switchInstruction); |
+ HBasicBlock expressionEnd = close(switchInstruction); |
LocalsHandler savedLocals = localsHandler; |
List<List<Constant>> matchExpressions = <List<Constant>>[]; |
@@ -4697,23 +4695,30 @@ |
HConstant hConstant = graph.addConstant(constant, compiler); |
switchInstruction.inputs.add(hConstant); |
hConstant.usedBy.add(switchInstruction); |
- expressionBlock.addSuccessor(block); |
+ expressionEnd.addSuccessor(block); |
} |
matchExpressions.add(caseConstants); |
if (isDefaultCase(switchCase)) { |
// An HSwitch has n inputs and n+1 successors, the last being the |
// default case. |
- expressionBlock.addSuccessor(block); |
+ expressionEnd.addSuccessor(block); |
hasDefault = true; |
} |
open(block); |
localsHandler = new LocalsHandler.from(savedLocals); |
buildSwitchCase(switchCase); |
- if (!isAborted() && caseIterator.hasNext) { |
- pushInvokeStatic(switchCase, getFallThroughErrorElement, []); |
- HInstruction error = pop(); |
- closeAndGotoExit(new HThrow(error)); |
+ if (!isAborted()) { |
+ if (caseIterator.hasNext) { |
+ pushInvokeStatic(switchCase, getFallThroughErrorElement, []); |
+ HInstruction error = pop(); |
+ closeAndGotoExit(new HThrow(error)); |
+ } else if (!isDefaultCase(switchCase)) { |
+ // If there is no default, we will add one later to avoid |
+ // the critical edge. So we generate a break statement to make |
+ // sure the last case does not fall through to the default case. |
+ jumpHandler.generateBreak(); |
+ } |
} |
statements.add( |
new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); |
@@ -4742,11 +4747,17 @@ |
caseHandlers.add(localsHandler); |
} |
if (!hasDefault) { |
- // The current flow is only aborted if the switch has a default that |
- // aborts (all previous cases must abort, and if there is no default, |
- // it's possible to miss all the cases). |
- expressionEnd.addSuccessor(joinBlock); |
+ // Always create a default case, to avoid a critical edge in the |
+ // graph. |
+ HBasicBlock defaultCase = addNewBlock(); |
+ expressionEnd.addSuccessor(defaultCase); |
+ open(defaultCase); |
+ close(new HGoto()); |
+ defaultCase.addSuccessor(joinBlock); |
caseHandlers.add(savedLocals); |
+ matchExpressions.add(<Constant>[]); |
+ statements.add(new HSubGraphBlockInformation(new SubGraph( |
+ defaultCase, defaultCase))); |
} |
assert(caseHandlers.length == joinBlock.predecessors.length); |
if (caseHandlers.length != 0) { |
@@ -4769,7 +4780,6 @@ |
new HSwitchBlockInformation(expressionInfo, |
matchExpressions, |
statements, |
- hasDefault, |
jumpHandler.target, |
jumpHandler.labels()), |
joinBlock); |