| 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 class Interceptors { | 5 class Interceptors { |
| 6 Compiler compiler; | 6 Compiler compiler; |
| 7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
| 8 | 8 |
| 9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
| 10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
| (...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 } | 492 } |
| 493 | 493 |
| 494 void endLoop(HBasicBlock loopEntry) { | 494 void endLoop(HBasicBlock loopEntry) { |
| 495 loopEntry.forEachPhi((HPhi phi) { | 495 loopEntry.forEachPhi((HPhi phi) { |
| 496 Element element = phi.element; | 496 Element element = phi.element; |
| 497 HInstruction postLoopDefinition = directLocals[element]; | 497 HInstruction postLoopDefinition = directLocals[element]; |
| 498 phi.addInput(postLoopDefinition); | 498 phi.addInput(postLoopDefinition); |
| 499 }); | 499 }); |
| 500 } | 500 } |
| 501 | 501 |
| 502 /** |
| 503 * Merge [otherLocals] into this locals handler, creating phi-nodes when |
| 504 * there is a conflict. |
| 505 * If a phi node is necessary, it will use the otherLocals instruction as the |
| 506 * first input, and this handler's instruction as the second. |
| 507 * NOTICE: This means that the predecessor corresponding to [otherLocals] |
| 508 * should be the first predecessor of the current block, and the one |
| 509 * corresponding to this locals handler should be the second. |
| 510 */ |
| 502 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { | 511 void mergeWith(LocalsHandler otherLocals, HBasicBlock joinBlock) { |
| 503 // If an element is in one map but not the other we can safely | 512 // If an element is in one map but not the other we can safely |
| 504 // ignore it. It means that a variable was declared in the | 513 // ignore it. It means that a variable was declared in the |
| 505 // block. Since variable declarations are scoped the declared | 514 // block. Since variable declarations are scoped the declared |
| 506 // variable cannot be alive outside the block. Note: this is only | 515 // variable cannot be alive outside the block. Note: this is only |
| 507 // true for nodes where we do joins. | 516 // true for nodes where we do joins. |
| 508 Map<Element, HInstruction> joinedLocals = new Map<Element, HInstruction>(); | 517 Map<Element, HInstruction> joinedLocals = new Map<Element, HInstruction>(); |
| 509 otherLocals.directLocals.forEach((element, instruction) { | 518 otherLocals.directLocals.forEach((element, instruction) { |
| 510 // We know 'this' cannot be modified. | 519 // We know 'this' cannot be modified. |
| 511 if (element === closureData.thisElement) { | 520 if (element === closureData.thisElement) { |
| 512 assert(directLocals[element] == instruction); | 521 assert(directLocals[element] == instruction); |
| 513 joinedLocals[element] = instruction; | 522 joinedLocals[element] = instruction; |
| 514 } else { | 523 } else { |
| 515 HInstruction mine = directLocals[element]; | 524 HInstruction mine = directLocals[element]; |
| 516 if (mine === null) return; | 525 if (mine === null) return; |
| 517 if (instruction === mine) { | 526 if (instruction === mine) { |
| 518 joinedLocals[element] = instruction; | 527 joinedLocals[element] = instruction; |
| 519 } else { | 528 } else { |
| 520 HInstruction phi = new HPhi.manyInputs(element, [instruction, mine]); | 529 HInstruction phi = new HPhi.manyInputs(element, [instruction, mine]); |
| 521 joinBlock.addPhi(phi); | 530 joinBlock.addPhi(phi); |
| 522 joinedLocals[element] = phi; | 531 joinedLocals[element] = phi; |
| 523 } | 532 } |
| 524 } | 533 } |
| 525 }); | 534 }); |
| 526 directLocals = joinedLocals; | 535 directLocals = joinedLocals; |
| 527 } | 536 } |
| 528 } | 537 } |
| 529 | 538 |
| 539 |
| 540 // Represents a single break instruction. |
| 541 class BreakHandlerEntry { |
| 542 final HBreak breakInstruction; |
| 543 final LocalsHandler locals; |
| 544 BreakHandlerEntry(this.breakInstruction, this.locals); |
| 545 } |
| 546 |
| 547 interface BreakHandler default BreakHandlerImpl { |
| 548 BreakHandler(SsaBuilder builder); |
| 549 void addTarget(StatementElement element); |
| 550 void addBreak(HBreak breakInstruction); |
| 551 void forEachBreak(Function action); |
| 552 void close(); |
| 553 List<SourceString> labels(); |
| 554 } |
| 555 |
| 556 // Inert break handler used to avoid null checks when a loop isn't |
| 557 // used as the target of a break, and therefore doesn't need a break |
| 558 // handler associated with it. |
| 559 class NullBreakHandler implements BreakHandler { |
| 560 const NullBreakHandler(); |
| 561 void addTarget(StatementElement element) { unreachable(); } |
| 562 void addBreak(HBreak breakInstruction) { unreachable() } |
| 563 void forEachBreak(Function ignored) { } |
| 564 void close() { } |
| 565 List<SourceString> labels() => const <SourceString>[]; |
| 566 } |
| 567 |
| 568 // Records breaks until a target block is available. |
| 569 // Breaks are always forward jumps. |
| 570 class BreakHandlerImpl implements BreakHandler{ |
| 571 final BreakHandler previous; |
| 572 final SsaBuilder builder; |
| 573 final List<StatementElement> elements; |
| 574 final List<BreakHandlerEntry> breaks; |
| 575 BreakHandlerImpl(SsaBuilder builder) |
| 576 : this.builder = builder, |
| 577 previous = builder.currentBreakHandler, |
| 578 elements = <StatementElement>[], |
| 579 breaks = <BreakHandlerEntry>[] { |
| 580 builder.currentBreakHandler = this; |
| 581 } |
| 582 |
| 583 void addTarget(StatementElement element) { |
| 584 assert(builder.breakTargets[element] === null); |
| 585 elements.add(element); |
| 586 builder.breakTargets[element] = this; |
| 587 } |
| 588 |
| 589 void addBreak(HBreak breakInstruction, |
| 590 LocalsHandler locals) { |
| 591 breaks.add(new BreakHandlerEntry(breakInstruction, locals)); |
| 592 } |
| 593 |
| 594 void forEachBreak(Function action) { |
| 595 for (BreakHandlerEntry entry in breaks) { |
| 596 action(entry.breakInstruction, entry.locals); |
| 597 } |
| 598 } |
| 599 |
| 600 void close() { |
| 601 assert(builder.currentBreakHandler === this); |
| 602 // The mapping from StatementElement to BreakHandler is no longer needed. |
| 603 for (StatementElement element in elements) { |
| 604 assert(builder.breakTargets[element] === this); |
| 605 builder.breakTargets.remove(element); |
| 606 } |
| 607 builder.currentBreakHandler = previous; |
| 608 } |
| 609 |
| 610 List<SourceString> labels() { |
| 611 List<SourceString> result = null; |
| 612 for (StatementElement element in elements) { |
| 613 SourceString name = element.name; |
| 614 if (!name.isEmpty()) { |
| 615 if (result === null) result = <SourceString>[]; |
| 616 result.add(name); |
| 617 } |
| 618 } |
| 619 return result === null ? const <SourceString>[] : result; |
| 620 } |
| 621 } |
| 622 |
| 530 class SsaBuilder implements Visitor { | 623 class SsaBuilder implements Visitor { |
| 531 final Compiler compiler; | 624 final Compiler compiler; |
| 532 TreeElements elements; | 625 TreeElements elements; |
| 533 final Interceptors interceptors; | 626 final Interceptors interceptors; |
| 534 final WorkItem work; | 627 final WorkItem work; |
| 535 bool methodInterceptionEnabled; | 628 bool methodInterceptionEnabled; |
| 536 HGraph graph; | 629 HGraph graph; |
| 537 LocalsHandler localsHandler; | 630 LocalsHandler localsHandler; |
| 538 | 631 |
| 632 Map<StatementElement, BreakHandler> breakTargets; |
| 633 |
| 539 // We build the Ssa graph by simulating a stack machine. | 634 // We build the Ssa graph by simulating a stack machine. |
| 540 List<HInstruction> stack; | 635 List<HInstruction> stack; |
| 541 | 636 |
| 542 // The current block to add instructions to. Might be null, if we are | 637 // The current block to add instructions to. Might be null, if we are |
| 543 // visiting dead code. | 638 // visiting dead code. |
| 544 HBasicBlock current; | 639 HBasicBlock current; |
| 545 | 640 |
| 641 // Linked list of active break-handlers. Will be removed in the order |
| 642 // they are added. |
| 643 BreakHandler currentBreakHandler = const NullBreakHandler(); |
| 644 // The break handler to use for an upcoming loop statement (temporarily set |
| 645 // if a labeled statement is labeling a loop). |
| 646 BreakHandler loopBreakHandler = null; |
| 647 |
| 546 SsaBuilder(Compiler compiler, WorkItem work) | 648 SsaBuilder(Compiler compiler, WorkItem work) |
| 547 : this.compiler = compiler, | 649 : this.compiler = compiler, |
| 548 this.work = work, | 650 this.work = work, |
| 549 interceptors = compiler.builder.interceptors, | 651 interceptors = compiler.builder.interceptors, |
| 550 methodInterceptionEnabled = true, | 652 methodInterceptionEnabled = true, |
| 551 elements = work.resolutionTree, | 653 elements = work.resolutionTree, |
| 552 graph = new HGraph(), | 654 graph = new HGraph(), |
| 553 stack = new List<HInstruction>() { | 655 stack = new List<HInstruction>(), |
| 656 breakTargets = new Map<StatementElement, BreakHandler>() { |
| 554 localsHandler = new LocalsHandler(this); | 657 localsHandler = new LocalsHandler(this); |
| 555 } | 658 } |
| 556 | 659 |
| 557 void disableMethodInterception() { | 660 void disableMethodInterception() { |
| 558 assert(methodInterceptionEnabled); | 661 assert(methodInterceptionEnabled); |
| 559 methodInterceptionEnabled = false; | 662 methodInterceptionEnabled = false; |
| 560 } | 663 } |
| 561 | 664 |
| 562 void enableMethodInterception() { | 665 void enableMethodInterception() { |
| 563 assert(!methodInterceptionEnabled); | 666 assert(!methodInterceptionEnabled); |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 visitExpressionStatement(ExpressionStatement node) { | 946 visitExpressionStatement(ExpressionStatement node) { |
| 844 visit(node.expression); | 947 visit(node.expression); |
| 845 pop(); | 948 pop(); |
| 846 } | 949 } |
| 847 | 950 |
| 848 /** | 951 /** |
| 849 * Creates a new loop-header block. The previous [current] block | 952 * Creates a new loop-header block. The previous [current] block |
| 850 * is closed with an [HGoto] and replaced by the newly created block. | 953 * is closed with an [HGoto] and replaced by the newly created block. |
| 851 * Also notifies the locals handler that we're entering a loop. | 954 * Also notifies the locals handler that we're entering a loop. |
| 852 */ | 955 */ |
| 853 void beginLoopHeader(Node node) { | 956 BreakHandler beginLoopHeader(Node node) { |
| 854 assert(!isAborted()); | 957 assert(!isAborted()); |
| 855 HBasicBlock previousBlock = close(new HGoto()); | 958 HBasicBlock previousBlock = close(new HGoto()); |
| 856 | 959 BreakHandler breakHandler = getLoopBreakHandler(node); |
| 857 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock(); | 960 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock(breakHandler.labels()); |
| 858 previousBlock.addSuccessor(loopEntry); | 961 previousBlock.addSuccessor(loopEntry); |
| 859 open(loopEntry); | 962 open(loopEntry); |
| 860 | 963 |
| 861 localsHandler.beginLoopHeader(node, loopEntry); | 964 localsHandler.beginLoopHeader(node, loopEntry); |
| 965 return breakHandler; |
| 862 } | 966 } |
| 863 | 967 |
| 864 /** | 968 /** |
| 865 * Ends the loop: | 969 * Ends the loop: |
| 866 * - creates a new block and adds it as successor to the [branchBlock]. | 970 * - creates a new block and adds it as successor to the [branchBlock]. |
| 867 * - opens the new block (setting as [current]). | 971 * - opens the new block (setting as [current]). |
| 868 * - notifies the locals handler that we're exiting a loop. | 972 * - notifies the locals handler that we're exiting a loop. |
| 869 */ | 973 */ |
| 870 void endLoop(HBasicBlock loopEntry, HBasicBlock branchBlock) { | 974 void endLoop(HBasicBlock loopEntry, |
| 975 HBasicBlock branchBlock, |
| 976 BreakHandler breakHandler) { |
| 871 HBasicBlock loopExitBlock = addNewBlock(); | 977 HBasicBlock loopExitBlock = addNewBlock(); |
| 872 assert(branchBlock.successors.length == 1); | 978 assert(branchBlock.successors.length == 1); |
| 873 branchBlock.addSuccessor(loopExitBlock); | 979 branchBlock.addSuccessor(loopExitBlock); |
| 874 open(loopExitBlock); | 980 open(loopExitBlock); |
| 875 localsHandler.endLoop(loopEntry); | 981 localsHandler.endLoop(loopEntry); |
| 982 breakHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { |
| 983 HBasicBlock joinBlock = addNewBlock(); |
| 984 breakInstruction.block.addSuccessor(joinBlock); |
| 985 goto(current, joinBlock); |
| 986 open(joinBlock); |
| 987 localsHandler.mergeWith(locals, joinBlock); |
| 988 }); |
| 876 } | 989 } |
| 877 | 990 |
| 878 // For while loops, initializer and update are null. | 991 // For while loops, initializer and update are null. |
| 879 visitLoop(Node loop, Node initializer, Expression condition, NodeList updates, | 992 visitLoop(Node loop, Node initializer, Expression condition, NodeList updates, |
| 880 Node body) { | 993 Node body) { |
| 881 // Generate: | 994 // Generate: |
| 882 // <initializer> | 995 // <initializer> |
| 883 // loop-entry: | 996 // loop-entry: |
| 884 // if (!<condition>) goto loop-exit; | 997 // if (!<condition>) goto loop-exit; |
| 885 // <body> | 998 // <body> |
| 886 // <updates> | 999 // <updates> |
| 887 // goto loop-entry; | 1000 // goto loop-entry; |
| 888 // loop-exit: | 1001 // loop-exit: |
| 889 if (condition === null || body === null) { | 1002 if (condition === null || body === null) { |
| 890 compiler.unimplemented( | 1003 compiler.unimplemented( |
| 891 'SsaBuilder.visitLoop with empty condition or body', | 1004 'SsaBuilder.visitLoop with empty condition or body', |
| 892 node: loop); | 1005 node: loop); |
| 893 } | 1006 } |
| 894 | 1007 |
| 895 localsHandler.startLoop(loop); | 1008 localsHandler.startLoop(loop); |
| 896 | 1009 |
| 897 // The initializer. | 1010 // The initializer. |
| 898 if (initializer !== null) { | 1011 if (initializer !== null) { |
| 899 visit(initializer); | 1012 visit(initializer); |
| 900 // We don't care about the value of the initialization. | 1013 // We don't care about the value of the initialization. |
| 901 if (initializer.asExpression() !== null) pop(); | 1014 if (initializer.asExpression() !== null) pop(); |
| 902 } | 1015 } |
| 903 assert(!isAborted()); | 1016 assert(!isAborted()); |
| 904 | 1017 |
| 905 beginLoopHeader(loop); | 1018 BreakHandler breakHandler = beginLoopHeader(loop); |
| 906 HBasicBlock conditionBlock = current; | 1019 HBasicBlock conditionBlock = current; |
| 907 | 1020 |
| 908 // The condition. | 1021 // The condition. |
| 909 visit(condition); | 1022 visit(condition); |
| 910 HBasicBlock conditionExitBlock = close(new HLoopBranch(popBoolified())); | 1023 HBasicBlock conditionExitBlock = close(new HLoopBranch(popBoolified())); |
| 911 | 1024 |
| 912 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 1025 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 913 | 1026 |
| 914 // The body. | 1027 // The body. |
| 915 HBasicBlock bodyBlock = addNewBlock(); | 1028 HBasicBlock bodyBlock = addNewBlock(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 940 // The result of the update instruction isn't used, and can just | 1053 // The result of the update instruction isn't used, and can just |
| 941 // be dropped. | 1054 // be dropped. |
| 942 HInstruction updateInstruction = pop(); | 1055 HInstruction updateInstruction = pop(); |
| 943 } | 1056 } |
| 944 } | 1057 } |
| 945 updateBlock = close(new HGoto()); | 1058 updateBlock = close(new HGoto()); |
| 946 // The back-edge completing the cycle. | 1059 // The back-edge completing the cycle. |
| 947 updateBlock.addSuccessor(conditionBlock); | 1060 updateBlock.addSuccessor(conditionBlock); |
| 948 conditionBlock.postProcessLoopHeader(); | 1061 conditionBlock.postProcessLoopHeader(); |
| 949 | 1062 |
| 950 endLoop(conditionBlock, conditionExitBlock); | 1063 endLoop(conditionBlock, conditionExitBlock, breakHandler); |
| 951 localsHandler = savedLocals; | 1064 localsHandler = savedLocals; |
| 952 } | 1065 } |
| 953 | 1066 |
| 954 visitFor(For node) { | 1067 visitFor(For node) { |
| 955 if (node.condition === null) { | 1068 if (node.condition === null) { |
| 956 compiler.unimplemented("SsaBuilder for loop without condition"); | 1069 compiler.unimplemented("SsaBuilder for loop without condition"); |
| 957 } | 1070 } |
| 958 assert(node.body !== null); | 1071 assert(node.body !== null); |
| 959 visitLoop(node, node.initializer, node.condition, node.update, node.body); | 1072 visitLoop(node, node.initializer, node.condition, node.update, node.body); |
| 960 } | 1073 } |
| 961 | 1074 |
| 962 visitWhile(While node) { | 1075 visitWhile(While node) { |
| 963 visitLoop(node, null, node.condition, null, node.body); | 1076 visitLoop(node, null, node.condition, null, node.body); |
| 964 } | 1077 } |
| 965 | 1078 |
| 966 visitDoWhile(DoWhile node) { | 1079 visitDoWhile(DoWhile node) { |
| 967 localsHandler.startLoop(node); | 1080 localsHandler.startLoop(node); |
| 968 beginLoopHeader(node); | 1081 BreakHandler breakHandler = beginLoopHeader(node); |
| 969 HBasicBlock loopEntryBlock = current; | 1082 HBasicBlock loopEntryBlock = current; |
| 970 | 1083 |
| 971 localsHandler.enterLoopBody(node); | 1084 localsHandler.enterLoopBody(node); |
| 972 visit(node.body); | 1085 visit(node.body); |
| 973 if (isAborted()) { | 1086 if (isAborted()) { |
| 974 compiler.unimplemented("SsaBuilder for loop with aborting body"); | 1087 compiler.unimplemented("SsaBuilder for loop with aborting body"); |
| 975 } | 1088 } |
| 976 | 1089 |
| 977 // If there are no continues we could avoid the creation of the condition | 1090 // If there are no continues we could avoid the creation of the condition |
| 978 // block. This could also lead to a block having multiple entries and exits. | 1091 // block. This could also lead to a block having multiple entries and exits. |
| 979 HBasicBlock bodyExitBlock = close(new HGoto()); | 1092 HBasicBlock bodyExitBlock = close(new HGoto()); |
| 980 HBasicBlock conditionBlock = addNewBlock(); | 1093 HBasicBlock conditionBlock = addNewBlock(); |
| 981 bodyExitBlock.addSuccessor(conditionBlock); | 1094 bodyExitBlock.addSuccessor(conditionBlock); |
| 982 open(conditionBlock); | 1095 open(conditionBlock); |
| 983 visit(node.condition); | 1096 visit(node.condition); |
| 984 assert(!isAborted()); | 1097 assert(!isAborted()); |
| 985 conditionBlock = close(new HLoopBranch(popBoolified())); | 1098 conditionBlock = close(new HLoopBranch(popBoolified())); |
| 986 | 1099 |
| 987 conditionBlock.addSuccessor(loopEntryBlock); // The back-edge. | 1100 conditionBlock.addSuccessor(loopEntryBlock); // The back-edge. |
| 988 loopEntryBlock.postProcessLoopHeader(); | 1101 loopEntryBlock.postProcessLoopHeader(); |
| 989 | 1102 |
| 990 endLoop(loopEntryBlock, conditionBlock); | 1103 endLoop(loopEntryBlock, conditionBlock, breakHandler); |
| 991 } | 1104 } |
| 992 | 1105 |
| 993 visitFunctionExpression(FunctionExpression node) { | 1106 visitFunctionExpression(FunctionExpression node) { |
| 994 ClosureData nestedClosureData = closureDataCache[node]; | 1107 ClosureData nestedClosureData = closureDataCache[node]; |
| 995 assert(nestedClosureData !== null); | 1108 assert(nestedClosureData !== null); |
| 996 assert(nestedClosureData.closureClassElement !== null); | 1109 assert(nestedClosureData.closureClassElement !== null); |
| 997 ClassElement closureClassElement = | 1110 ClassElement closureClassElement = |
| 998 nestedClosureData.closureClassElement; | 1111 nestedClosureData.closureClassElement; |
| 999 FunctionElement callElement = nestedClosureData.callElement; | 1112 FunctionElement callElement = nestedClosureData.callElement; |
| 1000 compiler.enqueue(new WorkItem.toCodegen(callElement, elements)); | 1113 compiler.enqueue(new WorkItem.toCodegen(callElement, elements)); |
| (...skipping 889 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1890 | 2003 |
| 1891 visitEmptyStatement(EmptyStatement node) { | 2004 visitEmptyStatement(EmptyStatement node) { |
| 1892 // Do nothing, empty statement. | 2005 // Do nothing, empty statement. |
| 1893 } | 2006 } |
| 1894 | 2007 |
| 1895 visitModifiers(Modifiers node) { | 2008 visitModifiers(Modifiers node) { |
| 1896 compiler.unimplemented('SsaBuilder.visitModifiers', node: node); | 2009 compiler.unimplemented('SsaBuilder.visitModifiers', node: node); |
| 1897 } | 2010 } |
| 1898 | 2011 |
| 1899 visitBreakStatement(BreakStatement node) { | 2012 visitBreakStatement(BreakStatement node) { |
| 1900 compiler.unimplemented('SsaBuilder.visitBreakStatement', node: node); | 2013 work.allowSpeculativeOptimization = false; |
| 2014 assert(!isAborted()); |
| 2015 StatementElement target = elements[node]; |
| 2016 assert(target !== null); |
| 2017 BreakHandler handler = breakTargets[target]; |
| 2018 assert(handler !== null); |
| 2019 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 2020 HBreak breakInstruction; |
| 2021 if (node.target === null) { |
| 2022 breakInstruction = new HBreak(); |
| 2023 } else { |
| 2024 breakInstruction = new HBreak(node.target.source); |
| 2025 } |
| 2026 close(breakInstruction); |
| 2027 handler.addBreak(breakInstruction, savedLocals); |
| 1901 } | 2028 } |
| 1902 | 2029 |
| 1903 visitContinueStatement(ContinueStatement node) { | 2030 visitContinueStatement(ContinueStatement node) { |
| 1904 compiler.unimplemented('SsaBuilder.visitContinueStatement', node: node); | 2031 compiler.unimplemented('SsaBuilder.visitContinueStatement', node: node); |
| 1905 } | 2032 } |
| 1906 | 2033 |
| 2034 BreakHandler getLoopBreakHandler(Loop node) { |
| 2035 StatementElement element = elements[node]; |
| 2036 BreakHandler handler; |
| 2037 if (loopBreakHandler === null) { |
| 2038 if (element === null) return const NullBreakHandler(); |
| 2039 handler = new BreakHandler(this); |
| 2040 } else { |
| 2041 handler = loopBreakHandler; |
| 2042 loopBreakHandler = null; |
| 2043 if (element === null) return handler; |
| 2044 } |
| 2045 handler.addTarget(element); |
| 2046 return handler; |
| 2047 } |
| 2048 |
| 1907 visitForInStatement(ForInStatement node) { | 2049 visitForInStatement(ForInStatement node) { |
| 1908 // Generate a structure equivalent to: | 2050 // Generate a structure equivalent to: |
| 1909 // Iterator<E> $iter = <iterable>.iterator() | 2051 // Iterator<E> $iter = <iterable>.iterator() |
| 1910 // while ($iter.hasNext()) { | 2052 // while ($iter.hasNext()) { |
| 1911 // E <declaredIdentifier> = $iter.next(); | 2053 // E <declaredIdentifier> = $iter.next(); |
| 1912 // <body> | 2054 // <body> |
| 1913 // } | 2055 // } |
| 1914 localsHandler.startLoop(node); | 2056 localsHandler.startLoop(node); |
| 1915 | 2057 |
| 1916 SourceString iteratorName = const SourceString("iterator"); | 2058 SourceString iteratorName = const SourceString("iterator"); |
| 1917 | 2059 |
| 1918 Selector selector = Selector.INVOCATION_0; | 2060 Selector selector = Selector.INVOCATION_0; |
| 1919 Element interceptor = interceptors.getStaticInterceptor(iteratorName, 0); | 2061 Element interceptor = interceptors.getStaticInterceptor(iteratorName, 0); |
| 1920 assert(interceptor != null); | 2062 assert(interceptor != null); |
| 1921 HStatic target = new HStatic(interceptor); | 2063 HStatic target = new HStatic(interceptor); |
| 1922 add(target); | 2064 add(target); |
| 1923 visit(node.expression); | 2065 visit(node.expression); |
| 1924 List<HInstruction> inputs = <HInstruction>[target, pop()]; | 2066 List<HInstruction> inputs = <HInstruction>[target, pop()]; |
| 1925 HInstruction iterator = new HInvokeInterceptor( | 2067 HInstruction iterator = new HInvokeInterceptor( |
| 1926 selector, iteratorName, false, inputs); | 2068 selector, iteratorName, false, inputs); |
| 1927 add(iterator); | 2069 add(iterator); |
| 1928 | 2070 |
| 1929 beginLoopHeader(node); | 2071 BreakHandler breakHandler = beginLoopHeader(node); |
| 1930 HBasicBlock conditionBlock = current; | 2072 HBasicBlock conditionBlock = current; |
| 1931 | 2073 |
| 1932 // The condition. | 2074 // The condition. |
| 1933 push(new HInvokeDynamicMethod( | 2075 push(new HInvokeDynamicMethod( |
| 1934 selector, const SourceString('hasNext'), [iterator])); | 2076 selector, const SourceString('hasNext'), [iterator])); |
| 1935 HBasicBlock conditionExitBlock = close(new HLoopBranch(popBoolified())); | 2077 HBasicBlock conditionExitBlock = close(new HLoopBranch(popBoolified())); |
| 1936 | 2078 |
| 1937 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2079 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 1938 | 2080 |
| 1939 // The body. | 2081 // The body. |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1969 // update block is the jump-target for continue statements. We could avoid | 2111 // update block is the jump-target for continue statements. We could avoid |
| 1970 // the creation if there is no continue, but for now we always create it. | 2112 // the creation if there is no continue, but for now we always create it. |
| 1971 HBasicBlock updateBlock = addNewBlock(); | 2113 HBasicBlock updateBlock = addNewBlock(); |
| 1972 bodyBlock.addSuccessor(updateBlock); | 2114 bodyBlock.addSuccessor(updateBlock); |
| 1973 open(updateBlock); | 2115 open(updateBlock); |
| 1974 updateBlock = close(new HGoto()); | 2116 updateBlock = close(new HGoto()); |
| 1975 // The back-edge completing the cycle. | 2117 // The back-edge completing the cycle. |
| 1976 updateBlock.addSuccessor(conditionBlock); | 2118 updateBlock.addSuccessor(conditionBlock); |
| 1977 conditionBlock.postProcessLoopHeader(); | 2119 conditionBlock.postProcessLoopHeader(); |
| 1978 | 2120 |
| 1979 endLoop(conditionBlock, conditionExitBlock); | 2121 endLoop(conditionBlock, conditionExitBlock, breakHandler); |
| 1980 localsHandler = savedLocals; | 2122 localsHandler = savedLocals; |
| 2123 breakHandler.close(); |
| 1981 } | 2124 } |
| 1982 | 2125 |
| 1983 visitLabelledStatement(LabelledStatement node) { | 2126 visitLabelledStatement(LabelledStatement node) { |
| 1984 compiler.unimplemented('SsaBuilder.visitLabelledStatement', node: node); | 2127 BreakHandler handler = null; |
| 2128 Node currentNode = node; |
| 2129 do { |
| 2130 StatementElement element = elements[currentNode]; |
| 2131 if (element !== null && element.isBreakTarget) { |
| 2132 if (handler === null) handler = new BreakHandler(this); |
| 2133 handler.addTarget(element); |
| 2134 } |
| 2135 currentNode = currentNode.statement; |
| 2136 } while (currentNode is LabelledStatement); |
| 2137 if (handler === null) { |
| 2138 // The labels are not break targets. |
| 2139 visit(currentNode); |
| 2140 } else if (currentNode is Loop || currentNode is SwitchStatement) { |
| 2141 // The labels apply to that statement, and will be handled there. |
| 2142 loopBreakHandler = handler; |
| 2143 visit(currentNode); |
| 2144 assert(loopBreakHandler === null); |
| 2145 } else { |
| 2146 // Introduce a new basic block. |
| 2147 HBasicBlock entryBlock = graph.addNewBlock(); |
| 2148 goto(current, entryBlock); |
| 2149 open(entryBlock); |
| 2150 visit(currentNode); |
| 2151 if (isAborted()) { |
| 2152 compiler.unimplemented( |
| 2153 "SsaBuilder for labeled statement with aborting body", node: node); |
| 2154 } |
| 2155 HBasicBlock exitBlock = current; |
| 2156 handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) { |
| 2157 HBasicBlock joinBlock = graph.addNewBlock(); |
| 2158 breakInstruction.block.addSuccessor(joinBlock); |
| 2159 if (!isAborted()) { |
| 2160 goto(current, joinBlock); |
| 2161 open(joinBlock); |
| 2162 localsHandler.mergeWith(locals, joinBlock); |
| 2163 } else { |
| 2164 open(joinBlock); |
| 2165 localsHandler = locals; |
| 2166 } |
| 2167 }); |
| 2168 if (current !== exitBlock) { |
| 2169 // There was at least one reachable break, so the label is needed. |
| 2170 HLabeledBlockInformation blockInfo = |
| 2171 new HLabeledBlockInformation(entryBlock, current, |
| 2172 handler.labels()); |
| 2173 handler.close(); |
| 2174 entryBlock.labeledBlockInformation = blockInfo; |
| 2175 // Mark both entry and exit with the information. You can |
| 2176 // tell which one is which by comparing with blockInfo.start/end. |
| 2177 // It doesn't matter which merge block we use, they won't be generating |
| 2178 // any code, so put the end-marker on the last join block. |
| 2179 current.labeledBlockInformation = blockInfo; |
| 2180 } |
| 2181 } |
| 1985 } | 2182 } |
| 1986 | 2183 |
| 1987 visitLiteralMap(LiteralMap node) { | 2184 visitLiteralMap(LiteralMap node) { |
| 1988 compiler.unimplemented('SsaBuilder.visitLiteralMap', node: node); | 2185 compiler.unimplemented('SsaBuilder.visitLiteralMap', node: node); |
| 1989 } | 2186 } |
| 1990 | 2187 |
| 1991 visitLiteralMapEntry(LiteralMapEntry node) { | 2188 visitLiteralMapEntry(LiteralMapEntry node) { |
| 1992 compiler.unimplemented('SsaBuilder.visitLiteralMapEntry', node: node); | 2189 compiler.unimplemented('SsaBuilder.visitLiteralMapEntry', node: node); |
| 1993 } | 2190 } |
| 1994 | 2191 |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2092 } | 2289 } |
| 2093 | 2290 |
| 2094 visitCatchBlock(CatchBlock node) { | 2291 visitCatchBlock(CatchBlock node) { |
| 2095 visit(node.block); | 2292 visit(node.block); |
| 2096 } | 2293 } |
| 2097 | 2294 |
| 2098 visitTypedef(Typedef node) { | 2295 visitTypedef(Typedef node) { |
| 2099 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 2296 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
| 2100 } | 2297 } |
| 2101 } | 2298 } |
| OLD | NEW |