| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 kernel.transformations.continuation; | 5 library kernel.transformations.continuation; |
| 6 | 6 |
| 7 import 'dart:math' as math; | 7 import 'dart:math' as math; |
| 8 | 8 |
| 9 import '../ast.dart'; | 9 import '../ast.dart'; |
| 10 import '../core_types.dart'; |
| 10 import '../visitor.dart'; | 11 import '../visitor.dart'; |
| 11 | 12 |
| 12 import 'async.dart'; | 13 import 'async.dart'; |
| 13 | 14 |
| 14 Program transformProgram(Program program) { | 15 Program transformProgram(Program program) { |
| 15 var helper = new HelperNodes.fromProgram(program); | 16 var helper = new HelperNodes.fromProgram(program); |
| 16 var rewriter = new RecursiveContinuationRewriter(helper); | 17 var rewriter = new RecursiveContinuationRewriter(helper); |
| 17 return rewriter.rewriteProgram(program); | 18 return rewriter.rewriteProgram(program); |
| 18 } | 19 } |
| 19 | 20 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 new VariableDeclaration(":stack_trace${depth}"), | 106 new VariableDeclaration(":stack_trace${depth}"), |
| 106 ]); | 107 ]); |
| 107 | 108 |
| 108 List<VariableDeclaration> variableDeclarations() => | 109 List<VariableDeclaration> variableDeclarations() => |
| 109 [asyncJumpVariable, asyncContextVariable] | 110 [asyncJumpVariable, asyncContextVariable] |
| 110 ..addAll(createCapturedTryVariables()) | 111 ..addAll(createCapturedTryVariables()) |
| 111 ..addAll(createCapturedCatchVariables()); | 112 ..addAll(createCapturedCatchVariables()); |
| 112 } | 113 } |
| 113 | 114 |
| 114 class SyncStarFunctionRewriter extends ContinuationRewriterBase { | 115 class SyncStarFunctionRewriter extends ContinuationRewriterBase { |
| 115 final VariableDeclaration iteratorVariable = | 116 final VariableDeclaration iteratorVariable; |
| 116 new VariableDeclaration(":iterator"); | |
| 117 | 117 |
| 118 SyncStarFunctionRewriter(helper, enclosingFunction) | 118 SyncStarFunctionRewriter(helper, enclosingFunction) |
| 119 : super(helper, enclosingFunction); | 119 : iteratorVariable = new VariableDeclaration(':iterator') |
| 120 ..type = helper.iteratorClass.rawType, |
| 121 super(helper, enclosingFunction); |
| 120 | 122 |
| 121 FunctionNode rewrite() { | 123 FunctionNode rewrite() { |
| 122 // :sync_body(:iterator) { | 124 // :sync_body(:iterator) { |
| 123 // modified <node.body>; | 125 // modified <node.body>; |
| 124 // } | 126 // } |
| 125 final nestedClosureVariable = new VariableDeclaration(":sync_op"); | 127 final nestedClosureVariable = new VariableDeclaration(":sync_op"); |
| 126 final function = new FunctionNode(buildClosureBody(), | 128 final function = new FunctionNode(buildClosureBody(), |
| 127 positionalParameters: [iteratorVariable], | 129 positionalParameters: [iteratorVariable], |
| 128 requiredParameterCount: 1, | 130 requiredParameterCount: 1, |
| 129 asyncMarker: AsyncMarker.SyncYielding) | 131 asyncMarker: AsyncMarker.SyncYielding) |
| 130 ..fileOffset = enclosingFunction.fileOffset | 132 ..fileOffset = enclosingFunction.fileOffset |
| 131 ..fileEndOffset = enclosingFunction.fileEndOffset; | 133 ..fileEndOffset = enclosingFunction.fileEndOffset |
| 134 ..returnType = helper.coreTypes.boolClass.rawType; |
| 135 |
| 132 final closureFunction = | 136 final closureFunction = |
| 133 new FunctionDeclaration(nestedClosureVariable, function) | 137 new FunctionDeclaration(nestedClosureVariable, function) |
| 134 ..fileOffset = enclosingFunction.parent.fileOffset; | 138 ..fileOffset = enclosingFunction.parent.fileOffset; |
| 135 | 139 |
| 136 // return new _SyncIterable(:sync_body); | 140 // return new _SyncIterable(:sync_body); |
| 137 final arguments = new Arguments([new VariableGet(nestedClosureVariable)]); | 141 final arguments = new Arguments([new VariableGet(nestedClosureVariable)]); |
| 138 final returnStatement = new ReturnStatement( | 142 final returnStatement = new ReturnStatement( |
| 139 new ConstructorInvocation(helper.syncIterableConstructor, arguments)); | 143 new ConstructorInvocation(helper.syncIterableConstructor, arguments)); |
| 140 | 144 |
| 141 enclosingFunction.body = new Block([] | 145 enclosingFunction.body = new Block([] |
| 142 ..addAll(variableDeclarations()) | 146 ..addAll(variableDeclarations()) |
| 143 ..addAll([closureFunction, returnStatement])); | 147 ..addAll([closureFunction, returnStatement])); |
| 144 enclosingFunction.body.parent = enclosingFunction; | 148 enclosingFunction.body.parent = enclosingFunction; |
| 145 enclosingFunction.asyncMarker = AsyncMarker.Sync; | 149 enclosingFunction.asyncMarker = AsyncMarker.Sync; |
| 146 return enclosingFunction; | 150 return enclosingFunction; |
| 147 } | 151 } |
| 148 | 152 |
| 149 Statement buildClosureBody() { | 153 Statement buildClosureBody() { |
| 150 // The body will insert calls to | 154 // The body will insert calls to |
| 151 // :iterator.current_= | 155 // :iterator.current_= |
| 152 // :iterator.isYieldEach= | 156 // :iterator.isYieldEach= |
| 153 // and return `true` as long as it did something and `false` when it's done. | 157 // and return `true` as long as it did something and `false` when it's done. |
| 154 return enclosingFunction.body.accept(this); | 158 return new Block([ |
| 159 enclosingFunction.body.accept(this), |
| 160 new ReturnStatement(new BoolLiteral(false)) |
| 161 ]); |
| 155 } | 162 } |
| 156 | 163 |
| 157 visitYieldStatement(YieldStatement node) { | 164 visitYieldStatement(YieldStatement node) { |
| 158 var transformedExpression = node.expression.accept(this); | 165 var transformedExpression = node.expression.accept(this); |
| 159 | 166 |
| 160 var statements = <Statement>[]; | 167 var statements = <Statement>[]; |
| 161 if (node.isYieldStar) { | 168 if (node.isYieldStar) { |
| 162 var markYieldEach = new ExpressionStatement(new PropertySet( | 169 var markYieldEach = new ExpressionStatement(new PropertySet( |
| 163 new VariableGet(iteratorVariable), | 170 new VariableGet(iteratorVariable), |
| 164 new Name("isYieldEach", helper.coreLibrary), | 171 new Name("isYieldEach", helper.coreLibrary), |
| 165 new BoolLiteral(true))); | 172 new BoolLiteral(true))); |
| 166 statements.add(markYieldEach); | 173 statements.add(markYieldEach); |
| 167 } | 174 } |
| 168 | 175 |
| 169 var setCurrentIteratorValue = new ExpressionStatement(new PropertySet( | 176 var setCurrentIteratorValue = new ExpressionStatement(new PropertySet( |
| 170 new VariableGet(iteratorVariable), | 177 new VariableGet(iteratorVariable), |
| 171 new Name("_current", helper.coreLibrary), | 178 new Name("_current", helper.coreLibrary), |
| 172 transformedExpression)); | 179 transformedExpression)); |
| 173 | 180 |
| 174 statements.add(setCurrentIteratorValue); | 181 statements.add(setCurrentIteratorValue); |
| 175 statements.add(createContinuationPoint(new BoolLiteral(true))); | 182 statements.add(createContinuationPoint(new BoolLiteral(true))); |
| 176 return new Block(statements); | 183 return new Block(statements); |
| 177 } | 184 } |
| 185 |
| 186 TreeNode visitReturnStatement(ReturnStatement node) { |
| 187 // sync* functions cannot return a value. |
| 188 assert(node.expression == null || node.expression is NullLiteral); |
| 189 node.expression = new BoolLiteral(false)..parent = node; |
| 190 return node; |
| 191 } |
| 178 } | 192 } |
| 179 | 193 |
| 180 abstract class AsyncRewriterBase extends ContinuationRewriterBase { | 194 abstract class AsyncRewriterBase extends ContinuationRewriterBase { |
| 181 final VariableDeclaration nestedClosureVariable = | 195 final VariableDeclaration nestedClosureVariable = |
| 182 new VariableDeclaration(":async_op"); | 196 new VariableDeclaration(":async_op"); |
| 183 final VariableDeclaration thenContinuationVariable = | 197 final VariableDeclaration thenContinuationVariable = |
| 184 new VariableDeclaration(":async_op_then"); | 198 new VariableDeclaration(":async_op_then"); |
| 185 final VariableDeclaration catchErrorContinuationVariable = | 199 final VariableDeclaration catchErrorContinuationVariable = |
| 186 new VariableDeclaration(":async_op_error"); | 200 new VariableDeclaration(":async_op_error"); |
| 187 | 201 |
| (...skipping 560 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 class AsyncFunctionRewriter extends AsyncRewriterBase { | 762 class AsyncFunctionRewriter extends AsyncRewriterBase { |
| 749 VariableDeclaration completerVariable; | 763 VariableDeclaration completerVariable; |
| 750 VariableDeclaration returnVariable; | 764 VariableDeclaration returnVariable; |
| 751 | 765 |
| 752 AsyncFunctionRewriter(helper, enclosingFunction) | 766 AsyncFunctionRewriter(helper, enclosingFunction) |
| 753 : super(helper, enclosingFunction); | 767 : super(helper, enclosingFunction); |
| 754 | 768 |
| 755 FunctionNode rewrite() { | 769 FunctionNode rewrite() { |
| 756 var statements = <Statement>[]; | 770 var statements = <Statement>[]; |
| 757 | 771 |
| 758 // var :completer = new Completer.sync(); | 772 // The original function return type should be Future<T> because the |
| 773 // function is async. If it was, we make a Completer<T>. Otherwise |
| 774 // We will make a malformed type. |
| 775 var future_type = enclosingFunction.returnType; |
| 776 DartType returnType = const DynamicType(); |
| 777 if (future_type is InterfaceType) { |
| 778 if (future_type.classNode == helper.futureClass) { |
| 779 if (future_type.typeArguments.length == 0) { |
| 780 returnType = const DynamicType(); |
| 781 } else if (future_type.typeArguments.length == 1) { |
| 782 returnType = future_type.typeArguments[0]; |
| 783 } else { |
| 784 returnType = const InvalidType(); |
| 785 } |
| 786 } |
| 787 } |
| 788 var completerTypeArguments = <DartType>[returnType]; |
| 789 var completerType = new InterfaceType( |
| 790 helper.completerClass, completerTypeArguments); |
| 791 |
| 792 // final Completer<T> :completer = new Completer<T>.sync(); |
| 759 completerVariable = new VariableDeclaration(":completer", | 793 completerVariable = new VariableDeclaration(":completer", |
| 760 initializer: new StaticInvocation(helper.completerConstructor, | 794 initializer: new StaticInvocation(helper.completerConstructor, |
| 761 new Arguments([], types: [const DynamicType()])) | 795 new Arguments([], types: completerTypeArguments)) |
| 762 ..fileOffset = enclosingFunction.body.fileOffset, | 796 ..fileOffset = enclosingFunction.body.fileOffset, |
| 763 isFinal: true); | 797 isFinal: true, |
| 798 type: completerType); |
| 764 statements.add(completerVariable); | 799 statements.add(completerVariable); |
| 765 | 800 |
| 766 returnVariable = new VariableDeclaration(":return_value"); | 801 returnVariable = new VariableDeclaration( |
| 802 ":return_value", type: returnType); |
| 767 statements.add(returnVariable); | 803 statements.add(returnVariable); |
| 768 | 804 |
| 769 setupAsyncContinuations(statements); | 805 setupAsyncContinuations(statements); |
| 770 | 806 |
| 771 // new Future.microtask(:async_op); | 807 // new Future.microtask(:async_op); |
| 772 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation( | 808 var newMicrotaskStatement = new ExpressionStatement(new StaticInvocation( |
| 773 helper.futureMicrotaskConstructor, | 809 helper.futureMicrotaskConstructor, |
| 774 new Arguments([new VariableGet(nestedClosureVariable)], | 810 new Arguments([new VariableGet(nestedClosureVariable)], |
| 775 types: [const DynamicType()])) | 811 types: [const DynamicType()])) |
| 776 ..fileOffset = enclosingFunction.fileOffset); | 812 ..fileOffset = enclosingFunction.fileOffset); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 820 .add(new ExpressionStatement(new VariableSet(returnVariable, expr))); | 856 .add(new ExpressionStatement(new VariableSet(returnVariable, expr))); |
| 821 statements | 857 statements |
| 822 .add(new BreakStatement(labeledBody)..fileOffset = node.fileOffset); | 858 .add(new BreakStatement(labeledBody)..fileOffset = node.fileOffset); |
| 823 return null; | 859 return null; |
| 824 } | 860 } |
| 825 } | 861 } |
| 826 | 862 |
| 827 class HelperNodes { | 863 class HelperNodes { |
| 828 final Library asyncLibrary; | 864 final Library asyncLibrary; |
| 829 final Library coreLibrary; | 865 final Library coreLibrary; |
| 866 final Class iteratorClass; |
| 867 final Class futureClass; |
| 868 final Class completerClass; |
| 830 final Procedure printProcedure; | 869 final Procedure printProcedure; |
| 831 final Procedure completerConstructor; | 870 final Procedure completerConstructor; |
| 832 final Procedure futureMicrotaskConstructor; | 871 final Procedure futureMicrotaskConstructor; |
| 833 final Constructor streamControllerConstructor; | 872 final Constructor streamControllerConstructor; |
| 834 final Constructor syncIterableConstructor; | 873 final Constructor syncIterableConstructor; |
| 835 final Constructor streamIteratorConstructor; | 874 final Constructor streamIteratorConstructor; |
| 836 final Procedure asyncThenWrapper; | 875 final Procedure asyncThenWrapper; |
| 837 final Procedure asyncErrorWrapper; | 876 final Procedure asyncErrorWrapper; |
| 838 final Procedure awaitHelper; | 877 final Procedure awaitHelper; |
| 878 final CoreTypes coreTypes; |
| 839 | 879 |
| 840 HelperNodes( | 880 HelperNodes( |
| 841 this.asyncLibrary, | 881 this.asyncLibrary, |
| 842 this.coreLibrary, | 882 this.coreLibrary, |
| 883 this.iteratorClass, |
| 884 this.futureClass, |
| 885 this.completerClass, |
| 843 this.printProcedure, | 886 this.printProcedure, |
| 844 this.completerConstructor, | 887 this.completerConstructor, |
| 845 this.syncIterableConstructor, | 888 this.syncIterableConstructor, |
| 846 this.streamIteratorConstructor, | 889 this.streamIteratorConstructor, |
| 847 this.futureMicrotaskConstructor, | 890 this.futureMicrotaskConstructor, |
| 848 this.streamControllerConstructor, | 891 this.streamControllerConstructor, |
| 849 this.asyncThenWrapper, | 892 this.asyncThenWrapper, |
| 850 this.asyncErrorWrapper, | 893 this.asyncErrorWrapper, |
| 851 this.awaitHelper); | 894 this.awaitHelper, |
| 895 this.coreTypes); |
| 852 | 896 |
| 853 factory HelperNodes.fromProgram(Program program) { | 897 factory HelperNodes.fromProgram(Program program) { |
| 854 Library findLibrary(String name) { | 898 Library findLibrary(String name) { |
| 855 Uri uri = Uri.parse(name); | 899 Uri uri = Uri.parse(name); |
| 856 for (var library in program.libraries) { | 900 for (var library in program.libraries) { |
| 857 if (library.importUri == uri) return library; | 901 if (library.importUri == uri) return library; |
| 858 } | 902 } |
| 859 throw 'Library "$name" not found'; | 903 throw 'Library "$name" not found'; |
| 860 } | 904 } |
| 861 | 905 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 888 } | 932 } |
| 889 } | 933 } |
| 890 throw 'Procedure "$name" not found'; | 934 throw 'Procedure "$name" not found'; |
| 891 } | 935 } |
| 892 | 936 |
| 893 var asyncLibrary = findLibrary('dart:async'); | 937 var asyncLibrary = findLibrary('dart:async'); |
| 894 var coreLibrary = findLibrary('dart:core'); | 938 var coreLibrary = findLibrary('dart:core'); |
| 895 | 939 |
| 896 var completerClass = findClass(asyncLibrary, 'Completer'); | 940 var completerClass = findClass(asyncLibrary, 'Completer'); |
| 897 var futureClass = findClass(asyncLibrary, 'Future'); | 941 var futureClass = findClass(asyncLibrary, 'Future'); |
| 942 var iteratorClass = findClass(coreLibrary, 'Iterator'); |
| 898 | 943 |
| 899 // The VM's dart:async implementation has renamed _StreamIteratorImpl to | 944 // The VM's dart:async implementation has renamed _StreamIteratorImpl to |
| 900 // _StreamIterator. To support both old and new library implementations we | 945 // _StreamIterator. To support both old and new library implementations we |
| 901 // look for the old name first and then the new name. | 946 // look for the old name first and then the new name. |
| 902 var streamIteratorClass; | 947 var streamIteratorClass; |
| 903 try { | 948 try { |
| 904 streamIteratorClass = findClass(asyncLibrary, '_StreamIteratorImpl'); | 949 streamIteratorClass = findClass(asyncLibrary, '_StreamIteratorImpl'); |
| 905 } catch (e) { | 950 } catch (e) { |
| 906 if (e == 'Class "_StreamIteratorImpl" not found') { | 951 if (e == 'Class "_StreamIteratorImpl" not found') { |
| 907 streamIteratorClass = findClass(asyncLibrary, '_StreamIterator'); | 952 streamIteratorClass = findClass(asyncLibrary, '_StreamIterator'); |
| 908 } else { | 953 } else { |
| 909 rethrow; | 954 rethrow; |
| 910 } | 955 } |
| 911 } | 956 } |
| 912 | 957 |
| 913 var syncIterableClass = findClass(coreLibrary, '_SyncIterable'); | 958 var syncIterableClass = findClass(coreLibrary, '_SyncIterable'); |
| 914 var streamControllerClass = | 959 var streamControllerClass = |
| 915 findClass(asyncLibrary, '_AsyncStarStreamController'); | 960 findClass(asyncLibrary, '_AsyncStarStreamController'); |
| 916 | 961 |
| 917 return new HelperNodes( | 962 return new HelperNodes( |
| 918 asyncLibrary, | 963 asyncLibrary, |
| 919 coreLibrary, | 964 coreLibrary, |
| 965 iteratorClass, |
| 966 futureClass, |
| 967 completerClass, |
| 920 findProcedure(coreLibrary, 'print'), | 968 findProcedure(coreLibrary, 'print'), |
| 921 findFactoryConstructor(completerClass, 'sync'), | 969 findFactoryConstructor(completerClass, 'sync'), |
| 922 findConstructor(syncIterableClass, ''), | 970 findConstructor(syncIterableClass, ''), |
| 923 findConstructor(streamIteratorClass, ''), | 971 findConstructor(streamIteratorClass, ''), |
| 924 findFactoryConstructor(futureClass, 'microtask'), | 972 findFactoryConstructor(futureClass, 'microtask'), |
| 925 findConstructor(streamControllerClass, ''), | 973 findConstructor(streamControllerClass, ''), |
| 926 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), | 974 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), |
| 927 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), | 975 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), |
| 928 findProcedure(asyncLibrary, '_awaitHelper')); | 976 findProcedure(asyncLibrary, '_awaitHelper'), |
| 977 new CoreTypes(program)); |
| 929 } | 978 } |
| 930 } | 979 } |
| OLD | NEW |