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

Unified Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 1232083002: dart2js cps: Emit unlabeled breaks and continues when possible. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update test Created 5 years, 5 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 | tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/js_backend/codegen/codegen.dart
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 31d030ff622970a9e12718834346d86cb264e5ff..2a4480e135dbdf4d73467d417e313f8e611b956d 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -48,6 +48,12 @@ class CodeGenerator extends tree_ir.StatementVisitor
final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
+ /// Stacks whose top element is the current target of an unlabeled break
+ /// or continue. For continues, this is the loop node itself.
+ final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack();
+ final tree_ir.FallthroughStack shortContinue =
+ new tree_ir.FallthroughStack();
+
Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
List<js.Statement> accumulator = new List<js.Statement>();
@@ -390,27 +396,36 @@ class CodeGenerator extends tree_ir.StatementVisitor
@override
void visitContinue(tree_ir.Continue node) {
tree_ir.Statement next = fallthrough.target;
- if (node.target.binding == next) {
- // Fall through to continue target
- fallthrough.use();
- } else if (next is tree_ir.Continue && next.target == node.target) {
- // Fall through to equivalent continue
+ if (node.target.binding == next ||
+ next is tree_ir.Continue && node.target == next.target) {
+ // Fall through to continue target or to equivalent continue.
fallthrough.use();
+ } else if (node.target.binding == shortContinue.target) {
+ // The target is the immediately enclosing loop.
+ shortContinue.use();
+ accumulator.add(new js.Continue(null));
} else {
usedLabels.add(node.target);
accumulator.add(new js.Continue(node.target.name));
}
}
+ /// True if [other] is the target of [node] or is a [Break] with the same
+ /// target. This means jumping to [other] is equivalent to executing [node].
+ bool isEffectiveBreakTarget(tree_ir.Break node, tree_ir.Statement other) {
+ return node.target.binding.next == other ||
+ other is tree_ir.Break && node.target == other.target;
+ }
+
@override
void visitBreak(tree_ir.Break node) {
- tree_ir.Statement next = fallthrough.target;
- if (node.target.binding.next == next) {
- // Fall through to break target
- fallthrough.use();
- } else if (next is tree_ir.Break && next.target == node.target) {
- // Fall through to equivalent break
+ if (isEffectiveBreakTarget(node, fallthrough.target)) {
+ // Fall through to break target or to equivalent break.
fallthrough.use();
+ } else if (isEffectiveBreakTarget(node, shortBreak.target)) {
+ // Unlabeled break to the break target or to an equivalent break.
+ shortBreak.use();
+ accumulator.add(new js.Break(null));
} else {
usedLabels.add(node.target);
accumulator.add(new js.Break(node.target.name));
@@ -443,22 +458,20 @@ class CodeGenerator extends tree_ir.StatementVisitor
@override
void visitLabeledStatement(tree_ir.LabeledStatement node) {
- accumulator.add(buildLabeled(() => buildBodyStatement(node.body),
- node.label,
- node.next));
+ fallthrough.push(node.next);
+ js.Statement body = buildBodyStatement(node.body);
+ fallthrough.pop();
+ accumulator.add(insertLabel(node.label, body));
visitStatement(node.next);
}
- js.Statement buildLabeled(js.Statement buildBody(),
- tree_ir.Label label,
- tree_ir.Statement fallthroughStatement) {
- fallthrough.push(fallthroughStatement);
- js.Statement result = buildBody();
+ /// Wraps a node in a labeled statement unless the label is unused.
+ js.Statement insertLabel(tree_ir.Label label, js.Statement node) {
if (usedLabels.remove(label)) {
- result = new js.LabeledStatement(label.name, result);
+ return new js.LabeledStatement(label.name, node);
+ } else {
+ return node;
}
- fallthrough.pop();
- return result;
}
/// Returns the current [accumulator] wrapped in a block if neccessary.
@@ -491,29 +504,36 @@ class CodeGenerator extends tree_ir.StatementVisitor
return result;
}
- js.Statement buildWhile(js.Expression condition,
- tree_ir.Statement body,
- tree_ir.Label label,
- tree_ir.Statement fallthroughStatement) {
- return buildLabeled(() => new js.While(condition, buildBodyStatement(body)),
- label,
- fallthroughStatement);
- }
-
@override
void visitWhileCondition(tree_ir.WhileCondition node) {
- accumulator.add(
- buildWhile(visitExpression(node.condition),
- node.body,
- node.label,
- node));
+ js.Expression condition = visitExpression(node.condition);
+ shortBreak.push(node.next);
+ shortContinue.push(node);
+ fallthrough.push(node);
+ js.Statement jsBody = buildBodyStatement(node.body);
+ fallthrough.pop();
+ shortContinue.pop();
+ shortBreak.pop();
+ accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
visitStatement(node.next);
}
@override
void visitWhileTrue(tree_ir.WhileTrue node) {
- accumulator.add(
- buildWhile(new js.LiteralBool(true), node.body, node.label, node));
+ js.Expression condition = new js.LiteralBool(true);
+ // A short break in the while will jump to the current fallthrough target.
+ shortBreak.push(fallthrough.target);
+ shortContinue.push(node);
+ fallthrough.push(node);
+ js.Statement jsBody = buildBodyStatement(node.body);
+ fallthrough.pop();
+ shortContinue.pop();
+ if (shortBreak.useCount > 0) {
+ // Short breaks use the current fallthrough target.
+ fallthrough.use();
+ }
+ shortBreak.pop();
+ accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
}
bool isNull(tree_ir.Expression node) {
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_backend_cps_ir_control_flow_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698