| Index: pkg/compiler/lib/src/ssa/builder_kernel.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
|
| index 1fc734fbda894d51b84ccc2690c7aa5bc998cf17..4dabdefd8bebe4ce7f2035f5e583f95dcf80f901 100644
|
| --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
|
| +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
|
| @@ -234,8 +234,7 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
|
| addParameter(typeParamElement, commonMasks.nonNullType);
|
| // This is a little bit wacky (and n^2) until we make the localsHandler
|
| // take Kernel DartTypes instead of just the AST DartTypes.
|
| - var typeVariableType = clsElement
|
| - .typeVariables
|
| + var typeVariableType = clsElement.typeVariables
|
| .firstWhere((TypeVariableType i) => i.name == typeParameter.name);
|
| localsHandler.directLocals[
|
| localsHandler.getTypeVariableAsLocal(typeVariableType)] = param;
|
| @@ -783,6 +782,146 @@ class KernelSsaBuilder extends ir.Visitor with GraphBuilder {
|
| }
|
|
|
| @override
|
| + visitDoStatement(ir.DoStatement doStatement) {
|
| + // TODO(efortuna): I think this can be rewritten using
|
| + // LoopHandler.handleLoop with some tricks about when the "update" happens.
|
| + LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
|
| + localsHandler.startLoop(astAdapter.getNode(doStatement));
|
| + JumpHandler jumpHandler = loopHandler.beginLoopHeader(doStatement);
|
| + HLoopInformation loopInfo = current.loopInformation;
|
| + HBasicBlock loopEntryBlock = current;
|
| + HBasicBlock bodyEntryBlock = current;
|
| + JumpTarget target =
|
| + elements.getTargetDefinition(astAdapter.getNode(doStatement));
|
| + bool hasContinues = target != null && target.isContinueTarget;
|
| + if (hasContinues) {
|
| + // Add extra block to hang labels on.
|
| + // It doesn't currently work if they are on the same block as the
|
| + // HLoopInfo. The handling of HLabeledBlockInformation will visit a
|
| + // SubGraph that starts at the same block again, so the HLoopInfo is
|
| + // either handled twice, or it's handled after the labeled block info,
|
| + // both of which generate the wrong code.
|
| + // Using a separate block is just a simple workaround.
|
| + bodyEntryBlock = openNewBlock();
|
| + }
|
| + localsHandler.enterLoopBody(astAdapter.getNode(doStatement));
|
| + doStatement.body.accept(this);
|
| +
|
| + // If there are no continues we could avoid the creation of the condition
|
| + // block. This could also lead to a block having multiple entries and exits.
|
| + HBasicBlock bodyExitBlock;
|
| + bool isAbortingBody = false;
|
| + if (current != null) {
|
| + bodyExitBlock = close(new HGoto());
|
| + } else {
|
| + isAbortingBody = true;
|
| + bodyExitBlock = lastOpenedBlock;
|
| + }
|
| +
|
| + SubExpression conditionExpression;
|
| + bool loopIsDegenerate = isAbortingBody && !hasContinues;
|
| + if (!loopIsDegenerate) {
|
| + HBasicBlock conditionBlock = addNewBlock();
|
| +
|
| + List<LocalsHandler> continueHandlers = <LocalsHandler>[];
|
| + jumpHandler
|
| + .forEachContinue((HContinue instruction, LocalsHandler locals) {
|
| + instruction.block.addSuccessor(conditionBlock);
|
| + continueHandlers.add(locals);
|
| + });
|
| +
|
| + if (!isAbortingBody) {
|
| + bodyExitBlock.addSuccessor(conditionBlock);
|
| + }
|
| +
|
| + if (!continueHandlers.isEmpty) {
|
| + if (!isAbortingBody) continueHandlers.add(localsHandler);
|
| + localsHandler =
|
| + savedLocals.mergeMultiple(continueHandlers, conditionBlock);
|
| + SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
|
| + List<LabelDefinition> labels = jumpHandler.labels;
|
| + HSubGraphBlockInformation bodyInfo =
|
| + new HSubGraphBlockInformation(bodyGraph);
|
| + HLabeledBlockInformation info;
|
| + if (!labels.isEmpty) {
|
| + info =
|
| + new HLabeledBlockInformation(bodyInfo, labels, isContinue: true);
|
| + } else {
|
| + info = new HLabeledBlockInformation.implicit(bodyInfo, target,
|
| + isContinue: true);
|
| + }
|
| + bodyEntryBlock.setBlockFlow(info, conditionBlock);
|
| + }
|
| + open(conditionBlock);
|
| +
|
| + doStatement.condition.accept(this);
|
| + assert(!isAborted());
|
| + HInstruction conditionInstruction = popBoolified();
|
| + HBasicBlock conditionEndBlock = close(
|
| + new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
|
| +
|
| + HBasicBlock avoidCriticalEdge = addNewBlock();
|
| + conditionEndBlock.addSuccessor(avoidCriticalEdge);
|
| + open(avoidCriticalEdge);
|
| + close(new HGoto());
|
| + avoidCriticalEdge.addSuccessor(loopEntryBlock); // The back-edge.
|
| +
|
| + conditionExpression =
|
| + new SubExpression(conditionBlock, conditionEndBlock);
|
| +
|
| + // Avoid a critical edge from the condition to the loop-exit body.
|
| + HBasicBlock conditionExitBlock = addNewBlock();
|
| + open(conditionExitBlock);
|
| + close(new HGoto());
|
| + conditionEndBlock.addSuccessor(conditionExitBlock);
|
| +
|
| + loopHandler.endLoop(
|
| + loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler);
|
| +
|
| + loopEntryBlock.postProcessLoopHeader();
|
| + SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock);
|
| + HLoopBlockInformation loopBlockInfo = new HLoopBlockInformation(
|
| + HLoopBlockInformation.DO_WHILE_LOOP,
|
| + null,
|
| + wrapExpressionGraph(conditionExpression),
|
| + wrapStatementGraph(bodyGraph),
|
| + null,
|
| + loopEntryBlock.loopInformation.target,
|
| + loopEntryBlock.loopInformation.labels,
|
| + sourceInformationBuilder.buildLoop(astAdapter.getNode(doStatement)));
|
| + loopEntryBlock.setBlockFlow(loopBlockInfo, current);
|
| + loopInfo.loopBlockInformation = loopBlockInfo;
|
| + } else {
|
| + // Since the loop has no back edge, we remove the loop information on the
|
| + // header.
|
| + loopEntryBlock.loopInformation = null;
|
| +
|
| + if (jumpHandler.hasAnyBreak()) {
|
| + // Null branchBlock because the body of the do-while loop always aborts,
|
| + // so we never get to the condition.
|
| + loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler);
|
| +
|
| + // Since the body of the loop has a break, we attach a synthesized label
|
| + // to the body.
|
| + SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
|
| + JumpTarget target =
|
| + elements.getTargetDefinition(astAdapter.getNode(doStatement));
|
| + LabelDefinition label = target.addLabel(null, 'loop');
|
| + label.setBreakTarget();
|
| + HLabeledBlockInformation info = new HLabeledBlockInformation(
|
| + new HSubGraphBlockInformation(bodyGraph), <LabelDefinition>[label]);
|
| + loopEntryBlock.setBlockFlow(info, current);
|
| + jumpHandler.forEachBreak((HBreak breakInstruction, _) {
|
| + HBasicBlock block = breakInstruction.block;
|
| + block.addAtExit(new HBreak.toLabel(label));
|
| + block.remove(breakInstruction);
|
| + });
|
| + }
|
| + }
|
| + jumpHandler.close();
|
| + }
|
| +
|
| + @override
|
| void visitIfStatement(ir.IfStatement ifStatement) {
|
| handleIf(
|
| visitCondition: () => ifStatement.condition.accept(this),
|
|
|