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 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 void enterLoopBody(Node node) { | 526 void enterLoopBody(Node node) { |
| 527 ClosureScope scopeData = closureData.capturingScopes[node]; | 527 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 528 if (scopeData == null) return; | 528 if (scopeData == null) return; |
| 529 // If there are no declared boxed loop variables then we did not create the | 529 // If there are no declared boxed loop variables then we did not create the |
| 530 // box before the initializer and we have to create the box now. | 530 // box before the initializer and we have to create the box now. |
| 531 if (!scopeData.hasBoxedLoopVariables()) { | 531 if (!scopeData.hasBoxedLoopVariables()) { |
| 532 enterScope(node, null); | 532 enterScope(node, null); |
| 533 } | 533 } |
| 534 } | 534 } |
| 535 | 535 |
| 536 void enterLoopUpdates(Loop node) { | 536 void enterLoopUpdates(Node node) { |
| 537 // If there are declared boxed loop variables then the updates might have | 537 // If there are declared boxed loop variables then the updates might have |
| 538 // access to the box and we must switch to a new box before executing the | 538 // access to the box and we must switch to a new box before executing the |
| 539 // updates. | 539 // updates. |
| 540 // In all other cases a new box will be created when entering the body of | 540 // In all other cases a new box will be created when entering the body of |
| 541 // the next iteration. | 541 // the next iteration. |
| 542 ClosureScope scopeData = closureData.capturingScopes[node]; | 542 ClosureScope scopeData = closureData.capturingScopes[node]; |
| 543 if (scopeData == null) return; | 543 if (scopeData == null) return; |
| 544 if (scopeData.hasBoxedLoopVariables()) { | 544 if (scopeData.hasBoxedLoopVariables()) { |
| 545 updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables); | 545 updateCaptureBox(scopeData.boxElement, scopeData.boxedLoopVariables); |
| 546 } | 546 } |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 729 builder.close(breakInstruction); | 729 builder.close(breakInstruction); |
| 730 jumps.add(new JumpHandlerEntry(breakInstruction, locals)); | 730 jumps.add(new JumpHandlerEntry(breakInstruction, locals)); |
| 731 } | 731 } |
| 732 | 732 |
| 733 void generateContinue([LabelElement label]) { | 733 void generateContinue([LabelElement label]) { |
| 734 HInstruction continueInstruction; | 734 HInstruction continueInstruction; |
| 735 if (label == null) { | 735 if (label == null) { |
| 736 continueInstruction = new HContinue(target); | 736 continueInstruction = new HContinue(target); |
| 737 } else { | 737 } else { |
| 738 continueInstruction = new HContinue.toLabel(label); | 738 continueInstruction = new HContinue.toLabel(label); |
| 739 // Switch case continue statements must be handled by the | |
| 740 // [SwitchCaseJumpHandler]. | |
| 741 assert(label.target.statement is! SwitchCase); | |
| 739 } | 742 } |
| 740 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | 743 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
| 741 builder.close(continueInstruction); | 744 builder.close(continueInstruction); |
| 742 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | 745 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); |
| 743 } | 746 } |
| 744 | 747 |
| 745 void forEachBreak(Function action) { | 748 void forEachBreak(Function action) { |
| 746 for (JumpHandlerEntry entry in jumps) { | 749 for (JumpHandlerEntry entry in jumps) { |
| 747 if (entry.isBreak()) action(entry.jumpInstruction, entry.locals); | 750 if (entry.isBreak()) action(entry.jumpInstruction, entry.locals); |
| 748 } | 751 } |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 776 List<LabelElement> labels() { | 779 List<LabelElement> labels() { |
| 777 List<LabelElement> result = null; | 780 List<LabelElement> result = null; |
| 778 for (LabelElement element in target.labels) { | 781 for (LabelElement element in target.labels) { |
| 779 if (result == null) result = <LabelElement>[]; | 782 if (result == null) result = <LabelElement>[]; |
| 780 result.add(element); | 783 result.add(element); |
| 781 } | 784 } |
| 782 return (result == null) ? const <LabelElement>[] : result; | 785 return (result == null) ? const <LabelElement>[] : result; |
| 783 } | 786 } |
| 784 } | 787 } |
| 785 | 788 |
| 789 /// Special [JumpHandler] implementation used to handle continue statements | |
| 790 /// targeting switch cases. | |
| 791 class SwitchCaseJumpHandler extends TargetJumpHandler { | |
| 792 /// Map from switch case targets to indices used to encode the flow of the | |
| 793 /// switch case loop. | |
| 794 final Map<TargetElement, int> targetIndexMap = new Map<TargetElement, int>(); | |
| 795 | |
| 796 SwitchCaseJumpHandler(SsaBuilder builder, | |
| 797 TargetElement target, | |
| 798 SwitchStatement node) | |
| 799 : super(builder, target) { | |
| 800 // The switch case indices must match those computed in | |
| 801 // [SsaBuilder.buildSwitchCaseConstants]. | |
| 802 // Switch indices are 1-based so we can bypass the synthetic loop when no | |
| 803 // cases match simply by branching on the index (which defaults to null). | |
| 804 int switchIndex = 1; | |
| 805 for (SwitchCase switchCase in node.cases) { | |
| 806 for (Node labelOrCase in switchCase.labelsAndCases) { | |
| 807 Node label = labelOrCase.asLabel(); | |
| 808 if (label != null) { | |
| 809 LabelElement labelElement = builder.elements[label]; | |
| 810 if (labelElement != null && labelElement.isContinueTarget) { | |
| 811 TargetElement continueTarget = labelElement.target; | |
| 812 targetIndexMap[continueTarget] = switchIndex; | |
| 813 assert(builder.jumpTargets[continueTarget] == null); | |
| 814 builder.jumpTargets[continueTarget] = this; | |
| 815 } | |
| 816 } | |
| 817 } | |
| 818 switchIndex++; | |
| 819 } | |
| 820 } | |
| 821 | |
| 822 void generateBreak([LabelElement label]) { | |
| 823 if (label == null) { | |
| 824 // Creates a special break instruction for the synthetic loop generated | |
| 825 // for a switch statement with continue statements. See | |
| 826 // [SsaBuilder.buildComplexSwitchStatement] for detail. | |
| 827 | |
| 828 HInstruction breakInstruction = | |
| 829 new HBreak(target, breakSwitchContinueLoop: true); | |
| 830 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
| 831 builder.close(breakInstruction); | |
| 832 jumps.add(new JumpHandlerEntry(breakInstruction, locals)); | |
| 833 } else { | |
| 834 super.generateBreak(label); | |
| 835 } | |
| 836 } | |
| 837 | |
| 838 bool isContinueToSwitchCase(LabelElement label) { | |
| 839 return label != null && targetIndexMap.containsKey(label.target); | |
| 840 } | |
| 841 | |
| 842 void generateContinue([LabelElement label]) { | |
| 843 if (isContinueToSwitchCase(label)) { | |
| 844 // Creates the special instructions 'label = i; continue l;' used in | |
| 845 // switch statements with continue statements. See | |
| 846 // [SsaBuilder.buildComplexSwitchStatement] for detail. | |
| 847 | |
| 848 assert(label != null); | |
| 849 HInstruction value = builder.graph.addConstantInt( | |
| 850 targetIndexMap[label.target], | |
| 851 builder.constantSystem); | |
| 852 builder.localsHandler.updateLocal(target, value); | |
| 853 | |
| 854 assert(label.target.labels.contains(label)); | |
| 855 HInstruction continueInstruction = new HContinue(target); | |
| 856 LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); | |
| 857 builder.close(continueInstruction); | |
| 858 jumps.add(new JumpHandlerEntry(continueInstruction, locals)); | |
| 859 } else { | |
| 860 super.generateContinue(label); | |
| 861 } | |
| 862 } | |
| 863 | |
| 864 void close() { | |
| 865 // The mapping from TargetElement to JumpHandler is no longer needed. | |
| 866 for (TargetElement target in targetIndexMap.keys) { | |
| 867 builder.jumpTargets.remove(target); | |
| 868 } | |
| 869 super.close(); | |
| 870 } | |
| 871 } | |
| 872 | |
| 786 class SsaBuilder extends ResolvedVisitor implements Visitor { | 873 class SsaBuilder extends ResolvedVisitor implements Visitor { |
| 787 final SsaBuilderTask builder; | 874 final SsaBuilderTask builder; |
| 788 final JavaScriptBackend backend; | 875 final JavaScriptBackend backend; |
| 789 final CodegenWorkItem work; | 876 final CodegenWorkItem work; |
| 790 final ConstantSystem constantSystem; | 877 final ConstantSystem constantSystem; |
| 791 HGraph graph; | 878 HGraph graph; |
| 792 LocalsHandler localsHandler; | 879 LocalsHandler localsHandler; |
| 793 HInstruction rethrowableException; | 880 HInstruction rethrowableException; |
| 794 Map<Element, HInstruction> parameters; | 881 Map<Element, HInstruction> parameters; |
| 795 final RuntimeTypes rti; | 882 final RuntimeTypes rti; |
| (...skipping 1101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1897 | 1984 |
| 1898 /** | 1985 /** |
| 1899 * Creates a new loop-header block. The previous [current] block | 1986 * Creates a new loop-header block. The previous [current] block |
| 1900 * is closed with an [HGoto] and replaced by the newly created block. | 1987 * is closed with an [HGoto] and replaced by the newly created block. |
| 1901 * Also notifies the locals handler that we're entering a loop. | 1988 * Also notifies the locals handler that we're entering a loop. |
| 1902 */ | 1989 */ |
| 1903 JumpHandler beginLoopHeader(Node node) { | 1990 JumpHandler beginLoopHeader(Node node) { |
| 1904 assert(!isAborted()); | 1991 assert(!isAborted()); |
| 1905 HBasicBlock previousBlock = close(new HGoto()); | 1992 HBasicBlock previousBlock = close(new HGoto()); |
| 1906 | 1993 |
| 1907 JumpHandler jumpHandler = createJumpHandler(node); | 1994 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); |
| 1908 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock( | 1995 HBasicBlock loopEntry = graph.addNewLoopHeaderBlock( |
| 1909 jumpHandler.target, | 1996 jumpHandler.target, |
| 1910 jumpHandler.labels()); | 1997 jumpHandler.labels()); |
| 1911 previousBlock.addSuccessor(loopEntry); | 1998 previousBlock.addSuccessor(loopEntry); |
| 1912 open(loopEntry); | 1999 open(loopEntry); |
| 1913 | 2000 |
| 1914 localsHandler.beginLoopHeader(loopEntry); | 2001 localsHandler.beginLoopHeader(loopEntry); |
| 1915 return jumpHandler; | 2002 return jumpHandler; |
| 1916 } | 2003 } |
| 1917 | 2004 |
| (...skipping 2200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4118 LabelElement label = elements[node.target]; | 4205 LabelElement label = elements[node.target]; |
| 4119 assert(label != null); | 4206 assert(label != null); |
| 4120 handler.generateContinue(label); | 4207 handler.generateContinue(label); |
| 4121 } | 4208 } |
| 4122 } | 4209 } |
| 4123 | 4210 |
| 4124 /** | 4211 /** |
| 4125 * Creates a [JumpHandler] for a statement. The node must be a jump | 4212 * Creates a [JumpHandler] for a statement. The node must be a jump |
| 4126 * target. If there are no breaks or continues targeting the statement, | 4213 * target. If there are no breaks or continues targeting the statement, |
| 4127 * a special "null handler" is returned. | 4214 * a special "null handler" is returned. |
| 4215 * | |
| 4216 * [isLoopJump] is [:true:] when the jump handler is for a loop. This is used | |
| 4217 * to distinguish the synthetized loop created for a switch statement with | |
| 4218 * continue statements from simple switch statements. | |
| 4128 */ | 4219 */ |
| 4129 JumpHandler createJumpHandler(Statement node) { | 4220 JumpHandler createJumpHandler(Statement node, {bool isLoopJump}) { |
| 4130 TargetElement element = elements[node]; | 4221 TargetElement element = elements[node]; |
| 4131 if (element == null || !identical(element.statement, node)) { | 4222 if (element == null || !identical(element.statement, node)) { |
| 4132 // No breaks or continues to this node. | 4223 // No breaks or continues to this node. |
| 4133 return new NullJumpHandler(compiler); | 4224 return new NullJumpHandler(compiler); |
| 4134 } | 4225 } |
| 4226 if (isLoopJump && node is SwitchStatement) { | |
| 4227 // Create a special jump handler for loops created for switch statements | |
| 4228 // with continue statements. | |
| 4229 return new SwitchCaseJumpHandler(this, element, node); | |
| 4230 } | |
| 4135 return new JumpHandler(this, element); | 4231 return new JumpHandler(this, element); |
| 4136 } | 4232 } |
| 4137 | 4233 |
| 4138 visitForIn(ForIn node) { | 4234 visitForIn(ForIn node) { |
| 4139 // Generate a structure equivalent to: | 4235 // Generate a structure equivalent to: |
| 4140 // Iterator<E> $iter = <iterable>.iterator; | 4236 // Iterator<E> $iter = <iterable>.iterator; |
| 4141 // while ($iter.moveNext()) { | 4237 // while ($iter.moveNext()) { |
| 4142 // E <declaredIdentifier> = $iter.current; | 4238 // E <declaredIdentifier> = $iter.current; |
| 4143 // <body> | 4239 // <body> |
| 4144 // } | 4240 // } |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4263 | 4359 |
| 4264 visitLiteralMapEntry(LiteralMapEntry node) { | 4360 visitLiteralMapEntry(LiteralMapEntry node) { |
| 4265 visit(node.value); | 4361 visit(node.value); |
| 4266 visit(node.key); | 4362 visit(node.key); |
| 4267 } | 4363 } |
| 4268 | 4364 |
| 4269 visitNamedArgument(NamedArgument node) { | 4365 visitNamedArgument(NamedArgument node) { |
| 4270 visit(node.expression); | 4366 visit(node.expression); |
| 4271 } | 4367 } |
| 4272 | 4368 |
| 4273 visitSwitchStatement(SwitchStatement node) { | 4369 Map<CaseMatch,Constant> buildSwitchCaseConstants(SwitchStatement node) { |
| 4274 if (tryBuildConstantSwitch(node)) return; | |
| 4275 | |
| 4276 LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); | |
| 4277 HBasicBlock startBlock = openNewBlock(); | |
| 4278 visit(node.expression); | |
| 4279 HInstruction expression = pop(); | |
| 4280 if (node.cases.isEmpty) { | |
| 4281 return; | |
| 4282 } | |
| 4283 | |
| 4284 Link<Node> cases = node.cases.nodes; | |
| 4285 JumpHandler jumpHandler = createJumpHandler(node); | |
| 4286 | |
| 4287 buildSwitchCases(cases, expression); | |
| 4288 | |
| 4289 HBasicBlock lastBlock = lastOpenedBlock; | |
| 4290 | |
| 4291 // Create merge block for break targets. | |
| 4292 HBasicBlock joinBlock = new HBasicBlock(); | |
| 4293 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; | |
| 4294 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | |
| 4295 instruction.block.addSuccessor(joinBlock); | |
| 4296 caseHandlers.add(locals); | |
| 4297 }); | |
| 4298 if (!isAborted()) { | |
| 4299 // The current flow is only aborted if the switch has a default that | |
| 4300 // aborts (all previous cases must abort, and if there is no default, | |
| 4301 // it's possible to miss all the cases). | |
| 4302 caseHandlers.add(localsHandler); | |
| 4303 goto(current, joinBlock); | |
| 4304 } | |
| 4305 if (caseHandlers.length != 0) { | |
| 4306 graph.addBlock(joinBlock); | |
| 4307 open(joinBlock); | |
| 4308 if (caseHandlers.length == 1) { | |
| 4309 localsHandler = caseHandlers[0]; | |
| 4310 } else { | |
| 4311 localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock); | |
| 4312 } | |
| 4313 } else { | |
| 4314 // The joinblock is not used. | |
| 4315 joinBlock = null; | |
| 4316 } | |
| 4317 startBlock.setBlockFlow( | |
| 4318 new HLabeledBlockInformation.implicit( | |
| 4319 new HSubGraphBlockInformation(new SubGraph(startBlock, lastBlock)), | |
| 4320 elements[node]), | |
| 4321 joinBlock); | |
| 4322 jumpHandler.close(); | |
| 4323 } | |
| 4324 | |
| 4325 bool tryBuildConstantSwitch(SwitchStatement node) { | |
| 4326 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); | 4370 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); |
| 4327 // First check whether all case expressions are compile-time constants, | 4371 // First check whether all case expressions are compile-time constants, |
| 4328 // and all have the same type that doesn't override operator==. | 4372 // and all have the same type that doesn't override operator==. |
| 4329 // TODO(lrn): Move the constant resolution to the resolver, so | 4373 // TODO(lrn): Move the constant resolution to the resolver, so |
| 4330 // we can report an error before reaching the backend. | 4374 // we can report an error before reaching the backend. |
| 4331 DartType firstConstantType = null; | 4375 DartType firstConstantType = null; |
| 4332 bool failure = false; | 4376 bool failure = false; |
| 4333 for (SwitchCase switchCase in node.cases) { | 4377 for (SwitchCase switchCase in node.cases) { |
| 4334 for (Node labelOrCase in switchCase.labelsAndCases) { | 4378 for (Node labelOrCase in switchCase.labelsAndCases) { |
| 4335 if (labelOrCase is CaseMatch) { | 4379 if (labelOrCase is CaseMatch) { |
| 4336 CaseMatch match = labelOrCase; | 4380 CaseMatch match = labelOrCase; |
| 4337 Constant constant = | 4381 Constant constant = |
| 4338 compiler.constantHandler.tryCompileNodeWithDefinitions( | 4382 compiler.constantHandler.compileNodeWithDefinitions( |
| 4339 match.expression, elements); | 4383 match.expression, elements, isConst: true); |
| 4340 if (constant == null) { | |
| 4341 compiler.reportWarning(match.expression, | |
| 4342 MessageKind.NOT_A_COMPILE_TIME_CONSTANT.error()); | |
| 4343 failure = true; | |
| 4344 continue; | |
| 4345 } | |
| 4346 if (firstConstantType == null) { | 4384 if (firstConstantType == null) { |
| 4347 firstConstantType = constant.computeType(compiler); | 4385 firstConstantType = constant.computeType(compiler); |
| 4348 if (nonPrimitiveTypeOverridesEquals(constant)) { | 4386 if (nonPrimitiveTypeOverridesEquals(constant)) { |
| 4349 compiler.reportWarning(match.expression, | 4387 compiler.reportError(match.expression, |
| 4350 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error()); | 4388 MessageKind.SWITCH_CASE_VALUE_OVERRIDES_EQUALS.error()); |
| 4351 failure = true; | 4389 failure = true; |
| 4352 } | 4390 } |
| 4353 } else { | 4391 } else { |
| 4354 DartType constantType = | 4392 DartType constantType = |
| 4355 constant.computeType(compiler); | 4393 constant.computeType(compiler); |
| 4356 if (constantType != firstConstantType) { | 4394 if (constantType != firstConstantType) { |
| 4357 compiler.reportWarning(match.expression, | 4395 compiler.reportError(match.expression, |
| 4358 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error()); | 4396 MessageKind.SWITCH_CASE_TYPES_NOT_EQUAL.error()); |
| 4359 failure = true; | 4397 failure = true; |
| 4360 } | 4398 } |
| 4361 } | 4399 } |
| 4362 constants[labelOrCase] = constant; | 4400 constants[labelOrCase] = constant; |
| 4363 } else { | 4401 } |
| 4364 compiler.reportWarning(node, "Unsupported: Labels on cases"); | 4402 } |
| 4365 failure = true; | 4403 } |
| 4366 } | 4404 return constants; |
| 4367 } | 4405 } |
| 4368 } | 4406 |
| 4369 if (failure) { | 4407 visitSwitchStatement(SwitchStatement node) { |
| 4370 return false; | 4408 Map<CaseMatch,Constant> constants = buildSwitchCaseConstants(node); |
| 4371 } | 4409 |
| 4410 // The switch case indices must match those computed in | |
| 4411 // [SwitchCaseJumpHandler]. | |
| 4412 bool hasContinue = false; | |
| 4413 Map<SwitchCase, int> caseIndex = new Map<SwitchCase, int>(); | |
| 4414 int switchIndex = 1; | |
| 4415 bool hasDefault = false; | |
| 4416 for (SwitchCase switchCase in node.cases) { | |
| 4417 for (Node labelOrCase in switchCase.labelsAndCases) { | |
| 4418 Node label = labelOrCase.asLabel(); | |
| 4419 if (label != null) { | |
| 4420 LabelElement labelElement = elements[label]; | |
| 4421 if (labelElement != null && labelElement.isContinueTarget) { | |
| 4422 hasContinue = true; | |
| 4423 } | |
| 4424 } | |
| 4425 } | |
| 4426 if (switchCase.isDefaultCase) { | |
| 4427 hasDefault = true; | |
| 4428 } | |
| 4429 caseIndex[switchCase] = switchIndex; | |
| 4430 switchIndex++; | |
| 4431 } | |
| 4432 if (!hasContinue) { | |
| 4433 // If the switch statement has no switch cases targeted by continue | |
| 4434 // statements we encode the switch statement directly. | |
| 4435 buildSimpleSwitchStatement(node, constants); | |
| 4436 } else { | |
| 4437 buildComplexSwitchStatement(node, constants, caseIndex, hasDefault); | |
| 4438 } | |
| 4439 } | |
| 4440 | |
| 4441 /** | |
| 4442 * Builds a simple switch statement which does not handle uses of continue | |
| 4443 * statements to labeled switch cases. | |
| 4444 */ | |
| 4445 void buildSimpleSwitchStatement(SwitchStatement node, | |
| 4446 Map<CaseMatch, Constant> constants) { | |
| 4447 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | |
| 4448 HInstruction buildExpression() { | |
| 4449 visit(node.expression); | |
| 4450 return pop(); | |
| 4451 } | |
| 4452 Iterable<Constant> getConstants(SwitchCase switchCase) { | |
| 4453 List<Constant> constantList = <Constant>[]; | |
| 4454 for (Node labelOrCase in switchCase.labelsAndCases) { | |
| 4455 if (labelOrCase is CaseMatch) { | |
| 4456 constantList.add(constants[labelOrCase]); | |
| 4457 } | |
| 4458 } | |
| 4459 return constantList; | |
| 4460 } | |
| 4461 bool isDefaultCase(SwitchCase switchCase) { | |
| 4462 return switchCase.isDefaultCase; | |
| 4463 } | |
| 4464 void buildSwitchCase(SwitchCase node) { | |
| 4465 visit(node.statements); | |
| 4466 } | |
| 4467 handleSwitch(node, | |
| 4468 jumpHandler, | |
| 4469 buildExpression, | |
| 4470 node.cases, | |
| 4471 getConstants, | |
| 4472 isDefaultCase, | |
| 4473 buildSwitchCase); | |
| 4474 jumpHandler.close(); | |
| 4475 } | |
| 4476 | |
| 4477 /** | |
| 4478 * Builds a switch statement that can handle arbitrary uses of continue | |
| 4479 * statements to labeled switch cases. | |
| 4480 */ | |
| 4481 void buildComplexSwitchStatement(SwitchStatement node, | |
| 4482 Map<CaseMatch, Constant> constants, | |
| 4483 Map<SwitchCase, int> caseIndex, | |
| 4484 bool hasDefault) { | |
| 4485 // If the switch statement has switch cases targeted by continue | |
| 4486 // statements we create the following encoding: | |
| 4487 // | |
| 4488 // switch (e) { | |
| 4489 // l_1: case e0: s_1; break; | |
| 4490 // l_2: case e1: s_2; continue l_i; | |
| 4491 // ... | |
| 4492 // l_n: default: s_n; continue l_j; | |
| 4493 // } | |
| 4494 // | |
| 4495 // is encoded as | |
| 4496 // | |
| 4497 // var target; | |
| 4498 // switch (e) { | |
| 4499 // case e1: target = 1; break; | |
| 4500 // case e2: target = 2; break; | |
| 4501 // ... | |
| 4502 // default: target = n; break; | |
| 4503 // } | |
| 4504 // l: while (true) { | |
| 4505 // switch (target) { | |
| 4506 // case 1: s_1; break l; | |
| 4507 // case 2: s_2; target = i; continue l; | |
| 4508 // ... | |
| 4509 // case n: s_n; target = j; continue l; | |
| 4510 // } | |
| 4511 // } | |
| 4512 | |
| 4513 TargetElement switchTarget = elements[node]; | |
| 4514 HInstruction initialValue = graph.addConstantNull(constantSystem); | |
| 4515 localsHandler.updateLocal(switchTarget, initialValue); | |
| 4516 | |
| 4517 JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: false); | |
| 4518 var switchCases = node.cases; | |
| 4519 if (!hasDefault) { | |
| 4520 // Use [:null:] as the marker for a synthetic default clause. | |
| 4521 // Adding this ensures that the local for [switchTarget] will not be live | |
| 4522 // in the switch expression. | |
|
ngeoffray
2013/05/17 09:00:10
This sentence is not fully correct. The reason we'
Johnni Winther
2013/05/17 09:13:34
Done.
| |
| 4523 switchCases = node.cases.nodes.toList()..add(null); | |
| 4524 } | |
| 4525 HInstruction buildExpression() { | |
| 4526 visit(node.expression); | |
| 4527 return pop(); | |
| 4528 } | |
| 4529 Iterable<Constant> getConstants(SwitchCase switchCase) { | |
| 4530 List<Constant> constantList = <Constant>[]; | |
| 4531 if (switchCase != null) { | |
| 4532 for (Node labelOrCase in switchCase.labelsAndCases) { | |
| 4533 if (labelOrCase is CaseMatch) { | |
| 4534 constantList.add(constants[labelOrCase]); | |
| 4535 } | |
| 4536 } | |
| 4537 } | |
| 4538 return constantList; | |
| 4539 } | |
| 4540 bool isDefaultCase(SwitchCase switchCase) { | |
| 4541 return switchCase == null || switchCase.isDefaultCase; | |
| 4542 } | |
| 4543 void buildSwitchCase(SwitchCase switchCase) { | |
| 4544 if (switchCase != null) { | |
| 4545 // Generate 'target = i; break;' for switch case i. | |
| 4546 int index = caseIndex[switchCase]; | |
| 4547 HInstruction value = graph.addConstantInt(index, constantSystem); | |
| 4548 localsHandler.updateLocal(switchTarget, value); | |
| 4549 } else { | |
| 4550 // Generate synthetic default case 'target = null; break;'. | |
| 4551 HInstruction value = graph.addConstantNull(constantSystem); | |
| 4552 localsHandler.updateLocal(switchTarget, value); | |
| 4553 } | |
| 4554 jumpTargets[switchTarget].generateBreak(); | |
| 4555 } | |
| 4556 handleSwitch(node, | |
| 4557 jumpHandler, | |
| 4558 buildExpression, | |
| 4559 switchCases, | |
| 4560 getConstants, | |
| 4561 isDefaultCase, | |
| 4562 buildSwitchCase); | |
| 4563 jumpHandler.close(); | |
| 4564 | |
| 4565 HInstruction buildCondition() => | |
| 4566 graph.addConstantBool(true, constantSystem); | |
| 4567 | |
| 4568 void buildSwitch() { | |
| 4569 HInstruction buildExpression() { | |
| 4570 return localsHandler.readLocal(switchTarget); | |
| 4571 } | |
| 4572 Iterable<Constant> getConstants(SwitchCase switchCase) { | |
| 4573 return <Constant>[constantSystem.createInt(caseIndex[switchCase])]; | |
| 4574 } | |
| 4575 void buildSwitchCase(SwitchCase switchCase) { | |
| 4576 visit(switchCase.statements); | |
| 4577 if (!isAborted()) { | |
| 4578 // Ensure that we break the loop if the case falls through. (This | |
| 4579 // is only possible for the last case.) | |
| 4580 jumpTargets[switchTarget].generateBreak(); | |
| 4581 } | |
| 4582 } | |
| 4583 // Pass a [NullJumpHandler] because the target for the contained break | |
| 4584 // is not the generated switch statement but instead the loop generated | |
| 4585 // in the call to [handleLoop] below. | |
| 4586 handleSwitch(node, | |
| 4587 new NullJumpHandler(compiler), | |
| 4588 buildExpression, node.cases, getConstants, | |
| 4589 (_) => false, // No case is default. | |
| 4590 buildSwitchCase); | |
| 4591 } | |
| 4592 | |
| 4593 void buildLoop() { | |
| 4594 handleLoop(node, | |
| 4595 () {}, | |
| 4596 buildCondition, | |
| 4597 () {}, | |
| 4598 buildSwitch); | |
| 4599 } | |
| 4600 | |
| 4601 if (hasDefault) { | |
| 4602 buildLoop(); | |
| 4603 } else { | |
| 4604 // If the switch statement has no default case, surround the loop with | |
| 4605 // a test of the target. | |
| 4606 void buildCondition() { | |
| 4607 push(createForeign('#', HType.BOOLEAN, | |
| 4608 [localsHandler.readLocal(switchTarget)])); | |
| 4609 } | |
| 4610 handleIf(node, buildCondition, buildLoop, () => {}); | |
| 4611 } | |
| 4612 } | |
| 4613 | |
| 4614 /** | |
| 4615 * Creates a switch statement. | |
| 4616 * | |
| 4617 * [jumpHandler] is the [JumpHandler] for the created switch statement. | |
| 4618 * [buildExpression] creates the switch expression. | |
| 4619 * [switchCases] must be either an [Iterable] of [SwitchCase] nodes or | |
| 4620 * a [Link] or a [NodeList] of [SwitchCase] nodes. | |
| 4621 * [getConstants] returns the set of constants for a switch case. | |
| 4622 * [isDefaultCase] returns [:true:] if the provided switch case should be | |
| 4623 * considered default for the created switch statement. | |
| 4624 * [buildSwitchCase] creates the statements for the switch case. | |
| 4625 */ | |
| 4626 void handleSwitch(Node errorNode, | |
| 4627 JumpHandler jumpHandler, | |
| 4628 HInstruction buildExpression(), | |
| 4629 var switchCases, | |
| 4630 Iterable<Constant> getConstants(SwitchCase switchCase), | |
| 4631 bool isDefaultCase(SwitchCase switchCase), | |
| 4632 void buildSwitchCase(SwitchCase switchCase)) { | |
| 4633 Map<CaseMatch, Constant> constants = new Map<CaseMatch, Constant>(); | |
| 4372 | 4634 |
| 4373 // TODO(ngeoffray): Handle switch-instruction in bailout code. | 4635 // TODO(ngeoffray): Handle switch-instruction in bailout code. |
| 4374 work.allowSpeculativeOptimization = false; | 4636 work.allowSpeculativeOptimization = false; |
| 4375 // Then build a switch structure. | 4637 // Then build a switch structure. |
| 4376 HBasicBlock expressionStart = openNewBlock(); | 4638 HBasicBlock expressionStart = openNewBlock(); |
| 4377 visit(node.expression); | 4639 HInstruction expression = buildExpression(); |
| 4378 HInstruction expression = pop(); | 4640 if (switchCases.isEmpty) { |
| 4379 if (node.cases.isEmpty) { | 4641 return; |
| 4380 return true; | |
| 4381 } | 4642 } |
| 4382 HBasicBlock expressionEnd = current; | 4643 HBasicBlock expressionEnd = current; |
| 4383 | 4644 |
| 4384 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); | 4645 HSwitch switchInstruction = new HSwitch(<HInstruction>[expression]); |
| 4385 HBasicBlock expressionBlock = close(switchInstruction); | 4646 HBasicBlock expressionBlock = close(switchInstruction); |
| 4386 JumpHandler jumpHandler = createJumpHandler(node); | |
| 4387 LocalsHandler savedLocals = localsHandler; | 4647 LocalsHandler savedLocals = localsHandler; |
| 4388 | 4648 |
| 4389 List<List<Constant>> matchExpressions = <List<Constant>>[]; | 4649 List<List<Constant>> matchExpressions = <List<Constant>>[]; |
| 4390 List<HStatementInformation> statements = <HStatementInformation>[]; | 4650 List<HStatementInformation> statements = <HStatementInformation>[]; |
| 4391 bool hasDefault = false; | 4651 bool hasDefault = false; |
| 4392 Element getFallThroughErrorElement = backend.getFallThroughError(); | 4652 Element getFallThroughErrorElement = backend.getFallThroughError(); |
| 4393 HasNextIterator<Node> caseIterator = | 4653 HasNextIterator<Node> caseIterator = |
| 4394 new HasNextIterator<Node>(node.cases.iterator); | 4654 new HasNextIterator<Node>(switchCases.iterator); |
| 4395 while (caseIterator.hasNext) { | 4655 while (caseIterator.hasNext) { |
| 4396 SwitchCase switchCase = caseIterator.next(); | 4656 SwitchCase switchCase = caseIterator.next(); |
| 4397 List<Constant> caseConstants = <Constant>[]; | 4657 List<Constant> caseConstants = <Constant>[]; |
| 4398 HBasicBlock block = graph.addNewBlock(); | 4658 HBasicBlock block = graph.addNewBlock(); |
| 4399 for (Node labelOrCase in switchCase.labelsAndCases) { | 4659 for (Constant constant in getConstants(switchCase)) { |
| 4400 if (labelOrCase is CaseMatch) { | 4660 caseConstants.add(constant); |
| 4401 Constant constant = constants[labelOrCase]; | 4661 HConstant hConstant = graph.addConstant(constant); |
| 4402 caseConstants.add(constant); | 4662 switchInstruction.inputs.add(hConstant); |
| 4403 HConstant hConstant = graph.addConstant(constant); | 4663 hConstant.usedBy.add(switchInstruction); |
| 4404 switchInstruction.inputs.add(hConstant); | 4664 expressionBlock.addSuccessor(block); |
| 4405 hConstant.usedBy.add(switchInstruction); | |
| 4406 expressionBlock.addSuccessor(block); | |
| 4407 } | |
| 4408 } | 4665 } |
| 4409 matchExpressions.add(caseConstants); | 4666 matchExpressions.add(caseConstants); |
| 4410 | 4667 |
| 4411 if (switchCase.isDefaultCase) { | 4668 if (isDefaultCase(switchCase)) { |
| 4412 // An HSwitch has n inputs and n+1 successors, the last being the | 4669 // An HSwitch has n inputs and n+1 successors, the last being the |
| 4413 // default case. | 4670 // default case. |
| 4414 expressionBlock.addSuccessor(block); | 4671 expressionBlock.addSuccessor(block); |
| 4415 hasDefault = true; | 4672 hasDefault = true; |
| 4416 } | 4673 } |
| 4417 open(block); | 4674 open(block); |
| 4418 localsHandler = new LocalsHandler.from(savedLocals); | 4675 localsHandler = new LocalsHandler.from(savedLocals); |
| 4419 visit(switchCase.statements); | 4676 buildSwitchCase(switchCase); |
| 4420 if (!isAborted() && caseIterator.hasNext) { | 4677 if (!isAborted() && caseIterator.hasNext) { |
| 4421 pushInvokeHelper0(getFallThroughErrorElement, HType.UNKNOWN); | 4678 pushInvokeHelper0(getFallThroughErrorElement, HType.UNKNOWN); |
| 4422 HInstruction error = pop(); | 4679 HInstruction error = pop(); |
| 4423 closeAndGotoExit(new HThrow(error)); | 4680 closeAndGotoExit(new HThrow(error)); |
| 4424 } | 4681 } |
| 4425 statements.add( | 4682 statements.add( |
| 4426 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); | 4683 new HSubGraphBlockInformation(new SubGraph(block, lastOpenedBlock))); |
| 4427 } | 4684 } |
| 4428 | 4685 |
| 4429 // Add a join-block if necessary. | 4686 // Add a join-block if necessary. |
| 4430 // We create [joinBlock] early, and then go through the cases that might | 4687 // We create [joinBlock] early, and then go through the cases that might |
| 4431 // want to jump to it. In each case, if we add [joinBlock] as a successor | 4688 // want to jump to it. In each case, if we add [joinBlock] as a successor |
| 4432 // of another block, we also add an element to [caseHandlers] that is used | 4689 // of another block, we also add an element to [caseHandlers] that is used |
| 4433 // to create the phis in [joinBlock]. | 4690 // to create the phis in [joinBlock]. |
| 4434 // If we never jump to the join block, [caseHandlers] will stay empty, and | 4691 // If we never jump to the join block, [caseHandlers] will stay empty, and |
| 4435 // the join block is never added to the graph. | 4692 // the join block is never added to the graph. |
| 4436 HBasicBlock joinBlock = new HBasicBlock(); | 4693 HBasicBlock joinBlock = new HBasicBlock(); |
| 4437 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; | 4694 List<LocalsHandler> caseHandlers = <LocalsHandler>[]; |
| 4438 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { | 4695 jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) { |
| 4439 instruction.block.addSuccessor(joinBlock); | 4696 instruction.block.addSuccessor(joinBlock); |
| 4440 caseHandlers.add(locals); | 4697 caseHandlers.add(locals); |
| 4441 }); | 4698 }); |
| 4699 jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) { | |
| 4700 assert(invariant(errorNode, false, | |
| 4701 message: 'Continue cannot target a switch.')); | |
| 4702 }); | |
| 4442 if (!isAborted()) { | 4703 if (!isAborted()) { |
| 4443 current.close(new HGoto()); | 4704 current.close(new HGoto()); |
| 4444 lastOpenedBlock.addSuccessor(joinBlock); | 4705 lastOpenedBlock.addSuccessor(joinBlock); |
| 4445 caseHandlers.add(localsHandler); | 4706 caseHandlers.add(localsHandler); |
| 4446 } | 4707 } |
| 4447 if (!hasDefault) { | 4708 if (!hasDefault) { |
| 4448 // The current flow is only aborted if the switch has a default that | 4709 // The current flow is only aborted if the switch has a default that |
| 4449 // aborts (all previous cases must abort, and if there is no default, | 4710 // aborts (all previous cases must abort, and if there is no default, |
| 4450 // it's possible to miss all the cases). | 4711 // it's possible to miss all the cases). |
| 4451 expressionEnd.addSuccessor(joinBlock); | 4712 expressionEnd.addSuccessor(joinBlock); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 4471 expressionStart.setBlockFlow( | 4732 expressionStart.setBlockFlow( |
| 4472 new HSwitchBlockInformation(expressionInfo, | 4733 new HSwitchBlockInformation(expressionInfo, |
| 4473 matchExpressions, | 4734 matchExpressions, |
| 4474 statements, | 4735 statements, |
| 4475 hasDefault, | 4736 hasDefault, |
| 4476 jumpHandler.target, | 4737 jumpHandler.target, |
| 4477 jumpHandler.labels()), | 4738 jumpHandler.labels()), |
| 4478 joinBlock); | 4739 joinBlock); |
| 4479 | 4740 |
| 4480 jumpHandler.close(); | 4741 jumpHandler.close(); |
| 4481 return true; | |
| 4482 } | 4742 } |
| 4483 | 4743 |
| 4484 bool nonPrimitiveTypeOverridesEquals(Constant constant) { | 4744 bool nonPrimitiveTypeOverridesEquals(Constant constant) { |
| 4485 // Function values override equals. Even static ones, since | 4745 // Function values override equals. Even static ones, since |
| 4486 // they inherit from [Function]. | 4746 // they inherit from [Function]. |
| 4487 if (constant.isFunction()) return true; | 4747 if (constant.isFunction()) return true; |
| 4488 | 4748 |
| 4489 // [Map] and [List] do not override equals. | 4749 // [Map] and [List] do not override equals. |
| 4490 // If constant is primitive, just return false. We know | 4750 // If constant is primitive, just return false. We know |
| 4491 // about the equals methods of num/String classes. | 4751 // about the equals methods of num/String classes. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 4509 // If the operator== declaration is in Object, it's not overridden. | 4769 // If the operator== declaration is in Object, it's not overridden. |
| 4510 return (operatorEq.getEnclosingClass() != compiler.objectClass); | 4770 return (operatorEq.getEnclosingClass() != compiler.objectClass); |
| 4511 } | 4771 } |
| 4512 | 4772 |
| 4513 Element lookupOperator(ClassElement classElement, SourceString operatorName) { | 4773 Element lookupOperator(ClassElement classElement, SourceString operatorName) { |
| 4514 SourceString dartMethodName = | 4774 SourceString dartMethodName = |
| 4515 Elements.constructOperatorName(operatorName, false); | 4775 Elements.constructOperatorName(operatorName, false); |
| 4516 return classElement.lookupMember(dartMethodName); | 4776 return classElement.lookupMember(dartMethodName); |
| 4517 } | 4777 } |
| 4518 | 4778 |
| 4519 | |
| 4520 // Recursively build an if/else structure to match the cases. | |
| 4521 void buildSwitchCases(Link<Node> cases, HInstruction expression, | |
| 4522 [int encounteredCaseTypes = 0]) { | |
| 4523 final int NO_TYPE = 0; | |
| 4524 final int INT_TYPE = 1; | |
| 4525 final int STRING_TYPE = 2; | |
| 4526 final int CONFLICT_TYPE = 3; | |
| 4527 int combine(int type1, int type2) => type1 | type2; | |
| 4528 | |
| 4529 SwitchCase node = cases.head; | |
| 4530 // Called for the statements on all but the last case block. | |
| 4531 // Ensures that a user expecting a fallthrough gets an error. | |
| 4532 void visitStatementsAndAbort() { | |
| 4533 visit(node.statements); | |
| 4534 if (!isAborted()) { | |
| 4535 compiler.reportWarning(node, 'Missing break at end of switch case'); | |
| 4536 Element element = | |
| 4537 compiler.findHelper(const SourceString("getFallThroughError")); | |
| 4538 pushInvokeHelper0(element, HType.UNKNOWN); | |
| 4539 HInstruction error = pop(); | |
| 4540 closeAndGotoExit(new HThrow(error)); | |
| 4541 } | |
| 4542 } | |
| 4543 | |
| 4544 Link<Node> skipLabels(Link<Node> labelsAndCases) { | |
| 4545 while (!labelsAndCases.isEmpty && labelsAndCases.head is Label) { | |
| 4546 labelsAndCases = labelsAndCases.tail; | |
| 4547 } | |
| 4548 return labelsAndCases; | |
| 4549 } | |
| 4550 | |
| 4551 Link<Node> labelsAndCases = skipLabels(node.labelsAndCases.nodes); | |
| 4552 if (labelsAndCases.isEmpty) { | |
| 4553 // Default case with no expressions. | |
| 4554 if (!node.isDefaultCase) { | |
| 4555 compiler.internalError("Case with no expression and not default", | |
| 4556 node: node); | |
| 4557 } | |
| 4558 visit(node.statements); | |
| 4559 // This must be the final case (otherwise "default" would be invalid), | |
| 4560 // so we don't need to check for fallthrough. | |
| 4561 return; | |
| 4562 } | |
| 4563 | |
| 4564 // Recursively build the test conditions. Leaves the result on the | |
| 4565 // expression stack. | |
| 4566 void buildTests(Link<Node> remainingCases) { | |
| 4567 // Build comparison for one case expression. | |
| 4568 void left() { | |
| 4569 CaseMatch match = remainingCases.head; | |
| 4570 // TODO(lrn): Move the constant resolution to the resolver, so | |
| 4571 // we can report an error before reaching the backend. | |
| 4572 Constant constant = | |
| 4573 compiler.constantHandler.tryCompileNodeWithDefinitions( | |
| 4574 match.expression, elements); | |
| 4575 if (constant != null) { | |
| 4576 stack.add(graph.addConstant(constant)); | |
| 4577 } else { | |
| 4578 visit(match.expression); | |
| 4579 } | |
| 4580 push(new HIdentity(pop(), expression)); | |
| 4581 } | |
| 4582 | |
| 4583 // If this is the last expression, just return it. | |
| 4584 Link<Node> tail = skipLabels(remainingCases.tail); | |
| 4585 if (tail.isEmpty) { | |
| 4586 left(); | |
| 4587 return; | |
| 4588 } | |
| 4589 | |
| 4590 void right() { | |
| 4591 buildTests(tail); | |
| 4592 } | |
| 4593 SsaBranchBuilder branchBuilder = | |
| 4594 new SsaBranchBuilder(this, remainingCases.head); | |
| 4595 branchBuilder.handleLogicalAndOr(left, right, isAnd: false); | |
| 4596 } | |
| 4597 | |
| 4598 if (node.isDefaultCase) { | |
| 4599 // Default case must be last. | |
| 4600 assert(cases.tail.isEmpty); | |
| 4601 // Perform the tests until one of them match, but then always execute the | |
| 4602 // statements. | |
| 4603 // TODO(lrn): Stop performing tests when all expressions are compile-time | |
| 4604 // constant strings or integers. | |
| 4605 handleIf(node, () { buildTests(labelsAndCases); }, (){}, null); | |
| 4606 visit(node.statements); | |
| 4607 } else { | |
| 4608 if (cases.tail.isEmpty) { | |
| 4609 handleIf(node, | |
| 4610 () { buildTests(labelsAndCases); }, | |
| 4611 () { visit(node.statements); }, | |
| 4612 null); | |
| 4613 } else { | |
| 4614 handleIf(node, | |
| 4615 () { buildTests(labelsAndCases); }, | |
| 4616 () { visitStatementsAndAbort(); }, | |
| 4617 () { buildSwitchCases(cases.tail, expression, | |
| 4618 encounteredCaseTypes); }); | |
| 4619 } | |
| 4620 } | |
| 4621 } | |
| 4622 | |
| 4623 visitSwitchCase(SwitchCase node) { | 4779 visitSwitchCase(SwitchCase node) { |
| 4624 compiler.internalError('SsaBuilder.visitSwitchCase'); | 4780 compiler.internalError('SsaBuilder.visitSwitchCase'); |
| 4625 } | 4781 } |
| 4626 | 4782 |
| 4627 visitCaseMatch(CaseMatch node) { | 4783 visitCaseMatch(CaseMatch node) { |
| 4628 compiler.internalError('SsaBuilder.visitCaseMatch'); | 4784 compiler.internalError('SsaBuilder.visitCaseMatch'); |
| 4629 } | 4785 } |
| 4630 | 4786 |
| 4631 visitTryStatement(TryStatement node) { | 4787 visitTryStatement(TryStatement node) { |
| 4632 work.allowSpeculativeOptimization = false; | 4788 work.allowSpeculativeOptimization = false; |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5277 new HSubGraphBlockInformation(elseBranch.graph)); | 5433 new HSubGraphBlockInformation(elseBranch.graph)); |
| 5278 | 5434 |
| 5279 HBasicBlock conditionStartBlock = conditionBranch.block; | 5435 HBasicBlock conditionStartBlock = conditionBranch.block; |
| 5280 conditionStartBlock.setBlockFlow(info, joinBlock); | 5436 conditionStartBlock.setBlockFlow(info, joinBlock); |
| 5281 SubGraph conditionGraph = conditionBranch.graph; | 5437 SubGraph conditionGraph = conditionBranch.graph; |
| 5282 HIf branch = conditionGraph.end.last; | 5438 HIf branch = conditionGraph.end.last; |
| 5283 assert(branch is HIf); | 5439 assert(branch is HIf); |
| 5284 branch.blockInformation = conditionStartBlock.blockFlow; | 5440 branch.blockInformation = conditionStartBlock.blockFlow; |
| 5285 } | 5441 } |
| 5286 } | 5442 } |
| OLD | NEW |