| Index: sdk/lib/_internal/compiler/implementation/ssa/builder.dart
|
| diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
|
| index 5275c522e4afb2f63360f01e228616963d3517c6..cab86dd5aa5504f8855e7144bd3a9d0b860804a3 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
|
| @@ -332,8 +332,7 @@ class LocalsHandler {
|
| if (element != null && element.isGenerativeConstructorBody()) {
|
| // The box is passed as a parameter to a generative
|
| // constructor body.
|
| - box = new HParameterValue(scopeData.boxElement);
|
| - builder.add(box);
|
| + box = builder.addParameter(scopeData.boxElement);
|
| } else {
|
| box = createBox();
|
| }
|
| @@ -394,8 +393,7 @@ class LocalsHandler {
|
| FunctionElement functionElement = element;
|
| FunctionSignature params = functionElement.computeSignature(compiler);
|
| params.orderedForEachParameter((Element parameterElement) {
|
| - HInstruction parameter = new HParameterValue(parameterElement);
|
| - builder.add(parameter);
|
| + HInstruction parameter = builder.addParameter(parameterElement);
|
| builder.parameters[parameterElement] = parameter;
|
| directLocals[parameterElement] = parameter;
|
| parameter.guaranteedType =
|
| @@ -665,6 +663,9 @@ class LocalsHandler {
|
| }
|
|
|
| void endLoop(HBasicBlock loopEntry) {
|
| + // If the loop has an aborting body, we don't update the loop
|
| + // phis.
|
| + if (loopEntry.predecessors.length == 1) return;
|
| loopEntry.forEachPhi((HPhi phi) {
|
| Element element = phi.sourceElement;
|
| HInstruction postLoopDefinition = directLocals[element];
|
| @@ -767,6 +768,8 @@ abstract class JumpHandler {
|
| void forEachBreak(void action(HBreak instruction, LocalsHandler locals));
|
| void forEachContinue(void action(HContinue instruction,
|
| LocalsHandler locals));
|
| + bool hasAnyContinue();
|
| + bool hasAnyBreak();
|
| void close();
|
| final TargetElement target;
|
| List<LabelElement> labels();
|
| @@ -791,6 +794,8 @@ class NullJumpHandler implements JumpHandler {
|
| void forEachBreak(Function ignored) { }
|
| void forEachContinue(Function ignored) { }
|
| void close() { }
|
| + bool hasAnyContinue() => false;
|
| + bool hasAnyBreak() => false;
|
|
|
| List<LabelElement> labels() => const <LabelElement>[];
|
| TargetElement get target => null;
|
| @@ -848,6 +853,20 @@ class TargetJumpHandler implements JumpHandler {
|
| }
|
| }
|
|
|
| + bool hasAnyContinue() {
|
| + for (JumpHandlerEntry entry in jumps) {
|
| + if (entry.isContinue()) return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + bool hasAnyBreak() {
|
| + for (JumpHandlerEntry entry in jumps) {
|
| + if (entry.isBreak()) return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| void close() {
|
| // The mapping from TargetElement to JumpHandler is no longer needed.
|
| builder.jumpTargets.remove(target);
|
| @@ -875,6 +894,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| HInstruction rethrowableException;
|
| Map<Element, HInstruction> parameters;
|
| final RuntimeTypeInformation rti;
|
| + HParameterValue lastAddedParameter;
|
|
|
| Map<TargetElement, JumpHandler> jumpTargets;
|
|
|
| @@ -926,6 +946,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| List<InliningState> inliningStack;
|
| Element returnElement;
|
| DartType returnType;
|
| + bool inTryStatement = false;
|
|
|
| void disableMethodInterception() {
|
| assert(methodInterceptionEnabled);
|
| @@ -1017,6 +1038,17 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| return bodyElement;
|
| }
|
|
|
| + HParameterValue addParameter(Element element) {
|
| + HParameterValue result = new HParameterValue(element);
|
| + if (lastAddedParameter == null) {
|
| + graph.entry.addBefore(graph.entry.first, result);
|
| + } else {
|
| + graph.entry.addAfter(lastAddedParameter, result);
|
| + }
|
| + lastAddedParameter = result;
|
| + return result;
|
| + }
|
| +
|
| /**
|
| * Documentation wanted -- johnniwinther
|
| *
|
| @@ -1435,8 +1467,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| if (currentElement.isGenerativeConstructorBody()) {
|
| // A generative constructor body receives extra parameters that
|
| // indicate if a parameter was passed to the factory.
|
| - check = new HParameterValue(checkResultElement);
|
| - add(check);
|
| + check = addParameter(checkResultElement);
|
| } else {
|
| // This is the code we emit for a parameter that is being checked
|
| // on whether it was given at value at the call site:
|
| @@ -1528,8 +1559,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| var enclosing = element.enclosingElement;
|
| if (element.isConstructor() && compiler.world.needsRti(enclosing)) {
|
| enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
|
| - HParameterValue param = new HParameterValue(typeVariable.element);
|
| - add(param);
|
| + HParameterValue param = addParameter(typeVariable.element);
|
| localsHandler.directLocals[typeVariable.element] = param;
|
| });
|
| }
|
| @@ -1715,14 +1745,18 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| HBasicBlock branchBlock,
|
| JumpHandler jumpHandler,
|
| LocalsHandler savedLocals) {
|
| + if (branchBlock == null && !jumpHandler.hasAnyBreak()) return;
|
| +
|
| HBasicBlock loopExitBlock = addNewBlock();
|
| - assert(branchBlock.successors.length == 1);
|
| + assert(branchBlock == null || branchBlock.successors.length == 1);
|
| List<LocalsHandler> breakLocals = <LocalsHandler>[];
|
| jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
|
| breakInstruction.block.addSuccessor(loopExitBlock);
|
| breakLocals.add(locals);
|
| });
|
| - branchBlock.addSuccessor(loopExitBlock);
|
| + if (branchBlock != null) {
|
| + branchBlock.addSuccessor(loopExitBlock);
|
| + }
|
| open(loopExitBlock);
|
| localsHandler.endLoop(loopEntry);
|
| if (!breakLocals.isEmpty) {
|
| @@ -1793,57 +1827,69 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| open(beginBodyBlock);
|
|
|
| localsHandler.enterLoopBody(loop);
|
| - hackAroundPossiblyAbortingBody(loop, body);
|
| + body();
|
| +
|
| + SubGraph bodyGraph = new SubGraph(beginBodyBlock, lastOpenedBlock);
|
| + HBasicBlock bodyBlock = current;
|
| + if (current != null) close(new HGoto());
|
| +
|
| + SubExpression updateGraph;
|
| +
|
| + // Check that the loop has at least one back-edge.
|
| + if (jumpHandler.hasAnyContinue() || bodyBlock != null) {
|
| + // Update.
|
| + // We create an update block, even when we are in a while loop. There the
|
| + // update block is the jump-target for continue statements. We could avoid
|
| + // the creation if there is no continue, but for now we always create it.
|
| + HBasicBlock updateBlock = addNewBlock();
|
| +
|
| + List<LocalsHandler> continueLocals = <LocalsHandler>[];
|
| + jumpHandler.forEachContinue((HContinue instruction,
|
| + LocalsHandler locals) {
|
| + instruction.block.addSuccessor(updateBlock);
|
| + continueLocals.add(locals);
|
| + });
|
|
|
| - SubGraph bodyGraph = new SubGraph(beginBodyBlock, current);
|
| - HBasicBlock bodyBlock = close(new HGoto());
|
|
|
| - // Update.
|
| - // We create an update block, even when we are in a while loop. There the
|
| - // update block is the jump-target for continue statements. We could avoid
|
| - // the creation if there is no continue, but for now we always create it.
|
| - HBasicBlock updateBlock = addNewBlock();
|
| + if (bodyBlock != null) {
|
| + continueLocals.add(localsHandler);
|
| + bodyBlock.addSuccessor(updateBlock);
|
| + }
|
| +
|
| + open(updateBlock);
|
| + localsHandler =
|
| + continueLocals[0].mergeMultiple(continueLocals, updateBlock);
|
| +
|
| + HLabeledBlockInformation labelInfo;
|
| + List<LabelElement> labels = jumpHandler.labels();
|
| + TargetElement target = elements[loop];
|
| + if (!labels.isEmpty) {
|
| + beginBodyBlock.setBlockFlow(
|
| + new HLabeledBlockInformation(
|
| + new HSubGraphBlockInformation(bodyGraph),
|
| + jumpHandler.labels(),
|
| + isContinue: true),
|
| + updateBlock);
|
| + } else if (target != null && target.isContinueTarget) {
|
| + beginBodyBlock.setBlockFlow(
|
| + new HLabeledBlockInformation.implicit(
|
| + new HSubGraphBlockInformation(bodyGraph),
|
| + target,
|
| + isContinue: true),
|
| + updateBlock);
|
| + }
|
| +
|
| + localsHandler.enterLoopUpdates(loop);
|
| +
|
| + update();
|
| +
|
| + HBasicBlock updateEndBlock = close(new HGoto());
|
| + // The back-edge completing the cycle.
|
| + updateEndBlock.addSuccessor(conditionBlock);
|
| + updateGraph = new SubExpression(updateBlock, updateEndBlock);
|
| + }
|
|
|
| - List<LocalsHandler> continueLocals = <LocalsHandler>[];
|
| - jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
|
| - instruction.block.addSuccessor(updateBlock);
|
| - continueLocals.add(locals);
|
| - });
|
| - bodyBlock.addSuccessor(updateBlock);
|
| - continueLocals.add(localsHandler);
|
| -
|
| - open(updateBlock);
|
| -
|
| - localsHandler = localsHandler.mergeMultiple(continueLocals, updateBlock);
|
| -
|
| - HLabeledBlockInformation labelInfo;
|
| - List<LabelElement> labels = jumpHandler.labels();
|
| - TargetElement target = elements[loop];
|
| - if (!labels.isEmpty) {
|
| - beginBodyBlock.setBlockFlow(
|
| - new HLabeledBlockInformation(
|
| - new HSubGraphBlockInformation(bodyGraph),
|
| - jumpHandler.labels(),
|
| - isContinue: true),
|
| - updateBlock);
|
| - } else if (target != null && target.isContinueTarget) {
|
| - beginBodyBlock.setBlockFlow(
|
| - new HLabeledBlockInformation.implicit(
|
| - new HSubGraphBlockInformation(bodyGraph),
|
| - target,
|
| - isContinue: true),
|
| - updateBlock);
|
| - }
|
| -
|
| - localsHandler.enterLoopUpdates(loop);
|
| -
|
| - update();
|
| -
|
| - HBasicBlock updateEndBlock = close(new HGoto());
|
| - // The back-edge completing the cycle.
|
| - updateEndBlock.addSuccessor(conditionBlock);
|
| conditionBlock.postProcessLoopHeader();
|
| - SubExpression updateGraph = new SubExpression(updateBlock, updateEndBlock);
|
|
|
| endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals);
|
| HLoopBlockInformation info =
|
| @@ -1928,51 +1974,71 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| bodyEntryBlock = openNewBlock();
|
| }
|
| localsHandler.enterLoopBody(node);
|
| - hackAroundPossiblyAbortingBody(node, () { visit(node.body); });
|
| + visit(node.body);
|
|
|
| // 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 = close(new HGoto());
|
| - HBasicBlock conditionBlock = addNewBlock();
|
| + HBasicBlock bodyExitBlock;
|
| + bool isAbortingBody = false;
|
| + if (current != null) {
|
| + bodyExitBlock = close(new HGoto());
|
| + } else {
|
| + isAbortingBody = true;
|
| + bodyExitBlock = lastOpenedBlock;
|
| + }
|
|
|
| - List<LocalsHandler> continueLocals = <LocalsHandler>[];
|
| - jumpHandler.forEachContinue((HContinue instruction, LocalsHandler locals) {
|
| - instruction.block.addSuccessor(conditionBlock);
|
| - continueLocals.add(locals);
|
| - });
|
| - bodyExitBlock.addSuccessor(conditionBlock);
|
| - if (!continueLocals.isEmpty) {
|
| - continueLocals.add(localsHandler);
|
| - localsHandler = savedLocals.mergeMultiple(continueLocals, conditionBlock);
|
| - SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
|
| - List<LabelElement> 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);
|
| + SubExpression conditionExpression;
|
| + HBasicBlock conditionEndBlock;
|
| + if (!isAbortingBody || hasContinues) {
|
| + HBasicBlock conditionBlock = addNewBlock();
|
| +
|
| + List<LocalsHandler> continueLocals = <LocalsHandler>[];
|
| + jumpHandler.forEachContinue((HContinue instruction,
|
| + LocalsHandler locals) {
|
| + instruction.block.addSuccessor(conditionBlock);
|
| + continueLocals.add(locals);
|
| + });
|
| +
|
| + if (!isAbortingBody) {
|
| + bodyExitBlock.addSuccessor(conditionBlock);
|
| }
|
| - bodyEntryBlock.setBlockFlow(info, conditionBlock);
|
| - }
|
| - open(conditionBlock);
|
|
|
| - visit(node.condition);
|
| - assert(!isAborted());
|
| - HInstruction conditionInstruction = popBoolified();
|
| - HBasicBlock conditionEndBlock =
|
| - close(new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
|
| + if (!continueLocals.isEmpty) {
|
| + if (!isAbortingBody) continueLocals.add(localsHandler);
|
| + localsHandler =
|
| + savedLocals.mergeMultiple(continueLocals, conditionBlock);
|
| + SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
|
| + List<LabelElement> 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);
|
| +
|
| + visit(node.condition);
|
| + assert(!isAborted());
|
| + HInstruction conditionInstruction = popBoolified();
|
| + conditionEndBlock = close(
|
| + new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
|
| +
|
| + conditionEndBlock.addSuccessor(loopEntryBlock); // The back-edge.
|
| + conditionExpression =
|
| + new SubExpression(conditionBlock, conditionEndBlock);
|
| + }
|
|
|
| - conditionEndBlock.addSuccessor(loopEntryBlock); // The back-edge.
|
| loopEntryBlock.postProcessLoopHeader();
|
|
|
| endLoop(loopEntryBlock, conditionEndBlock, jumpHandler, localsHandler);
|
| jumpHandler.close();
|
|
|
| - SubExpression conditionExpression =
|
| - new SubExpression(conditionBlock, conditionEndBlock);
|
| SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
|
|
|
| HLoopBlockInformation loopBlockInfo =
|
| @@ -2198,7 +2264,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| }
|
|
|
| String getTargetName(ErroneousElement error, [String prefix]) {
|
| - String result = error.targetName.slowToString();
|
| + String result = error.name.slowToString();
|
| if (?prefix) {
|
| result = '$prefix $result';
|
| }
|
| @@ -3007,7 +3073,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| compiler.internalError("Unresolved element: $constructor", node: node);
|
| }
|
| FunctionElement functionElement = constructor;
|
| - constructor = functionElement.defaultImplementation;
|
| + constructor = functionElement.redirectionTarget;
|
| // TODO(5346): Try to avoid the need for calling [declaration] before
|
| // creating an [HStatic].
|
| HInstruction target = new HStatic(constructor.declaration);
|
| @@ -3241,6 +3307,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
|
|
| visitNewExpression(NewExpression node) {
|
| Element element = elements[node.send];
|
| + if (!Elements.isErroneousElement(element)) {
|
| + element = element.redirectionTarget;
|
| + }
|
| if (Elements.isErroneousElement(element)) {
|
| ErroneousElement error = element;
|
| if (error.messageKind == MessageKind.CANNOT_FIND_CONSTRUCTOR) {
|
| @@ -3444,15 +3513,20 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| dup();
|
| }
|
|
|
| + void handleInTryStatement() {
|
| + if (!inTryStatement) return;
|
| + HBasicBlock block = close(new HExitTry());
|
| + HBasicBlock newBlock = graph.addNewBlock();
|
| + block.addSuccessor(newBlock);
|
| + open(newBlock);
|
| + }
|
| +
|
| visitReturn(Return node) {
|
| if (identical(node.getBeginToken().stringValue, 'native')) {
|
| native.handleSsaNative(this, node.expression);
|
| return;
|
| }
|
| - if (node.isRedirectingFactoryBody) {
|
| - compiler.internalError("Unimplemented: Redirecting factory constructor",
|
| - node: node);
|
| - }
|
| + assert(invariant(node, !node.isRedirectingFactoryBody));
|
| HInstruction value;
|
| if (node.expression == null) {
|
| value = graph.addConstantNull(constantSystem);
|
| @@ -3465,6 +3539,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| value = potentiallyCheckType(value, returnType);
|
| }
|
| }
|
| +
|
| + handleInTryStatement();
|
| +
|
| if (!inliningStack.isEmpty) {
|
| localsHandler.updateLocal(returnElement, value);
|
| } else {
|
| @@ -3555,6 +3632,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
|
|
| visitBreakStatement(BreakStatement node) {
|
| assert(!isAborted());
|
| + handleInTryStatement();
|
| TargetElement target = elements[node];
|
| assert(target != null);
|
| JumpHandler handler = jumpTargets[target];
|
| @@ -3568,6 +3646,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| }
|
|
|
| visitContinueStatement(ContinueStatement node) {
|
| + handleInTryStatement();
|
| TargetElement target = elements[node];
|
| assert(target != null);
|
| JumpHandler handler = jumpTargets[target];
|
| @@ -3678,7 +3757,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| JumpHandler handler = new JumpHandler(this, targetElement);
|
| // Introduce a new basic block.
|
| HBasicBlock entryBlock = openNewBlock();
|
| - hackAroundPossiblyAbortingBody(node, () { visit(body); });
|
| + visit(body);
|
| SubGraph bodyGraph = new SubGraph(entryBlock, lastOpenedBlock);
|
|
|
| HBasicBlock joinBlock = graph.addNewBlock();
|
| @@ -4107,6 +4186,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| HBasicBlock enterBlock = openNewBlock();
|
| HTry tryInstruction = new HTry();
|
| close(tryInstruction);
|
| + bool oldInTryStatement = inTryStatement;
|
| + inTryStatement = true;
|
|
|
| HBasicBlock startTryBlock;
|
| HBasicBlock endTryBlock;
|
| @@ -4221,6 +4302,22 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| HBasicBlock exitBlock = graph.addNewBlock();
|
|
|
| addOptionalSuccessor(b1, b2) { if (b2 != null) b1.addSuccessor(b2); }
|
| + addExitTrySuccessor(successor) {
|
| + if (successor == null) return;
|
| + // Iterate over all blocks created inside this try/catch, and
|
| + // attach successor information to blocks that end with
|
| + // [HExitTry].
|
| + for (int i = startTryBlock.id; i < successor.id; i++) {
|
| + HBasicBlock block = graph.blocks[i];
|
| + var last = block.last;
|
| + if (last is HExitTry) {
|
| + block.addSuccessor(successor);
|
| + } else if (last is HTry) {
|
| + // Skip all blocks inside this nested try/catch.
|
| + i = last.joinBlock.id;
|
| + }
|
| + }
|
| + }
|
|
|
| // Setup all successors. The entry block that contains the [HTry]
|
| // has 1) the body, 2) the catch, 3) the finally, and 4) the exit
|
| @@ -4249,6 +4346,12 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| endFinallyBlock.addSuccessor(exitBlock);
|
| }
|
|
|
| + // If a block inside try/catch aborts (eg with a return statement),
|
| + // we explicitely mark this block a predecessor of the catch
|
| + // block and the finally block.
|
| + addExitTrySuccessor(startCatchBlock);
|
| + addExitTrySuccessor(startFinallyBlock);
|
| +
|
| // Use the locals handler not altered by the catch and finally
|
| // blocks.
|
| localsHandler = savedLocals;
|
| @@ -4260,6 +4363,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| wrapStatementGraph(catchGraph),
|
| wrapStatementGraph(finallyGraph)),
|
| exitBlock);
|
| + inTryStatement = oldInTryStatement;
|
| }
|
|
|
| visitScriptTag(ScriptTag node) {
|
| @@ -4290,18 +4394,6 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
|
| if (element == builder.compiler.stringClass) return HType.STRING;
|
| return HType.UNKNOWN;
|
| }
|
| -
|
| - /** HACK HACK HACK */
|
| - void hackAroundPossiblyAbortingBody(Node statement, void body()) {
|
| - visitCondition() {
|
| - stack.add(graph.addConstantBool(true, constantSystem));
|
| - }
|
| - buildBody() {
|
| - // TODO(lrn): Make sure to take continue into account.
|
| - body();
|
| - }
|
| - handleIf(statement, visitCondition, buildBody, null);
|
| - }
|
| }
|
|
|
| /**
|
|
|