Chromium Code Reviews| 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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |