Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Unified Diff: lib/compiler/implementation/ssa/builder.dart

Issue 10544024: Implement constant switch as JS switch. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments. Added to Tracer. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/ssa/builder.dart
diff --git a/lib/compiler/implementation/ssa/builder.dart b/lib/compiler/implementation/ssa/builder.dart
index 3675c3807a66c8d2a433d51f3ba34e3b0fcf6bf6..1f18b7cb03240de0922772074dfe335a7caeecaa 100644
--- a/lib/compiler/implementation/ssa/builder.dart
+++ b/lib/compiler/implementation/ssa/builder.dart
@@ -2921,6 +2921,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
}
visitSwitchStatement(SwitchStatement node) {
+ if (tryBuildConstantSwitch(node)) return;
+
LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
HBasicBlock startBlock = openNewBlock();
visit(node.expression);
@@ -2928,8 +2930,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
if (node.cases.isEmpty()) {
return;
}
- Link<Node> cases = node.cases.nodes;
+ Link<Node> cases = node.cases.nodes;
JumpHandler jumpHandler = createJumpHandler(node);
buildSwitchCases(cases, expression);
@@ -2970,10 +2972,141 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
jumpHandler.close();
}
+ bool tryBuildConstantSwitch(SwitchStatement node) {
+ Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>();
+ // First check whether all case expressions are compile-time constants.
+ for (SwitchCase switchCase in node.cases) {
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ if (labelOrCase is CaseMatch) {
+ CaseMatch match = labelOrCase;
+ Constant constant =
+ compiler.constantHandler.tryCompileNodeWithDefinitions(
+ match.expression, elements);
+ if (constant === null) return false;
+ constants[labelOrCase] = constant;
+ } else {
+ // We don't handle labels yet.
+ return false;
+ }
+ }
+ }
+ // TODO(ngeoffray): Handle switch-instruction in bailout code.
+ work.allowSpeculativeOptimization = false;
+ // Then build a switch structure.
+ HBasicBlock expressionStart = openNewBlock();
+ visit(node.expression);
+ HInstruction expression = pop();
+ if (node.cases.isEmpty()) {
+ return true;
+ }
+ HBasicBlock expressionEnd = current;
+
+ HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]);
+ HBasicBlock expressionBlock = close(switchInstruction);
+ JumpHandler jumpHandler = createJumpHandler(node);
+ LocalsHandler savedLocals = localsHandler;
+
+ List<List<Constant>> matchExpressions = <List<Constant>>[];
+ List<HStatementInformation> statements = <HStatementInformation>[];
+ bool hasDefault = false;
+ Element getFallThroughErrorElement =
+ compiler.findHelper(const SourceString("getFallThroughError"));
+ Iterator<Node> caseIterator = node.cases.iterator();
+ while (caseIterator.hasNext()) {
+ SwitchCase switchCase = caseIterator.next();
+ List<Constant> caseConstants = <Constant>[];
+ HBasicBlock block = graph.addNewBlock();
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ if (labelOrCase is CaseMatch) {
+ Constant constant = constants[labelOrCase];
+ caseConstants.add(constant);
+ HConstant hConstant = graph.addConstant(constant);
+ switchInstruction.inputs.add(hConstant);
+ hConstant.usedBy.add(switchInstruction);
+ expressionBlock.addSuccessor(block);
+ }
+ }
+ matchExpressions.add(caseConstants);
+
+ if (switchCase.isDefaultCase) {
+ // An HSwitch has n inputs and n+1 successors, the last being the
+ // default case.
+ expressionBlock.addSuccessor(block);
+ hasDefault = true;
+ }
+ open(block);
+ localsHandler = new LocalsHandler.from(savedLocals);
+ visit(switchCase.statements);
+ if (!isAborted() && caseIterator.hasNext()) {
+ push(new HStatic(getFallThroughErrorElement));
+ HInstruction error = new HInvokeStatic(
+ Selector.INVOCATION_0, <HInstruction>[pop()]);
+ add(error);
+ close(new HThrow(error));
+ }
+ statements.add(
+ new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock)));
+ }
+
+ // Add a join-block if necessary.
+ // We create [joinBlock] early, and then go through the cases that might
+ // want to jump to it. In each case, if we add [joinBlock] as a successor
+ // of another block, we also add an element to [caseLocals] that is used
+ // to create the phis in [joinBlock].
+ // If we never jump to the join block, [caseLocals] will stay empty, and
+ // the join block is never added to the graph.
+ HBasicBlock joinBlock = new HBasicBlock();
+ List<LocalsHandler> caseLocals = <LocalsHandler>[];
+ jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
+ instruction.block.addSuccessor(joinBlock);
+ caseLocals.add(locals);
+ });
+ if (!isAborted()) {
+ current.close(new HGoto());
+ lastOpenedBlock.addSuccessor(joinBlock);
+ caseLocals.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);
+ caseLocals.add(savedLocals);
+ }
+ assert(caseLocals.length == joinBlock.predecessors.length);
+ if (caseLocals.length != 0) {
+ graph.addBlock(joinBlock);
+ open(joinBlock);
+ if (caseLocals.length == 1) {
+ localsHandler = caseLocals[0];
+ } else {
+ localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock);
+ }
+ } else {
+ // The joinblock is not used.
+ joinBlock = null;
+ }
+
+ HSubExpressionBlockInformation expressionInfo =
+ new HSubExpressionBlockInformation(new SubExpression(expressionStart,
+ expressionEnd));
+ expressionStart.setBlockFlow(
+ new HSwitchBlockInformation(expressionInfo,
+ matchExpressions,
+ statements,
+ hasDefault,
+ jumpHandler.target,
+ jumpHandler.labels()),
+ joinBlock);
+
+ jumpHandler.close();
+ return true;
+ }
+
// Recursively build an if/else structure to match the cases.
- buildSwitchCases(Link<Node> cases, HInstruction expression,
- [int encounteredCaseTypes = 0]) {
+ void buildSwitchCases(Link<Node> cases, HInstruction expression,
+ [int encounteredCaseTypes = 0]) {
final int NO_TYPE = 0;
final int INT_TYPE = 1;
final int STRING_TYPE = 2;
« no previous file with comments | « no previous file | lib/compiler/implementation/ssa/codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698