Chromium Code Reviews| 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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A special element for the extra parameter taken by intercepted | 8 * A special element for the extra parameter taken by intercepted |
| 9 * methods. We need to override [Element.computeType] because our | 9 * methods. We need to override [Element.computeType] because our |
| 10 * optimizers may look at its declared type. | 10 * optimizers may look at its declared type. |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 super(backend.compiler); | 29 super(backend.compiler); |
| 30 | 30 |
| 31 HGraph build(CodegenWorkItem work) { | 31 HGraph build(CodegenWorkItem work) { |
| 32 return measure(() { | 32 return measure(() { |
| 33 Element element = work.element.implementation; | 33 Element element = work.element.implementation; |
| 34 HInstruction.idCounter = 0; | 34 HInstruction.idCounter = 0; |
| 35 ConstantSystem constantSystem = compiler.backend.constantSystem; | 35 ConstantSystem constantSystem = compiler.backend.constantSystem; |
| 36 SsaBuilder builder = new SsaBuilder(constantSystem, this, work); | 36 SsaBuilder builder = new SsaBuilder(constantSystem, this, work); |
| 37 HGraph graph; | 37 HGraph graph; |
| 38 ElementKind kind = element.kind; | 38 ElementKind kind = element.kind; |
| 39 if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR)) { | 39 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| 40 graph = compileConstructor(builder, work); | 40 graph = compileConstructor(builder, work); |
| 41 } else if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR_BODY) || | 41 } else if (kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY || |
| 42 identical(kind, ElementKind.FUNCTION) || | 42 kind == ElementKind.FUNCTION || |
| 43 identical(kind, ElementKind.GETTER) || | 43 kind == ElementKind.GETTER || |
| 44 identical(kind, ElementKind.SETTER)) { | 44 kind == ElementKind.SETTER) { |
| 45 graph = builder.buildMethod(element); | 45 graph = builder.buildMethod(element); |
| 46 } else if (identical(kind, ElementKind.FIELD)) { | 46 } else if (kind == ElementKind.FIELD) { |
| 47 graph = builder.buildLazyInitializer(element); | 47 graph = builder.buildLazyInitializer(element); |
| 48 } else { | 48 } else { |
| 49 compiler.internalErrorOnElement(element, | 49 compiler.internalErrorOnElement(element, |
| 50 'unexpected element kind $kind'); | 50 'unexpected element kind $kind'); |
| 51 } | 51 } |
| 52 assert(graph.isValid()); | 52 assert(graph.isValid()); |
| 53 if (!identical(kind, ElementKind.FIELD)) { | 53 if (!identical(kind, ElementKind.FIELD)) { |
| 54 FunctionElement function = element; | 54 FunctionElement function = element; |
| 55 graph.calledInLoop = compiler.world.isCalledInLoop(function); | 55 graph.calledInLoop = compiler.world.isCalledInLoop(function); |
| 56 OptionalParameterTypes defaultValueTypes = null; | 56 OptionalParameterTypes defaultValueTypes = null; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 } | 103 } |
| 104 | 104 |
| 105 HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { | 105 HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) { |
| 106 // The body of the constructor will be generated in a separate function. | 106 // The body of the constructor will be generated in a separate function. |
| 107 final ClassElement classElement = work.element.getEnclosingClass(); | 107 final ClassElement classElement = work.element.getEnclosingClass(); |
| 108 return builder.buildFactory(classElement.implementation, | 108 return builder.buildFactory(classElement.implementation, |
| 109 work.element.implementation); | 109 work.element.implementation); |
| 110 } | 110 } |
| 111 } | 111 } |
| 112 | 112 |
| 113 | |
| 113 /** | 114 /** |
| 114 * Keeps track of locals (including parameters and phis) when building. The | 115 * Keeps track of locals (including parameters and phis) when building. The |
| 115 * 'this' reference is treated as parameter and hence handled by this class, | 116 * 'this' reference is treated as parameter and hence handled by this class, |
| 116 * too. | 117 * too. |
| 117 */ | 118 */ |
| 118 class LocalsHandler { | 119 class LocalsHandler { |
| 119 /** | 120 /** |
| 120 * The values of locals that can be directly accessed (without redirections | 121 * The values of locals that can be directly accessed (without redirections |
| 121 * to boxes or closure-fields). | 122 * to boxes or closure-fields). |
| 122 * | 123 * |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 HInstruction box = readLocal(redirect.enclosingElement); | 434 HInstruction box = readLocal(redirect.enclosingElement); |
| 434 builder.add(new HFieldSet(redirect, box, value)); | 435 builder.add(new HFieldSet(redirect, box, value)); |
| 435 } else { | 436 } else { |
| 436 assert(isUsedInTry(element)); | 437 assert(isUsedInTry(element)); |
| 437 HLocalValue local = getLocal(element); | 438 HLocalValue local = getLocal(element); |
| 438 builder.add(new HLocalSet(element, local, value)); | 439 builder.add(new HLocalSet(element, local, value)); |
| 439 } | 440 } |
| 440 } | 441 } |
| 441 | 442 |
| 442 /** | 443 /** |
| 443 * This function must be called before visiting any children of the loop. In | 444 * This function, startLoop, must be called before visiting any children of |
| 444 * particular it needs to be called before executing the initializers. | 445 * the loop. In particular it needs to be called before executing the |
| 446 * initializers. | |
| 445 * | 447 * |
| 446 * The [LocalsHandler] will make the boxes and updates at the right moment. | 448 * The [LocalsHandler] will make the boxes and updates at the right moment. |
| 447 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] (for | 449 * The builder just needs to call [enterLoopBody] and [enterLoopUpdates] (for |
| 448 * [For] loops) at the correct places. For phi-handling [beginLoopHeader] and | 450 * [For] loops) at the correct places. For phi-handling [beginLoopHeader] and |
| 449 * [endLoop] must also be called. | 451 * [endLoop] must also be called. |
| 450 * | 452 * |
| 451 * The correct place for the box depends on the given loop. In most cases | 453 * The correct place for the box depends on the given loop. In most cases |
| 452 * the box will be created when entering the loop-body: while, do-while, and | 454 * the box will be created when entering the loop-body: while, do-while, and |
| 453 * for-in (assuming the call to [:next:] is inside the body) can always be | 455 * for-in (assuming the call to [:next:] is inside the body) can always be |
| 454 * constructed this way. | 456 * constructed this way. |
| (...skipping 332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 787 /** | 789 /** |
| 788 * Variables stored in the current activation. These variables are | 790 * Variables stored in the current activation. These variables are |
| 789 * being updated in try/catch blocks, and should be | 791 * being updated in try/catch blocks, and should be |
| 790 * accessed indirectly through [HLocalGet] and [HLocalSet]. | 792 * accessed indirectly through [HLocalGet] and [HLocalSet]. |
| 791 */ | 793 */ |
| 792 Map<Element, HLocalValue> activationVariables; | 794 Map<Element, HLocalValue> activationVariables; |
| 793 | 795 |
| 794 // We build the Ssa graph by simulating a stack machine. | 796 // We build the Ssa graph by simulating a stack machine. |
| 795 List<HInstruction> stack; | 797 List<HInstruction> stack; |
| 796 | 798 |
| 797 // The current block to add instructions to. Might be null, if we are | 799 /** |
| 798 // visiting dead code. | 800 * The current block to add instructions to. Might be null, if we are |
| 799 HBasicBlock current; | 801 * visiting dead code, but see [isReachable]. |
| 800 // The most recently opened block. Has the same value as [current] while | 802 */ |
| 801 // the block is open, but unlike [current], it isn't cleared when the current | 803 HBasicBlock _current; |
| 802 // block is closed. | 804 |
| 805 /** | |
| 806 * The most recently opened block. Has the same value as [_current] while | |
| 807 * the block is open, but unlike [_current], it isn't cleared when the | |
| 808 * current block is closed. | |
| 809 */ | |
| 803 HBasicBlock lastOpenedBlock; | 810 HBasicBlock lastOpenedBlock; |
| 804 | 811 |
| 812 /** | |
| 813 * Indicates whether the current block is dead (because it has a throw or a | |
| 814 * return further up). If this is false, then [_current] may be null. If the | |
| 815 * block is dead then it may also be aborted, but for simplicity we only | |
| 816 * abort on statement boundaries, not in the middle of expressions. See | |
| 817 * isAborted. | |
| 818 */ | |
| 819 bool isReachable = true; | |
| 820 | |
| 805 final List<Element> sourceElementStack; | 821 final List<Element> sourceElementStack; |
| 806 | 822 |
| 807 Element get currentElement => sourceElementStack.last.declaration; | 823 Element get currentElement => sourceElementStack.last.declaration; |
| 808 Compiler get compiler => builder.compiler; | 824 Compiler get compiler => builder.compiler; |
| 809 CodeEmitterTask get emitter => builder.emitter; | 825 CodeEmitterTask get emitter => builder.emitter; |
| 810 | 826 |
| 811 SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work) | 827 SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work) |
| 812 : this.builder = builder, | 828 : this.builder = builder, |
| 813 this.backend = builder.backend, | 829 this.backend = builder.backend, |
| 814 this.work = work, | 830 this.work = work, |
| 815 graph = new HGraph(), | 831 graph = new HGraph(), |
| 816 stack = new List<HInstruction>(), | 832 stack = new List<HInstruction>(), |
| 817 activationVariables = new Map<Element, HLocalValue>(), | 833 activationVariables = new Map<Element, HLocalValue>(), |
| 818 jumpTargets = new Map<TargetElement, JumpHandler>(), | 834 jumpTargets = new Map<TargetElement, JumpHandler>(), |
| 819 parameters = new Map<Element, HInstruction>(), | 835 parameters = new Map<Element, HInstruction>(), |
| 820 sourceElementStack = <Element>[work.element], | 836 sourceElementStack = <Element>[work.element], |
| 821 inliningStack = <InliningState>[], | 837 inliningStack = <InliningState>[], |
| 822 rti = builder.backend.rti, | 838 rti = builder.backend.rti, |
| 823 super(work.resolutionTree) { | 839 super(work.resolutionTree) { |
| 824 localsHandler = new LocalsHandler(this); | 840 localsHandler = new LocalsHandler(this); |
| 825 } | 841 } |
| 826 | 842 |
| 827 static const MAX_INLINING_DEPTH = 3; | 843 static const MAX_INLINING_DEPTH = 3; |
| 828 static const MAX_INLINING_NODES = 46; | 844 static const MAX_INLINING_NODES = 46; |
| 829 List<InliningState> inliningStack; | 845 List<InliningState> inliningStack; |
| 830 Element returnElement; | 846 Element returnElement; |
| 831 DartType returnType; | 847 DartType returnType; |
| 832 bool inTryStatement = false; | 848 bool inTryStatement = false; |
| 833 | 849 |
| 850 HBasicBlock get current => _current; | |
| 851 void set current(c) { | |
| 852 isReachable = c != null; | |
| 853 _current = c; | |
| 854 } | |
| 855 | |
| 834 /** | 856 /** |
| 835 * Compiles compile-time constants. Never returns [:null:]. If the | 857 * Compiles compile-time constants. Never returns [:null:]. If the |
| 836 * initial value is not a compile-time constants, it reports an | 858 * initial value is not a compile-time constants, it reports an |
| 837 * internal error. | 859 * internal error. |
| 838 */ | 860 */ |
| 839 Constant compileConstant(VariableElement element) { | 861 Constant compileConstant(VariableElement element) { |
| 840 return compiler.constantHandler.compileConstant(element); | 862 return compiler.constantHandler.compileConstant(element); |
| 841 } | 863 } |
| 842 | 864 |
| 843 Constant compileVariable(VariableElement element) { | 865 Constant compileVariable(VariableElement element) { |
| (...skipping 812 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1656 current = null; | 1678 current = null; |
| 1657 return result; | 1679 return result; |
| 1658 } | 1680 } |
| 1659 | 1681 |
| 1660 void goto(HBasicBlock from, HBasicBlock to) { | 1682 void goto(HBasicBlock from, HBasicBlock to) { |
| 1661 from.close(new HGoto()); | 1683 from.close(new HGoto()); |
| 1662 from.addSuccessor(to); | 1684 from.addSuccessor(to); |
| 1663 } | 1685 } |
| 1664 | 1686 |
| 1665 bool isAborted() { | 1687 bool isAborted() { |
| 1666 return current == null; | 1688 return _current == null; |
| 1667 } | 1689 } |
| 1668 | 1690 |
| 1669 /** | 1691 /** |
| 1670 * Creates a new block, transitions to it from any current block, and | 1692 * Creates a new block, transitions to it from any current block, and |
| 1671 * opens the new block. | 1693 * opens the new block. |
| 1672 */ | 1694 */ |
| 1673 HBasicBlock openNewBlock() { | 1695 HBasicBlock openNewBlock() { |
| 1674 HBasicBlock newBlock = addNewBlock(); | 1696 HBasicBlock newBlock = addNewBlock(); |
| 1675 if (!isAborted()) goto(current, newBlock); | 1697 if (!isAborted()) goto(current, newBlock); |
| 1676 open(newBlock); | 1698 open(newBlock); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1743 'length': sourceFile.text.length}); | 1765 'length': sourceFile.text.length}); |
| 1744 } | 1766 } |
| 1745 return location; | 1767 return location; |
| 1746 } | 1768 } |
| 1747 | 1769 |
| 1748 void visit(Node node) { | 1770 void visit(Node node) { |
| 1749 if (node != null) node.accept(this); | 1771 if (node != null) node.accept(this); |
| 1750 } | 1772 } |
| 1751 | 1773 |
| 1752 visitBlock(Block node) { | 1774 visitBlock(Block node) { |
| 1775 if (!isReachable) return; // This can happen when inlining. | |
|
ngeoffray
2013/04/11 09:31:08
// This only happens when inlining
Can you add: a
| |
| 1753 for (Link<Node> link = node.statements.nodes; | 1776 for (Link<Node> link = node.statements.nodes; |
| 1754 !link.isEmpty; | 1777 !link.isEmpty; |
| 1755 link = link.tail) { | 1778 link = link.tail) { |
| 1756 visit(link.head); | 1779 visit(link.head); |
| 1757 if (isAborted()) { | 1780 if (!isReachable) { |
| 1758 // The block has been aborted by a return or a throw. | 1781 // The block has been aborted by a return or a throw. |
| 1759 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); | 1782 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); |
| 1760 return; | 1783 return; |
| 1761 } | 1784 } |
| 1762 } | 1785 } |
| 1763 assert(!current.isClosed()); | 1786 assert(!current.isClosed()); |
| 1764 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); | 1787 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); |
| 1765 } | 1788 } |
| 1766 | 1789 |
| 1767 visitClassNode(ClassNode node) { | 1790 visitClassNode(ClassNode node) { |
| 1768 compiler.internalError('visitClassNode should not be called', node: node); | 1791 compiler.internalError('visitClassNode should not be called', node: node); |
| 1769 } | 1792 } |
| 1770 | 1793 |
| 1771 visitExpressionStatement(ExpressionStatement node) { | 1794 visitExpressionStatement(ExpressionStatement node) { |
| 1795 assert(isReachable); | |
| 1772 visit(node.expression); | 1796 visit(node.expression); |
| 1773 pop(); | 1797 pop(); |
| 1774 } | 1798 } |
| 1775 | 1799 |
| 1776 /** | 1800 /** |
| 1777 * Creates a new loop-header block. The previous [current] block | 1801 * Creates a new loop-header block. The previous [current] block |
| 1778 * is closed with an [HGoto] and replaced by the newly created block. | 1802 * is closed with an [HGoto] and replaced by the newly created block. |
| 1779 * Also notifies the locals handler that we're entering a loop. | 1803 * Also notifies the locals handler that we're entering a loop. |
| 1780 */ | 1804 */ |
| 1781 JumpHandler beginLoopHeader(Node node) { | 1805 JumpHandler beginLoopHeader(Node node) { |
| (...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2040 HBasicBlock block = breakInstruction.block; | 2064 HBasicBlock block = breakInstruction.block; |
| 2041 block.addAtExit(new HBreak.toLabel(label)); | 2065 block.addAtExit(new HBreak.toLabel(label)); |
| 2042 block.remove(breakInstruction); | 2066 block.remove(breakInstruction); |
| 2043 }); | 2067 }); |
| 2044 } | 2068 } |
| 2045 } | 2069 } |
| 2046 jumpHandler.close(); | 2070 jumpHandler.close(); |
| 2047 } | 2071 } |
| 2048 | 2072 |
| 2049 visitFor(For node) { | 2073 visitFor(For node) { |
| 2074 assert(isReachable); | |
| 2050 assert(node.body != null); | 2075 assert(node.body != null); |
| 2051 void buildInitializer() { | 2076 void buildInitializer() { |
| 2052 if (node.initializer == null) return; | 2077 if (node.initializer == null) return; |
| 2053 Node initializer = node.initializer; | 2078 Node initializer = node.initializer; |
| 2054 if (initializer != null) { | 2079 if (initializer != null) { |
| 2055 visit(initializer); | 2080 visit(initializer); |
| 2056 if (initializer.asExpression() != null) { | 2081 if (initializer.asExpression() != null) { |
| 2057 pop(); | 2082 pop(); |
| 2058 } | 2083 } |
| 2059 } | 2084 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2074 HInstruction updateInstruction = pop(); | 2099 HInstruction updateInstruction = pop(); |
| 2075 } | 2100 } |
| 2076 } | 2101 } |
| 2077 void buildBody() { | 2102 void buildBody() { |
| 2078 visit(node.body); | 2103 visit(node.body); |
| 2079 } | 2104 } |
| 2080 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 2105 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 2081 } | 2106 } |
| 2082 | 2107 |
| 2083 visitWhile(While node) { | 2108 visitWhile(While node) { |
| 2109 assert(isReachable); | |
| 2084 HInstruction buildCondition() { | 2110 HInstruction buildCondition() { |
| 2085 visit(node.condition); | 2111 visit(node.condition); |
| 2086 return popBoolified(); | 2112 return popBoolified(); |
| 2087 } | 2113 } |
| 2088 handleLoop(node, | 2114 handleLoop(node, |
| 2089 () {}, | 2115 () {}, |
| 2090 buildCondition, | 2116 buildCondition, |
| 2091 () {}, | 2117 () {}, |
| 2092 () { visit(node.body); }); | 2118 () { visit(node.body); }); |
| 2093 } | 2119 } |
| 2094 | 2120 |
| 2095 visitDoWhile(DoWhile node) { | 2121 visitDoWhile(DoWhile node) { |
| 2122 assert(isReachable); | |
| 2096 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2123 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 2097 localsHandler.startLoop(node); | 2124 localsHandler.startLoop(node); |
| 2098 JumpHandler jumpHandler = beginLoopHeader(node); | 2125 JumpHandler jumpHandler = beginLoopHeader(node); |
| 2099 HLoopInformation loopInfo = current.loopInformation; | 2126 HLoopInformation loopInfo = current.loopInformation; |
| 2100 HBasicBlock loopEntryBlock = current; | 2127 HBasicBlock loopEntryBlock = current; |
| 2101 HBasicBlock bodyEntryBlock = current; | 2128 HBasicBlock bodyEntryBlock = current; |
| 2102 TargetElement target = elements[node]; | 2129 TargetElement target = elements[node]; |
| 2103 bool hasContinues = target != null && target.isContinueTarget; | 2130 bool hasContinues = target != null && target.isContinueTarget; |
| 2104 if (hasContinues) { | 2131 if (hasContinues) { |
| 2105 // Add extra block to hang labels on. | 2132 // Add extra block to hang labels on. |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2248 } | 2275 } |
| 2249 }); | 2276 }); |
| 2250 | 2277 |
| 2251 HType type = new HType.nonNullExact( | 2278 HType type = new HType.nonNullExact( |
| 2252 compiler.functionClass.computeType(compiler), | 2279 compiler.functionClass.computeType(compiler), |
| 2253 compiler); | 2280 compiler); |
| 2254 push(new HForeignNew(closureClassElement, type, capturedVariables)); | 2281 push(new HForeignNew(closureClassElement, type, capturedVariables)); |
| 2255 } | 2282 } |
| 2256 | 2283 |
| 2257 visitFunctionDeclaration(FunctionDeclaration node) { | 2284 visitFunctionDeclaration(FunctionDeclaration node) { |
| 2285 assert(isReachable); | |
| 2258 visit(node.function); | 2286 visit(node.function); |
| 2259 localsHandler.updateLocal(elements[node], pop()); | 2287 localsHandler.updateLocal(elements[node], pop()); |
| 2260 } | 2288 } |
| 2261 | 2289 |
| 2262 visitIdentifier(Identifier node) { | 2290 visitIdentifier(Identifier node) { |
| 2263 if (node.isThis()) { | 2291 if (node.isThis()) { |
| 2264 stack.add(localsHandler.readThis()); | 2292 stack.add(localsHandler.readThis()); |
| 2265 } else { | 2293 } else { |
| 2266 compiler.internalError("SsaBuilder.visitIdentifier on non-this", | 2294 compiler.internalError("SsaBuilder.visitIdentifier on non-this", |
| 2267 node: node); | 2295 node: node); |
| 2268 } | 2296 } |
| 2269 } | 2297 } |
| 2270 | 2298 |
| 2271 visitIf(If node) { | 2299 visitIf(If node) { |
| 2300 assert(isReachable); | |
| 2272 handleIf(node, | 2301 handleIf(node, |
| 2273 () => visit(node.condition), | 2302 () => visit(node.condition), |
| 2274 () => visit(node.thenPart), | 2303 () => visit(node.thenPart), |
| 2275 node.elsePart != null ? () => visit(node.elsePart) : null); | 2304 node.elsePart != null ? () => visit(node.elsePart) : null); |
| 2276 } | 2305 } |
| 2277 | 2306 |
| 2278 void handleIf(Node diagnosticNode, | 2307 void handleIf(Node diagnosticNode, |
| 2279 void visitCondition(), void visitThen(), void visitElse()) { | 2308 void visitCondition(), void visitThen(), void visitElse()) { |
| 2280 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 2309 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
| 2281 branchBuilder.handleIf(visitCondition, visitThen, visitElse); | 2310 branchBuilder.handleIf(visitCondition, visitThen, visitElse); |
| (...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3867 open(newBlock); | 3896 open(newBlock); |
| 3868 } | 3897 } |
| 3869 | 3898 |
| 3870 visitReturn(Return node) { | 3899 visitReturn(Return node) { |
| 3871 if (identical(node.getBeginToken().stringValue, 'native')) { | 3900 if (identical(node.getBeginToken().stringValue, 'native')) { |
| 3872 native.handleSsaNative(this, node.expression); | 3901 native.handleSsaNative(this, node.expression); |
| 3873 return; | 3902 return; |
| 3874 } | 3903 } |
| 3875 assert(invariant(node, !node.isRedirectingFactoryBody)); | 3904 assert(invariant(node, !node.isRedirectingFactoryBody)); |
| 3876 HInstruction value; | 3905 HInstruction value; |
| 3877 if (node.expression == null) { | 3906 if (node.expression == null || !isReachable) { |
|
ngeoffray
2013/04/11 09:31:08
I think you can remove the isReachable check.
| |
| 3878 value = graph.addConstantNull(constantSystem); | 3907 value = graph.addConstantNull(constantSystem); |
| 3879 } else { | 3908 } else { |
| 3880 visit(node.expression); | 3909 visit(node.expression); |
| 3881 value = pop(); | 3910 value = pop(); |
| 3882 value = potentiallyCheckType(value, returnType); | 3911 value = potentiallyCheckType(value, returnType); |
| 3883 } | 3912 } |
| 3884 | 3913 |
| 3885 handleInTryStatement(); | 3914 handleInTryStatement(); |
| 3886 | 3915 |
| 3887 if (!inliningStack.isEmpty) { | 3916 if (!inliningStack.isEmpty) { |
| 3888 localsHandler.updateLocal(returnElement, value); | 3917 localsHandler.updateLocal(returnElement, value); |
| 3889 } else { | 3918 } else { |
| 3890 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); | 3919 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); |
| 3891 } | 3920 } |
| 3892 } | 3921 } |
| 3893 | 3922 |
| 3894 visitThrow(Throw node) { | 3923 visitThrow(Throw node) { |
| 3895 if (node.expression == null) { | 3924 if (node.expression == null) { |
| 3896 HInstruction exception = rethrowableException; | 3925 HInstruction exception = rethrowableException; |
| 3897 if (exception == null) { | 3926 if (exception == null) { |
| 3898 exception = graph.addConstantNull(constantSystem); | 3927 exception = graph.addConstantNull(constantSystem); |
| 3899 compiler.internalError( | 3928 compiler.internalError( |
| 3900 'rethrowableException should not be null', node: node); | 3929 'rethrowableException should not be null', node: node); |
| 3901 } | 3930 } |
| 3902 close(new HThrow(exception, isRethrow: true)); | 3931 close(new HThrow(exception, isRethrow: true)); |
| 3903 } else { | 3932 } else { |
| 3904 visit(node.expression); | 3933 if (inliningStack.isEmpty) { |
| 3905 close(new HThrow(pop())); | 3934 visit(node.expression); |
| 3935 close(new HThrow(pop())); | |
| 3936 } else if (isReachable) { | |
| 3937 // We don't close the block when we are inlining, because we could be | |
| 3938 // inside an expression, and it is rather complicated to close the | |
| 3939 // block at an arbitrary place in an expression. | |
| 3940 visit(node.expression); | |
| 3941 add(new HThrowExpression(pop())); | |
| 3942 isReachable = false; | |
| 3943 } | |
| 3906 } | 3944 } |
| 3907 } | 3945 } |
| 3908 | 3946 |
| 3909 visitTypeAnnotation(TypeAnnotation node) { | 3947 visitTypeAnnotation(TypeAnnotation node) { |
| 3910 compiler.internalError('visiting type annotation in SSA builder', | 3948 compiler.internalError('visiting type annotation in SSA builder', |
| 3911 node: node); | 3949 node: node); |
| 3912 } | 3950 } |
| 3913 | 3951 |
| 3914 visitVariableDefinitions(VariableDefinitions node) { | 3952 visitVariableDefinitions(VariableDefinitions node) { |
| 3953 assert(isReachable); | |
| 3915 for (Link<Node> link = node.definitions.nodes; | 3954 for (Link<Node> link = node.definitions.nodes; |
| 3916 !link.isEmpty; | 3955 !link.isEmpty; |
| 3917 link = link.tail) { | 3956 link = link.tail) { |
| 3918 Node definition = link.head; | 3957 Node definition = link.head; |
| 3919 if (definition is Identifier) { | 3958 if (definition is Identifier) { |
| 3920 HInstruction initialValue = graph.addConstantNull(constantSystem); | 3959 HInstruction initialValue = graph.addConstantNull(constantSystem); |
| 3921 localsHandler.updateLocal(elements[definition], initialValue); | 3960 localsHandler.updateLocal(elements[definition], initialValue); |
| 3922 } else { | 3961 } else { |
| 3923 assert(definition is SendSet); | 3962 assert(definition is SendSet); |
| 3924 visitSendSet(definition); | 3963 visitSendSet(definition); |
| (...skipping 973 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4898 } | 4937 } |
| 4899 node.visitChildren(this); | 4938 node.visitChildren(this); |
| 4900 seenReturn = true; | 4939 seenReturn = true; |
| 4901 } | 4940 } |
| 4902 | 4941 |
| 4903 void visitTryStatement(Node node) { | 4942 void visitTryStatement(Node node) { |
| 4904 if (!registerNode()) return; | 4943 if (!registerNode()) return; |
| 4905 tooDifficult = true; | 4944 tooDifficult = true; |
| 4906 } | 4945 } |
| 4907 | 4946 |
| 4908 void visitThrow(Node node) { | 4947 void visitThrow(Throw node) { |
| 4909 if (!registerNode()) return; | 4948 if (!registerNode()) return; |
| 4910 tooDifficult = true; | 4949 // We can't inline rethrows and we don't want to handle throw after a return |
| 4950 // even if it is in an "if". | |
| 4951 if (seenReturn || node.expression == null) tooDifficult = true; | |
| 4911 } | 4952 } |
| 4912 } | 4953 } |
| 4913 | 4954 |
| 4914 class InliningState { | 4955 class InliningState { |
| 4915 /** | 4956 /** |
| 4916 * Documentation wanted -- johnniwinther | 4957 * Documentation wanted -- johnniwinther |
| 4917 * | 4958 * |
| 4918 * Invariant: [function] must be an implementation element. | 4959 * Invariant: [function] must be an implementation element. |
| 4919 */ | 4960 */ |
| 4920 final PartialFunctionElement function; | 4961 final PartialFunctionElement function; |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5162 new HSubGraphBlockInformation(elseBranch.graph)); | 5203 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5163 | 5204 |
| 5164 HBasicBlock conditionStartBlock = conditionBranch.block; | 5205 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5165 conditionStartBlock.setBlockFlow(info, joinBlock); | 5206 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5166 SubGraph conditionGraph = conditionBranch.graph; | 5207 SubGraph conditionGraph = conditionBranch.graph; |
| 5167 HIf branch = conditionGraph.end.last; | 5208 HIf branch = conditionGraph.end.last; |
| 5168 assert(branch is HIf); | 5209 assert(branch is HIf); |
| 5169 branch.blockInformation = conditionStartBlock.blockFlow; | 5210 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5170 } | 5211 } |
| 5171 } | 5212 } |
| OLD | NEW |