| 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 |