| 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);
|
|
|