| 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 487eb4508fd26b79eba8879da264ec83b0baac8f..8bb26fd773bd3439b8db3e8c9a99466e54209db6 100644
|
| --- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
|
| +++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
|
| @@ -68,6 +68,18 @@ class CodeGenerator extends tree_ir.StatementVisitor
|
| final tree_ir.FallthroughStack shortContinue =
|
| new tree_ir.FallthroughStack();
|
|
|
| + /// When the top element is true, [Unreachable] statements will be emitted
|
| + /// as [Return]s, otherwise they are emitted as empty because they are
|
| + /// followed by the end of the method.
|
| + ///
|
| + /// Note on why the [fallthrough] stack should not be used for this:
|
| + /// Ordinary statements may choose whether to use the [fallthrough] target,
|
| + /// and the choice to do so may disable an optimization in [visitIf].
|
| + /// But omitting an unreachable 'return' should have lower priority than
|
| + /// the optimizations in [visitIf], so [visitIf] will instead tell the
|
| + /// [Unreachable] statements whether they may use fallthrough or not.
|
| + List<bool> emitUnreachableAsReturn = <bool>[false];
|
| +
|
| Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
|
|
|
| List<js.Statement> accumulator = new List<js.Statement>();
|
| @@ -534,16 +546,34 @@ class CodeGenerator extends tree_ir.StatementVisitor
|
|
|
| @override
|
| void visitExpressionStatement(tree_ir.ExpressionStatement node) {
|
| - accumulator.add(new js.ExpressionStatement(
|
| - visitExpression(node.expression)));
|
| - visitStatement(node.next);
|
| + js.Expression exp = visitExpression(node.expression);
|
| + if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
|
| + // Emit as 'return exp' to assist local analysis in the VM.
|
| + accumulator.add(new js.Return(exp));
|
| + } else {
|
| + accumulator.add(new js.ExpressionStatement(exp));
|
| + visitStatement(node.next);
|
| + }
|
| + }
|
| +
|
| + bool isNullReturn(tree_ir.Statement node) {
|
| + return node is tree_ir.Return && isNull(node.value);
|
| + }
|
| +
|
| + bool isEndOfMethod(tree_ir.Statement node) {
|
| + return isNullReturn(node) ||
|
| + node is tree_ir.Break && isNullReturn(node.target.binding.next);
|
| }
|
|
|
| @override
|
| void visitIf(tree_ir.If node) {
|
| js.Expression condition = visitExpression(node.condition);
|
| int usesBefore = fallthrough.useCount;
|
| + // Unless the 'else' part ends the method. make sure to terminate any
|
| + // uncompletable code paths in the 'then' part.
|
| + emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
|
| js.Statement thenBody = buildBodyStatement(node.thenStatement);
|
| + emitUnreachableAsReturn.removeLast();
|
| bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
|
| if (thenHasFallthrough) {
|
| js.Statement elseBody = buildBodyStatement(node.elseStatement);
|
| @@ -614,7 +644,9 @@ class CodeGenerator extends tree_ir.StatementVisitor
|
| shortBreak.push(node.next);
|
| shortContinue.push(node);
|
| fallthrough.push(node);
|
| + emitUnreachableAsReturn.add(true);
|
| js.Statement body = buildBodyStatement(node.body);
|
| + emitUnreachableAsReturn.removeLast();
|
| fallthrough.pop();
|
| shortContinue.pop();
|
| shortBreak.pop();
|
| @@ -644,7 +676,9 @@ class CodeGenerator extends tree_ir.StatementVisitor
|
| shortBreak.push(fallthrough.target);
|
| shortContinue.push(node);
|
| fallthrough.push(node);
|
| + emitUnreachableAsReturn.add(true);
|
| js.Statement jsBody = buildBodyStatement(node.body);
|
| + emitUnreachableAsReturn.removeLast();
|
| fallthrough.pop();
|
| shortContinue.pop();
|
| if (shortBreak.useCount > 0) {
|
| @@ -683,8 +717,10 @@ class CodeGenerator extends tree_ir.StatementVisitor
|
|
|
| @override
|
| void visitUnreachable(tree_ir.Unreachable node) {
|
| - // Output nothing.
|
| - // TODO(asgerf): Emit a throw/return to assist local analysis in the VM?
|
| + if (emitUnreachableAsReturn.last) {
|
| + // Emit a return to assist local analysis in the VM.
|
| + accumulator.add(new js.Return());
|
| + }
|
| }
|
|
|
| @override
|
|
|