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 that the current block is dead (because it has a throw or a | |
| 814 * return further up. If this is true, then [_current] may be null. If it | |
|
ngeoffray
2013/04/10 12:06:39
Missing ending paren after 'further up'.
erikcorry
2013/04/10 12:52:32
Done.
| |
| 815 * is dead then it may also be aborted, but for simplicity we only abort on | |
| 816 * statement boundaries, not in the middle of expressions. See isAborted. | |
| 817 */ | |
| 818 bool isReachable = true; | |
|
karlklose
2013/04/09 11:58:46
The comment does not really match the name of the
erikcorry
2013/04/10 12:52:32
Done.
| |
| 819 | |
| 805 final List<Element> sourceElementStack; | 820 final List<Element> sourceElementStack; |
| 806 | 821 |
| 807 Element get currentElement => sourceElementStack.last.declaration; | 822 Element get currentElement => sourceElementStack.last.declaration; |
| 808 Compiler get compiler => builder.compiler; | 823 Compiler get compiler => builder.compiler; |
| 809 CodeEmitterTask get emitter => builder.emitter; | 824 CodeEmitterTask get emitter => builder.emitter; |
| 810 | 825 |
| 811 SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work) | 826 SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work) |
| 812 : this.builder = builder, | 827 : this.builder = builder, |
| 813 this.backend = builder.backend, | 828 this.backend = builder.backend, |
| 814 this.work = work, | 829 this.work = work, |
| 815 graph = new HGraph(), | 830 graph = new HGraph(), |
| 816 stack = new List<HInstruction>(), | 831 stack = new List<HInstruction>(), |
| 817 activationVariables = new Map<Element, HLocalValue>(), | 832 activationVariables = new Map<Element, HLocalValue>(), |
| 818 jumpTargets = new Map<TargetElement, JumpHandler>(), | 833 jumpTargets = new Map<TargetElement, JumpHandler>(), |
| 819 parameters = new Map<Element, HInstruction>(), | 834 parameters = new Map<Element, HInstruction>(), |
| 820 sourceElementStack = <Element>[work.element], | 835 sourceElementStack = <Element>[work.element], |
| 821 inliningStack = <InliningState>[], | 836 inliningStack = <InliningState>[], |
| 822 rti = builder.backend.rti, | 837 rti = builder.backend.rti, |
| 823 super(work.resolutionTree) { | 838 super(work.resolutionTree) { |
| 824 localsHandler = new LocalsHandler(this); | 839 localsHandler = new LocalsHandler(this); |
| 825 } | 840 } |
| 826 | 841 |
| 827 static const MAX_INLINING_DEPTH = 3; | 842 static const MAX_INLINING_DEPTH = 3; |
| 828 static const MAX_INLINING_NODES = 46; | 843 static const MAX_INLINING_NODES = 46; |
| 829 List<InliningState> inliningStack; | 844 List<InliningState> inliningStack; |
| 830 Element returnElement; | 845 Element returnElement; |
| 831 DartType returnType; | 846 DartType returnType; |
| 832 bool inTryStatement = false; | 847 bool inTryStatement = false; |
| 833 | 848 |
| 849 HBasicBlock get current => _current; | |
| 850 void set current(c) { | |
| 851 isReachable = c != null; | |
| 852 _current = c; | |
| 853 } | |
| 854 | |
| 834 /** | 855 /** |
| 835 * Compiles compile-time constants. Never returns [:null:]. If the | 856 * Compiles compile-time constants. Never returns [:null:]. If the |
| 836 * initial value is not a compile-time constants, it reports an | 857 * initial value is not a compile-time constants, it reports an |
| 837 * internal error. | 858 * internal error. |
| 838 */ | 859 */ |
| 839 Constant compileConstant(VariableElement element) { | 860 Constant compileConstant(VariableElement element) { |
| 840 return compiler.constantHandler.compileConstant(element); | 861 return compiler.constantHandler.compileConstant(element); |
| 841 } | 862 } |
| 842 | 863 |
| 843 Constant compileVariable(VariableElement element) { | 864 Constant compileVariable(VariableElement element) { |
| (...skipping 903 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1747 | 1768 |
| 1748 void visit(Node node) { | 1769 void visit(Node node) { |
| 1749 if (node != null) node.accept(this); | 1770 if (node != null) node.accept(this); |
| 1750 } | 1771 } |
| 1751 | 1772 |
| 1752 visitBlock(Block node) { | 1773 visitBlock(Block node) { |
| 1753 for (Link<Node> link = node.statements.nodes; | 1774 for (Link<Node> link = node.statements.nodes; |
| 1754 !link.isEmpty; | 1775 !link.isEmpty; |
| 1755 link = link.tail) { | 1776 link = link.tail) { |
| 1756 visit(link.head); | 1777 visit(link.head); |
| 1757 if (isAborted()) { | 1778 if (!isReachable) { |
| 1758 // The block has been aborted by a return or a throw. | 1779 // The block has been aborted by a return or a throw. |
| 1759 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); | 1780 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); |
| 1760 return; | 1781 return; |
| 1761 } | 1782 } |
| 1762 } | 1783 } |
| 1763 assert(!current.isClosed()); | 1784 assert(!current.isClosed()); |
| 1764 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); | 1785 if (!stack.isEmpty) compiler.cancel('non-empty instruction stack'); |
| 1765 } | 1786 } |
| 1766 | 1787 |
| 1767 visitClassNode(ClassNode node) { | 1788 visitClassNode(ClassNode node) { |
| 1768 compiler.internalError('visitClassNode should not be called', node: node); | 1789 compiler.internalError('visitClassNode should not be called', node: node); |
| 1769 } | 1790 } |
| 1770 | 1791 |
| 1771 visitExpressionStatement(ExpressionStatement node) { | 1792 visitExpressionStatement(ExpressionStatement node) { |
| 1772 visit(node.expression); | 1793 if (isReachable) { |
|
ngeoffray
2013/04/10 12:06:39
It looks weird to check this here while the code l
erikcorry
2013/04/10 12:52:32
I replaced all these checks with asserts and it tu
ngeoffray
2013/04/10 13:02:58
Isn't that a bug if that assert is hit? Do you kno
erikcorry
2013/04/11 09:09:35
It's the inlined throw test that I just introduced
| |
| 1773 pop(); | 1794 visit(node.expression); |
| 1795 pop(); | |
| 1796 } | |
| 1774 } | 1797 } |
| 1775 | 1798 |
| 1776 /** | 1799 /** |
| 1777 * Creates a new loop-header block. The previous [current] block | 1800 * Creates a new loop-header block. The previous [current] block |
| 1778 * is closed with an [HGoto] and replaced by the newly created block. | 1801 * is closed with an [HGoto] and replaced by the newly created block. |
| 1779 * Also notifies the locals handler that we're entering a loop. | 1802 * Also notifies the locals handler that we're entering a loop. |
| 1780 */ | 1803 */ |
| 1781 JumpHandler beginLoopHeader(Node node) { | 1804 JumpHandler beginLoopHeader(Node node) { |
| 1782 assert(!isAborted()); | 1805 assert(!isAborted()); |
| 1783 HBasicBlock previousBlock = close(new HGoto()); | 1806 HBasicBlock previousBlock = close(new HGoto()); |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2040 HBasicBlock block = breakInstruction.block; | 2063 HBasicBlock block = breakInstruction.block; |
| 2041 block.addAtExit(new HBreak.toLabel(label)); | 2064 block.addAtExit(new HBreak.toLabel(label)); |
| 2042 block.remove(breakInstruction); | 2065 block.remove(breakInstruction); |
| 2043 }); | 2066 }); |
| 2044 } | 2067 } |
| 2045 } | 2068 } |
| 2046 jumpHandler.close(); | 2069 jumpHandler.close(); |
| 2047 } | 2070 } |
| 2048 | 2071 |
| 2049 visitFor(For node) { | 2072 visitFor(For node) { |
| 2073 if (!isReachable) return; | |
|
karlklose
2013/04/09 11:58:46
Would it be enough to abort in visitBlock instead
erikcorry
2013/04/10 12:52:32
I tried replacing this if with an assert and it wa
| |
| 2050 assert(node.body != null); | 2074 assert(node.body != null); |
| 2051 void buildInitializer() { | 2075 void buildInitializer() { |
| 2052 if (node.initializer == null) return; | 2076 if (node.initializer == null) return; |
| 2053 Node initializer = node.initializer; | 2077 Node initializer = node.initializer; |
| 2054 if (initializer != null) { | 2078 if (initializer != null) { |
| 2055 visit(initializer); | 2079 visit(initializer); |
| 2056 if (initializer.asExpression() != null) { | 2080 if (initializer.asExpression() != null) { |
| 2057 pop(); | 2081 pop(); |
| 2058 } | 2082 } |
| 2059 } | 2083 } |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 2074 HInstruction updateInstruction = pop(); | 2098 HInstruction updateInstruction = pop(); |
| 2075 } | 2099 } |
| 2076 } | 2100 } |
| 2077 void buildBody() { | 2101 void buildBody() { |
| 2078 visit(node.body); | 2102 visit(node.body); |
| 2079 } | 2103 } |
| 2080 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); | 2104 handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
| 2081 } | 2105 } |
| 2082 | 2106 |
| 2083 visitWhile(While node) { | 2107 visitWhile(While node) { |
| 2108 if (!isReachable) return; | |
| 2084 HInstruction buildCondition() { | 2109 HInstruction buildCondition() { |
| 2085 visit(node.condition); | 2110 visit(node.condition); |
| 2086 return popBoolified(); | 2111 return popBoolified(); |
| 2087 } | 2112 } |
| 2088 handleLoop(node, | 2113 handleLoop(node, |
| 2089 () {}, | 2114 () {}, |
| 2090 buildCondition, | 2115 buildCondition, |
| 2091 () {}, | 2116 () {}, |
| 2092 () { visit(node.body); }); | 2117 () { visit(node.body); }); |
| 2093 } | 2118 } |
| 2094 | 2119 |
| 2095 visitDoWhile(DoWhile node) { | 2120 visitDoWhile(DoWhile node) { |
| 2121 if (!isReachable) return; | |
| 2096 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2122 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 2097 localsHandler.startLoop(node); | 2123 localsHandler.startLoop(node); |
| 2098 JumpHandler jumpHandler = beginLoopHeader(node); | 2124 JumpHandler jumpHandler = beginLoopHeader(node); |
| 2099 HLoopInformation loopInfo = current.loopInformation; | 2125 HLoopInformation loopInfo = current.loopInformation; |
| 2100 HBasicBlock loopEntryBlock = current; | 2126 HBasicBlock loopEntryBlock = current; |
| 2101 HBasicBlock bodyEntryBlock = current; | 2127 HBasicBlock bodyEntryBlock = current; |
| 2102 TargetElement target = elements[node]; | 2128 TargetElement target = elements[node]; |
| 2103 bool hasContinues = target != null && target.isContinueTarget; | 2129 bool hasContinues = target != null && target.isContinueTarget; |
| 2104 if (hasContinues) { | 2130 if (hasContinues) { |
| 2105 // Add extra block to hang labels on. | 2131 // Add extra block to hang labels on. |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2248 } | 2274 } |
| 2249 }); | 2275 }); |
| 2250 | 2276 |
| 2251 HType type = new HType.nonNullExact( | 2277 HType type = new HType.nonNullExact( |
| 2252 compiler.functionClass.computeType(compiler), | 2278 compiler.functionClass.computeType(compiler), |
| 2253 compiler); | 2279 compiler); |
| 2254 push(new HForeignNew(closureClassElement, type, capturedVariables)); | 2280 push(new HForeignNew(closureClassElement, type, capturedVariables)); |
| 2255 } | 2281 } |
| 2256 | 2282 |
| 2257 visitFunctionDeclaration(FunctionDeclaration node) { | 2283 visitFunctionDeclaration(FunctionDeclaration node) { |
| 2284 if (!isReachable) return; | |
| 2258 visit(node.function); | 2285 visit(node.function); |
| 2259 localsHandler.updateLocal(elements[node], pop()); | 2286 localsHandler.updateLocal(elements[node], pop()); |
| 2260 } | 2287 } |
| 2261 | 2288 |
| 2262 visitIdentifier(Identifier node) { | 2289 visitIdentifier(Identifier node) { |
| 2263 if (node.isThis()) { | 2290 if (node.isThis()) { |
| 2264 stack.add(localsHandler.readThis()); | 2291 stack.add(localsHandler.readThis()); |
| 2265 } else { | 2292 } else { |
| 2266 compiler.internalError("SsaBuilder.visitIdentifier on non-this", | 2293 compiler.internalError("SsaBuilder.visitIdentifier on non-this", |
| 2267 node: node); | 2294 node: node); |
| 2268 } | 2295 } |
| 2269 } | 2296 } |
| 2270 | 2297 |
| 2271 visitIf(If node) { | 2298 visitIf(If node) { |
| 2299 if (!isReachable) return; | |
| 2272 handleIf(node, | 2300 handleIf(node, |
| 2273 () => visit(node.condition), | 2301 () => visit(node.condition), |
| 2274 () => visit(node.thenPart), | 2302 () => visit(node.thenPart), |
| 2275 node.elsePart != null ? () => visit(node.elsePart) : null); | 2303 node.elsePart != null ? () => visit(node.elsePart) : null); |
| 2276 } | 2304 } |
| 2277 | 2305 |
| 2278 void handleIf(Node diagnosticNode, | 2306 void handleIf(Node diagnosticNode, |
| 2279 void visitCondition(), void visitThen(), void visitElse()) { | 2307 void visitCondition(), void visitThen(), void visitElse()) { |
| 2280 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); | 2308 SsaBranchBuilder branchBuilder = new SsaBranchBuilder(this, diagnosticNode); |
| 2281 branchBuilder.handleIf(visitCondition, visitThen, visitElse); | 2309 branchBuilder.handleIf(visitCondition, visitThen, visitElse); |
| (...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3867 open(newBlock); | 3895 open(newBlock); |
| 3868 } | 3896 } |
| 3869 | 3897 |
| 3870 visitReturn(Return node) { | 3898 visitReturn(Return node) { |
| 3871 if (identical(node.getBeginToken().stringValue, 'native')) { | 3899 if (identical(node.getBeginToken().stringValue, 'native')) { |
| 3872 native.handleSsaNative(this, node.expression); | 3900 native.handleSsaNative(this, node.expression); |
| 3873 return; | 3901 return; |
| 3874 } | 3902 } |
| 3875 assert(invariant(node, !node.isRedirectingFactoryBody)); | 3903 assert(invariant(node, !node.isRedirectingFactoryBody)); |
| 3876 HInstruction value; | 3904 HInstruction value; |
| 3877 if (node.expression == null) { | 3905 if (node.expression == null || !isReachable) { |
| 3878 value = graph.addConstantNull(constantSystem); | 3906 value = graph.addConstantNull(constantSystem); |
| 3879 } else { | 3907 } else { |
| 3880 visit(node.expression); | 3908 visit(node.expression); |
| 3881 value = pop(); | 3909 value = pop(); |
| 3882 value = potentiallyCheckType(value, returnType); | 3910 value = potentiallyCheckType(value, returnType); |
| 3883 } | 3911 } |
| 3884 | 3912 |
| 3885 handleInTryStatement(); | 3913 handleInTryStatement(); |
| 3886 | 3914 |
| 3887 if (!inliningStack.isEmpty) { | 3915 if (!inliningStack.isEmpty) { |
| 3888 localsHandler.updateLocal(returnElement, value); | 3916 localsHandler.updateLocal(returnElement, value); |
| 3889 } else { | 3917 } else { |
| 3890 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); | 3918 close(attachPosition(new HReturn(value), node)).addSuccessor(graph.exit); |
| 3891 } | 3919 } |
| 3892 } | 3920 } |
| 3893 | 3921 |
| 3894 visitThrow(Throw node) { | 3922 visitThrow(Throw node) { |
| 3895 if (node.expression == null) { | 3923 if (node.expression == null) { |
| 3896 HInstruction exception = rethrowableException; | 3924 HInstruction exception = rethrowableException; |
| 3897 if (exception == null) { | 3925 if (exception == null) { |
| 3898 exception = graph.addConstantNull(constantSystem); | 3926 exception = graph.addConstantNull(constantSystem); |
| 3899 compiler.internalError( | 3927 compiler.internalError( |
| 3900 'rethrowableException should not be null', node: node); | 3928 'rethrowableException should not be null', node: node); |
| 3901 } | 3929 } |
| 3902 close(new HThrow(exception, isRethrow: true)); | 3930 close(new HThrow(exception, isRethrow: true)); |
| 3903 } else { | 3931 } else { |
| 3904 visit(node.expression); | 3932 if (inliningStack.isEmpty) { |
| 3905 close(new HThrow(pop())); | 3933 if (isReachable) { |
|
ngeoffray
2013/04/10 12:06:39
I can't see why this can happen.
erikcorry
2013/04/10 12:52:32
Perhaps if there is more than one throw in an inli
ngeoffray
2013/04/10 13:02:58
But the first throw would abort visiting the block
erikcorry
2013/04/11 09:09:35
I couldn't make this trigger so I removed it.
| |
| 3934 visit(node.expression); | |
| 3935 } else { | |
| 3936 stack.add(graph.addConstantNull(constantSystem)); | |
| 3937 } | |
| 3938 close(new HThrow(pop())); | |
| 3939 } else if (isReachable) { | |
| 3940 // We don't close the block when we are inlining, because we could be | |
| 3941 // inside an expression, and it is rather complicated to close the | |
| 3942 // block at an arbitrary place in an expression. | |
| 3943 visit(node.expression); | |
| 3944 add(new HThrowExpression(pop())); | |
| 3945 isReachable = false; | |
| 3946 } | |
| 3906 } | 3947 } |
| 3907 } | 3948 } |
| 3908 | 3949 |
| 3909 visitTypeAnnotation(TypeAnnotation node) { | 3950 visitTypeAnnotation(TypeAnnotation node) { |
| 3910 compiler.internalError('visiting type annotation in SSA builder', | 3951 compiler.internalError('visiting type annotation in SSA builder', |
| 3911 node: node); | 3952 node: node); |
| 3912 } | 3953 } |
| 3913 | 3954 |
| 3914 visitVariableDefinitions(VariableDefinitions node) { | 3955 visitVariableDefinitions(VariableDefinitions node) { |
| 3956 if (!isReachable) return; | |
| 3915 for (Link<Node> link = node.definitions.nodes; | 3957 for (Link<Node> link = node.definitions.nodes; |
| 3916 !link.isEmpty; | 3958 !link.isEmpty; |
| 3917 link = link.tail) { | 3959 link = link.tail) { |
| 3918 Node definition = link.head; | 3960 Node definition = link.head; |
| 3919 if (definition is Identifier) { | 3961 if (definition is Identifier) { |
| 3920 HInstruction initialValue = graph.addConstantNull(constantSystem); | 3962 HInstruction initialValue = graph.addConstantNull(constantSystem); |
| 3921 localsHandler.updateLocal(elements[definition], initialValue); | 3963 localsHandler.updateLocal(elements[definition], initialValue); |
| 3922 } else { | 3964 } else { |
| 3923 assert(definition is SendSet); | 3965 assert(definition is SendSet); |
| 3924 visitSendSet(definition); | 3966 visitSendSet(definition); |
| (...skipping 973 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4898 } | 4940 } |
| 4899 node.visitChildren(this); | 4941 node.visitChildren(this); |
| 4900 seenReturn = true; | 4942 seenReturn = true; |
| 4901 } | 4943 } |
| 4902 | 4944 |
| 4903 void visitTryStatement(Node node) { | 4945 void visitTryStatement(Node node) { |
| 4904 if (!registerNode()) return; | 4946 if (!registerNode()) return; |
| 4905 tooDifficult = true; | 4947 tooDifficult = true; |
| 4906 } | 4948 } |
| 4907 | 4949 |
| 4908 void visitThrow(Node node) { | 4950 void visitThrow(Throw node) { |
| 4909 if (!registerNode()) return; | 4951 if (!registerNode()) return; |
| 4910 tooDifficult = true; | 4952 // We can't inline rethrows and we don't want to handle throw after a return |
| 4953 // even if it is in an "if". | |
| 4954 if (seenReturn || node.expression == null) tooDifficult = true; | |
| 4911 } | 4955 } |
| 4912 } | 4956 } |
| 4913 | 4957 |
| 4914 class InliningState { | 4958 class InliningState { |
| 4915 /** | 4959 /** |
| 4916 * Documentation wanted -- johnniwinther | 4960 * Documentation wanted -- johnniwinther |
| 4917 * | 4961 * |
| 4918 * Invariant: [function] must be an implementation element. | 4962 * Invariant: [function] must be an implementation element. |
| 4919 */ | 4963 */ |
| 4920 final PartialFunctionElement function; | 4964 final PartialFunctionElement function; |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5162 new HSubGraphBlockInformation(elseBranch.graph)); | 5206 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5163 | 5207 |
| 5164 HBasicBlock conditionStartBlock = conditionBranch.block; | 5208 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5165 conditionStartBlock.setBlockFlow(info, joinBlock); | 5209 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5166 SubGraph conditionGraph = conditionBranch.graph; | 5210 SubGraph conditionGraph = conditionBranch.graph; |
| 5167 HIf branch = conditionGraph.end.last; | 5211 HIf branch = conditionGraph.end.last; |
| 5168 assert(branch is HIf); | 5212 assert(branch is HIf); |
| 5169 branch.blockInformation = conditionStartBlock.blockFlow; | 5213 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5170 } | 5214 } |
| 5171 } | 5215 } |
| OLD | NEW |