Index: pkg/compiler/lib/src/ssa/builder.dart |
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart |
index bf008a2c8506abdd389af5c5a701b6c0c935968e..91266f3a12d44855e451896e058146a215e10708 100644 |
--- a/pkg/compiler/lib/src/ssa/builder.dart |
+++ b/pkg/compiler/lib/src/ssa/builder.dart |
@@ -40,7 +40,9 @@ import '../util/util.dart'; |
import '../world.dart' show ClassWorld; |
import 'graph_builder.dart'; |
+import 'jump_handler.dart'; |
import 'locals_handler.dart'; |
+import 'loop_handler.dart'; |
import 'nodes.dart'; |
import 'optimize.dart'; |
import 'ssa_branch_builder.dart'; |
@@ -125,226 +127,6 @@ class SsaBuilderTask extends CompilerTask { |
} |
} |
-// Represents a single break/continue instruction. |
-class JumpHandlerEntry { |
- final HJump jumpInstruction; |
- final LocalsHandler locals; |
- bool isBreak() => jumpInstruction is HBreak; |
- bool isContinue() => jumpInstruction is HContinue; |
- JumpHandlerEntry(this.jumpInstruction, this.locals); |
-} |
- |
-abstract class JumpHandler { |
- factory JumpHandler(SsaBuilder builder, JumpTarget target) { |
- return new TargetJumpHandler(builder, target); |
- } |
- void generateBreak([LabelDefinition label]); |
- void generateContinue([LabelDefinition label]); |
- void forEachBreak(void action(HBreak instruction, LocalsHandler locals)); |
- void forEachContinue( |
- void action(HContinue instruction, LocalsHandler locals)); |
- bool hasAnyContinue(); |
- bool hasAnyBreak(); |
- void close(); |
- final JumpTarget target; |
- List<LabelDefinition> labels(); |
-} |
- |
-// Insert break handler used to avoid null checks when a target isn't |
-// used as the target of a break, and therefore doesn't need a break |
-// handler associated with it. |
-class NullJumpHandler implements JumpHandler { |
- final DiagnosticReporter reporter; |
- |
- NullJumpHandler(this.reporter); |
- |
- void generateBreak([LabelDefinition label]) { |
- reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
- 'NullJumpHandler.generateBreak should not be called.'); |
- } |
- |
- void generateContinue([LabelDefinition label]) { |
- reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
- 'NullJumpHandler.generateContinue should not be called.'); |
- } |
- |
- void forEachBreak(Function ignored) {} |
- void forEachContinue(Function ignored) {} |
- void close() {} |
- bool hasAnyContinue() => false; |
- bool hasAnyBreak() => false; |
- |
- List<LabelDefinition> labels() => const <LabelDefinition>[]; |
- JumpTarget get target => null; |
-} |
- |
-// Records breaks until a target block is available. |
-// Breaks are always forward jumps. |
-// Continues in loops are implemented as breaks of the body. |
-// Continues in switches is currently not handled. |
-class TargetJumpHandler implements JumpHandler { |
- final SsaBuilder builder; |
- final JumpTarget target; |
- final List<JumpHandlerEntry> jumps; |
- |
- TargetJumpHandler(SsaBuilder builder, this.target) |
- : this.builder = builder, |
- jumps = <JumpHandlerEntry>[] { |
- assert(builder.jumpTargets[target] == null); |
- builder.jumpTargets[target] = this; |
- } |
- |
- void generateBreak([LabelDefinition label]) { |
- HInstruction breakInstruction; |
- if (label == null) { |
- breakInstruction = new HBreak(target); |
- } else { |
- breakInstruction = new HBreak.toLabel(label); |
- } |
- LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
- builder.close(breakInstruction); |
- jumps.add(new JumpHandlerEntry(breakInstruction, locals)); |
- } |
- |
- void generateContinue([LabelDefinition label]) { |
- HInstruction continueInstruction; |
- if (label == null) { |
- continueInstruction = new HContinue(target); |
- } else { |
- continueInstruction = new HContinue.toLabel(label); |
- // Switch case continue statements must be handled by the |
- // [SwitchCaseJumpHandler]. |
- assert(label.target.statement is! ast.SwitchCase); |
- } |
- LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
- builder.close(continueInstruction); |
- jumps.add(new JumpHandlerEntry(continueInstruction, locals)); |
- } |
- |
- void forEachBreak(Function action) { |
- for (JumpHandlerEntry entry in jumps) { |
- if (entry.isBreak()) action(entry.jumpInstruction, entry.locals); |
- } |
- } |
- |
- void forEachContinue(Function action) { |
- for (JumpHandlerEntry entry in jumps) { |
- if (entry.isContinue()) action(entry.jumpInstruction, entry.locals); |
- } |
- } |
- |
- 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); |
- } |
- |
- List<LabelDefinition> labels() { |
- List<LabelDefinition> result = null; |
- for (LabelDefinition element in target.labels) { |
- if (result == null) result = <LabelDefinition>[]; |
- result.add(element); |
- } |
- return (result == null) ? const <LabelDefinition>[] : result; |
- } |
-} |
- |
-/// Special [JumpHandler] implementation used to handle continue statements |
-/// targeting switch cases. |
-class SwitchCaseJumpHandler extends TargetJumpHandler { |
- /// Map from switch case targets to indices used to encode the flow of the |
- /// switch case loop. |
- final Map<JumpTarget, int> targetIndexMap = new Map<JumpTarget, int>(); |
- |
- SwitchCaseJumpHandler( |
- SsaBuilder builder, JumpTarget target, ast.SwitchStatement node) |
- : super(builder, target) { |
- // The switch case indices must match those computed in |
- // [SsaFromAstMixin.buildSwitchCaseConstants]. |
- // Switch indices are 1-based so we can bypass the synthetic loop when no |
- // cases match simply by branching on the index (which defaults to null). |
- int switchIndex = 1; |
- for (ast.SwitchCase switchCase in node.cases) { |
- for (ast.Node labelOrCase in switchCase.labelsAndCases) { |
- ast.Node label = labelOrCase.asLabel(); |
- if (label != null) { |
- LabelDefinition labelElement = |
- builder.elements.getLabelDefinition(label); |
- if (labelElement != null && labelElement.isContinueTarget) { |
- JumpTarget continueTarget = labelElement.target; |
- targetIndexMap[continueTarget] = switchIndex; |
- assert(builder.jumpTargets[continueTarget] == null); |
- builder.jumpTargets[continueTarget] = this; |
- } |
- } |
- } |
- switchIndex++; |
- } |
- } |
- |
- void generateBreak([LabelDefinition label]) { |
- if (label == null) { |
- // Creates a special break instruction for the synthetic loop generated |
- // for a switch statement with continue statements. See |
- // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. |
- |
- HInstruction breakInstruction = |
- new HBreak(target, breakSwitchContinueLoop: true); |
- LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
- builder.close(breakInstruction); |
- jumps.add(new JumpHandlerEntry(breakInstruction, locals)); |
- } else { |
- super.generateBreak(label); |
- } |
- } |
- |
- bool isContinueToSwitchCase(LabelDefinition label) { |
- return label != null && targetIndexMap.containsKey(label.target); |
- } |
- |
- void generateContinue([LabelDefinition label]) { |
- if (isContinueToSwitchCase(label)) { |
- // Creates the special instructions 'label = i; continue l;' used in |
- // switch statements with continue statements. See |
- // [SsaFromAstMixin.buildComplexSwitchStatement] for detail. |
- |
- assert(label != null); |
- HInstruction value = builder.graph |
- .addConstantInt(targetIndexMap[label.target], builder.compiler); |
- builder.localsHandler.updateLocal(target, value); |
- |
- assert(label.target.labels.contains(label)); |
- HInstruction continueInstruction = new HContinue(target); |
- LocalsHandler locals = new LocalsHandler.from(builder.localsHandler); |
- builder.close(continueInstruction); |
- jumps.add(new JumpHandlerEntry(continueInstruction, locals)); |
- } else { |
- super.generateContinue(label); |
- } |
- } |
- |
- void close() { |
- // The mapping from TargetElement to JumpHandler is no longer needed. |
- for (JumpTarget target in targetIndexMap.keys) { |
- builder.jumpTargets.remove(target); |
- } |
- super.close(); |
- } |
-} |
- |
/** |
* This class builds SSA nodes for functions represented in AST. |
*/ |
@@ -376,7 +158,6 @@ class SsaBuilder extends ast.Visitor |
// used only for codegen, but currently we want to experiment using it for |
// code-analysis too. |
final CodegenRegistry registry; |
- final Compiler compiler; |
final GlobalTypeInferenceResults inferenceResults; |
final JavaScriptBackend backend; |
final ConstantSystem constantSystem; |
@@ -397,13 +178,6 @@ class SsaBuilder extends ast.Visitor |
bool inExpressionOfThrow = false; |
/** |
- * The loop nesting is consulted when inlining a function invocation in |
- * [tryInlineMethod]. The inlining heuristics take this information into |
- * account. |
- */ |
- int loopNesting = 0; |
- |
- /** |
* This stack contains declaration elements of the functions being built |
* or inlined by this builder. |
*/ |
@@ -411,8 +185,6 @@ class SsaBuilder extends ast.Visitor |
HInstruction rethrowableException; |
- Map<JumpTarget, JumpHandler> jumpTargets = <JumpTarget, JumpHandler>{}; |
- |
/// Returns `true` if the current element is an `async` function. |
bool get isBuildingAsyncFunction { |
Element element = sourceElement; |
@@ -420,6 +192,9 @@ class SsaBuilder extends ast.Visitor |
element.asyncMarker == AsyncMarker.ASYNC); |
} |
+ /// Handles the building of loops. |
+ LoopHandler<ast.Node> loopHandler; |
+ |
// TODO(sigmund): make most args optional |
SsaBuilder( |
this.target, |
@@ -428,13 +203,13 @@ class SsaBuilder extends ast.Visitor |
JavaScriptBackend backend, |
this.nativeEmitter, |
SourceInformationStrategy sourceInformationFactory) |
- : this.compiler = backend.compiler, |
- this.infoReporter = backend.compiler.dumpInfoTask, |
+ : this.infoReporter = backend.compiler.dumpInfoTask, |
this.backend = backend, |
this.constantSystem = backend.constantSystem, |
this.rti = backend.rti, |
this.inferenceResults = backend.compiler.globalInference.results { |
assert(target.isImplementation); |
+ compiler = backend.compiler; |
graph.element = target; |
sourceElementStack.add(target); |
sourceInformationBuilder = |
@@ -442,6 +217,7 @@ class SsaBuilder extends ast.Visitor |
graph.sourceInformation = |
sourceInformationBuilder.buildVariableDeclaration(); |
localsHandler = new LocalsHandler(this, target, null, compiler); |
+ loopHandler = new SsaLoopHandler(this); |
} |
BackendHelpers get helpers => backend.helpers; |
@@ -632,7 +408,7 @@ class SsaBuilder extends ast.Visitor |
FunctionElement function = element; |
ResolvedAst functionResolvedAst = function.resolvedAst; |
- bool insideLoop = loopNesting > 0 || graph.calledInLoop; |
+ bool insideLoop = loopDepth > 0 || graph.calledInLoop; |
// Bail out early if the inlining decision is in the cache and we can't |
// inline (no need to check the hard constraints). |
@@ -1953,275 +1729,6 @@ class SsaBuilder extends ast.Visitor |
} |
} |
- /** |
- * Creates a new loop-header block. The previous [current] block |
- * is closed with an [HGoto] and replaced by the newly created block. |
- * Also notifies the locals handler that we're entering a loop. |
- */ |
- JumpHandler beginLoopHeader(ast.Node node) { |
- assert(!isAborted()); |
- HBasicBlock previousBlock = close(new HGoto()); |
- |
- JumpHandler jumpHandler = createJumpHandler(node, isLoopJump: true); |
- HBasicBlock loopEntry = |
- graph.addNewLoopHeaderBlock(jumpHandler.target, jumpHandler.labels()); |
- previousBlock.addSuccessor(loopEntry); |
- open(loopEntry); |
- |
- localsHandler.beginLoopHeader(loopEntry); |
- return jumpHandler; |
- } |
- |
- /** |
- * Ends the loop: |
- * - creates a new block and adds it as successor to the [branchExitBlock] 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. |
- * [branchExitBlock] is the exit (branching) block of the condition. Generally |
- * this is not the top of the loop, since this would lead to critical edges. |
- * 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 branchExitBlock, |
- JumpHandler jumpHandler, LocalsHandler savedLocals) { |
- HBasicBlock loopExitBlock = addNewBlock(); |
- |
- 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); |
- 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 (branchExitBlock != null) { |
- branchExitBlock.addSuccessor(loopExitBlock); |
- } |
- // Update the phis at the loop entry with the current values of locals. |
- localsHandler.endLoop(loopEntry); |
- |
- // Start generating code for the exit block. |
- open(loopExitBlock); |
- |
- // Create a new localsHandler for the loopExitBlock with the correct phis. |
- if (!breakHandlers.isEmpty) { |
- if (branchExitBlock != 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; |
- } |
- } |
- |
- HSubGraphBlockInformation wrapStatementGraph(SubGraph statements) { |
- if (statements == null) return null; |
- return new HSubGraphBlockInformation(statements); |
- } |
- |
- HSubExpressionBlockInformation wrapExpressionGraph(SubExpression expression) { |
- if (expression == null) return null; |
- return new HSubExpressionBlockInformation(expression); |
- } |
- |
- // For while loops, initializer and update are null. |
- // The condition function must return a boolean result. |
- // None of the functions must leave anything on the stack. |
- void handleLoop(ast.Node loop, void initialize(), HInstruction condition(), |
- void update(), void body()) { |
- // Generate: |
- // <initializer> |
- // loop-entry: |
- // if (!<condition>) goto loop-exit; |
- // <body> |
- // <updates> |
- // goto loop-entry; |
- // loop-exit: |
- |
- localsHandler.startLoop(loop); |
- |
- // The initializer. |
- SubExpression initializerGraph = null; |
- HBasicBlock startBlock; |
- if (initialize != null) { |
- HBasicBlock initializerBlock = openNewBlock(); |
- startBlock = initializerBlock; |
- initialize(); |
- assert(!isAborted()); |
- initializerGraph = new SubExpression(initializerBlock, current); |
- } |
- |
- loopNesting++; |
- JumpHandler jumpHandler = beginLoopHeader(loop); |
- HLoopInformation loopInfo = current.loopInformation; |
- HBasicBlock conditionBlock = current; |
- if (startBlock == null) startBlock = conditionBlock; |
- |
- HInstruction conditionInstruction = condition(); |
- HBasicBlock conditionEndBlock = |
- close(new HLoopBranch(conditionInstruction)); |
- SubExpression conditionExpression = |
- new SubExpression(conditionBlock, conditionEndBlock); |
- |
- // 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. |
- HBasicBlock beginBodyBlock = addNewBlock(); |
- conditionEndBlock.addSuccessor(beginBodyBlock); |
- open(beginBodyBlock); |
- |
- localsHandler.enterLoopBody(loop); |
- body(); |
- |
- SubGraph bodyGraph = new SubGraph(beginBodyBlock, lastOpenedBlock); |
- HBasicBlock bodyBlock = current; |
- if (current != null) close(new HGoto()); |
- |
- SubExpression updateGraph; |
- |
- 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> continueHandlers = <LocalsHandler>[]; |
- jumpHandler |
- .forEachContinue((HContinue instruction, LocalsHandler locals) { |
- instruction.block.addSuccessor(updateBlock); |
- continueHandlers.add(locals); |
- }); |
- |
- if (bodyBlock != null) { |
- continueHandlers.add(localsHandler); |
- bodyBlock.addSuccessor(updateBlock); |
- } |
- |
- open(updateBlock); |
- localsHandler = |
- continueHandlers[0].mergeMultiple(continueHandlers, updateBlock); |
- |
- List<LabelDefinition> labels = jumpHandler.labels(); |
- JumpTarget target = elements.getTargetDefinition(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); |
- |
- // Avoid a critical edge from the condition to the loop-exit body. |
- HBasicBlock conditionExitBlock = addNewBlock(); |
- open(conditionExitBlock); |
- close(new HGoto()); |
- conditionEndBlock.addSuccessor(conditionExitBlock); |
- |
- endLoop(conditionBlock, conditionExitBlock, jumpHandler, savedLocals); |
- |
- conditionBlock.postProcessLoopHeader(); |
- HLoopBlockInformation info = new HLoopBlockInformation( |
- _loopKind(loop), |
- wrapExpressionGraph(initializerGraph), |
- wrapExpressionGraph(conditionExpression), |
- wrapStatementGraph(bodyGraph), |
- wrapExpressionGraph(updateGraph), |
- conditionBlock.loopInformation.target, |
- conditionBlock.loopInformation.labels, |
- sourceInformationBuilder.buildLoop(loop)); |
- |
- startBlock.setBlockFlow(info, current); |
- loopInfo.loopBlockInformation = info; |
- } else { |
- // The body of the for/while loop always aborts, so there is no back edge. |
- // We turn the code into: |
- // if (condition) { |
- // body; |
- // } else { |
- // // We always create an empty else block to avoid critical edges. |
- // } |
- // |
- // If there is any break in the body, we attach a synthetic |
- // label to the if. |
- HBasicBlock elseBlock = addNewBlock(); |
- open(elseBlock); |
- close(new HGoto()); |
- // Pass the elseBlock as the branchBlock, because that's the block we go |
- // to just before leaving the 'loop'. |
- endLoop(conditionBlock, elseBlock, jumpHandler, savedLocals); |
- |
- SubGraph elseGraph = new SubGraph(elseBlock, elseBlock); |
- // Remove the loop information attached to the header. |
- conditionBlock.loopInformation = null; |
- |
- // Remove the [HLoopBranch] instruction and replace it with |
- // [HIf]. |
- HInstruction condition = conditionEndBlock.last.inputs[0]; |
- conditionEndBlock.addAtExit(new HIf(condition)); |
- conditionEndBlock.addSuccessor(elseBlock); |
- conditionEndBlock.remove(conditionEndBlock.last); |
- HIfBlockInformation info = new HIfBlockInformation( |
- wrapExpressionGraph(conditionExpression), |
- wrapStatementGraph(bodyGraph), |
- wrapStatementGraph(elseGraph)); |
- |
- conditionEndBlock.setBlockFlow(info, current); |
- HIf ifBlock = conditionEndBlock.last; |
- ifBlock.blockInformation = conditionEndBlock.blockFlow; |
- |
- // If the body has any break, attach a synthesized label to the |
- // if block. |
- if (jumpHandler.hasAnyBreak()) { |
- JumpTarget target = elements.getTargetDefinition(loop); |
- LabelDefinition label = target.addLabel(null, 'loop'); |
- label.setBreakTarget(); |
- SubGraph labelGraph = new SubGraph(conditionBlock, current); |
- HLabeledBlockInformation labelInfo = new HLabeledBlockInformation( |
- new HSubGraphBlockInformation(labelGraph), |
- <LabelDefinition>[label]); |
- |
- conditionBlock.setBlockFlow(labelInfo, current); |
- |
- jumpHandler.forEachBreak((HBreak breakInstruction, _) { |
- HBasicBlock block = breakInstruction.block; |
- block.addAtExit(new HBreak.toLabel(label)); |
- block.remove(breakInstruction); |
- }); |
- } |
- } |
- jumpHandler.close(); |
- loopNesting--; |
- } |
- |
visitFor(ast.For node) { |
assert(isReachable); |
assert(node.body != null); |
@@ -2256,7 +1763,8 @@ class SsaBuilder extends ast.Visitor |
visit(node.body); |
} |
- handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
+ loopHandler.handleLoop( |
+ node, buildInitializer, buildCondition, buildUpdate, buildBody); |
} |
visitWhile(ast.While node) { |
@@ -2266,7 +1774,7 @@ class SsaBuilder extends ast.Visitor |
return popBoolified(); |
} |
- handleLoop(node, () {}, buildCondition, () {}, () { |
+ loopHandler.handleLoop(node, () {}, buildCondition, () {}, () { |
visit(node.body); |
}); |
} |
@@ -2275,8 +1783,8 @@ class SsaBuilder extends ast.Visitor |
assert(isReachable); |
LocalsHandler savedLocals = new LocalsHandler.from(localsHandler); |
localsHandler.startLoop(node); |
- loopNesting++; |
- JumpHandler jumpHandler = beginLoopHeader(node); |
+ loopDepth++; |
+ JumpHandler jumpHandler = loopHandler.beginLoopHeader(node); |
HLoopInformation loopInfo = current.loopInformation; |
HBasicBlock loopEntryBlock = current; |
HBasicBlock bodyEntryBlock = current; |
@@ -2363,7 +1871,8 @@ class SsaBuilder extends ast.Visitor |
close(new HGoto()); |
conditionEndBlock.addSuccessor(conditionExitBlock); |
- endLoop(loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); |
+ loopHandler.endLoop( |
+ loopEntryBlock, conditionExitBlock, jumpHandler, localsHandler); |
loopEntryBlock.postProcessLoopHeader(); |
SubGraph bodyGraph = new SubGraph(loopEntryBlock, bodyExitBlock); |
@@ -2386,7 +1895,7 @@ class SsaBuilder extends ast.Visitor |
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); |
+ loopHandler.endLoop(loopEntryBlock, null, jumpHandler, localsHandler); |
// Since the body of the loop has a break, we attach a synthesized label |
// to the body. |
@@ -2405,7 +1914,7 @@ class SsaBuilder extends ast.Visitor |
} |
} |
jumpHandler.close(); |
- loopNesting--; |
+ loopDepth--; |
} |
visitFunctionExpression(ast.FunctionExpression node) { |
@@ -6056,7 +5565,7 @@ class SsaBuilder extends ast.Visitor |
* a special "null handler" is returned. |
* |
* [isLoopJump] is [:true:] when the jump handler is for a loop. This is used |
- * to distinguish the synthetized loop created for a switch statement with |
+ * to distinguish the synthesized loop created for a switch statement with |
* continue statements from simple switch statements. |
*/ |
JumpHandler createJumpHandler(ast.Statement node, {bool isLoopJump}) { |
@@ -6125,7 +5634,7 @@ class SsaBuilder extends ast.Visitor |
void buildUpdate() {} |
buildProtectedByFinally(() { |
- handleLoop( |
+ loopHandler.handleLoop( |
node, buildInitializer, buildCondition, buildUpdate, buildBody); |
}, () { |
pushInvokeDynamic(node, Selectors.cancel, null, [streamIterator]); |
@@ -6195,7 +5704,8 @@ class SsaBuilder extends ast.Visitor |
visit(node.body); |
} |
- handleLoop(node, buildInitializer, buildCondition, () {}, buildBody); |
+ loopHandler.handleLoop( |
+ node, buildInitializer, buildCondition, () {}, buildBody); |
} |
buildAssignLoopVariable(ast.ForIn node, HInstruction value) { |
@@ -6314,7 +5824,8 @@ class SsaBuilder extends ast.Visitor |
localsHandler.updateLocal(indexVariable, addInstruction); |
} |
- handleLoop(node, buildInitializer, buildCondition, buildUpdate, buildBody); |
+ loopHandler.handleLoop( |
+ node, buildInitializer, buildCondition, buildUpdate, buildBody); |
} |
visitLabel(ast.Label node) { |
@@ -6658,7 +6169,7 @@ class SsaBuilder extends ast.Visitor |
} |
void buildLoop() { |
- handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
+ loopHandler.handleLoop(node, () {}, buildCondition, () {}, buildSwitch); |
} |
if (hasDefault) { |
@@ -7560,19 +7071,3 @@ class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> { |
builder.push(new HDynamicType(type, new TypeMask.exact(cls, classWorld))); |
} |
} |
- |
-/// Determine what kind of loop [node] represents. The result is one of the |
-/// kinds defined in [HLoopBlockInformation]. |
-int _loopKind(ast.Node node) => node.accept(const _LoopTypeVisitor()); |
- |
-class _LoopTypeVisitor extends ast.Visitor { |
- const _LoopTypeVisitor(); |
- int visitNode(ast.Node node) => HLoopBlockInformation.NOT_A_LOOP; |
- int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP; |
- int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP; |
- int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP; |
- int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
- int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP; |
- int visitSwitchStatement(ast.SwitchStatement node) => |
- HLoopBlockInformation.SWITCH_CONTINUE_LOOP; |
-} |