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 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 597 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 608 } | 608 } |
| 609 | 609 |
| 610 | 610 |
| 611 // Represents a single break instruction. | 611 // Represents a single break instruction. |
| 612 class BreakHandlerEntry { | 612 class BreakHandlerEntry { |
| 613 final HBreak breakInstruction; | 613 final HBreak breakInstruction; |
| 614 final LocalsHandler locals; | 614 final LocalsHandler locals; |
| 615 BreakHandlerEntry(this.breakInstruction, this.locals); | 615 BreakHandlerEntry(this.breakInstruction, this.locals); |
| 616 } | 616 } |
| 617 | 617 |
| 618 interface BreakHandler default BreakHandlerImpl { | 618 interface BreakHandler default BreakHandlerImpl { |
|
ahe
2012/03/13 10:17:15
Do we really need an interface for this?
Lasse Reichstein Nielsen
2012/03/13 12:09:38
Maybe not, but I like making the NullBreakHandler
| |
| 619 BreakHandler(SsaBuilder builder, StatementElement target); | 619 BreakHandler(SsaBuilder builder, StatementElement target); |
| 620 void addBreak(HBreak breakInstruction, LocalsHandler locals); | 620 void addBreak(HBreak breakInstruction, LocalsHandler locals); |
| 621 void forEachBreak(Function action); | 621 void forEachBreak(Function action); |
| 622 void close(); | 622 void close(); |
| 623 List<SourceString> labels(); | 623 List<LabelElement> labels(); |
|
ahe
2012/03/13 10:17:15
I like seeing a move from SourceString to Element.
| |
| 624 } | 624 } |
| 625 | 625 |
| 626 // Inert break handler used to avoid null checks when a loop isn't | 626 // Inert break handler used to avoid null checks when a loop isn't |
| 627 // used as the target of a break, and therefore doesn't need a break | 627 // used as the target of a break, and therefore doesn't need a break |
| 628 // handler associated with it. | 628 // handler associated with it. |
| 629 class NullBreakHandler implements BreakHandler { | 629 class NullBreakHandler implements BreakHandler { |
| 630 const NullBreakHandler(); | 630 const NullBreakHandler(); |
| 631 void addBreak(HBreak breakInstruction, LocalsHandler locals) { | 631 void addBreak(HBreak breakInstruction, LocalsHandler locals) { |
| 632 unreachable(); | 632 unreachable(); |
| 633 } | 633 } |
| 634 void forEachBreak(Function ignored) { } | 634 void forEachBreak(Function ignored) { } |
| 635 void close() { } | 635 void close() { } |
| 636 List<SourceString> labels() => const <SourceString>[]; | 636 List<LabelElement> labels() => const <LabelElement>[]; |
| 637 } | 637 } |
| 638 | 638 |
| 639 // Records breaks until a target block is available. | 639 // Records breaks until a target block is available. |
| 640 // Breaks are always forward jumps. | 640 // Breaks are always forward jumps. |
| 641 class BreakHandlerImpl implements BreakHandler { | 641 class BreakHandlerImpl implements BreakHandler { |
| 642 final BreakHandler previous; | 642 final BreakHandler previous; |
| 643 final SsaBuilder builder; | 643 final SsaBuilder builder; |
| 644 final StatementElement target; | 644 final StatementElement target; |
| 645 final List<BreakHandlerEntry> breaks; | 645 final List<BreakHandlerEntry> breaks; |
| 646 BreakHandlerImpl(SsaBuilder builder, this.target) | 646 BreakHandlerImpl(SsaBuilder builder, this.target) |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 662 } | 662 } |
| 663 } | 663 } |
| 664 | 664 |
| 665 void close() { | 665 void close() { |
| 666 assert(builder.currentBreakHandler === this); | 666 assert(builder.currentBreakHandler === this); |
| 667 // The mapping from StatementElement to BreakHandler is no longer needed. | 667 // The mapping from StatementElement to BreakHandler is no longer needed. |
| 668 builder.breakTargets.remove(target); | 668 builder.breakTargets.remove(target); |
| 669 builder.currentBreakHandler = previous; | 669 builder.currentBreakHandler = previous; |
| 670 } | 670 } |
| 671 | 671 |
| 672 List<SourceString> labels() { | 672 List<LabelElement> labels() { |
| 673 List<SourceString> result = null; | 673 List<LabelElement> result = null; |
| 674 for (LabelElement element in target.labels) { | 674 for (LabelElement element in target.labels) { |
| 675 if (element.isBreakTarget) { | 675 if (element.isBreakTarget) { |
| 676 if (result === null) result = <SourceString>[]; | 676 if (result === null) result = <LabelElement>[]; |
| 677 result.add(element.label.source); | 677 result.add(element); |
| 678 } | 678 } |
| 679 } | 679 } |
| 680 return (result === null) ? const <SourceString>[] : result; | 680 return (result === null) ? const <LabelElement>[] : result; |
| 681 } | 681 } |
| 682 } | 682 } |
| 683 | 683 |
| 684 class SsaBuilder implements Visitor { | 684 class SsaBuilder implements Visitor { |
| 685 final Compiler compiler; | 685 final Compiler compiler; |
| 686 TreeElements elements; | 686 TreeElements elements; |
| 687 final Interceptors interceptors; | 687 final Interceptors interceptors; |
| 688 final WorkItem work; | 688 final WorkItem work; |
| 689 bool methodInterceptionEnabled; | 689 bool methodInterceptionEnabled; |
| 690 HGraph graph; | 690 HGraph graph; |
| 691 LocalsHandler localsHandler; | 691 LocalsHandler localsHandler; |
| 692 HInstruction rethrowableException; | 692 HInstruction rethrowableException; |
| 693 | 693 |
| 694 Map<StatementElement, BreakHandler> breakTargets; | 694 Map<StatementElement, BreakHandler> breakTargets; |
| 695 | 695 |
| 696 // We build the Ssa graph by simulating a stack machine. | 696 // We build the Ssa graph by simulating a stack machine. |
| 697 List<HInstruction> stack; | 697 List<HInstruction> stack; |
| 698 | 698 |
| 699 // The current block to add instructions to. Might be null, if we are | 699 // The current block to add instructions to. Might be null, if we are |
| 700 // visiting dead code. | 700 // visiting dead code. |
| 701 HBasicBlock current; | 701 HBasicBlock current; |
| 702 // The most recently opened block. Has the same value as [current] while | 702 // The most recently opened block. Has the same value as [current] while |
| 703 // the block is open, but unlike [current], it isn't cleared when the current | 703 // the block is open, but unlike [current], it isn't cleared when the current |
| 704 // block is closed. | 704 // block is closed. |
| 705 HBasicBlock lastOpenedBlock; | 705 HBasicBlock lastOpenedBlock; |
| 706 | 706 |
| 707 // Linked list of active break-handlers. Will be removed in the order | 707 // Linked list of active break-handlers. Will be removed in the order |
| 708 // they are added. | 708 // they are added. |
| 709 BreakHandler currentBreakHandler = const NullBreakHandler(); | 709 BreakHandler currentBreakHandler = const NullBreakHandler(); |
| 710 // The break handler to use for an upcoming loop statement (temporarily set | |
| 711 // if a labeled statement is labeling a loop). | |
| 712 BreakHandler loopBreakHandler = null; | |
| 713 | 710 |
| 714 SsaBuilder(Compiler compiler, WorkItem work) | 711 SsaBuilder(Compiler compiler, WorkItem work) |
| 715 : this.compiler = compiler, | 712 : this.compiler = compiler, |
| 716 this.work = work, | 713 this.work = work, |
| 717 interceptors = compiler.builder.interceptors, | 714 interceptors = compiler.builder.interceptors, |
| 718 methodInterceptionEnabled = true, | 715 methodInterceptionEnabled = true, |
| 719 elements = work.resolutionTree, | 716 elements = work.resolutionTree, |
| 720 graph = new HGraph(), | 717 graph = new HGraph(), |
| 721 stack = new List<HInstruction>(), | 718 stack = new List<HInstruction>(), |
| 722 breakTargets = new Map<StatementElement, BreakHandler>() { | 719 breakTargets = new Map<StatementElement, BreakHandler>() { |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 998 } | 995 } |
| 999 | 996 |
| 1000 /** | 997 /** |
| 1001 * Creates a new loop-header block. The previous [current] block | 998 * Creates a new loop-header block. The previous [current] block |
| 1002 * is closed with an [HGoto] and replaced by the newly created block. | 999 * is closed with an [HGoto] and replaced by the newly created block. |
| 1003 * Also notifies the locals handler that we're entering a loop. | 1000 * Also notifies the locals handler that we're entering a loop. |
| 1004 */ | 1001 */ |
| 1005 BreakHandler beginLoopHeader(Node node) { | 1002 BreakHandler beginLoopHeader(Node node) { |
| 1006 assert(!isAborted()); | 1003 assert(!isAborted()); |
| 1007 HBasicBlock previousBlock = close(new HGoto()); | 1004 HBasicBlock previousBlock = close(new HGoto()); |
| 1008 BreakHandler breakHandler = getLoopBreakHandler(node); | 1005 BreakHandler breakHandler = getBreakHandler(node); |
| 1009 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock(breakHandler.labels()); | 1006 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock(breakHandler.labels()); |
| 1010 previousBlock.addSuccessor(loopEntry); | 1007 previousBlock.addSuccessor(loopEntry); |
| 1011 open(loopEntry); | 1008 open(loopEntry); |
| 1012 | 1009 |
| 1013 localsHandler.beginLoopHeader(node, loopEntry); | 1010 localsHandler.beginLoopHeader(node, loopEntry); |
| 1014 return breakHandler; | 1011 return breakHandler; |
| 1015 } | 1012 } |
| 1016 | 1013 |
| 1017 /** | 1014 /** |
| 1018 * Ends the loop: | 1015 * Ends the loop: |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1259 } else if (thenBlock !== null) { | 1256 } else if (thenBlock !== null) { |
| 1260 // The only predecessor is the then branch. | 1257 // The only predecessor is the then branch. |
| 1261 localsHandler = thenLocals; | 1258 localsHandler = thenLocals; |
| 1262 } | 1259 } |
| 1263 } | 1260 } |
| 1264 condition.blockInformation = | 1261 condition.blockInformation = |
| 1265 new HIfBlockInformation(condition, thenGraph, elseGraph, joinBlock); | 1262 new HIfBlockInformation(condition, thenGraph, elseGraph, joinBlock); |
| 1266 } | 1263 } |
| 1267 | 1264 |
| 1268 void visitLogicalAndOr(Send node, Operator op) { | 1265 void visitLogicalAndOr(Send node, Operator op) { |
| 1266 handleLogicalAndOr(() { visit(node.receiver); }, | |
| 1267 () { visit(node.argumentsNode); }, | |
| 1268 isAnd: (const SourceString("&&") == op.source)); | |
| 1269 } | |
| 1270 | |
| 1271 | |
| 1272 void handleLogicalAndOr(void left(), void right(), [bool isAnd = true]) { | |
| 1269 // x && y is transformed into: | 1273 // x && y is transformed into: |
| 1270 // t0 = boolify(x); | 1274 // t0 = boolify(x); |
| 1271 // if (t0) t1 = boolify(y); | 1275 // if (t0) t1 = boolify(y); |
| 1272 // result = phi(t0, t1); | 1276 // result = phi(t0, t1); |
| 1273 // | 1277 // |
| 1274 // x || y is transformed into: | 1278 // x || y is transformed into: |
| 1275 // t0 = boolify(x); | 1279 // t0 = boolify(x); |
| 1276 // if (not(t0)) t1 = boolify(y); | 1280 // if (not(t0)) t1 = boolify(y); |
| 1277 // result = phi(t0, t1); | 1281 // result = phi(t0, t1); |
| 1278 bool isAnd = (const SourceString("&&") == op.source); | 1282 left(); |
| 1279 | |
| 1280 visit(node.receiver); | |
| 1281 HInstruction boolifiedLeft = popBoolified(); | 1283 HInstruction boolifiedLeft = popBoolified(); |
| 1282 HInstruction condition; | 1284 HInstruction condition; |
| 1283 if (isAnd) { | 1285 if (isAnd) { |
| 1284 condition = boolifiedLeft; | 1286 condition = boolifiedLeft; |
| 1285 } else { | 1287 } else { |
| 1286 condition = new HNot(boolifiedLeft); | 1288 condition = new HNot(boolifiedLeft); |
| 1287 add(condition); | 1289 add(condition); |
| 1288 } | 1290 } |
| 1289 HIf branch = new HIf(condition, false); | 1291 HIf branch = new HIf(condition, false); |
| 1290 HBasicBlock leftBlock = close(branch); | 1292 HBasicBlock leftBlock = close(branch); |
| 1291 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 1293 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 1292 | 1294 |
| 1293 HBasicBlock rightBlock = addNewBlock(); | 1295 HBasicBlock rightBlock = addNewBlock(); |
| 1294 leftBlock.addSuccessor(rightBlock); | 1296 leftBlock.addSuccessor(rightBlock); |
| 1295 open(rightBlock); | 1297 open(rightBlock); |
| 1296 visit(node.argumentsNode); | 1298 |
| 1299 right(); | |
| 1297 HInstruction boolifiedRight = popBoolified(); | 1300 HInstruction boolifiedRight = popBoolified(); |
| 1298 SubGraph rightGraph = new SubGraph(rightBlock, current); | 1301 SubGraph rightGraph = new SubGraph(rightBlock, current); |
| 1299 rightBlock = close(new HGoto()); | 1302 rightBlock = close(new HGoto()); |
| 1300 | 1303 |
| 1301 HBasicBlock joinBlock = addNewBlock(); | 1304 HBasicBlock joinBlock = addNewBlock(); |
| 1302 leftBlock.addSuccessor(joinBlock); | 1305 leftBlock.addSuccessor(joinBlock); |
| 1303 rightBlock.addSuccessor(joinBlock); | 1306 rightBlock.addSuccessor(joinBlock); |
| 1304 open(joinBlock); | 1307 open(joinBlock); |
| 1305 | 1308 |
| 1306 branch.blockInformation = | 1309 branch.blockInformation = |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1641 SourceString name = selector.namedArguments[i]; | 1644 SourceString name = selector.namedArguments[i]; |
| 1642 if (name == parameter.name) { | 1645 if (name == parameter.name) { |
| 1643 foundIndex = i; | 1646 foundIndex = i; |
| 1644 break; | 1647 break; |
| 1645 } | 1648 } |
| 1646 } | 1649 } |
| 1647 if (foundIndex != -1) { | 1650 if (foundIndex != -1) { |
| 1648 list.add(namedArguments[foundIndex]); | 1651 list.add(namedArguments[foundIndex]); |
| 1649 } else { | 1652 } else { |
| 1650 Constant constant = compiler.compileVariable(parameter); | 1653 Constant constant = compiler.compileVariable(parameter); |
| 1651 list.add(graph.addConstant(constant)); | 1654 list.add(graph.addConstant(constant)); |
| 1652 } | 1655 } |
| 1653 } | 1656 } |
| 1654 } | 1657 } |
| 1655 } | 1658 } |
| 1656 | 1659 |
| 1657 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { | 1660 void addGenericSendArgumentsToList(Link<Node> link, List<HInstruction> list) { |
| 1658 for (; !link.isEmpty(); link = link.tail) { | 1661 for (; !link.isEmpty(); link = link.tail) { |
| 1659 visit(link.head); | 1662 visit(link.head); |
| 1660 list.add(pop()); | 1663 list.add(pop()); |
| 1661 } | 1664 } |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2113 visitBreakStatement(BreakStatement node) { | 2116 visitBreakStatement(BreakStatement node) { |
| 2114 work.allowSpeculativeOptimization = false; | 2117 work.allowSpeculativeOptimization = false; |
| 2115 assert(!isAborted()); | 2118 assert(!isAborted()); |
| 2116 StatementElement target = elements[node]; | 2119 StatementElement target = elements[node]; |
| 2117 assert(target !== null); | 2120 assert(target !== null); |
| 2118 BreakHandler handler = breakTargets[target]; | 2121 BreakHandler handler = breakTargets[target]; |
| 2119 assert(handler !== null); | 2122 assert(handler !== null); |
| 2120 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | 2123 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
| 2121 HBreak breakInstruction; | 2124 HBreak breakInstruction; |
| 2122 if (node.target === null) { | 2125 if (node.target === null) { |
| 2123 breakInstruction = new HBreak(); | 2126 breakInstruction = new HBreak(target); |
| 2124 } else { | 2127 } else { |
| 2125 breakInstruction = new HBreak(node.target.source); | 2128 LabelElement label = elements[node.target]; |
| 2129 breakInstruction = new HBreak(label); | |
| 2126 } | 2130 } |
| 2127 close(breakInstruction); | 2131 close(breakInstruction); |
| 2128 handler.addBreak(breakInstruction, savedLocals); | 2132 handler.addBreak(breakInstruction, savedLocals); |
| 2129 } | 2133 } |
| 2130 | 2134 |
| 2131 visitContinueStatement(ContinueStatement node) { | 2135 visitContinueStatement(ContinueStatement node) { |
| 2132 // TODO(lrn): Replace this with a real implementation of continue. | 2136 // TODO(lrn): Replace this with a real implementation of continue. |
| 2133 compiler.reportWarning(node, 'continue not implemented'); | 2137 compiler.reportWarning(node, 'continue not implemented'); |
| 2134 generateUnimplemented('continue not implemented'); | 2138 generateUnimplemented('continue not implemented'); |
| 2135 } | 2139 } |
| 2136 | 2140 |
| 2137 BreakHandler getLoopBreakHandler(Node node) { | 2141 BreakHandler getBreakHandler(Node node) { |
| 2138 StatementElement element = elements[node]; | 2142 StatementElement element = elements[node]; |
| 2139 BreakHandler handler; | 2143 if (element === null) return const NullBreakHandler(); |
| 2140 if (loopBreakHandler === null) { | 2144 return new BreakHandler(this, element); |
| 2141 if (element === null) return const NullBreakHandler(); | |
| 2142 handler = new BreakHandler(this, element); | |
| 2143 } else { | |
| 2144 handler = loopBreakHandler; | |
| 2145 loopBreakHandler = null; | |
| 2146 if (element === null) return handler; | |
| 2147 } | |
| 2148 return handler; | |
| 2149 } | 2145 } |
| 2150 | 2146 |
| 2151 visitForInStatement(ForInStatement node) { | 2147 visitForInStatement(ForInStatement node) { |
| 2152 // Generate a structure equivalent to: | 2148 // Generate a structure equivalent to: |
| 2153 // Iterator<E> $iter = <iterable>.iterator() | 2149 // Iterator<E> $iter = <iterable>.iterator() |
| 2154 // while ($iter.hasNext()) { | 2150 // while ($iter.hasNext()) { |
| 2155 // E <declaredIdentifier> = $iter.next(); | 2151 // E <declaredIdentifier> = $iter.next(); |
| 2156 // <body> | 2152 // <body> |
| 2157 // } | 2153 // } |
| 2158 localsHandler.startLoop(node); | 2154 localsHandler.startLoop(node); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2300 visit(node.value); | 2296 visit(node.value); |
| 2301 visit(node.key); | 2297 visit(node.key); |
| 2302 } | 2298 } |
| 2303 | 2299 |
| 2304 visitNamedArgument(NamedArgument node) { | 2300 visitNamedArgument(NamedArgument node) { |
| 2305 visit(node.expression); | 2301 visit(node.expression); |
| 2306 } | 2302 } |
| 2307 | 2303 |
| 2308 visitSwitchStatement(SwitchStatement node) { | 2304 visitSwitchStatement(SwitchStatement node) { |
| 2309 work.allowSpeculativeOptimization = false; | 2305 work.allowSpeculativeOptimization = false; |
| 2306 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | |
| 2307 HBasicBlock startBlock = graph.addNewBlock(); | |
| 2308 goto(current, startBlock); | |
| 2309 open(startBlock); | |
| 2310 visit(node.expression); | 2310 visit(node.expression); |
| 2311 HInstruction expression = pop(); | 2311 HInstruction expression = pop(); |
| 2312 if (node.cases.isEmpty()) { | |
| 2313 return; | |
| 2314 } | |
| 2312 Link<Node> cases = node.cases.nodes; | 2315 Link<Node> cases = node.cases.nodes; |
| 2313 int count = 0; | 2316 |
| 2314 handleThen() { | 2317 BreakHandler breakHandler = getBreakHandler(node); |
| 2315 if (cases.head.statements.nodes.isEmpty()) { | 2318 |
| 2316 compiler.unimplemented('fall-through', node: cases.head); | 2319 buildSwitchCases(cases, expression); |
| 2320 | |
| 2321 HBasicBlock lastBlock = lastOpenedBlock; | |
| 2322 | |
| 2323 // Create merge block for break targets. | |
| 2324 HBasicBlock joinBlock = new HBasicBlock(); | |
| 2325 List<LocalsHandler> caseLocals = <LocalsHandler>[]; | |
| 2326 breakHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | |
| 2327 instruction.block.addSuccessor(joinBlock); | |
| 2328 caseLocals.add(locals); | |
| 2329 }); | |
| 2330 if (!isAborted()) { | |
|
floitsch
2012/03/12 13:46:05
Please add comment when this happens: it's never a
Lasse Reichstein Nielsen
2012/03/13 12:09:38
Done.
| |
| 2331 caseLocals.add(localsHandler); | |
| 2332 } | |
| 2333 if (caseLocals.length != 0) { | |
| 2334 graph.addBlock(joinBlock); | |
| 2335 if (!isAborted()) { | |
| 2336 goto(current, joinBlock); | |
| 2317 } | 2337 } |
| 2318 visit(cases.head.statements); | 2338 open(joinBlock); |
| 2319 cases = cases.tail; | 2339 if (caseLocals.length == 1) { |
| 2340 localsHandler = caseLocals[0]; | |
| 2341 } else { | |
| 2342 localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock); | |
| 2343 } | |
| 2344 } else { | |
| 2345 // The joinblock is not used. | |
| 2346 joinBlock = null; | |
| 2320 } | 2347 } |
| 2321 handleElse() { | 2348 startBlock.labeledBlockInformation = new HLabeledBlockInformation.implicit( |
| 2322 if (cases.isEmpty()) return; | 2349 new SubGraph(startBlock, lastBlock), |
| 2323 if (cases.head.asDefaultCase() !== null) { | 2350 joinBlock, |
| 2324 stack.add(graph.addConstantBool(true)); | 2351 elements[node]); |
| 2325 if (!cases.tail.isEmpty()) { | 2352 } |
| 2326 compiler.unimplemented('default case not last', node: cases.head); | 2353 |
| 2327 } | 2354 |
| 2328 } else { | 2355 // Recursively build an if/else structure to match the cases. |
| 2329 SwitchCase switchCase = cases.head; | 2356 buildSwitchCases(Link<Node> cases, HInstruction expression) { |
| 2330 visit(switchCase.expression); | 2357 SwitchCase node = cases.head; |
| 2331 HInstruction caseExpression = pop(); | 2358 |
| 2359 // Called for the statements on all but the last case block. | |
| 2360 // Ensures that a user expecting a fallthrough gets an error. | |
| 2361 void visitStatementsAndAbort() { | |
| 2362 visit(node.statements); | |
| 2363 if (!isAborted()) { | |
| 2364 compiler.reportWarning(node, 'Missing break at end of switch case'); | |
|
floitsch
2012/03/12 13:46:05
Shouldn't that be caught earlier?
If yes add at le
Lasse Reichstein Nielsen
2012/03/13 12:09:38
How? This is the first time we actually detect whe
| |
| 2365 Element element = | |
| 2366 compiler.findHelper(const SourceString("getFallThroughError")); | |
| 2367 push(new HStatic(element)); | |
| 2368 HInstruction error = new HInvokeStatic( | |
| 2369 Selector.INVOCATION_0, <HInstruction>[pop()]); | |
| 2370 add(error); | |
| 2371 close(new HThrow(error)); | |
| 2372 } | |
| 2373 } | |
| 2374 | |
| 2375 Link<Node> expressions = node.expressions.nodes; | |
| 2376 if (expressions.isEmpty()) { | |
| 2377 // Default case with no expressions. | |
| 2378 if (!node.isDefaultCase) { | |
| 2379 compiler.internalError("Case with no expression and not default"); | |
|
ahe
2012/03/13 10:17:15
Please pass the node.
Lasse Reichstein Nielsen
2012/03/13 12:09:38
Done.
| |
| 2380 } | |
| 2381 visit(node.statements); | |
| 2382 // This must be the final case (otherwise "default" would be invalid), | |
| 2383 // so we don't need to check for fallthrough. | |
| 2384 return; | |
| 2385 } | |
| 2386 | |
| 2387 // Recursively build the test conditions. Leaves the result on the | |
| 2388 // expression stack. | |
| 2389 void buildTests(Link<Node> expressions) { | |
| 2390 // Build comparison for one case expression. | |
| 2391 void left() { | |
| 2332 Element equalsHelper = interceptors.getEqualsInterceptor(); | 2392 Element equalsHelper = interceptors.getEqualsInterceptor(); |
| 2333 HInstruction target = new HStatic(equalsHelper); | 2393 HInstruction target = new HStatic(equalsHelper); |
| 2334 add(target); | 2394 add(target); |
| 2335 push(new HEquals(target, caseExpression, expression)); | 2395 visit(expressions.head); |
| 2396 push(new HEquals(target, pop(), expression)); | |
| 2336 } | 2397 } |
| 2337 handleIf(handleThen, handleElse); | 2398 |
| 2399 // If this is the last expression, just return it. | |
| 2400 if (expressions.tail.isEmpty()) { | |
| 2401 left(); | |
| 2402 return; | |
| 2403 } | |
| 2404 | |
| 2405 void right() { | |
| 2406 buildTests(expressions.tail); | |
| 2407 } | |
| 2408 handleLogicalAndOr(left, right, isAnd: false); | |
| 2338 } | 2409 } |
| 2339 | 2410 |
| 2340 localsHandler.startLoop(node); | 2411 buildTests(expressions); |
| 2341 BreakHandler breakHandler = beginLoopHeader(node); | 2412 HInstruction result = popBoolified(); |
| 2342 HBasicBlock loopEntryBlock = current; | |
| 2343 localsHandler.enterLoopBody(node); | |
| 2344 | 2413 |
| 2345 handleElse(); | 2414 if (node.isDefaultCase) { |
| 2415 // Don't actually use the condition result. | |
| 2416 visitStatementsAndAbort(); | |
| 2417 } else { | |
| 2418 stack.add(result); | |
| 2419 if (cases.tail.isEmpty()) { | |
| 2420 handleIf(() { visit(node.statements); }, null); | |
| 2421 } else { | |
| 2422 handleIf(() { visitStatementsAndAbort(); }, | |
| 2423 () { buildSwitchCases(cases.tail, expression); }); | |
| 2424 } | |
| 2425 } | |
| 2426 } | |
| 2346 | 2427 |
| 2347 if (isAborted()) { | 2428 visitSwitchCase(SwitchCase node) { |
| 2348 compiler.unimplemented("SsaBuilder for loop with aborting body", | 2429 unreachable(); |
|
ahe
2012/03/13 10:17:15
Please make sure to pass in the node to unreachabl
Lasse Reichstein Nielsen
2012/03/13 12:09:38
I dont' think unreachable takes an argument (defin
| |
| 2349 node: node); | |
| 2350 } | |
| 2351 | |
| 2352 HBasicBlock bodyExitBlock = close(new HGoto()); | |
| 2353 HBasicBlock conditionBlock = addNewBlock(); | |
| 2354 bodyExitBlock.addSuccessor(conditionBlock); | |
| 2355 open(conditionBlock); | |
| 2356 stack.add(graph.addConstantBool(false)); | |
| 2357 | |
| 2358 conditionBlock = close(new HLoopBranch(popBoolified(), | |
| 2359 HLoopBranch.DO_WHILE_LOOP)); | |
| 2360 | |
| 2361 conditionBlock.addSuccessor(loopEntryBlock); // The back-edge. | |
| 2362 loopEntryBlock.postProcessLoopHeader(); | |
| 2363 | |
| 2364 endLoop(loopEntryBlock, conditionBlock, breakHandler); | |
| 2365 } | 2430 } |
| 2366 | 2431 |
| 2367 visitTryStatement(TryStatement node) { | 2432 visitTryStatement(TryStatement node) { |
| 2368 work.allowSpeculativeOptimization = false; | 2433 work.allowSpeculativeOptimization = false; |
| 2369 assert(!work.isBailoutVersion()); | 2434 assert(!work.isBailoutVersion()); |
| 2370 HBasicBlock enterBlock = graph.addNewBlock(); | 2435 HBasicBlock enterBlock = graph.addNewBlock(); |
| 2371 close(new HGoto()).addSuccessor(enterBlock); | 2436 close(new HGoto()).addSuccessor(enterBlock); |
| 2372 open(enterBlock); | 2437 open(enterBlock); |
| 2373 HTry tryInstruction = new HTry(); | 2438 HTry tryInstruction = new HTry(); |
| 2374 List<HBasicBlock> blocks = <HBasicBlock>[]; | 2439 List<HBasicBlock> blocks = <HBasicBlock>[]; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2486 // Normally, we would call [close] here. However, then we hit | 2551 // Normally, we would call [close] here. However, then we hit |
| 2487 // another unimplemented feature: aborting loop body. Simply | 2552 // another unimplemented feature: aborting loop body. Simply |
| 2488 // calling [add] does not work as it asserts that the instruction | 2553 // calling [add] does not work as it asserts that the instruction |
| 2489 // isn't a control flow instruction. So we inline parts of [add]. | 2554 // isn't a control flow instruction. So we inline parts of [add]. |
| 2490 current.addAfter(current.last, new HThrow(message)); | 2555 current.addAfter(current.last, new HThrow(message)); |
| 2491 if (isExpression) { | 2556 if (isExpression) { |
| 2492 stack.add(graph.addConstantNull()); | 2557 stack.add(graph.addConstantNull()); |
| 2493 } | 2558 } |
| 2494 } | 2559 } |
| 2495 } | 2560 } |
| OLD | NEW |