| 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;
|
| -}
|
|
|