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

Side by Side Diff: pkg/compiler/lib/src/js/rewrite_async.dart

Issue 926553005: Move the try-catch out of the async-function (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update unit test Created 5 years, 10 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 rewrite_async; 5 library rewrite_async;
6 6
7 // TODO(sigurdm): Move the try/catch expression to a js_helper function.
8 // That would also simplify the sync* case, where the error can just be thrown.
9
10 import "dart:math" show max; 7 import "dart:math" show max;
11 import 'dart:collection'; 8 import 'dart:collection';
12 9
13 import 'package:_internal/compiler/js_lib/shared/async_await_error_codes.dart' 10 import 'package:_internal/compiler/js_lib/shared/async_await_error_codes.dart'
14 as error_codes; 11 as error_codes;
15 12
16 import "js.dart" as js; 13 import "js.dart" as js;
17 14
18 import '../util/util.dart'; 15 import '../util/util.dart';
19 import '../dart2jslib.dart' show DiagnosticListener; 16 import '../dart2jslib.dart' show DiagnosticListener;
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 /// 691 ///
695 /// function (x, y, z) async { 692 /// function (x, y, z) async {
696 /// var p = await foo(); 693 /// var p = await foo();
697 /// return bar(p); 694 /// return bar(p);
698 /// } 695 /// }
699 /// 696 ///
700 /// Becomes (without error handling): 697 /// Becomes (without error handling):
701 /// 698 ///
702 /// function(x, y, z) { 699 /// function(x, y, z) {
703 /// var goto = 0, returnValue, completer = new Completer(), p; 700 /// var goto = 0, returnValue, completer = new Completer(), p;
704 /// function helper(result) { 701 /// function body(result) {
705 /// while (true) { 702 /// while (true) {
706 /// switch (goto) { 703 /// switch (goto) {
707 /// case 0: 704 /// case 0:
708 /// goto = 1 // Remember where to continue when the future succeeds. 705 /// goto = 1 // Remember where to continue when the future succeeds.
709 /// return thenHelper(foo(), helper, completer); 706 /// return thenHelper(foo(), helper, completer);
710 /// case 1: 707 /// case 1:
711 /// p = result; 708 /// p = result;
712 /// returnValue = bar(p); 709 /// returnValue = bar(p);
713 /// goto = 2; 710 /// goto = 2;
714 /// break; 711 /// break;
715 /// case 2: 712 /// case 2:
716 /// return thenHelper(returnValue, null, completer) 713 /// return thenHelper(returnValue, null, completer)
717 /// } 714 /// }
718 /// } 715 /// }
719 /// return thenHelper(null, helper, completer); 716 /// return thenHelper(null, helper, completer);
720 /// } 717 /// }
721 /// } 718 /// }
722 /// 719 ///
723 /// Try/catch is implemented by maintaining [handlerName] to contain the label 720 /// Try/catch is implemented by maintaining [handlerName] to contain the label
724 /// of the current handler. The switch is nested inside a try/catch that will 721 /// of the current handler. If [bodyName] throws, the caller should catch the
725 /// redirect the flow to the current handler. 722 /// error and recall [bodyName] with first argument [error_codes.ERROR] and
723 /// second argument the error.
726 /// 724 ///
727 /// A `finally` clause is compiled similar to normal code, with the additional 725 /// A `finally` clause is compiled similar to normal code, with the additional
728 /// complexity that `finally` clauses need to know where to jump to after the 726 /// complexity that `finally` clauses need to know where to jump to after the
729 /// clause is done. In the translation, each flow-path that enters a `finally` 727 /// clause is done. In the translation, each flow-path that enters a `finally`
730 /// sets up the variable [nextName] with a stack of finally-blocks and a final 728 /// sets up the variable [nextName] with a stack of finally-blocks and a final
731 /// jump-target (exit, catch, ...). 729 /// jump-target (exit, catch, ...).
732 /// 730 ///
733 /// function (x, y, z) async { 731 /// function(x, y, z) async {
734 /// try { 732 /// try {
735 /// try { 733 /// try {
736 /// throw "error"; 734 /// throw "error";
737 /// } finally { 735 /// } finally {
738 /// finalize1(); 736 /// finalize1();
739 /// } 737 /// }
740 /// } catch (e) { 738 /// } catch (e) {
741 /// handle(e); 739 /// handle(e);
742 /// } finally { 740 /// } finally {
743 /// finalize2(); 741 /// finalize2();
744 /// } 742 /// }
745 /// } 743 /// }
746 /// 744 ///
747 /// Translates into (besides the fact that structures not containing 745 /// Translates into (besides the fact that structures not containing
748 /// await/yield/yield* are left intact): 746 /// await/yield/yield* are left intact):
749 /// 747 ///
750 /// function(x, y, z) { 748 /// function(x, y, z) {
751 /// var goto = 0; 749 /// var goto = 0;
752 /// var returnValue; 750 /// var returnValue;
753 /// var completer = new Completer(); 751 /// var completer = new Completer();
754 /// var handler = 8; // Outside try-blocks go to the rethrow label. 752 /// var handler = 8; // Outside try-blocks go to the rethrow label.
755 /// var p; 753 /// var p;
756 /// var storedError; 754 /// var currentError;
757 /// // The result can be either the result of an awaited future, or an 755 /// // The result can be either the result of an awaited future, or an
758 /// // error if the future completed with an error. 756 /// // error if the future completed with an error.
759 /// function helper(errorCode, result) { 757 /// function body(errorCode, result) {
760 /// if (errorCode == 1) { 758 /// if (errorCode == 1) {
761 /// storedError = result; 759 /// currentError = result;
762 /// goto = handler; 760 /// goto = handler;
763 /// } 761 /// }
764 /// while (true) { 762 /// while (true) {
765 /// try { 763 /// switch (goto) {
766 /// switch (goto) { 764 /// case 0:
767 /// case 0: 765 /// handler = 4; // The outer catch-handler
768 /// handler = 4; // The outer catch-handler 766 /// handler = 1; // The inner (implicit) catch-handler
769 /// handler = 1; // The inner (implicit) catch-handler 767 /// throw "error";
770 /// throw "error"; 768 /// next = [3];
771 /// next = [3]; 769 /// // After the finally (2) continue normally after the try.
772 /// // After the finally (2) continue normally after the try. 770 /// goto = 2;
773 /// goto = 2; 771 /// break;
774 /// break; 772 /// case 1: // (implicit) catch handler for inner try.
775 /// case 1: // (implicit) catch handler for inner try. 773 /// next = [3]; // destination after the finally.
776 /// next = [3]; // destination after the finally. 774 /// // fall-though to the finally handler.
777 /// // fall-though to the finally handler. 775 /// case 2: // finally for inner try
778 /// case 2: // finally for inner try 776 /// handler = 4; // catch-handler for outer try.
779 /// handler = 4; // catch-handler for outer try. 777 /// finalize1();
780 /// finalize1(); 778 /// goto = next.pop();
781 /// goto = next.pop(); 779 /// break;
782 /// break; 780 /// case 3: // exiting inner try.
783 /// case 3: // exiting inner try. 781 /// next = [6];
784 /// next = [6]; 782 /// goto = 5; // finally handler for outer try.
785 /// goto = 5; // finally handler for outer try. 783 /// break;
786 /// break; 784 /// case 4: // catch handler for outer try.
787 /// case 4: // catch handler for outer try. 785 /// handler = 5; // If the handler throws, do the finally ..
788 /// handler = 5; // If the handler throws, do the finally .. 786 /// next = [8] // ... and rethrow.
789 /// next = [8] // ... and rethrow. 787 /// e = storedError;
790 /// e = storedError; 788 /// handle(e);
791 /// handle(e); 789 /// // Fall through to finally.
792 /// // Fall through to finally. 790 /// case 5: // finally handler for outer try.
793 /// case 5: // finally handler for outer try. 791 /// handler = null;
794 /// handler = null; 792 /// finalize2();
795 /// finalize2(); 793 /// goto = next.pop();
796 /// goto = next.pop(); 794 /// break;
797 /// break; 795 /// case 6: // Exiting outer try.
798 /// case 6: // Exiting outer try. 796 /// case 7: // return
799 /// case 7: // return 797 /// return thenHelper(returnValue, 0, completer);
800 /// return thenHelper(returnValue, 0, completer); 798 /// case 8: // Rethrow
801 /// case 8: // Rethrow 799 /// return thenHelper(currentError, 1, completer);
802 /// return thenHelper(storedError, 1, completer);
803 /// }
804 /// } catch (error) {
805 /// storedError = error;
806 /// goto = handler;
807 /// } 800 /// }
808 /// } 801 /// }
809 /// return thenHelper(null, helper, completer); 802 /// return thenHelper(null, helper, completer);
810 /// } 803 /// }
811 /// } 804 /// }
812 /// 805 ///
813 @override 806 @override
814 js.Expression visitFun(js.Fun node) { 807 js.Expression visitFun(js.Fun node) {
815 if (isSync) return node; 808 if (isSync) return node;
816 809
(...skipping 11 matching lines...) Expand all
828 addExit(); 821 addExit();
829 822
830 List<js.SwitchClause> clauses = labelledParts.keys.map((label) { 823 List<js.SwitchClause> clauses = labelledParts.keys.map((label) {
831 return new js.Case(js.number(label), new js.Block(labelledParts[label])); 824 return new js.Case(js.number(label), new js.Block(labelledParts[label]));
832 }).toList(); 825 }).toList();
833 js.Statement helperBody = 826 js.Statement helperBody =
834 new js.Switch(new js.VariableUse(gotoName), clauses); 827 new js.Switch(new js.VariableUse(gotoName), clauses);
835 if (hasJumpThoughOuterLabel) { 828 if (hasJumpThoughOuterLabel) {
836 helperBody = new js.LabeledStatement(outerLabelName, helperBody); 829 helperBody = new js.LabeledStatement(outerLabelName, helperBody);
837 } 830 }
838 helperBody = js.js.statement(""" 831
839 try {
840 #body
841 } catch (#error){
842 #currentError = #error;
843 #goto = #handler;
844 }""", {
845 "body": helperBody,
846 "goto": gotoName,
847 "error": errorName,
848 "currentError": currentErrorName,
849 "handler": handlerName,
850 });
851 List<js.VariableInitialization> inits = <js.VariableInitialization>[]; 832 List<js.VariableInitialization> inits = <js.VariableInitialization>[];
852 833
853 js.VariableInitialization makeInit(String name, js.Expression initValue) { 834 js.VariableInitialization makeInit(String name, js.Expression initValue) {
854 return new js.VariableInitialization( 835 return new js.VariableInitialization(
855 new js.VariableDeclaration(name), initValue); 836 new js.VariableDeclaration(name), initValue);
856 } 837 }
857 838
858 inits.add(makeInit(gotoName, js.number(0))); 839 inits.add(makeInit(gotoName, js.number(0)));
859 if (isAsync) { 840 if (isAsync) {
860 inits.add(makeInit(completerName, new js.New(newCompleter, []))); 841 inits.add(makeInit(completerName, new js.New(newCompleter, [])));
861 } else if (isAsyncStar) { 842 } else if (isAsyncStar) {
862 inits.add(makeInit(controllerName, 843 inits.add(makeInit(controllerName,
863 new js.Call(newController, [new js.VariableUse(bodyName)]))); 844 new js.Call(newController, [new js.VariableUse(bodyName)])));
sra1 2015/02/19 20:55:02 new js.Call... -> js('#(#)', [newController, bo
sigurdm 2015/02/23 14:58:37 Done.
864 } 845 }
865 inits.add(makeInit(handlerName, js.number(rethrowLabel))); 846 inits.add(makeInit(handlerName, js.number(rethrowLabel)));
866 inits.add(makeInit(currentErrorName, null)); 847 inits.add(makeInit(currentErrorName, null));
867 if (hasJumpThroughFinally || analysis.hasYield) { 848 if (hasJumpThroughFinally || analysis.hasYield) {
868 inits.add(makeInit(nextName, null)); 849 inits.add(makeInit(nextName, null));
869 } 850 }
870 if (analysis.hasExplicitReturns && isAsync) { 851 if (analysis.hasExplicitReturns && isAsync) {
871 inits.add(makeInit(returnValueName, null)); 852 inits.add(makeInit(returnValueName, null));
872 } 853 }
873 if (isSyncStar) {
874 inits.add(makeInit(resultName, null));
875 }
876 if (analysis.hasThis && !isSyncStar) { 854 if (analysis.hasThis && !isSyncStar) {
877 // Sync* functions must remember `this` on the level of the outer 855 // Sync* functions must remember `this` on the level of the outer
878 // function. 856 // function.
879 inits.add(makeInit(selfName, new js.This())); 857 inits.add(makeInit(selfName, new js.This()));
sra1 2015/02/19 20:55:02 new js.This() --> js('this')
sigurdm 2015/02/23 14:58:37 Done.
880 } 858 }
881 inits.addAll(localVariables.map((js.VariableDeclaration decl) { 859 inits.addAll(localVariables.map((js.VariableDeclaration decl) {
882 return new js.VariableInitialization(decl, null); 860 return new js.VariableInitialization(decl, null);
883 })); 861 }));
884 inits.addAll(new Iterable.generate(tempVarHighWaterMark, 862 inits.addAll(new Iterable.generate(tempVarHighWaterMark,
885 (int i) => makeInit(useTempVar(i + 1).name, null))); 863 (int i) => makeInit(useTempVar(i + 1).name, null)));
886 js.VariableDeclarationList varDecl = new js.VariableDeclarationList(inits); 864 js.VariableDeclarationList varDecl = new js.VariableDeclarationList(inits);
887 // TODO(sigurdm): Explain the difference between these cases. 865 // TODO(sigurdm): Explain the difference between these cases.
888 if (isSyncStar) { 866 if (isSyncStar) {
889 return js.js(""" 867 return js.js("""
890 function (#params) { 868 function (#params) {
891 if (#needsThis) 869 if (#needsThis)
892 var #self = this; 870 var #self = this;
893 return new #newIterable(function () { 871 return new #newIterable(function () {
894 #varDecl; 872 #varDecl;
895 return function #body() { 873 return function #body(#errorCode, #result) {
874 if (#errorCode == #ERROR) {
sra1 2015/02/19 20:55:02 == --> ===
sigurdm 2015/02/23 14:58:37 Done.
875 #currentError = #result;
876 #goto = #handler;
877 }
896 while (true) 878 while (true)
897 #helperBody; 879 #helperBody;
898 }; 880 };
899 }); 881 });
900 } 882 }
901 """, { 883 """, {
902 "params": node.params, 884 "params": node.params,
903 "needsThis": analysis.hasThis, 885 "needsThis": analysis.hasThis,
904 "helperBody": helperBody, 886 "helperBody": helperBody,
905 "varDecl": varDecl, 887 "varDecl": varDecl,
888 "errorCode": errorCodeName,
906 "newIterable": newIterable, 889 "newIterable": newIterable,
907 "body": bodyName, 890 "body": bodyName,
908 "self": selfName, 891 "self": selfName,
892 "result": resultName,
893 "goto": gotoName,
894 "handler": handlerName,
895 "currentError": currentErrorName,
896 "ERROR": js.number(error_codes.ERROR),
909 }); 897 });
910 } 898 }
911 return js.js(""" 899 return js.js("""
912 function (#params) { 900 function (#params) {
913 #varDecl; 901 #varDecl;
914 function #bodyName(#errorCode, #result) { 902 function #bodyName(#errorCode, #result) {
915 if (#hasYield) 903 if (#hasYield)
916 switch (#errorCode) { 904 switch (#errorCode) {
917 case #STREAM_WAS_CANCELED: 905 case #STREAM_WAS_CANCELED:
918 #next = #nextWhenCanceled; 906 #next = #nextWhenCanceled;
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
1111 return withExpression(node.condition, (js.Expression condition) { 1099 return withExpression(node.condition, (js.Expression condition) {
1112 return new js.Conditional(condition, node.then, node.otherwise); 1100 return new js.Conditional(condition, node.then, node.otherwise);
1113 }); 1101 });
1114 } 1102 }
1115 int thenLabel = newLabel("then"); 1103 int thenLabel = newLabel("then");
1116 int joinLabel = newLabel("join"); 1104 int joinLabel = newLabel("join");
1117 int elseLabel = newLabel("else"); 1105 int elseLabel = newLabel("else");
1118 withExpression(node.condition, (js.Expression condition) { 1106 withExpression(node.condition, (js.Expression condition) {
1119 addExpressionStatement(new js.Assignment(new js.VariableUse(gotoName), 1107 addExpressionStatement(new js.Assignment(new js.VariableUse(gotoName),
1120 new js.Conditional( 1108 new js.Conditional(
1121 condition, js.number(thenLabel), js.number(elseLabel)))); 1109 condition, js.number(thenLabel), js.number(elseLabel))));
sra1 2015/02/19 20:55:02 js.statement('# = # ? # : #', gotoName, conditio
sigurdm 2015/02/23 14:58:37 Done.
1122 }, store: false); 1110 }, store: false);
1123 addBreak(); 1111 addBreak();
1124 beginLabel(thenLabel); 1112 beginLabel(thenLabel);
1125 withExpression(node.then, (js.Expression value) { 1113 withExpression(node.then, (js.Expression value) {
1126 if (!isResult(value)) { 1114 if (!isResult(value)) {
1127 addExpressionStatement( 1115 addExpressionStatement(
1128 new js.Assignment(new js.VariableUse(resultName), value)); 1116 new js.Assignment(new js.VariableUse(resultName), value));
1129 } 1117 }
1130 }, store: false); 1118 }, store: false);
1131 addGoto(joinLabel); 1119 addGoto(joinLabel);
(...skipping 1175 matching lines...) Expand 10 before | Expand all | Expand 10 after
2307 return condition || body; 2295 return condition || body;
2308 } 2296 }
2309 2297
2310 @override 2298 @override
2311 bool visitDartYield(js.DartYield node) { 2299 bool visitDartYield(js.DartYield node) {
2312 hasYield = true; 2300 hasYield = true;
2313 visit(node.expression); 2301 visit(node.expression);
2314 return true; 2302 return true;
2315 } 2303 }
2316 } 2304 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/js_lib/js_helper.dart » ('j') | sdk/lib/_internal/compiler/js_lib/js_helper.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698