Index: sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart |
diff --git a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart |
index 2b27aab37ebf2b513f730f22967bb4dece4666a8..d1605c8c713cb6b0e450f0908830a22560740bbc 100644 |
--- a/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart |
+++ b/sdk/lib/_internal/compiler/implementation/cps_ir/cps_ir_builder.dart |
@@ -884,6 +884,133 @@ class IrBuilder { |
} |
} |
+ /// Creates a for-in loop, `for (v in e) b`. |
+ /// |
+ /// [buildExpression] creates the expression, `e`. The variable, `v`, can |
+ /// take one of three forms: |
+ /// 1) `v` can be declared within the for-in statement, like in |
+ /// `for (var v in e)`, in which case, [buildVariableDeclaration] |
+ /// creates its declaration and [variableElement] is the element for |
+ /// the declared variable, |
+ /// 2) `v` is predeclared statically known variable, that is top-level, |
+ /// static, or local variable, in which case [variableElement] is the |
+ /// variable element, and [variableSelector] defines its write access, |
+ /// 3) `v` is an instance variable in which case [variableSelector] |
+ /// defines its write access. |
+ /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used |
+ /// to identify which `break` and `continue` statements that have this for-in |
+ /// statement as their target. |
+ void buildForIn({SubbuildFunction buildExpression, |
+ SubbuildFunction buildVariableDeclaration, |
+ Element variableElement, |
+ Selector variableSelector, |
+ SubbuildFunction buildBody, |
+ JumpTarget target}) { |
+ // The for-in loop |
+ // |
+ // for (a in e) s; |
+ // |
+ // Is compiled analogously to: |
+ // |
+ // a = e.iterator; |
+ // while (a.moveNext()) { |
+ // var n0 = a.current; |
+ // s; |
+ // } |
+ |
+ // The condition and body are delimited. |
+ IrBuilder condBuilder = new IrBuilder.recursive(this); |
+ |
+ ir.Primitive expressionReceiver = buildExpression(this); |
+ List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); |
+ |
+ ir.Parameter iterator = new ir.Parameter(null); |
+ ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); |
+ add(new ir.LetCont(iteratorInvoked, |
+ new ir.InvokeMethod(expressionReceiver, |
+ new Selector.getter("iterator", null), iteratorInvoked, |
+ emptyArguments))); |
+ |
+ ir.Parameter condition = new ir.Parameter(null); |
+ ir.Continuation moveNextInvoked = new ir.Continuation([condition]); |
+ condBuilder.add(new ir.LetCont(moveNextInvoked, |
+ new ir.InvokeMethod(iterator, |
+ new Selector.call("moveNext", null, 0), |
+ moveNextInvoked, emptyArguments))); |
+ |
+ JumpCollector breakCollector = new JumpCollector(target); |
+ JumpCollector continueCollector = new JumpCollector(target); |
+ state.breakCollectors.add(breakCollector); |
+ state.continueCollectors.add(continueCollector); |
+ |
+ IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); |
+ if (buildVariableDeclaration != null) { |
+ buildVariableDeclaration(bodyBuilder); |
+ } |
+ |
+ ir.Parameter currentValue = new ir.Parameter(null); |
+ ir.Continuation currentInvoked = new ir.Continuation([currentValue]); |
+ bodyBuilder.add(new ir.LetCont(currentInvoked, |
+ new ir.InvokeMethod(iterator, new Selector.getter("current", null), |
+ currentInvoked, emptyArguments))); |
+ if (Elements.isLocal(variableElement)) { |
+ bodyBuilder.buildLocalSet(variableElement, currentValue); |
+ } else if (Elements.isStaticOrTopLevel(variableElement)) { |
+ bodyBuilder.buildStaticSet( |
+ variableElement, variableSelector, currentValue); |
+ } else { |
+ ir.Primitive receiver = bodyBuilder.buildThis(); |
+ bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue); |
+ } |
+ |
+ buildBody(bodyBuilder); |
+ assert(state.breakCollectors.last == breakCollector); |
+ assert(state.continueCollectors.last == continueCollector); |
+ state.breakCollectors.removeLast(); |
+ state.continueCollectors.removeLast(); |
+ |
+ // Create body entry and loop exit continuations and a branch to them. |
+ ir.Continuation bodyContinuation = new ir.Continuation([]); |
+ ir.Continuation exitContinuation = new ir.Continuation([]); |
+ ir.LetCont branch = |
+ new ir.LetCont(exitContinuation, |
+ new ir.LetCont(bodyContinuation, |
+ new ir.Branch(new ir.IsTrue(condition), |
+ bodyContinuation, |
+ exitContinuation))); |
+ // If there are breaks in the body, then there must be a join-point |
+ // continuation for the normal exit and the breaks. |
+ bool hasBreaks = !breakCollector.isEmpty; |
+ ir.LetCont letJoin; |
+ if (hasBreaks) { |
+ letJoin = new ir.LetCont(null, branch); |
+ condBuilder.add(letJoin); |
+ condBuilder._current = branch; |
+ } else { |
+ condBuilder.add(branch); |
+ } |
+ ir.Continuation loopContinuation = |
+ new ir.Continuation(condBuilder._parameters); |
+ if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); |
+ invokeFullJoin( |
+ loopContinuation, continueCollector, recursive: true); |
+ bodyContinuation.body = bodyBuilder._root; |
+ |
+ loopContinuation.body = condBuilder._root; |
+ add(new ir.LetCont(loopContinuation, |
+ new ir.InvokeContinuation(loopContinuation, |
+ environment.index2value))); |
+ if (hasBreaks) { |
+ _current = branch; |
+ environment = condBuilder.environment; |
+ breakCollector.addJump(this); |
+ letJoin.continuation = createJoin(environment.length, breakCollector); |
+ _current = letJoin; |
+ } else { |
+ _current = condBuilder._current; |
+ environment = condBuilder.environment; |
+ } |
+ } |
/// Creates a while loop in which the condition and body are created by |
/// [buildCondition] and [buildBody], respectively. |
@@ -1170,6 +1297,14 @@ class IrBuilder { |
return joinContinuation.parameters.last; |
} |
+ /// Creates an access to `this`. |
+ ir.Primitive buildThis() { |
+ assert(isOpen); |
+ ir.Primitive result = new ir.This(); |
+ add(new ir.LetPrim(result)); |
+ return result; |
+ } |
+ |
/// Create a non-recursive join-point continuation. |
/// |
/// Given the environment length at the join point and a list of |