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

Side by Side Diff: pkg/compiler/lib/src/js_backend/codegen/codegen.dart

Issue 1476293003: dart2js cps: Emit 'return' after throwing call to assist VM analysis. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Update test case expected output Created 5 years 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 unified diff | Download patch
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library code_generator; 5 library code_generator;
6 6
7 import 'glue.dart'; 7 import 'glue.dart';
8 8
9 import '../../closure.dart' show 9 import '../../closure.dart' show
10 ClosureClassElement; 10 ClosureClassElement;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 Set<String> usedVariableNames = new Set<String>(); 61 Set<String> usedVariableNames = new Set<String>();
62 62
63 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack(); 63 final tree_ir.FallthroughStack fallthrough = new tree_ir.FallthroughStack();
64 64
65 /// Stacks whose top element is the current target of an unlabeled break 65 /// Stacks whose top element is the current target of an unlabeled break
66 /// or continue. For continues, this is the loop node itself. 66 /// or continue. For continues, this is the loop node itself.
67 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack(); 67 final tree_ir.FallthroughStack shortBreak = new tree_ir.FallthroughStack();
68 final tree_ir.FallthroughStack shortContinue = 68 final tree_ir.FallthroughStack shortContinue =
69 new tree_ir.FallthroughStack(); 69 new tree_ir.FallthroughStack();
70 70
71 /// When the top element is true, [Unreachable] statements will be emitted
72 /// as [Return]s, otherwise they are emitted as empty because they are
73 /// followed by the end of the method.
74 ///
75 /// Note on why the [fallthrough] stack should not be used for this:
76 /// Ordinary statements may choose whether to use the [fallthrough] target,
77 /// and the choice to do so may disable an optimization in [visitIf].
78 /// But omitting an unreachable 'return' should have lower priority than
79 /// the optimizations in [visitIf], so [visitIf] will instead tell the
80 /// [Unreachable] statements whether they may use fallthrough or not.
81 List<bool> emitUnreachableAsReturn = <bool>[false];
82
71 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>(); 83 Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
72 84
73 List<js.Statement> accumulator = new List<js.Statement>(); 85 List<js.Statement> accumulator = new List<js.Statement>();
74 86
75 CodeGenerator(this.glue, this.registry); 87 CodeGenerator(this.glue, this.registry);
76 88
77 /// Generates JavaScript code for the body of [function]. 89 /// Generates JavaScript code for the body of [function].
78 js.Fun buildFunction(tree_ir.FunctionDefinition function) { 90 js.Fun buildFunction(tree_ir.FunctionDefinition function) {
79 registerDefaultParameterValues(function.element); 91 registerDefaultParameterValues(function.element);
80 currentFunction = function.element; 92 currentFunction = function.element;
(...skipping 446 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 shortContinue.use(); 539 shortContinue.use();
528 accumulator.add(new js.Continue(null)); 540 accumulator.add(new js.Continue(null));
529 } else { 541 } else {
530 usedLabels.add(node.target); 542 usedLabels.add(node.target);
531 accumulator.add(new js.Break(node.target.name)); 543 accumulator.add(new js.Break(node.target.name));
532 } 544 }
533 } 545 }
534 546
535 @override 547 @override
536 void visitExpressionStatement(tree_ir.ExpressionStatement node) { 548 void visitExpressionStatement(tree_ir.ExpressionStatement node) {
537 accumulator.add(new js.ExpressionStatement( 549 js.Expression exp = visitExpression(node.expression);
538 visitExpression(node.expression))); 550 if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
539 visitStatement(node.next); 551 // Emit as 'return exp' to assist local analysis in the VM.
552 accumulator.add(new js.Return(exp));
553 } else {
554 accumulator.add(new js.ExpressionStatement(exp));
555 visitStatement(node.next);
556 }
557 }
558
559 bool isNullReturn(tree_ir.Statement node) {
560 return node is tree_ir.Return && isNull(node.value);
561 }
562
563 bool isEndOfMethod(tree_ir.Statement node) {
564 return isNullReturn(node) ||
565 node is tree_ir.Break && isNullReturn(node.target.binding.next);
540 } 566 }
541 567
542 @override 568 @override
543 void visitIf(tree_ir.If node) { 569 void visitIf(tree_ir.If node) {
544 js.Expression condition = visitExpression(node.condition); 570 js.Expression condition = visitExpression(node.condition);
545 int usesBefore = fallthrough.useCount; 571 int usesBefore = fallthrough.useCount;
572 // Unless the 'else' part ends the method. make sure to terminate any
573 // uncompletable code paths in the 'then' part.
574 emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
546 js.Statement thenBody = buildBodyStatement(node.thenStatement); 575 js.Statement thenBody = buildBodyStatement(node.thenStatement);
576 emitUnreachableAsReturn.removeLast();
547 bool thenHasFallthrough = (fallthrough.useCount > usesBefore); 577 bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
548 if (thenHasFallthrough) { 578 if (thenHasFallthrough) {
549 js.Statement elseBody = buildBodyStatement(node.elseStatement); 579 js.Statement elseBody = buildBodyStatement(node.elseStatement);
550 accumulator.add(new js.If(condition, thenBody, elseBody)); 580 accumulator.add(new js.If(condition, thenBody, elseBody));
551 } else { 581 } else {
552 // The 'then' body cannot complete normally, so emit a short 'if' 582 // The 'then' body cannot complete normally, so emit a short 'if'
553 // and put the 'else' body after it. 583 // and put the 'else' body after it.
554 accumulator.add(new js.If.noElse(condition, thenBody)); 584 accumulator.add(new js.If.noElse(condition, thenBody));
555 visitStatement(node.elseStatement); 585 visitStatement(node.elseStatement);
556 } 586 }
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 js.Expression makeSequence(List<tree_ir.Expression> list) { 637 js.Expression makeSequence(List<tree_ir.Expression> list) {
608 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y)); 638 return list.map(visitExpression).reduce((x,y) => new js.Binary(',', x, y));
609 } 639 }
610 640
611 @override 641 @override
612 void visitFor(tree_ir.For node) { 642 void visitFor(tree_ir.For node) {
613 js.Expression condition = visitExpression(node.condition); 643 js.Expression condition = visitExpression(node.condition);
614 shortBreak.push(node.next); 644 shortBreak.push(node.next);
615 shortContinue.push(node); 645 shortContinue.push(node);
616 fallthrough.push(node); 646 fallthrough.push(node);
647 emitUnreachableAsReturn.add(true);
617 js.Statement body = buildBodyStatement(node.body); 648 js.Statement body = buildBodyStatement(node.body);
649 emitUnreachableAsReturn.removeLast();
618 fallthrough.pop(); 650 fallthrough.pop();
619 shortContinue.pop(); 651 shortContinue.pop();
620 shortBreak.pop(); 652 shortBreak.pop();
621 js.Statement loopNode; 653 js.Statement loopNode;
622 if (node.updates.isEmpty) { 654 if (node.updates.isEmpty) {
623 loopNode = new js.While(condition, body); 655 loopNode = new js.While(condition, body);
624 } else { // Compile as a for loop. 656 } else { // Compile as a for loop.
625 js.Expression init; 657 js.Expression init;
626 if (accumulator.isNotEmpty && 658 if (accumulator.isNotEmpty &&
627 accumulator.last is js.ExpressionStatement) { 659 accumulator.last is js.ExpressionStatement) {
628 // Take the preceding expression from the accumulator and use 660 // Take the preceding expression from the accumulator and use
629 // it as the initializer expression. 661 // it as the initializer expression.
630 js.ExpressionStatement initStmt = accumulator.removeLast(); 662 js.ExpressionStatement initStmt = accumulator.removeLast();
631 init = initStmt.expression; 663 init = initStmt.expression;
632 } 664 }
633 js.Expression update = makeSequence(node.updates); 665 js.Expression update = makeSequence(node.updates);
634 loopNode = new js.For(init, condition, update, body); 666 loopNode = new js.For(init, condition, update, body);
635 } 667 }
636 accumulator.add(insertLabel(node.label, loopNode)); 668 accumulator.add(insertLabel(node.label, loopNode));
637 visitStatement(node.next); 669 visitStatement(node.next);
638 } 670 }
639 671
640 @override 672 @override
641 void visitWhileTrue(tree_ir.WhileTrue node) { 673 void visitWhileTrue(tree_ir.WhileTrue node) {
642 js.Expression condition = new js.LiteralBool(true); 674 js.Expression condition = new js.LiteralBool(true);
643 // A short break in the while will jump to the current fallthrough target. 675 // A short break in the while will jump to the current fallthrough target.
644 shortBreak.push(fallthrough.target); 676 shortBreak.push(fallthrough.target);
645 shortContinue.push(node); 677 shortContinue.push(node);
646 fallthrough.push(node); 678 fallthrough.push(node);
679 emitUnreachableAsReturn.add(true);
647 js.Statement jsBody = buildBodyStatement(node.body); 680 js.Statement jsBody = buildBodyStatement(node.body);
681 emitUnreachableAsReturn.removeLast();
648 fallthrough.pop(); 682 fallthrough.pop();
649 shortContinue.pop(); 683 shortContinue.pop();
650 if (shortBreak.useCount > 0) { 684 if (shortBreak.useCount > 0) {
651 // Short breaks use the current fallthrough target. 685 // Short breaks use the current fallthrough target.
652 fallthrough.use(); 686 fallthrough.use();
653 } 687 }
654 shortBreak.pop(); 688 shortBreak.pop();
655 accumulator.add(insertLabel(node.label, new js.While(condition, jsBody))); 689 accumulator.add(insertLabel(node.label, new js.While(condition, jsBody)));
656 } 690 }
657 691
(...skipping 18 matching lines...) Expand all
676 accumulator.add(new js.Throw(visitExpression(node.value))); 710 accumulator.add(new js.Throw(visitExpression(node.value)));
677 } 711 }
678 712
679 @override 713 @override
680 void visitRethrow(tree_ir.Rethrow node) { 714 void visitRethrow(tree_ir.Rethrow node) {
681 glue.reportInternalError('rethrow seen in JavaScript output'); 715 glue.reportInternalError('rethrow seen in JavaScript output');
682 } 716 }
683 717
684 @override 718 @override
685 void visitUnreachable(tree_ir.Unreachable node) { 719 void visitUnreachable(tree_ir.Unreachable node) {
686 // Output nothing. 720 if (emitUnreachableAsReturn.last) {
687 // TODO(asgerf): Emit a throw/return to assist local analysis in the VM? 721 // Emit a return to assist local analysis in the VM.
722 accumulator.add(new js.Return());
723 }
688 } 724 }
689 725
690 @override 726 @override
691 void visitTry(tree_ir.Try node) { 727 void visitTry(tree_ir.Try node) {
692 js.Block tryBlock = buildBodyBlock(node.tryBody); 728 js.Block tryBlock = buildBodyBlock(node.tryBody);
693 tree_ir.Variable exceptionVariable = node.catchParameters.first; 729 tree_ir.Variable exceptionVariable = node.catchParameters.first;
694 js.VariableDeclaration exceptionParameter = 730 js.VariableDeclaration exceptionParameter =
695 new js.VariableDeclaration(getVariableName(exceptionVariable)); 731 new js.VariableDeclaration(getVariableName(exceptionVariable));
696 js.Block catchBlock = buildBodyBlock(node.catchBody); 732 js.Block catchBlock = buildBodyBlock(node.catchBody);
697 js.Catch catchPart = new js.Catch(exceptionParameter, catchBlock); 733 js.Catch catchPart = new js.Catch(exceptionParameter, catchBlock);
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after
1086 void registerDefaultParameterValues(ExecutableElement element) { 1122 void registerDefaultParameterValues(ExecutableElement element) {
1087 if (element is! FunctionElement) return; 1123 if (element is! FunctionElement) return;
1088 FunctionElement function = element; 1124 FunctionElement function = element;
1089 if (function.isStatic) return; // Defaults are inlined at call sites. 1125 if (function.isStatic) return; // Defaults are inlined at call sites.
1090 function.functionSignature.forEachOptionalParameter((param) { 1126 function.functionSignature.forEachOptionalParameter((param) {
1091 ConstantValue constant = glue.getDefaultParameterValue(param); 1127 ConstantValue constant = glue.getDefaultParameterValue(param);
1092 registry.registerCompileTimeConstant(constant); 1128 registry.registerCompileTimeConstant(constant);
1093 }); 1129 });
1094 } 1130 }
1095 } 1131 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698