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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2610903004: Implement async/await/yield and async for-in (Closed)
Patch Set: . Created 3 years, 11 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/graph_builder.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) 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 import 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../closure.dart'; 7 import '../closure.dart';
8 import '../common.dart'; 8 import '../common.dart';
9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
10 import '../common/names.dart'; 10 import '../common/names.dart';
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 if (expression is ir.Throw) { 558 if (expression is ir.Throw) {
559 // TODO(sra): Prevent generating a statement when inlining. 559 // TODO(sra): Prevent generating a statement when inlining.
560 _visitThrowExpression(expression.expression); 560 _visitThrowExpression(expression.expression);
561 closeAndGotoExit(new HThrow(pop(), null)); 561 closeAndGotoExit(new HThrow(pop(), null));
562 } else { 562 } else {
563 expression.accept(this); 563 expression.accept(this);
564 pop(); 564 pop();
565 } 565 }
566 } 566 }
567 567
568 /// Returns true if the [type] is a valid return type for an asynchronous
569 /// function.
570 ///
571 /// Asynchronous functions return a `Future`, and a valid return is thus
572 /// either dynamic, Object, or Future.
573 ///
574 /// We do not accept the internal Future implementation class.
575 bool isValidAsyncReturnType(ir.DartType type) {
576 // TODO(sigurdm): In an internal library a function could be declared:
577 //
578 // _FutureImpl foo async => 1;
579 //
580 // This should be valid (because the actual value returned from an async
581 // function is a `_FutureImpl`), but currently false is returned in this
582 // case.
583 return type is ir.DynamicType ||
584 type == astAdapter.objectClass.thisType ||
585 (type is ir.InterfaceType && type == astAdapter.futureClass.thisType);
586 }
587
568 @override 588 @override
569 void visitReturnStatement(ir.ReturnStatement returnStatement) { 589 void visitReturnStatement(ir.ReturnStatement returnStatement) {
570 HInstruction value; 590 HInstruction value;
571 if (returnStatement.expression == null) { 591 if (returnStatement.expression == null) {
572 value = graph.addConstantNull(closedWorld); 592 value = graph.addConstantNull(closedWorld);
573 } else { 593 } else {
574 assert(_targetFunction != null && _targetFunction is ir.FunctionNode); 594 assert(_targetFunction != null && _targetFunction is ir.FunctionNode);
575 returnStatement.expression.accept(this); 595 returnStatement.expression.accept(this);
576 value = typeBuilder.potentiallyCheckOrTrustType( 596 value = pop();
577 pop(), astAdapter.getFunctionReturnType(_targetFunction)); 597 if (_targetFunction.asyncMarker == ir.AsyncMarker.Async) {
598 var returnType = astAdapter.getDartType(_targetFunction.returnType);
599 if (compiler.options.enableTypeAssertions &&
600 !isValidAsyncReturnType(_targetFunction.returnType)) {
601 generateTypeError(
602 returnStatement,
603 "Async function returned a Future,"
604 " was declared to return a ${_targetFunction.returnType}.");
605 pop();
606 return;
607 }
608 } else {
609 value = typeBuilder.potentiallyCheckOrTrustType(
610 value, astAdapter.getFunctionReturnType(_targetFunction));
611 }
578 } 612 }
579 // TODO(het): Add source information 613 // TODO(het): Add source information
580 // TODO(het): Set a return value instead of closing the function when we 614 // TODO(het): Set a return value instead of closing the function when we
581 // support inlining. 615 // support inlining.
582 closeAndGotoExit(new HReturn(value, null)); 616 closeAndGotoExit(new HReturn(value, null));
583 } 617 }
584 618
585 @override 619 @override
586 void visitForStatement(ir.ForStatement forStatement) { 620 void visitForStatement(ir.ForStatement forStatement) {
587 assert(isReachable); 621 assert(isReachable);
(...skipping 26 matching lines...) Expand all
614 forStatement.body.accept(this); 648 forStatement.body.accept(this);
615 } 649 }
616 650
617 loopHandler.handleLoop( 651 loopHandler.handleLoop(
618 forStatement, buildInitializer, buildCondition, buildUpdate, buildBody); 652 forStatement, buildInitializer, buildCondition, buildUpdate, buildBody);
619 } 653 }
620 654
621 @override 655 @override
622 void visitForInStatement(ir.ForInStatement forInStatement) { 656 void visitForInStatement(ir.ForInStatement forInStatement) {
623 if (forInStatement.isAsync) { 657 if (forInStatement.isAsync) {
624 compiler.reporter.internalError(astAdapter.getNode(forInStatement), 658 _buildAsyncForIn(forInStatement);
625 "Cannot compile async for-in using kernel.");
626 } 659 }
627 // If the expression being iterated over is a JS indexable type, we can 660 // If the expression being iterated over is a JS indexable type, we can
628 // generate an optimized version of for-in that uses indexing. 661 // generate an optimized version of for-in that uses indexing.
629 if (astAdapter.isJsIndexableIterator(forInStatement, closedWorld)) { 662 if (astAdapter.isJsIndexableIterator(forInStatement, closedWorld)) {
630 _buildForInIndexable(forInStatement); 663 _buildForInIndexable(forInStatement);
631 } else { 664 } else {
632 _buildForInIterator(forInStatement); 665 _buildForInIterator(forInStatement);
633 } 666 }
634 } 667 }
635 668
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 selector: Selectors.current); 803 selector: Selectors.current);
771 localsHandler.updateLocal( 804 localsHandler.updateLocal(
772 astAdapter.getLocal(forInStatement.variable), pop()); 805 astAdapter.getLocal(forInStatement.variable), pop());
773 forInStatement.body.accept(this); 806 forInStatement.body.accept(this);
774 } 807 }
775 808
776 loopHandler.handleLoop( 809 loopHandler.handleLoop(
777 forInStatement, buildInitializer, buildCondition, () {}, buildBody); 810 forInStatement, buildInitializer, buildCondition, () {}, buildBody);
778 } 811 }
779 812
813 void _buildAsyncForIn(ir.ForInStatement forInStatement) {
814 // The async-for is implemented with a StreamIterator.
815 HInstruction streamIterator;
816
817 forInStatement.iterable.accept(this);
818 _pushStaticInvocation(
819 astAdapter.streamIteratorConstructor,
820 [pop(), graph.addConstantNull(closedWorld)],
821 astAdapter.streamIteratorConstructorType);
822 streamIterator = pop();
823
824 void buildInitializer() {}
825
826 HInstruction buildCondition() {
827 TypeMask mask = astAdapter.typeOfIteratorMoveNext(forInStatement);
828 _pushDynamicInvocation(forInStatement, mask, [streamIterator],
829 selector: Selectors.moveNext);
830 HInstruction future = pop();
831 push(new HAwait(future, astAdapter.makeSubtypeOfObject(closedWorld)));
832 return popBoolified();
833 }
834
835 void buildBody() {
836 TypeMask mask = astAdapter.typeOfIteratorCurrent(forInStatement);
837 _pushDynamicInvocation(forInStatement, mask, [streamIterator],
838 selector: Selectors.current);
839 localsHandler.updateLocal(
840 astAdapter.getLocal(forInStatement.variable), pop());
841 forInStatement.body.accept(this);
842 }
843
844 void buildUpdate() {}
845
846 // Creates a synthetic try/finally block in case anything async goes amiss.
847 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this);
848 // Build fake try body:
849 loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition,
850 buildUpdate, buildBody);
851
852 void finalizerFunction() {
853 _pushDynamicInvocation(forInStatement, null, [streamIterator],
854 selector: Selectors.cancel);
855 push(new HAwait(pop(), astAdapter.makeSubtypeOfObject(closedWorld)));
856 pop();
sra1 2017/01/14 02:56:23 push/pop = add
Emily Fortuna 2017/01/17 20:58:21 Done.
857 }
858
859 tryBuilder
860 ..closeTryBody()
861 ..buildFinallyBlock(
862 new ir.TryFinally(null, new _FakeStatement(finalizerFunction)))
sra1 2017/01/14 02:56:23 I'd rather buildFinallyBlock took a function (fina
Emily Fortuna 2017/01/17 20:58:21 Done.
863 ..cleanUp();
864 }
865
780 HInstruction callSetRuntimeTypeInfo( 866 HInstruction callSetRuntimeTypeInfo(
781 HInstruction typeInfo, HInstruction newObject) { 867 HInstruction typeInfo, HInstruction newObject) {
782 // Set the runtime type information on the object. 868 // Set the runtime type information on the object.
783 ir.Procedure typeInfoSetterFn = astAdapter.setRuntimeTypeInfo; 869 ir.Procedure typeInfoSetterFn = astAdapter.setRuntimeTypeInfo;
784 // TODO(efortuna): Insert source information in this static invocation. 870 // TODO(efortuna): Insert source information in this static invocation.
785 _pushStaticInvocation(typeInfoSetterFn, <HInstruction>[newObject, typeInfo], 871 _pushStaticInvocation(typeInfoSetterFn, <HInstruction>[newObject, typeInfo],
786 commonMasks.dynamicType); 872 commonMasks.dynamicType);
787 873
788 // The new object will now be referenced through the 874 // The new object will now be referenced through the
789 // `setRuntimeTypeInfo` call. We therefore set the type of that 875 // `setRuntimeTypeInfo` call. We therefore set the type of that
(...skipping 1438 matching lines...) Expand 10 before | Expand all | Expand 10 after
2228 void _visitThrowExpression(ir.Expression expression) { 2314 void _visitThrowExpression(ir.Expression expression) {
2229 bool old = _inExpressionOfThrow; 2315 bool old = _inExpressionOfThrow;
2230 try { 2316 try {
2231 _inExpressionOfThrow = true; 2317 _inExpressionOfThrow = true;
2232 expression.accept(this); 2318 expression.accept(this);
2233 } finally { 2319 } finally {
2234 _inExpressionOfThrow = old; 2320 _inExpressionOfThrow = old;
2235 } 2321 }
2236 } 2322 }
2237 2323
2324 void visitYieldStatement(ir.YieldStatement yieldStatement) {
2325 yieldStatement.expression.accept(this);
2326 add(new HYield(pop(), yieldStatement.isYieldStar));
2327 }
2328
2329 @override
2330 void visitAwaitExpression(ir.AwaitExpression await) {
2331 await.operand.accept(this);
2332 HInstruction awaited = pop();
2333 // TODO(herhut): Improve this type.
2334 push(new HAwait(awaited, astAdapter.makeSubtypeOfObject(closedWorld)));
2335 }
2336
2238 @override 2337 @override
2239 void visitRethrow(ir.Rethrow rethrowNode) { 2338 void visitRethrow(ir.Rethrow rethrowNode) {
2240 HInstruction exception = rethrowableException; 2339 HInstruction exception = rethrowableException;
2241 if (exception == null) { 2340 if (exception == null) {
2242 exception = graph.addConstantNull(closedWorld); 2341 exception = graph.addConstantNull(closedWorld);
2243 compiler.reporter.internalError(astAdapter.getNode(rethrowNode), 2342 compiler.reporter.internalError(astAdapter.getNode(rethrowNode),
2244 'rethrowableException should not be null.'); 2343 'rethrowableException should not be null.');
2245 } 2344 }
2246 SourceInformation sourceInformation = null; 2345 SourceInformation sourceInformation = null;
2247 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true)); 2346 closeAndGotoExit(new HThrow(exception, sourceInformation, isRethrow: true));
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
2297 tryCatch.body.accept(this); 2396 tryCatch.body.accept(this);
2298 tryBuilder 2397 tryBuilder
2299 ..closeTryBody() 2398 ..closeTryBody()
2300 ..buildCatch(tryCatch); 2399 ..buildCatch(tryCatch);
2301 } else { 2400 } else {
2302 tryFinally.body.accept(this); 2401 tryFinally.body.accept(this);
2303 tryBuilder.closeTryBody(); 2402 tryBuilder.closeTryBody();
2304 } 2403 }
2305 2404
2306 tryBuilder 2405 tryBuilder
2307 ..buildFinallyBlock(tryFinally) 2406 ..buildFinallyBlock(tryFinally)
sra1 2017/01/14 02:56:23 ..buildFinallyBlock(() { tryFinally.finalizer.acce
Emily Fortuna 2017/01/17 20:58:21 Done.
2308 ..cleanUp(); 2407 ..cleanUp();
2309 } 2408 }
2310 } 2409 }
2311 2410
2312 /// Class in charge of building try, catch and/or finally blocks. This handles 2411 /// Class in charge of building try, catch and/or finally blocks. This handles
2313 /// the instructions that need to be output and the dominator calculation of 2412 /// the instructions that need to be output and the dominator calculation of
2314 /// this sequence of code. 2413 /// this sequence of code.
2315 class TryCatchFinallyBuilder { 2414 class TryCatchFinallyBuilder {
2316 HBasicBlock enterBlock; 2415 HBasicBlock enterBlock;
2317 HBasicBlock startTryBlock; 2416 HBasicBlock startTryBlock;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
2394 2493
2395 // If a block inside try/catch aborts (eg with a return statement), 2494 // If a block inside try/catch aborts (eg with a return statement),
2396 // we explicitely mark this block a predecessor of the catch 2495 // we explicitely mark this block a predecessor of the catch
2397 // block and the finally block. 2496 // block and the finally block.
2398 _addExitTrySuccessor(startCatchBlock); 2497 _addExitTrySuccessor(startCatchBlock);
2399 _addExitTrySuccessor(startFinallyBlock); 2498 _addExitTrySuccessor(startFinallyBlock);
2400 } 2499 }
2401 2500
2402 /// Build the finally{} clause of a try/{catch}/finally statement. Note this 2501 /// Build the finally{} clause of a try/{catch}/finally statement. Note this
2403 /// does not examine the body of the try clause, only the finally portion. 2502 /// does not examine the body of the try clause, only the finally portion.
2404 void buildFinallyBlock(ir.TryFinally tryFinally) { 2503 void buildFinallyBlock(ir.TryFinally tryFinally) {
sra1 2017/01/14 02:56:23 buildFinallyBlock(void buildFinalizer()) {
Emily Fortuna 2017/01/17 20:58:20 Done.
2405 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals); 2504 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals);
2406 startFinallyBlock = kernelBuilder.graph.addNewBlock(); 2505 startFinallyBlock = kernelBuilder.graph.addNewBlock();
2407 kernelBuilder.open(startFinallyBlock); 2506 kernelBuilder.open(startFinallyBlock);
2408 tryFinally.finalizer.accept(kernelBuilder); 2507 tryFinally.finalizer.accept(kernelBuilder);
sra1 2017/01/14 02:56:23 buildFinalizer();
Emily Fortuna 2017/01/17 20:58:21 Done.
2409 if (!kernelBuilder.isAborted()) { 2508 if (!kernelBuilder.isAborted()) {
2410 endFinallyBlock = kernelBuilder.close(new HGoto()); 2509 endFinallyBlock = kernelBuilder.close(new HGoto());
2411 } 2510 }
2412 tryInstruction.finallyBlock = startFinallyBlock; 2511 tryInstruction.finallyBlock = startFinallyBlock;
2413 finallyGraph = 2512 finallyGraph =
2414 new SubGraph(startFinallyBlock, kernelBuilder.lastOpenedBlock); 2513 new SubGraph(startFinallyBlock, kernelBuilder.lastOpenedBlock);
2415 } 2514 }
2416 2515
2417 void closeTryBody() { 2516 void closeTryBody() {
2418 // We use a [HExitTry] instead of a [HGoto] for the try block 2517 // We use a [HExitTry] instead of a [HGoto] for the try block
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
2523 kernelBuilder.open(exitBlock); 2622 kernelBuilder.open(exitBlock);
2524 enterBlock.setBlockFlow( 2623 enterBlock.setBlockFlow(
2525 new HTryBlockInformation( 2624 new HTryBlockInformation(
2526 kernelBuilder.wrapStatementGraph(bodyGraph), 2625 kernelBuilder.wrapStatementGraph(bodyGraph),
2527 exception, 2626 exception,
2528 kernelBuilder.wrapStatementGraph(catchGraph), 2627 kernelBuilder.wrapStatementGraph(catchGraph),
2529 kernelBuilder.wrapStatementGraph(finallyGraph)), 2628 kernelBuilder.wrapStatementGraph(finallyGraph)),
2530 exitBlock); 2629 exitBlock);
2531 } 2630 }
2532 } 2631 }
2632
2633 /// Helper class to do the work of acting like a ir.TryFinally finalizer
2634 /// statement without actually having any source code. This is used for the
2635 /// buildAsyncForIn method but allows us to reuse code in
2636 /// TryCatchFinallyBuilder. Sure would be nice if we could have nested classes.
2637 class _FakeStatement extends ir.Statement {
sra1 2017/01/14 02:56:23 I'm not keen on this. See other comments
Emily Fortuna 2017/01/17 20:58:20 Done.
2638 Function finalizerFunc;
2639 _FakeStatement(this.finalizerFunc);
2640
2641 accept(ir.StatementVisitor not_used) => finalizerFunc();
2642
2643 visitChildren(ir.Visitor v) {}
2644 transformChildren(ir.Transformer v) {}
2645 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/graph_builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698