Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(957)

Unified Diff: sdk/lib/_internal/compiler/implementation/ssa/builder.dart

Issue 13723002: dart2js: Fix SSA corner case with always breaking loop and failing assert (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 44fcda2919853742d0212712ed0b74c2d8ee2de3..9eed786f2c3068cd6b1905f924133cdde5fcf4c6 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -496,13 +496,17 @@ class LocalsHandler {
}
}
- void beginLoopHeader(Node node, HBasicBlock loopEntry) {
+ /**
+ * Create phis at the loop entry for local variables (ready for the values
+ * from the back edge). Populate the phis with the current values.
+ */
+ void beginLoopHeader(HBasicBlock loopEntry) {
// Create a copy because we modify the map while iterating over it.
- Map<Element, HInstruction> saved =
+ Map<Element, HInstruction> savedDirectLocals =
new LinkedHashMap<Element, HInstruction>.from(directLocals);
// Create phis for all elements in the definitions environment.
- saved.forEach((Element element, HInstruction instruction) {
+ savedDirectLocals.forEach((Element element, HInstruction instruction) {
if (isAccessedDirectly(element)) {
// We know 'this' cannot be modified.
if (!identical(element, closureData.thisElement)) {
@@ -539,6 +543,10 @@ class LocalsHandler {
}
}
+ /**
+ * Goes through the phis created in beginLoopHeader entry and adds the
+ * input from the back edge (from the current value of directLocals) to them.
+ */
void endLoop(HBasicBlock loopEntry) {
// If the loop has an aborting body, we don't update the loop
// phis.
@@ -586,15 +594,16 @@ class LocalsHandler {
}
/**
- * The current localsHandler is not used for its values, only for its
- * declared variables. This is a way to exclude local values from the
- * result when they are no longer in scope.
- * Returns the new LocalsHandler to use (may not be [this]).
+ * When control flow merges, this method can be used to merge several
+ * localsHandlers into a new one using phis. The new localsHandler is
+ * returned. Unless it is also in the list, the current localsHandler is not
+ * used for its values, only for its declared variables. This is a way to
+ * exclude local values from the result when they are no longer in scope.
*/
- LocalsHandler mergeMultiple(List<LocalsHandler> locals,
+ LocalsHandler mergeMultiple(List<LocalsHandler> localsHandlers,
HBasicBlock joinBlock) {
- assert(locals.length > 0);
- if (locals.length == 1) return locals[0];
+ assert(localsHandlers.length > 0);
+ if (localsHandlers.length == 1) return localsHandlers[0];
Map<Element, HInstruction> joinedLocals =
new LinkedHashMap<Element,HInstruction>();
HInstruction thisValue = null;
@@ -610,8 +619,8 @@ class LocalsHandler {
thisValue = instruction;
}
});
- for (LocalsHandler local in locals) {
- local.directLocals.forEach((Element element, HInstruction instruction) {
+ for (LocalsHandler handler in localsHandlers) {
+ handler.directLocals.forEach((Element element, HInstruction instruction) {
HPhi phi = joinedLocals[element];
if (phi != null) {
phi.addInput(instruction);
@@ -1736,7 +1745,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
'length': sourceFile.text.length});
}
return location;
-}
+ }
void visit(Node node) {
if (node != null) node.accept(this);
@@ -1782,37 +1791,56 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
previousBlock.addSuccessor(loopEntry);
open(loopEntry);
- localsHandler.beginLoopHeader(node, loopEntry);
+ localsHandler.beginLoopHeader(loopEntry);
return jumpHandler;
}
/**
* Ends the loop:
- * - creates a new block and adds it as successor to the [branchBlock].
+ * - creates a new block and adds it as successor to the [branchBlock] and
+ * any blocks that end in break.
* - opens the new block (setting as [current]).
* - notifies the locals handler that we're exiting a loop.
+ * [savedLocals] are the locals from the end of the loop condition.
+ * [branchBlock] is the exit (branching) block of the condition. For the
+ * while and for loops this is at the top of the loop. For do-while it is
+ * the end of the body. It is null for degenerate do-while loops that have
+ * no back edge because they abort (throw/return/break in the body and have
+ * no continues).
*/
void endLoop(HBasicBlock loopEntry,
HBasicBlock branchBlock,
JumpHandler jumpHandler,
LocalsHandler savedLocals) {
- if (branchBlock == null && !jumpHandler.hasAnyBreak()) return;
-
HBasicBlock loopExitBlock = addNewBlock();
- assert(branchBlock == null || branchBlock.successors.length == 1);
- List<LocalsHandler> breakLocals = <LocalsHandler>[];
+ List<LocalsHandler> breakHandlers = <LocalsHandler>[];
+ // Collect data for the successors and the phis at each break.
jumpHandler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
breakInstruction.block.addSuccessor(loopExitBlock);
- breakLocals.add(locals);
+ breakHandlers.add(locals);
});
+ // The exit block is a successor of the loop condition if it is reached.
+ // We don't add the successor in the case of a while/for loop that aborts
+ // because the caller of endLoop will be wiring up a special empty else
+ // block instead.
if (branchBlock != null) {
branchBlock.addSuccessor(loopExitBlock);
}
- open(loopExitBlock);
+ // Update the phis at the loop entry with the current values of locals.
localsHandler.endLoop(loopEntry);
- if (!breakLocals.isEmpty) {
- breakLocals.add(savedLocals);
- localsHandler = savedLocals.mergeMultiple(breakLocals, loopExitBlock);
+
+ // Start generating code for the exit block.
+ open(loopExitBlock);
+
+ // Create a new localsHandler for the loopExitBlock with the correct phis.
+ if (!breakHandlers.isEmpty) {
+ if (branchBlock != null) {
+ // Add the values of the locals at the end of the condition block to
+ // the phis. These are the values that flow to the exit if the
+ // condition fails.
+ breakHandlers.add(savedLocals);
+ }
+ localsHandler = savedLocals.mergeMultiple(breakHandlers, loopExitBlock);
} else {
localsHandler = savedLocals;
}
@@ -1870,6 +1898,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
SubExpression conditionExpression =
new SubExpression(conditionBlock, conditionExitBlock);
+ // Save the values of the local variables at the end of the condition
+ // block. These are the values that will flow to the loop exit if the
+ // condition fails.
LocalsHandler savedLocals = new LocalsHandler.from(localsHandler);
// The body.
@@ -1886,30 +1917,30 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
SubExpression updateGraph;
- // Check that the loop has at least one back-edge.
- if (jumpHandler.hasAnyContinue() || bodyBlock != null) {
+ bool loopIsDegenerate = !jumpHandler.hasAnyContinue() && bodyBlock == null;
+ if (!loopIsDegenerate) {
// 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>[];
+ List<LocalsHandler> continueHandlers = <LocalsHandler>[];
jumpHandler.forEachContinue((HContinue instruction,
LocalsHandler locals) {
instruction.block.addSuccessor(updateBlock);
- continueLocals.add(locals);
+ continueHandlers.add(locals);
});
if (bodyBlock != null) {
- continueLocals.add(localsHandler);
+ continueHandlers.add(localsHandler);
bodyBlock.addSuccessor(updateBlock);
}
open(updateBlock);
localsHandler =
- continueLocals[0].mergeMultiple(continueLocals, updateBlock);
+ continueHandlers[0].mergeMultiple(continueHandlers, updateBlock);
HLabeledBlockInformation labelInfo;
List<LabelElement> labels = jumpHandler.labels();
@@ -1938,10 +1969,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
// The back-edge completing the cycle.
updateEndBlock.addSuccessor(conditionBlock);
updateGraph = new SubExpression(updateBlock, updateEndBlock);
- }
- if (jumpHandler.hasAnyContinue() || bodyBlock != null) {
endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals);
+
conditionBlock.postProcessLoopHeader();
HLoopBlockInformation info =
new HLoopBlockInformation(
@@ -1958,7 +1988,8 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
startBlock.setBlockFlow(info, current);
loopInfo.loopBlockInformation = info;
} else {
- // There is no back edge for the loop, so we turn the code into:
+ // The body of the for/while loop always aborts, so there is no back edge.
+ // We turn the code into:
// if (condition) {
// body;
// } else {
@@ -1970,12 +2001,10 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
HBasicBlock elseBlock = addNewBlock();
open(elseBlock);
close(new HGoto());
- endLoop(conditionBlock, null, jumpHandler, savedLocals);
+ // Pass the elseBlock as the branchBlock, because that's the block we go
+ // to just before leaving the 'loop'.
+ endLoop(conditionBlock, elseBlock, jumpHandler, savedLocals);
- // [endLoop] will not create an exit block if there are no
- // breaks.
- if (current == null) open(addNewBlock());
- elseBlock.addSuccessor(current);
SubGraph elseGraph = new SubGraph(elseBlock, elseBlock);
// Remove the loop information attached to the header.
conditionBlock.loopInformation = null;
@@ -2099,25 +2128,25 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
}
SubExpression conditionExpression;
- HBasicBlock conditionEndBlock;
- if (!isAbortingBody || hasContinues) {
+ bool loopIsDegenerate = isAbortingBody && !hasContinues;
+ if (!loopIsDegenerate) {
HBasicBlock conditionBlock = addNewBlock();
- List<LocalsHandler> continueLocals = <LocalsHandler>[];
+ List<LocalsHandler> continueHandlers = <LocalsHandler>[];
jumpHandler.forEachContinue((HContinue instruction,
LocalsHandler locals) {
instruction.block.addSuccessor(conditionBlock);
- continueLocals.add(locals);
+ continueHandlers.add(locals);
});
if (!isAbortingBody) {
bodyExitBlock.addSuccessor(conditionBlock);
}
- if (!continueLocals.isEmpty) {
- if (!isAbortingBody) continueLocals.add(localsHandler);
+ if (!continueHandlers.isEmpty) {
+ if (!isAbortingBody) continueHandlers.add(localsHandler);
localsHandler =
- savedLocals.mergeMultiple(continueLocals, conditionBlock);
+ savedLocals.mergeMultiple(continueHandlers, conditionBlock);
SubGraph bodyGraph = new SubGraph(bodyEntryBlock, bodyExitBlock);
List<LabelElement> labels = jumpHandler.labels();
HSubGraphBlockInformation bodyInfo =
@@ -2137,7 +2166,7 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
visit(node.condition);
assert(!isAborted());
HInstruction conditionInstruction = popBoolified();
- conditionEndBlock = close(
+ HBasicBlock conditionEndBlock = close(
new HLoopBranch(conditionInstruction, HLoopBranch.DO_WHILE_LOOP));
HBasicBlock avoidCriticalEdge = addNewBlock();
@@ -2148,10 +2177,9 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
conditionExpression =
new SubExpression(conditionBlock, conditionEndBlock);
- }
- endLoop(loopEntryBlock, conditionEndBlock, jumpHandler, localsHandler);
- if (!isAbortingBody || hasContinues) {
+ endLoop(loopEntryBlock, conditionEndBlock, jumpHandler, localsHandler);
+
loopEntryBlock.postProcessLoopHeader();
SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock);
HLoopBlockInformation loopBlockInfo =
@@ -2168,13 +2196,17 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
loopEntryBlock.setBlockFlow(loopBlockInfo, current);
loopInfo.loopBlockInformation = loopBlockInfo;
} else {
- // If the loop has no back edge, we remove the loop information
- // on the header.
+ // Since the loop has no back edge, we remove the loop information on the
+ // header.
loopEntryBlock.loopInformation = null;
- // If the body of the loop has any break, we attach a
- // synthesized label to the body.
if (jumpHandler.hasAnyBreak()) {
+ // Null branchBlock because the body of the do-while loop always aborts,
+ // so we never get to the condition.
+ 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);
TargetElement target = elements[node];
LabelElement label = target.addLabel(null, 'loop');
@@ -4077,18 +4109,18 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
SubGraph bodyGraph = new SubGraph(entryBlock, lastOpenedBlock);
HBasicBlock joinBlock = graph.addNewBlock();
- List<LocalsHandler> breakLocals = <LocalsHandler>[];
+ List<LocalsHandler> breakHandlers = <LocalsHandler>[];
handler.forEachBreak((HBreak breakInstruction, LocalsHandler locals) {
breakInstruction.block.addSuccessor(joinBlock);
- breakLocals.add(locals);
+ breakHandlers.add(locals);
});
- bool hasBreak = breakLocals.length > 0;
+ bool hasBreak = breakHandlers.length > 0;
if (!isAborted()) {
goto(current, joinBlock);
- breakLocals.add(localsHandler);
+ breakHandlers.add(localsHandler);
}
open(joinBlock);
- localsHandler = beforeLocals.mergeMultiple(breakLocals, joinBlock);
+ localsHandler = beforeLocals.mergeMultiple(breakHandlers, joinBlock);
if (hasBreak) {
// There was at least one reachable break, so the label is needed.
@@ -4151,25 +4183,25 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
// Create merge block for break targets.
HBasicBlock joinBlock = new HBasicBlock();
- List<LocalsHandler> caseLocals = <LocalsHandler>[];
+ List<LocalsHandler> caseHandlers = <LocalsHandler>[];
jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
instruction.block.addSuccessor(joinBlock);
- caseLocals.add(locals);
+ caseHandlers.add(locals);
});
if (!isAborted()) {
// The current flow is only aborted if the switch has a default that
// aborts (all previous cases must abort, and if there is no default,
// it's possible to miss all the cases).
- caseLocals.add(localsHandler);
+ caseHandlers.add(localsHandler);
goto(current, joinBlock);
}
- if (caseLocals.length != 0) {
+ if (caseHandlers.length != 0) {
graph.addBlock(joinBlock);
open(joinBlock);
- if (caseLocals.length == 1) {
- localsHandler = caseLocals[0];
+ if (caseHandlers.length == 1) {
+ localsHandler = caseHandlers[0];
} else {
- localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock);
+ localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
}
} else {
// The joinblock is not used.
@@ -4290,36 +4322,36 @@ class SsaBuilder extends ResolvedVisitor implements Visitor {
// Add a join-block if necessary.
// We create [joinBlock] early, and then go through the cases that might
// want to jump to it. In each case, if we add [joinBlock] as a successor
- // of another block, we also add an element to [caseLocals] that is used
+ // of another block, we also add an element to [caseHandlers] that is used
// to create the phis in [joinBlock].
- // If we never jump to the join block, [caseLocals] will stay empty, and
+ // If we never jump to the join block, [caseHandlers] will stay empty, and
// the join block is never added to the graph.
HBasicBlock joinBlock = new HBasicBlock();
- List<LocalsHandler> caseLocals = <LocalsHandler>[];
+ List<LocalsHandler> caseHandlers = <LocalsHandler>[];
jumpHandler.forEachBreak((HBreak instruction, LocalsHandler locals) {
instruction.block.addSuccessor(joinBlock);
- caseLocals.add(locals);
+ caseHandlers.add(locals);
});
if (!isAborted()) {
current.close(new HGoto());
lastOpenedBlock.addSuccessor(joinBlock);
- caseLocals.add(localsHandler);
+ caseHandlers.add(localsHandler);
}
if (!hasDefault) {
// The current flow is only aborted if the switch has a default that
// aborts (all previous cases must abort, and if there is no default,
// it's possible to miss all the cases).
expressionEnd.addSuccessor(joinBlock);
- caseLocals.add(savedLocals);
+ caseHandlers.add(savedLocals);
}
- assert(caseLocals.length == joinBlock.predecessors.length);
- if (caseLocals.length != 0) {
+ assert(caseHandlers.length == joinBlock.predecessors.length);
+ if (caseHandlers.length != 0) {
graph.addBlock(joinBlock);
open(joinBlock);
- if (caseLocals.length == 1) {
- localsHandler = caseLocals[0];
+ if (caseHandlers.length == 1) {
+ localsHandler = caseHandlers[0];
} else {
- localsHandler = savedLocals.mergeMultiple(caseLocals, joinBlock);
+ localsHandler = savedLocals.mergeMultiple(caseHandlers, joinBlock);
}
} else {
// The joinblock is not used.
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/ssa/nodes.dart » ('j') | tests/language/inlined_throw_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698