OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 'dart:collection'; | 5 import 'dart:collection'; |
6 | 6 |
7 import 'package:js_runtime/shared/embedded_names.dart'; | 7 import 'package:js_runtime/shared/embedded_names.dart'; |
8 | 8 |
9 import '../closure.dart'; | 9 import '../closure.dart'; |
10 import '../common.dart'; | 10 import '../common.dart'; |
(...skipping 1689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1700 } | 1700 } |
1701 } | 1701 } |
1702 | 1702 |
1703 void buildBody() { | 1703 void buildBody() { |
1704 visit(node.body); | 1704 visit(node.body); |
1705 } | 1705 } |
1706 | 1706 |
1707 loopHandler.handleLoop( | 1707 loopHandler.handleLoop( |
1708 node, | 1708 node, |
1709 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 1709 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 1710 elements.getTargetDefinition(node), |
1710 buildInitializer, | 1711 buildInitializer, |
1711 buildCondition, | 1712 buildCondition, |
1712 buildUpdate, | 1713 buildUpdate, |
1713 buildBody); | 1714 buildBody); |
1714 } | 1715 } |
1715 | 1716 |
1716 visitWhile(ast.While node) { | 1717 visitWhile(ast.While node) { |
1717 assert(isReachable); | 1718 assert(isReachable); |
1718 HInstruction buildCondition() { | 1719 HInstruction buildCondition() { |
1719 visit(node.condition); | 1720 visit(node.condition); |
1720 return popBoolified(); | 1721 return popBoolified(); |
1721 } | 1722 } |
1722 | 1723 |
1723 loopHandler.handleLoop( | 1724 loopHandler.handleLoop( |
1724 node, | 1725 node, |
1725 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 1726 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 1727 elements.getTargetDefinition(node), |
1726 () {}, | 1728 () {}, |
1727 buildCondition, | 1729 buildCondition, |
1728 () {}, () { | 1730 () {}, () { |
1729 visit(node.body); | 1731 visit(node.body); |
1730 }); | 1732 }); |
1731 } | 1733 } |
1732 | 1734 |
1733 visitDoWhile(ast.DoWhile node) { | 1735 visitDoWhile(ast.DoWhile node) { |
1734 assert(isReachable); | 1736 assert(isReachable); |
1735 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 1737 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
1736 var loopClosureInfo = | 1738 var loopClosureInfo = |
1737 closureDataLookup.getClosureRepresentationInfoForLoop(node); | 1739 closureDataLookup.getClosureRepresentationInfoForLoop(node); |
1738 localsHandler.startLoop(loopClosureInfo); | 1740 localsHandler.startLoop(loopClosureInfo); |
1739 loopDepth++; | 1741 loopDepth++; |
1740 JumpHandler jumpHandler = loopHandler.beginLoopHeader(node); | 1742 JumpTarget target = elements.getTargetDefinition(node); |
| 1743 JumpHandler jumpHandler = loopHandler.beginLoopHeader(node, target); |
1741 HLoopInformation loopInfo = current.loopInformation; | 1744 HLoopInformation loopInfo = current.loopInformation; |
1742 HBasicBlock loopEntryBlock = current; | 1745 HBasicBlock loopEntryBlock = current; |
1743 HBasicBlock bodyEntryBlock = current; | 1746 HBasicBlock bodyEntryBlock = current; |
1744 JumpTarget target = elements.getTargetDefinition(node); | |
1745 bool hasContinues = target != null && target.isContinueTarget; | 1747 bool hasContinues = target != null && target.isContinueTarget; |
1746 if (hasContinues) { | 1748 if (hasContinues) { |
1747 // Add extra block to hang labels on. | 1749 // Add extra block to hang labels on. |
1748 // It doesn't currently work if they are on the same block as the | 1750 // It doesn't currently work if they are on the same block as the |
1749 // HLoopInfo. The handling of HLabeledBlockInformation will visit a | 1751 // HLoopInfo. The handling of HLabeledBlockInformation will visit a |
1750 // SubGraph that starts at the same block again, so the HLoopInfo is | 1752 // SubGraph that starts at the same block again, so the HLoopInfo is |
1751 // either handled twice, or it's handled after the labeled block info, | 1753 // either handled twice, or it's handled after the labeled block info, |
1752 // both of which generate the wrong code. | 1754 // both of which generate the wrong code. |
1753 // Using a separate block is just a simple workaround. | 1755 // Using a separate block is just a simple workaround. |
1754 bodyEntryBlock = openNewBlock(); | 1756 bodyEntryBlock = openNewBlock(); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1847 | 1849 |
1848 if (jumpHandler.hasAnyBreak()) { | 1850 if (jumpHandler.hasAnyBreak()) { |
1849 // Null branchBlock because the body of the do-while loop always aborts, | 1851 // Null branchBlock because the body of the do-while loop always aborts, |
1850 // so we never get to the condition. | 1852 // so we never get to the condition. |
1851 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); | 1853 loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); |
1852 | 1854 |
1853 // Since the body of the loop has a break, we attach a synthesized label | 1855 // Since the body of the loop has a break, we attach a synthesized label |
1854 // to the body. | 1856 // to the body. |
1855 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); | 1857 SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock); |
1856 JumpTarget target = elements.getTargetDefinition(node); | 1858 JumpTarget target = elements.getTargetDefinition(node); |
1857 LabelDefinition label = target.addLabel(null, 'loop'); | 1859 LabelDefinition label = |
1858 label.setBreakTarget(); | 1860 target.addLabel(null, 'loop', isBreakTarget: true); |
1859 HLabeledBlockInformation info = new HLabeledBlockInformation( | 1861 HLabeledBlockInformation info = new HLabeledBlockInformation( |
1860 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); | 1862 new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]); |
1861 loopEntryBlock.setBlockFlow(info, current); | 1863 loopEntryBlock.setBlockFlow(info, current); |
1862 jumpHandler.forEachBreak((HBreak breakInstruction, _) { | 1864 jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
1863 HBasicBlock block = breakInstruction.block; | 1865 HBasicBlock block = breakInstruction.block; |
1864 block.addAtExit(new HBreak.toLabel(label)); | 1866 block.addAtExit(new HBreak.toLabel(label)); |
1865 block.remove(breakInstruction); | 1867 block.remove(breakInstruction); |
1866 }); | 1868 }); |
1867 } | 1869 } |
1868 } | 1870 } |
(...skipping 3502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5371 | 5373 |
5372 /** | 5374 /** |
5373 * Creates a [JumpHandler] for a statement. The node must be a jump | 5375 * Creates a [JumpHandler] for a statement. The node must be a jump |
5374 * target. If there are no breaks or continues targeting the statement, | 5376 * target. If there are no breaks or continues targeting the statement, |
5375 * a special "null handler" is returned. | 5377 * a special "null handler" is returned. |
5376 * | 5378 * |
5377 * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used | 5379 * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used |
5378 * to distinguish the synthesized loop created for a switch statement with | 5380 * to distinguish the synthesized loop created for a switch statement with |
5379 * continue statements from simple switch statements. | 5381 * continue statements from simple switch statements. |
5380 */ | 5382 */ |
5381 JumpHandler createJumpHandler(ast.Statement node, {bool isLoopJump}) { | 5383 JumpHandler createJumpHandler(ast.Statement node, JumpTarget jumpTarget, |
5382 JumpTarget element = elements.getTargetDefinition(node); | 5384 {bool isLoopJump}) { |
5383 if (element == null || !identical(element.statement, node)) { | 5385 if (jumpTarget == null || !identical(jumpTarget.statement, node)) { |
5384 // No breaks or continues to this node. | 5386 // No breaks or continues to this node. |
5385 return new NullJumpHandler(reporter); | 5387 return new NullJumpHandler(reporter); |
5386 } | 5388 } |
5387 if (isLoopJump && node is ast.SwitchStatement) { | 5389 if (isLoopJump && node is ast.SwitchStatement) { |
5388 // Create a special jump handler for loops created for switch statements | 5390 // Create a special jump handler for loops created for switch statements |
5389 // with continue statements. | 5391 // with continue statements. |
5390 return new AstSwitchCaseJumpHandler(this, element, node); | 5392 return new AstSwitchCaseJumpHandler(this, jumpTarget, node); |
5391 } | 5393 } |
5392 return new JumpHandler(this, element); | 5394 return new JumpHandler(this, jumpTarget); |
5393 } | 5395 } |
5394 | 5396 |
5395 visitAsyncForIn(ast.AsyncForIn node) { | 5397 visitAsyncForIn(ast.AsyncForIn node) { |
5396 // The async-for is implemented with a StreamIterator. | 5398 // The async-for is implemented with a StreamIterator. |
5397 HInstruction streamIterator; | 5399 HInstruction streamIterator; |
5398 | 5400 |
5399 visit(node.expression); | 5401 visit(node.expression); |
5400 HInstruction expression = pop(); | 5402 HInstruction expression = pop(); |
5401 ConstructorElement constructor = commonElements.streamIteratorConstructor; | 5403 ConstructorElement constructor = commonElements.streamIteratorConstructor; |
5402 pushInvokeStatic( | 5404 pushInvokeStatic( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5438 | 5440 |
5439 visit(node.body); | 5441 visit(node.body); |
5440 } | 5442 } |
5441 | 5443 |
5442 void buildUpdate() {} | 5444 void buildUpdate() {} |
5443 | 5445 |
5444 buildProtectedByFinally(() { | 5446 buildProtectedByFinally(() { |
5445 loopHandler.handleLoop( | 5447 loopHandler.handleLoop( |
5446 node, | 5448 node, |
5447 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 5449 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 5450 elements.getTargetDefinition(node), |
5448 buildInitializer, | 5451 buildInitializer, |
5449 buildCondition, | 5452 buildCondition, |
5450 buildUpdate, | 5453 buildUpdate, |
5451 buildBody); | 5454 buildBody); |
5452 }, () { | 5455 }, () { |
5453 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); | 5456 pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
5454 push(new HAwait(pop(), | 5457 push(new HAwait(pop(), |
5455 new TypeMask.subclass(commonElements.objectClass, closedWorld))); | 5458 new TypeMask.subclass(commonElements.objectClass, closedWorld))); |
5456 pop(); | 5459 pop(); |
5457 }); | 5460 }); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5510 Selector call = Selectors.current; | 5513 Selector call = Selectors.current; |
5511 TypeMask mask = elementInferenceResults.typeOfIteratorCurrent(node); | 5514 TypeMask mask = elementInferenceResults.typeOfIteratorCurrent(node); |
5512 pushInvokeDynamic(node, call, mask, [iterator]); | 5515 pushInvokeDynamic(node, call, mask, [iterator]); |
5513 buildAssignLoopVariable(node, pop()); | 5516 buildAssignLoopVariable(node, pop()); |
5514 visit(node.body); | 5517 visit(node.body); |
5515 } | 5518 } |
5516 | 5519 |
5517 loopHandler.handleLoop( | 5520 loopHandler.handleLoop( |
5518 node, | 5521 node, |
5519 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 5522 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 5523 elements.getTargetDefinition(node), |
5520 buildInitializer, | 5524 buildInitializer, |
5521 buildCondition, | 5525 buildCondition, |
5522 () {}, | 5526 () {}, |
5523 buildBody); | 5527 buildBody); |
5524 } | 5528 } |
5525 | 5529 |
5526 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { | 5530 buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
5527 ast.Node identifier = node.declaredIdentifier; | 5531 ast.Node identifier = node.declaredIdentifier; |
5528 Element variable = elements.getForInVariable(node); | 5532 Element variable = elements.getForInVariable(node); |
5529 Selector selector = elements.getSelector(identifier); | 5533 Selector selector = elements.getSelector(identifier); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5634 HInstruction one = graph.addConstantInt(1, closedWorld); | 5638 HInstruction one = graph.addConstantInt(1, closedWorld); |
5635 HInstruction addInstruction = | 5639 HInstruction addInstruction = |
5636 new HAdd(index, one, null, commonMasks.positiveIntType); | 5640 new HAdd(index, one, null, commonMasks.positiveIntType); |
5637 add(addInstruction); | 5641 add(addInstruction); |
5638 localsHandler.updateLocal(indexVariable, addInstruction); | 5642 localsHandler.updateLocal(indexVariable, addInstruction); |
5639 } | 5643 } |
5640 | 5644 |
5641 loopHandler.handleLoop( | 5645 loopHandler.handleLoop( |
5642 node, | 5646 node, |
5643 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 5647 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 5648 elements.getTargetDefinition(node), |
5644 buildInitializer, | 5649 buildInitializer, |
5645 buildCondition, | 5650 buildCondition, |
5646 buildUpdate, | 5651 buildUpdate, |
5647 buildBody); | 5652 buildBody); |
5648 } | 5653 } |
5649 | 5654 |
5650 visitLabel(ast.Label node) { | 5655 visitLabel(ast.Label node) { |
5651 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); | 5656 reporter.internalError(node, 'SsaFromAstMixin.visitLabel.'); |
5652 } | 5657 } |
5653 | 5658 |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5833 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); | 5838 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); |
5834 } | 5839 } |
5835 } | 5840 } |
5836 | 5841 |
5837 /** | 5842 /** |
5838 * Builds a simple switch statement which does not handle uses of continue | 5843 * Builds a simple switch statement which does not handle uses of continue |
5839 * statements to labeled switch cases. | 5844 * statements to labeled switch cases. |
5840 */ | 5845 */ |
5841 void buildSimpleSwitchStatement( | 5846 void buildSimpleSwitchStatement( |
5842 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { | 5847 ast.SwitchStatement node, Map<ast.CaseMatch, ConstantValue> constants) { |
5843 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | 5848 JumpHandler jumpHandler = createJumpHandler( |
| 5849 node, elements.getTargetDefinition(node), |
| 5850 isLoopJump: false); |
5844 HInstruction buildExpression() { | 5851 HInstruction buildExpression() { |
5845 visit(node.expression); | 5852 visit(node.expression); |
5846 return pop(); | 5853 return pop(); |
5847 } | 5854 } |
5848 | 5855 |
5849 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { | 5856 Iterable<ConstantValue> getConstants(ast.SwitchCase switchCase) { |
5850 List<ConstantValue> constantList = <ConstantValue>[]; | 5857 List<ConstantValue> constantList = <ConstantValue>[]; |
5851 for (ast.Node labelOrCase in switchCase.labelsAndCases) { | 5858 for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
5852 if (labelOrCase is ast.CaseMatch) { | 5859 if (labelOrCase is ast.CaseMatch) { |
5853 constantList.add(constants[labelOrCase]); | 5860 constantList.add(constants[labelOrCase]); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5903 // case 2: s_2; target = i; continue l; | 5910 // case 2: s_2; target = i; continue l; |
5904 // ... | 5911 // ... |
5905 // case n: s_n; target = j; continue l; | 5912 // case n: s_n; target = j; continue l; |
5906 // } | 5913 // } |
5907 // } | 5914 // } |
5908 | 5915 |
5909 JumpTarget switchTarget = elements.getTargetDefinition(node); | 5916 JumpTarget switchTarget = elements.getTargetDefinition(node); |
5910 HInstruction initialValue = graph.addConstantNull(closedWorld); | 5917 HInstruction initialValue = graph.addConstantNull(closedWorld); |
5911 localsHandler.updateLocal(switchTarget, initialValue); | 5918 localsHandler.updateLocal(switchTarget, initialValue); |
5912 | 5919 |
5913 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | 5920 JumpHandler jumpHandler = |
| 5921 createJumpHandler(node, switchTarget, isLoopJump: false); |
5914 dynamic switchCases = node.cases; | 5922 dynamic switchCases = node.cases; |
5915 if (!hasDefault) { | 5923 if (!hasDefault) { |
5916 // Use [:null:] as the marker for a synthetic default clause. | 5924 // Use [:null:] as the marker for a synthetic default clause. |
5917 // The synthetic default is added because otherwise, there would be no | 5925 // The synthetic default is added because otherwise, there would be no |
5918 // good place to give a default value to the local. | 5926 // good place to give a default value to the local. |
5919 switchCases = node.cases.nodes.toList()..add(null); | 5927 switchCases = node.cases.nodes.toList()..add(null); |
5920 } | 5928 } |
5921 HInstruction buildExpression() { | 5929 HInstruction buildExpression() { |
5922 visit(node.expression); | 5930 visit(node.expression); |
5923 return pop(); | 5931 return pop(); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5987 node.cases, | 5995 node.cases, |
5988 getConstants, | 5996 getConstants, |
5989 (_) => false, // No case is default. | 5997 (_) => false, // No case is default. |
5990 buildSwitchCase); | 5998 buildSwitchCase); |
5991 } | 5999 } |
5992 | 6000 |
5993 void buildLoop() { | 6001 void buildLoop() { |
5994 loopHandler.handleLoop( | 6002 loopHandler.handleLoop( |
5995 node, | 6003 node, |
5996 closureDataLookup.getClosureRepresentationInfoForLoop(node), | 6004 closureDataLookup.getClosureRepresentationInfoForLoop(node), |
| 6005 switchTarget, |
5997 () {}, | 6006 () {}, |
5998 buildCondition, | 6007 buildCondition, |
5999 () {}, | 6008 () {}, |
6000 buildSwitch); | 6009 buildSwitch); |
6001 } | 6010 } |
6002 | 6011 |
6003 if (hasDefault) { | 6012 if (hasDefault) { |
6004 buildLoop(); | 6013 buildLoop(); |
6005 } else { | 6014 } else { |
6006 // If the switch statement has no default case, surround the loop with | 6015 // If the switch statement has no default case, surround the loop with |
(...skipping 842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6849 this.oldReturnLocal, | 6858 this.oldReturnLocal, |
6850 this.oldReturnType, | 6859 this.oldReturnType, |
6851 this.oldResolvedAst, | 6860 this.oldResolvedAst, |
6852 this.oldStack, | 6861 this.oldStack, |
6853 this.oldLocalsHandler, | 6862 this.oldLocalsHandler, |
6854 this.inTryStatement, | 6863 this.inTryStatement, |
6855 this.allFunctionsCalledOnce, | 6864 this.allFunctionsCalledOnce, |
6856 this.oldElementInferenceResults) | 6865 this.oldElementInferenceResults) |
6857 : super(function); | 6866 : super(function); |
6858 } | 6867 } |
OLD | NEW |