| 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 '../visitor.dart'; | 10 import '../visitor.dart'; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 return new AsyncFunctionRewriter(helper, node).rewrite(); | 43 return new AsyncFunctionRewriter(helper, node).rewrite(); |
| 44 case AsyncMarker.AsyncStar: | 44 case AsyncMarker.AsyncStar: |
| 45 return new AsyncStarFunctionRewriter(helper, node).rewrite(); | 45 return new AsyncStarFunctionRewriter(helper, node).rewrite(); |
| 46 } | 46 } |
| 47 } | 47 } |
| 48 } | 48 } |
| 49 | 49 |
| 50 abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter { | 50 abstract class ContinuationRewriterBase extends RecursiveContinuationRewriter { |
| 51 final FunctionNode enclosingFunction; | 51 final FunctionNode enclosingFunction; |
| 52 | 52 |
| 53 int currentTryDepth; // Nesting depth for try-blocks. | 53 int currentTryDepth = 0; // Nesting depth for try-blocks. |
| 54 int currentCatchDepth = 0; // Nesting depth for catch-blocks. | 54 int currentCatchDepth = 0; // Nesting depth for catch-blocks. |
| 55 int capturedTryDepth = 0; // Deepest yield point within a try-block. | |
| 56 int capturedCatchDepth = 0; // Deepest yield point within a catch-block. | |
| 57 | 55 |
| 58 ContinuationRewriterBase(HelperNodes helper, this.enclosingFunction, | 56 // For both, try-catch and try-finally, the VM needs to have saved-try-context |
| 59 {this.currentTryDepth: 0}) | 57 // and exception/stacktrace available (both need the correct context when |
| 58 // entering catch/finally blocks and finally needs exception/stacktrace for |
| 59 // rethrow). |
| 60 int capturedDepth = 0; // Deepest yield point within try/catch-blocks. |
| 61 |
| 62 ContinuationRewriterBase(HelperNodes helper, this.enclosingFunction) |
| 60 : super(helper); | 63 : super(helper); |
| 61 | 64 |
| 62 Statement createContinuationPoint([Expression value]) { | 65 Statement createContinuationPoint([Expression value]) { |
| 63 if (value == null) value = new NullLiteral(); | 66 if (value == null) value = new NullLiteral(); |
| 64 capturedTryDepth = math.max(capturedTryDepth, currentTryDepth); | 67 capturedDepth = |
| 65 capturedCatchDepth = math.max(capturedCatchDepth, currentCatchDepth); | 68 math.max(capturedDepth, currentTryDepth + currentCatchDepth); |
| 66 return new YieldStatement(value, isNative: true); | 69 return new YieldStatement(value, isNative: true); |
| 67 } | 70 } |
| 68 | 71 |
| 69 TreeNode visitTryCatch(TryCatch node) { | 72 TreeNode visitTryCatch(TryCatch node) { |
| 70 if (node.body != null) { | 73 if (node.body != null) { |
| 71 currentTryDepth++; | 74 currentTryDepth++; |
| 72 node.body = node.body.accept(this); | 75 node.body = node.body.accept(this); |
| 73 node.body?.parent = node; | 76 node.body?.parent = node; |
| 74 currentTryDepth--; | 77 currentTryDepth--; |
| 75 } | 78 } |
| 76 | 79 |
| 77 currentCatchDepth++; | 80 ++currentCatchDepth; |
| 78 transformList(node.catches, this, node); | 81 transformList(node.catches, this, node); |
| 79 currentCatchDepth--; | 82 --currentCatchDepth; |
| 80 return node; | 83 return node; |
| 81 } | 84 } |
| 82 | 85 |
| 83 TreeNode visitTryFinally(TryFinally node) { | 86 TreeNode visitTryFinally(TryFinally node) { |
| 84 if (node.body != null) { | 87 if (node.body != null) { |
| 85 currentTryDepth++; | 88 currentTryDepth++; |
| 86 node.body = node.body.accept(this); | 89 node.body = node.body.accept(this); |
| 87 node.body?.parent = node; | 90 node.body?.parent = node; |
| 88 currentTryDepth--; | 91 currentTryDepth--; |
| 89 } | 92 } |
| 90 if (node.finalizer != null) { | 93 if (node.finalizer != null) { |
| 91 node.finalizer = node.finalizer.accept(this); | 94 node.finalizer = node.finalizer.accept(this); |
| 92 node.finalizer?.parent = node; | 95 node.finalizer?.parent = node; |
| 93 } | 96 } |
| 94 return node; | 97 return node; |
| 95 } | 98 } |
| 96 | 99 |
| 97 Iterable<VariableDeclaration> createCapturedTryVariables() => | 100 Iterable<VariableDeclaration> createCapturedTryVariables() => |
| 98 new Iterable.generate(capturedTryDepth, | 101 new Iterable.generate(capturedDepth, |
| 99 (depth) => new VariableDeclaration(":saved_try_context_var${depth}")); | 102 (depth) => new VariableDeclaration(":saved_try_context_var${depth}")); |
| 100 | 103 |
| 101 Iterable<VariableDeclaration> createCapturedCatchVariables() => | 104 Iterable<VariableDeclaration> createCapturedCatchVariables() => |
| 102 new Iterable.generate(capturedCatchDepth).expand((depth) => [ | 105 new Iterable.generate(capturedDepth).expand((depth) => [ |
| 103 new VariableDeclaration(":exception${depth}"), | 106 new VariableDeclaration(":exception${depth}"), |
| 104 new VariableDeclaration(":stack_trace${depth}"), | 107 new VariableDeclaration(":stack_trace${depth}"), |
| 105 ]); | 108 ]); |
| 106 | 109 |
| 107 List<VariableDeclaration> variableDeclarations() => | 110 List<VariableDeclaration> variableDeclarations() => |
| 108 [asyncJumpVariable, asyncContextVariable] | 111 [asyncJumpVariable, asyncContextVariable] |
| 109 ..addAll(createCapturedTryVariables()) | 112 ..addAll(createCapturedTryVariables()) |
| 110 ..addAll(createCapturedCatchVariables()); | 113 ..addAll(createCapturedCatchVariables()); |
| 111 } | 114 } |
| 112 | 115 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 final VariableDeclaration thenContinuationVariable = | 185 final VariableDeclaration thenContinuationVariable = |
| 183 new VariableDeclaration(":async_op_then"); | 186 new VariableDeclaration(":async_op_then"); |
| 184 final VariableDeclaration catchErrorContinuationVariable = | 187 final VariableDeclaration catchErrorContinuationVariable = |
| 185 new VariableDeclaration(":async_op_error"); | 188 new VariableDeclaration(":async_op_error"); |
| 186 | 189 |
| 187 LabeledStatement labeledBody; | 190 LabeledStatement labeledBody; |
| 188 | 191 |
| 189 ExpressionLifter expressionRewriter; | 192 ExpressionLifter expressionRewriter; |
| 190 | 193 |
| 191 AsyncRewriterBase(helper, enclosingFunction) | 194 AsyncRewriterBase(helper, enclosingFunction) |
| 192 // Body is wrapped in the try-catch so initial currentTryDepth is 1. | 195 : super(helper, enclosingFunction) {} |
| 193 : super(helper, enclosingFunction, currentTryDepth: 1) {} | |
| 194 | 196 |
| 195 void setupAsyncContinuations(List<Statement> statements) { | 197 void setupAsyncContinuations(List<Statement> statements) { |
| 196 expressionRewriter = new ExpressionLifter(this); | 198 expressionRewriter = new ExpressionLifter(this); |
| 197 | 199 |
| 198 // var :async_op_then; | 200 // var :async_op_then; |
| 199 statements.add(thenContinuationVariable); | 201 statements.add(thenContinuationVariable); |
| 200 | 202 |
| 201 // var :async_op_error; | 203 // var :async_op_error; |
| 202 statements.add(catchErrorContinuationVariable); | 204 statements.add(catchErrorContinuationVariable); |
| 203 | 205 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 final boundCatchErrorClosure = new StaticInvocation( | 242 final boundCatchErrorClosure = new StaticInvocation( |
| 241 helper.asyncErrorWrapper, | 243 helper.asyncErrorWrapper, |
| 242 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)])); | 244 new Arguments(<Expression>[new VariableGet(nestedClosureVariable)])); |
| 243 final catchErrorClosureVariableAssign = new ExpressionStatement( | 245 final catchErrorClosureVariableAssign = new ExpressionStatement( |
| 244 new VariableSet( | 246 new VariableSet( |
| 245 catchErrorContinuationVariable, boundCatchErrorClosure)); | 247 catchErrorContinuationVariable, boundCatchErrorClosure)); |
| 246 statements.add(catchErrorClosureVariableAssign); | 248 statements.add(catchErrorClosureVariableAssign); |
| 247 } | 249 } |
| 248 | 250 |
| 249 Statement buildWrappedBody() { | 251 Statement buildWrappedBody() { |
| 252 ++currentCatchDepth; |
| 250 labeledBody = new LabeledStatement(null); | 253 labeledBody = new LabeledStatement(null); |
| 251 labeledBody.body = visitDelimited(enclosingFunction.body) | 254 labeledBody.body = visitDelimited(enclosingFunction.body) |
| 252 ..parent = labeledBody; | 255 ..parent = labeledBody; |
| 253 | 256 |
| 254 var exceptionVariable = new VariableDeclaration(":exception"); | 257 var exceptionVariable = new VariableDeclaration(":exception"); |
| 255 var stackTraceVariable = new VariableDeclaration(":stack_trace"); | 258 var stackTraceVariable = new VariableDeclaration(":stack_trace"); |
| 256 | 259 |
| 257 return new TryCatch(buildReturn(labeledBody), <Catch>[ | 260 var body = buildReturn(labeledBody); |
| 261 --currentCatchDepth; |
| 262 return new TryCatch(body, <Catch>[ |
| 258 new Catch( | 263 new Catch( |
| 259 exceptionVariable, | 264 exceptionVariable, |
| 260 new Block(<Statement>[ | 265 new Block(<Statement>[ |
| 261 buildCatchBody(exceptionVariable, stackTraceVariable) | 266 buildCatchBody(exceptionVariable, stackTraceVariable) |
| 262 ]), | 267 ]), |
| 263 stackTrace: stackTraceVariable) | 268 stackTrace: stackTraceVariable) |
| 264 ]); | 269 ]); |
| 265 } | 270 } |
| 266 | 271 |
| 267 Statement buildCatchBody( | 272 Statement buildCatchBody( |
| (...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 var returnStatement = new ReturnStatement( | 682 var returnStatement = new ReturnStatement( |
| 678 new PropertyGet(completerGet, new Name('stream', helper.asyncLibrary))); | 683 new PropertyGet(completerGet, new Name('stream', helper.asyncLibrary))); |
| 679 statements.add(returnStatement); | 684 statements.add(returnStatement); |
| 680 | 685 |
| 681 enclosingFunction.body = new Block(statements); | 686 enclosingFunction.body = new Block(statements); |
| 682 enclosingFunction.body.parent = enclosingFunction; | 687 enclosingFunction.body.parent = enclosingFunction; |
| 683 enclosingFunction.asyncMarker = AsyncMarker.Sync; | 688 enclosingFunction.asyncMarker = AsyncMarker.Sync; |
| 684 return enclosingFunction; | 689 return enclosingFunction; |
| 685 } | 690 } |
| 686 | 691 |
| 692 Statement buildWrappedBody() { |
| 693 ++currentTryDepth; |
| 694 Statement body = super.buildWrappedBody(); |
| 695 --currentTryDepth; |
| 696 var tryFinally = |
| 697 new TryFinally(body, new Block(<Statement>[buildFinallyBody()])); |
| 698 return tryFinally; |
| 699 } |
| 700 |
| 687 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { | 701 Statement buildCatchBody(exceptionVariable, stackTraceVariable) { |
| 688 return new ExpressionStatement(new MethodInvocation( | 702 return new ExpressionStatement(new MethodInvocation( |
| 689 new VariableGet(controllerVariable), | 703 new VariableGet(controllerVariable), |
| 690 new Name("completeError", helper.asyncLibrary), | 704 new Name("addError", helper.asyncLibrary), |
| 691 new Arguments(<Expression>[ | 705 new Arguments(<Expression>[ |
| 692 new VariableGet(exceptionVariable), | 706 new VariableGet(exceptionVariable), |
| 693 new VariableGet(stackTraceVariable) | 707 new VariableGet(stackTraceVariable) |
| 694 ]))); | 708 ]))); |
| 695 } | 709 } |
| 696 | 710 |
| 711 Statement buildFinallyBody() { |
| 712 return new ExpressionStatement(new MethodInvocation( |
| 713 new VariableGet(controllerVariable), |
| 714 new Name("close", helper.asyncLibrary), |
| 715 new Arguments(<Expression>[]))); |
| 716 } |
| 717 |
| 697 Statement buildReturn(Statement body) { | 718 Statement buildReturn(Statement body) { |
| 698 // Async* functions cannot return a value. The returns from the function | 719 // Async* functions cannot return a value. The returns from the function |
| 699 // have been translated into breaks from the labeled body. | 720 // have been translated into breaks from the labeled body. |
| 700 return new Block(<Statement>[ | 721 return new Block(<Statement>[ |
| 701 body, | 722 body, |
| 702 new ExpressionStatement(new MethodInvocation( | 723 new ReturnStatement()..fileOffset = enclosingFunction.fileEndOffset, |
| 703 new VariableGet(controllerVariable), | |
| 704 new Name("close", helper.asyncLibrary), | |
| 705 new Arguments(<Expression>[]))), | |
| 706 new ReturnStatement()..fileOffset = enclosingFunction.fileEndOffset | |
| 707 ]); | 724 ]); |
| 708 } | 725 } |
| 709 | 726 |
| 710 TreeNode visitYieldStatement(YieldStatement stmt) { | 727 TreeNode visitYieldStatement(YieldStatement stmt) { |
| 711 Expression expr = expressionRewriter.rewrite(stmt.expression, statements); | 728 Expression expr = expressionRewriter.rewrite(stmt.expression, statements); |
| 712 | 729 |
| 713 var addExpression = new MethodInvocation( | 730 var addExpression = new MethodInvocation( |
| 714 new VariableGet(controllerVariable), | 731 new VariableGet(controllerVariable), |
| 715 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), | 732 new Name(stmt.isYieldStar ? 'addStream' : 'add', helper.asyncLibrary), |
| 716 new Arguments(<Expression>[expr]))..fileOffset = stmt.fileOffset; | 733 new Arguments(<Expression>[expr]))..fileOffset = stmt.fileOffset; |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 907 findFactoryConstructor(completerClass, 'sync'), | 924 findFactoryConstructor(completerClass, 'sync'), |
| 908 findConstructor(syncIterableClass, ''), | 925 findConstructor(syncIterableClass, ''), |
| 909 findConstructor(streamIteratorClass, ''), | 926 findConstructor(streamIteratorClass, ''), |
| 910 findFactoryConstructor(futureClass, 'microtask'), | 927 findFactoryConstructor(futureClass, 'microtask'), |
| 911 findConstructor(streamControllerClass, ''), | 928 findConstructor(streamControllerClass, ''), |
| 912 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), | 929 findProcedure(asyncLibrary, '_asyncThenWrapperHelper'), |
| 913 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), | 930 findProcedure(asyncLibrary, '_asyncErrorWrapperHelper'), |
| 914 findProcedure(asyncLibrary, '_awaitHelper')); | 931 findProcedure(asyncLibrary, '_awaitHelper')); |
| 915 } | 932 } |
| 916 } | 933 } |
| OLD | NEW |