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

Side by Side Diff: pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart

Issue 1040093002: Change the collection of continuation jumps. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Incorporated review comments, rebased. Created 5 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.ir_builder; 5 library dart2js.ir_builder;
6 6
7 import '../constants/expressions.dart'; 7 import '../constants/expressions.dart';
8 import '../constants/values.dart' show PrimitiveConstantValue; 8 import '../constants/values.dart' show PrimitiveConstantValue;
9 import '../dart_types.dart'; 9 import '../dart_types.dart';
10 import '../dart2jslib.dart'; 10 import '../dart2jslib.dart';
(...skipping 26 matching lines...) Expand all
37 index2value = <ir.Primitive>[]; 37 index2value = <ir.Primitive>[];
38 38
39 /// Construct an environment that is a copy of another one. 39 /// Construct an environment that is a copy of another one.
40 /// 40 ///
41 /// The mapping from elements to indexes is shared, not copied. 41 /// The mapping from elements to indexes is shared, not copied.
42 Environment.from(Environment other) 42 Environment.from(Environment other)
43 : variable2index = other.variable2index, 43 : variable2index = other.variable2index,
44 index2variable = new List<Local>.from(other.index2variable), 44 index2variable = new List<Local>.from(other.index2variable),
45 index2value = new List<ir.Primitive>.from(other.index2value); 45 index2value = new List<ir.Primitive>.from(other.index2value);
46 46
47 /// Construct an environment that is shaped like another one but with a
48 /// fresh parameter for each variable.
49 ///
50 /// The mapping from elements to indexes is shared, not copied.
51 Environment.fresh(Environment other)
52 : variable2index = other.variable2index,
53 index2variable = new List<Local>.from(other.index2variable),
54 index2value = other.index2variable.map((Local local) {
55 return new ir.Parameter(local);
56 }).toList();
57
47 get length => index2variable.length; 58 get length => index2variable.length;
48 59
49 ir.Primitive operator [](int index) => index2value[index]; 60 ir.Primitive operator [](int index) => index2value[index];
50 61
51 void extend(Local element, ir.Primitive value) { 62 void extend(Local element, ir.Primitive value) {
52 // Assert that the name is not already in the environment. `null` is used 63 // Assert that the name is not already in the environment. `null` is used
53 // as the name of anonymous variables. Because the variable2index map is 64 // as the name of anonymous variables. Because the variable2index map is
54 // shared, `null` can already occur. This is safe because such variables 65 // shared, `null` can already occur. This is safe because such variables
55 // are not looked up by name. 66 // are not looked up by name.
56 // 67 //
57 // TODO(kmillikin): This is still kind of fishy. Refactor to not share 68 // TODO(kmillikin): This is still kind of fishy. Refactor to not share
58 // name maps or else garbage collect unneeded names. 69 // name maps or else garbage collect unneeded names.
59 assert(element == null || !variable2index.containsKey(element)); 70 assert(element == null || !variable2index.containsKey(element));
60 variable2index[element] = index2variable.length; 71 variable2index[element] = index2variable.length;
61 index2variable.add(element); 72 index2variable.add(element);
62 index2value.add(value); 73 index2value.add(value);
63 } 74 }
64 75
76 void discard(int count) {
77 assert(count <= index2variable.length);
78 // The map from variables to their index are shared, so we cannot remove
79 // the mapping in `variable2index`.
80 index2variable.length -= count;
81 index2value.length -= count;
82 }
83
65 ir.Primitive lookup(Local element) { 84 ir.Primitive lookup(Local element) {
66 assert(invariant(element, variable2index.containsKey(element), 85 assert(invariant(element, variable2index.containsKey(element),
67 message: "Unknown variable: $element.")); 86 message: "Unknown variable: $element."));
68 return index2value[variable2index[element]]; 87 return index2value[variable2index[element]];
69 } 88 }
70 89
71 void update(Local element, ir.Primitive value) { 90 void update(Local element, ir.Primitive value) {
72 index2value[variable2index[element]] = value; 91 index2value[variable2index[element]] = value;
73 } 92 }
74 93
(...skipping 10 matching lines...) Expand all
85 // The variable maps to the same index in both environments. 104 // The variable maps to the same index in both environments.
86 int index = variable2index[variable]; 105 int index = variable2index[variable];
87 if (index == null || index != other.variable2index[variable]) { 106 if (index == null || index != other.variable2index[variable]) {
88 return false; 107 return false;
89 } 108 }
90 } 109 }
91 return true; 110 return true;
92 } 111 }
93 } 112 }
94 113
95 /// A class to collect breaks or continues. 114 /// The abstract base class of objects that emit jumps to a continuation and
96 /// 115 /// give a handle to the continuation and its environment.
97 /// When visiting a potential target of breaks or continues, any breaks or 116 abstract class JumpCollector {
98 /// continues are collected by a JumpCollector and processed later, on demand.
99 /// The site of the break or continue is represented by a continuation
100 /// invocation that will have its target and arguments filled in later.
101 ///
102 /// The environment of the builder at that point is captured and should not
103 /// be subsequently mutated until the jump is resolved.
104 class JumpCollector {
105 final JumpTarget target; 117 final JumpTarget target;
106 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; 118
107 final List<Environment> _environments = <Environment>[]; 119 ir.Continuation _continuation = null;
108 final List<Iterable<LocalVariableElement>> boxedTryVariables = 120 final Environment _continuationEnvironment;
121
122 final List<Iterable<LocalVariableElement>> _boxedTryVariables =
109 <Iterable<LocalVariableElement>>[]; 123 <Iterable<LocalVariableElement>>[];
110 124
111 JumpCollector(this.target); 125 JumpCollector(this._continuationEnvironment, this.target);
112 126
113 bool get isEmpty => _invocations.isEmpty; 127 /// True if the collector has not recorded any jumps to its continuation.
114 int get length => _invocations.length; 128 bool get isEmpty;
115 List<ir.InvokeContinuation> get invocations => _invocations; 129
116 List<Environment> get environments => _environments; 130 /// The continuation encapsulated by this collector.
117 131 ir.Continuation get continuation;
118 void addJump(IrBuilder builder) { 132
119 // Unbox all variables that were boxed on entry to try blocks between the 133 /// The compile-time environment to be used for translating code in the body
120 // jump and the target. 134 /// of the continuation.
121 for (Iterable<LocalVariableElement> boxedOnEntry in boxedTryVariables) { 135 Environment get environment;
136
137 /// Emit a jump to the continuation for a given [IrBuilder].
138 void addJump(IrBuilder builder);
139
140 /// Add a set of variables that were boxed on entry to a try block.
141 ///
142 /// All jumps from a try block to targets outside have to unbox the
143 /// variables that were boxed on entry before invoking the target
144 /// continuation. Call this function before translating a try block and
145 /// call [leaveTry] after translating it.
146 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) {
147 // The boxed variables are maintained as a stack to make leaving easy.
148 _boxedTryVariables.add(boxedOnEntry);
149 }
150
151 /// Remove the most recently added set of variables boxed on entry to a try
152 /// block.
153 ///
154 /// Call [enterTry] before translating a try block and call this function
155 /// after translating it.
156 void leaveTry() {
157 _boxedTryVariables.removeLast();
158 }
159
160 void _buildTryExit(IrBuilder builder) {
161 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) {
122 for (LocalVariableElement variable in boxedOnEntry) { 162 for (LocalVariableElement variable in boxedOnEntry) {
123 assert(builder.isInMutableVariable(variable)); 163 assert(builder.isInMutableVariable(variable));
124 ir.Primitive value = builder.buildLocalGet(variable); 164 ir.Primitive value = builder.buildLocalGet(variable);
125 builder.environment.update(variable, value); 165 builder.environment.update(variable, value);
126 } 166 }
127 } 167 }
168 }
169 }
170
171 /// A class to collect 'forward' jumps.
172 ///
173 /// A forward jump to a continuation in the sense of the CPS translation is
174 /// a jump where the jump is emitted before any code in the body of the
175 /// continuation is translated. They have the property that continuation
176 /// parameters and the environment for the translation of the body can be
177 /// determined based on the invocations, before translating the body. A
178 /// [ForwardJumpCollector] can encapsulate a continuation where all the
179 /// jumps are forward ones.
180 ///
181 /// Examples of forward jumps in the translation are join points of
182 /// if-then-else and breaks from loops.
183 ///
184 /// The implementation strategy is that the collector collects invocation
185 /// sites and the environments at those sites. Then it constructs a
186 /// continuation 'on demand' after all the jumps are seen. It determines
187 /// continuation parameters, the environment for the translation of code in
188 /// the continuation body, and the arguments at the invocation site only
189 /// after all the jumps to the continuation are seen.
190 class ForwardJumpCollector extends JumpCollector {
191 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[];
192 final List<Environment> _invocationEnvironments = <Environment>[];
193
194 /// Construct a collector with a given base environment.
195 ///
196 /// The base environment is the one in scope at the site that the
197 /// continuation represented by this collector will be bound. The
198 /// environment is copied by the collector. Subsequent mutation of the
199 /// original environment will not affect the collector.
200 ForwardJumpCollector(Environment environment, {JumpTarget target: null})
201 : super(new Environment.from(environment), target);
202
203 bool get isEmpty => _invocations.isEmpty;
204
205 ir.Continuation get continuation {
206 if (_continuation == null) _setContinuation();
207 return _continuation;
208 }
209
210 Environment get environment {
211 if (_continuation == null) _setContinuation();
212 return _continuationEnvironment;
213 }
214
215 void addJump(IrBuilder builder) {
216 assert(_continuation == null);
217 _buildTryExit(builder);
128 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); 218 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized();
129 builder.add(invoke); 219 builder.add(invoke);
130 _invocations.add(invoke); 220 _invocations.add(invoke);
131 _environments.add(builder.environment); 221 _invocationEnvironments.add(builder.environment);
132 builder._current = null; 222 builder._current = null;
133 // TODO(kmillikin): Can we set builder.environment to null to make it 223 // TODO(kmillikin): Can we set builder.environment to null to make it
134 // less likely to mutate it? 224 // less likely to mutate it?
135 } 225 }
136 226
137 /// Add a set of variables that were boxed on entry to a try block. 227 void _setContinuation() {
138 /// 228 assert(_continuation == null);
139 /// Jumps from a try block to targets outside have to unbox the variables 229 // We have seen all invocations of this continuation, and recorded the
140 /// that were boxed on entry before invoking the target continuation. Call 230 // environment in effect at each invocation site.
141 /// this function before translating a try block and call [leaveTry] after 231
142 /// translating it. 232 // Compute the union of the assigned variables reaching the continuation.
143 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { 233 //
144 // The boxed variables are maintained as a stack to make leaving easy. 234 // There is a continuation parameter for each environment variable
145 boxedTryVariables.add(boxedOnEntry); 235 // that has a different value (from the environment in scope at the
146 } 236 // continuation binding) on some path. `_environment` is initially a copy
147 237 // of the environment in scope at the continuation binding. Compute the
148 /// Remove the most recently added set of variables boxed on entry to a try 238 // continuation parameters and add them to `_environment` so it will become
149 /// block. 239 // the one in scope for the continuation body.
150 /// 240 List<ir.Parameter> parameters = <ir.Parameter>[];
151 /// Call [enterTry] before translating a try block and call this function 241 if (_invocationEnvironments.isNotEmpty) {
152 /// after translating it. 242 int length = _continuationEnvironment.length;
153 void leaveTry() { 243 for (int varIndex = 0; varIndex < length; ++varIndex) {
154 boxedTryVariables.removeLast(); 244 for (Environment invocationEnvironment in _invocationEnvironments) {
155 } 245 assert(invocationEnvironment.sameDomain(length,
156 } 246 _continuationEnvironment));
157 247 if (invocationEnvironment[varIndex] !=
248 _continuationEnvironment[varIndex]) {
249 ir.Parameter parameter = new ir.Parameter(
250 _continuationEnvironment.index2variable[varIndex]);
251 _continuationEnvironment.index2value[varIndex] = parameter;
252 parameters.add(parameter);
253 break;
254 }
255 }
256 }
257 }
258 _continuation = new ir.Continuation(parameters);
259
260 // Compute the intersection of the parameters with the environments at
261 // each continuation invocation. Initialize the invocations.
262 for (int jumpIndex = 0; jumpIndex < _invocations.length; ++jumpIndex) {
263 Environment invocationEnvironment = _invocationEnvironments[jumpIndex];
264 List<ir.Reference> arguments = <ir.Reference>[];
265 int varIndex = 0;
266 for (ir.Parameter parameter in parameters) {
267 varIndex =
268 _continuationEnvironment.index2value.indexOf(parameter, varIndex);
269 arguments.add(new ir.Reference(invocationEnvironment[varIndex]));
270 }
271 ir.InvokeContinuation invocation = _invocations[jumpIndex];
272 invocation.continuation = new ir.Reference(_continuation);
273 invocation.arguments = arguments;
274 }
275 }
276 }
277
278 /// A class to collect 'backward' jumps.
279 ///
280 /// A backward jump to a continuation in the sense of the CPS translation is
281 /// a jump where some code in the body of the continuation is translated
282 /// before the jump is emitted. They have the property that the
283 /// continuation parameters and the environment for the translation of the
284 /// body must be determined before emitting all the invocations. A
285 /// [BackwardJumpCollector] can ecapsulate a continuation where some jumps
286 /// are backward ones.
287 ///
288 /// Examples of backward jumps in the translation are the recursive
289 /// invocations of loop continuations.
290 ///
291 /// The implementation strategy is that the collector inserts a continuation
292 /// parameter for each variable in scope at the entry to the continuation,
293 /// before emitting any jump to the continuation. When a jump is added, it
294 /// is given an argument for each continuation parameter.
295 class BackwardJumpCollector extends JumpCollector {
296 /// Construct a collector with a given base environment.
297 ///
298 /// The base environment is the one in scope at the site that the
299 /// continuation represented by this collector will be bound. The
300 /// translation of the continuation body will use an environment with the
301 /// same shape, but with fresh continuation parameters for each variable.
302 BackwardJumpCollector(Environment environment, {JumpTarget target: null})
303 : super(new Environment.fresh(environment), target) {
304 List<ir.Parameter> parameters =
305 new List<ir.Parameter>.from(_continuationEnvironment.index2value);
306 _continuation = new ir.Continuation(parameters, isRecursive: true);
307 }
308
309 bool isEmpty = true;
310
311 ir.Continuation get continuation => _continuation;
312 Environment get environment => _continuationEnvironment;
313
314 void addJump(IrBuilder builder) {
315 assert(_continuation.parameters.length <= builder.environment.length);
316 isEmpty = false;
317 _buildTryExit(builder);
318 builder.add(new ir.InvokeContinuation(_continuation,
319 builder.environment.index2value.take(_continuation.parameters.length)
320 .toList(),
321 isRecursive: true));
322 builder._current = null;
323 }
324 }
325
158 /// Function for building a node in the context of the current builder. 326 /// Function for building a node in the context of the current builder.
159 typedef ir.Node BuildFunction(node); 327 typedef ir.Node BuildFunction(node);
160 328
161 /// Function for building nodes in the context of the provided [builder]. 329 /// Function for building nodes in the context of the provided [builder].
162 typedef ir.Node SubbuildFunction(IrBuilder builder); 330 typedef ir.Node SubbuildFunction(IrBuilder builder);
163 331
164 /// Mixin that provides encapsulated access to nested builders. 332 /// Mixin that provides encapsulated access to nested builders.
165 abstract class IrBuilderMixin<N> { 333 abstract class IrBuilderMixin<N> {
166 IrBuilder _irBuilder; 334 IrBuilder _irBuilder;
167 335
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 ir.Expression _current = null; 527 ir.Expression _current = null;
360 528
361 /// Initialize a new top-level IR builder. 529 /// Initialize a new top-level IR builder.
362 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { 530 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
363 state = new IrBuilderDelimitedState(constantSystem, currentElement); 531 state = new IrBuilderDelimitedState(constantSystem, currentElement);
364 environment = new Environment.empty(); 532 environment = new Environment.empty();
365 } 533 }
366 534
367 /// Construct a delimited visitor for visiting a subtree. 535 /// Construct a delimited visitor for visiting a subtree.
368 /// 536 ///
369 /// The delimited visitor has its own compile-time environment mapping 537 /// Build a subterm that is not (yet) connected to the CPS term. The
370 /// local variables to their values, which is initially a copy of the parent 538 /// delimited visitor has its own has its own context for building an IR
371 /// environment. It has its own context for building an IR expression, so 539 /// expression, so the built expression is not plugged into the parent's
372 /// the built expression is not plugged into the parent's context. 540 /// context. It has its own compile-time environment mapping local
373 IrBuilder makeDelimitedBuilder() { 541 /// variables to their values. If an optional environment argument is
542 /// supplied, it is used as the builder's initial environment. Otherwise
543 /// the environment is initially a copy of the parent builder's environment.
544 IrBuilder makeDelimitedBuilder([Environment env = null]) {
374 return _makeInstance() 545 return _makeInstance()
375 ..state = state 546 ..state = state
376 ..environment = new Environment.from(environment); 547 ..environment = env != null ? env : new Environment.from(environment);
377 } 548 }
378 549
379 /// Construct a builder for making constructor field initializers. 550 /// Construct a builder for making constructor field initializers.
380 IrBuilder makeInitializerBuilder() { 551 IrBuilder makeInitializerBuilder() {
381 return _makeInstance() 552 return _makeInstance()
382 ..state = new IrBuilderDelimitedState(state.constantSystem, 553 ..state = new IrBuilderDelimitedState(state.constantSystem,
383 state.currentElement) 554 state.currentElement)
384 ..environment = new Environment.from(environment); 555 ..environment = new Environment.from(environment);
385 } 556 }
386 557
387 /// Construct a visitor for a recursive continuation.
388 ///
389 /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
390 /// for all the local variables in the parent, because the invocation sites
391 /// of the continuation are not all known when the builder is created. The
392 /// recursive invocations will be passed values for all the local variables,
393 /// which may be eliminated later if they are redundant---if they take on
394 /// the same value at all invocation sites.
395 IrBuilder makeRecursiveBuilder() {
396 IrBuilder inner = _makeInstance()
397 ..state = state
398 ..environment = new Environment.empty();
399 environment.index2variable.forEach(inner.createLocalParameter);
400 return inner;
401 }
402
403 /// Construct a builder for an inner function. 558 /// Construct a builder for an inner function.
404 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) { 559 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
405 IrBuilderDelimitedState innerState = 560 IrBuilderDelimitedState innerState =
406 new IrBuilderDelimitedState(state.constantSystem, currentElement) 561 new IrBuilderDelimitedState(state.constantSystem, currentElement)
407 ..enclosingMethodThisParameter = state.enclosingMethodThisParameter; 562 ..enclosingMethodThisParameter = state.enclosingMethodThisParameter;
408 return _makeInstance() 563 return _makeInstance()
409 ..state = innerState 564 ..state = innerState
410 ..environment = new Environment.empty(); 565 ..environment = new Environment.empty();
411 } 566 }
412 567
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 ir.Constant buildStringLiteral(String value) { 698 ir.Constant buildStringLiteral(String value) {
544 return _buildPrimitiveConstant( 699 return _buildPrimitiveConstant(
545 state.constantSystem.createString(new ast.DartString.literal(value))); 700 state.constantSystem.createString(new ast.DartString.literal(value)));
546 } 701 }
547 702
548 /// Creates a non-constant list literal of the provided [type] and with the 703 /// Creates a non-constant list literal of the provided [type] and with the
549 /// provided [values]. 704 /// provided [values].
550 ir.Primitive buildListLiteral(InterfaceType type, 705 ir.Primitive buildListLiteral(InterfaceType type,
551 Iterable<ir.Primitive> values) { 706 Iterable<ir.Primitive> values) {
552 assert(isOpen); 707 assert(isOpen);
553 return addPrimitive(new ir.LiteralList(type, values)); 708 return addPrimitive(new ir.LiteralList(type, values.toList()));
554 } 709 }
555 710
556 /// Creates a non-constant map literal of the provided [type] and with the 711 /// Creates a non-constant map literal of the provided [type] and with the
557 /// entries build from the [keys] and [values] using [build]. 712 /// entries build from the [keys] and [values] using [build].
558 ir.Primitive buildMapLiteral(InterfaceType type, 713 ir.Primitive buildMapLiteral(InterfaceType type,
559 Iterable keys, 714 Iterable keys,
560 Iterable values, 715 Iterable values,
561 BuildFunction build) { 716 BuildFunction build) {
562 assert(isOpen); 717 assert(isOpen);
563 List<ir.LiteralMapEntry> entries = <ir.LiteralMapEntry>[]; 718 List<ir.LiteralMapEntry> entries = <ir.LiteralMapEntry>[];
564 Iterator key = keys.iterator; 719 Iterator key = keys.iterator;
565 Iterator value = values.iterator; 720 Iterator value = values.iterator;
566 while (key.moveNext() && value.moveNext()) { 721 while (key.moveNext() && value.moveNext()) {
567 entries.add(new ir.LiteralMapEntry( 722 entries.add(new ir.LiteralMapEntry(
568 build(key.current), build(value.current))); 723 build(key.current), build(value.current)));
569 } 724 }
570 assert(!key.moveNext() && !value.moveNext()); 725 assert(!key.moveNext() && !value.moveNext());
571 return addPrimitive(new ir.LiteralMap(type, entries)); 726 return addPrimitive(new ir.LiteralMap(type, entries));
572 } 727 }
573 728
574 /// Creates a conditional expression with the provided [condition] where the 729 /// Creates a conditional expression with the provided [condition] where the
575 /// then and else expression are created through the [buildThenExpression] and 730 /// then and else expression are created through the [buildThenExpression]
576 /// [buildElseExpression] functions, respectively. 731 /// and [buildElseExpression] functions, respectively.
577 ir.Primitive buildConditional( 732 ir.Primitive buildConditional(
578 ir.Primitive condition, 733 ir.Primitive condition,
579 ir.Primitive buildThenExpression(IrBuilder builder), 734 ir.Primitive buildThenExpression(IrBuilder builder),
580 ir.Primitive buildElseExpression(IrBuilder builder)) { 735 ir.Primitive buildElseExpression(IrBuilder builder)) {
581
582 assert(isOpen); 736 assert(isOpen);
583 737
584 // The then and else expressions are delimited. 738 // The then and else expressions are delimited.
585 IrBuilder thenBuilder = makeDelimitedBuilder(); 739 IrBuilder thenBuilder = makeDelimitedBuilder();
586 IrBuilder elseBuilder = makeDelimitedBuilder(); 740 IrBuilder elseBuilder = makeDelimitedBuilder();
587 ir.Primitive thenValue = buildThenExpression(thenBuilder); 741 ir.Primitive thenValue = buildThenExpression(thenBuilder);
588 ir.Primitive elseValue = buildElseExpression(elseBuilder); 742 ir.Primitive elseValue = buildElseExpression(elseBuilder);
589 743
590 // Treat the values of the subexpressions as named values in the 744 // Treat the values of the subexpressions as named values in the
591 // environment, so they will be treated as arguments to the join-point 745 // environment, so they will be treated as arguments to the join-point
592 // continuation. 746 // continuation. We know the environments are the right size because
747 // expressions cannot introduce variable bindings.
593 assert(environment.length == thenBuilder.environment.length); 748 assert(environment.length == thenBuilder.environment.length);
594 assert(environment.length == elseBuilder.environment.length); 749 assert(environment.length == elseBuilder.environment.length);
750 // Extend the join-point environment with a placeholder for the value of
751 // the expression. Optimistically assume that the value is the value of
752 // the first subexpression. This value might noe even be in scope at the
753 // join-point because it's bound in the first subexpression. However, if
754 // that is the case, it will necessarily differ from the value of the
755 // other subexpression and cause the introduction of a join-point
756 // continuation parameter. If the two values do happen to be the same,
757 // this will avoid inserting a useless continuation parameter.
758 environment.extend(null, thenValue);
595 thenBuilder.environment.extend(null, thenValue); 759 thenBuilder.environment.extend(null, thenValue);
596 elseBuilder.environment.extend(null, elseValue); 760 elseBuilder.environment.extend(null, elseValue);
597 JumpCollector jumps = new JumpCollector(null); 761 JumpCollector join = new ForwardJumpCollector(environment);
598 jumps.addJump(thenBuilder); 762 thenBuilder.jumpTo(join);
599 jumps.addJump(elseBuilder); 763 elseBuilder.jumpTo(join);
600 ir.Continuation joinContinuation =
601 createJoin(environment.length + 1, jumps);
602 764
603 // Build the term 765 // Build the term
604 // let cont join(x, ..., result) = [] in 766 // let cont join(x, ..., result) = [] in
605 // let cont then() = [[thenPart]]; join(v, ...) 767 // let cont then() = [[thenPart]]; join(v, ...)
606 // and else() = [[elsePart]]; join(v, ...) 768 // and else() = [[elsePart]]; join(v, ...)
607 // in 769 // in
608 // if condition (then, else) 770 // if condition (then, else)
609 ir.Continuation thenContinuation = new ir.Continuation([]); 771 ir.Continuation thenContinuation = new ir.Continuation([]);
610 ir.Continuation elseContinuation = new ir.Continuation([]); 772 ir.Continuation elseContinuation = new ir.Continuation([]);
611 thenContinuation.body = thenBuilder._root; 773 thenContinuation.body = thenBuilder._root;
612 elseContinuation.body = elseBuilder._root; 774 elseContinuation.body = elseBuilder._root;
613 add(new ir.LetCont(joinContinuation, 775 add(new ir.LetCont(join.continuation,
614 new ir.LetCont.many(<ir.Continuation>[thenContinuation, 776 new ir.LetCont.many(<ir.Continuation>[thenContinuation,
615 elseContinuation], 777 elseContinuation],
616 new ir.Branch(new ir.IsTrue(condition), 778 new ir.Branch(new ir.IsTrue(condition),
617 thenContinuation, 779 thenContinuation,
618 elseContinuation)))); 780 elseContinuation))));
781 environment = join.environment;
782 environment.discard(1);
619 return (thenValue == elseValue) 783 return (thenValue == elseValue)
620 ? thenValue 784 ? thenValue
621 : joinContinuation.parameters.last; 785 : join.continuation.parameters.last;
622 } 786 }
623 787
624 /** 788 /**
625 * Add an explicit `return null` for functions that don't have a return 789 * Add an explicit `return null` for functions that don't have a return
626 * statement on each branch. This includes functions with an empty body, 790 * statement on each branch. This includes functions with an empty body,
627 * such as `foo(){ }`. 791 * such as `foo(){ }`.
628 */ 792 */
629 void _ensureReturn() { 793 void _ensureReturn() {
630 if (!isOpen) return; 794 if (!isOpen) return;
631 ir.Constant constant = buildNullLiteral(); 795 ir.Constant constant = buildNullLiteral();
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
878 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen 1042 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen
879 ? <ir.Continuation>[elseContinuation, thenContinuation] 1043 ? <ir.Continuation>[elseContinuation, thenContinuation]
880 : <ir.Continuation>[thenContinuation, elseContinuation]; 1044 : <ir.Continuation>[thenContinuation, elseContinuation];
881 1045
882 ir.Expression result = 1046 ir.Expression result =
883 new ir.LetCont.many(arms, 1047 new ir.LetCont.many(arms,
884 new ir.Branch(new ir.IsTrue(condition), 1048 new ir.Branch(new ir.IsTrue(condition),
885 thenContinuation, 1049 thenContinuation,
886 elseContinuation)); 1050 elseContinuation));
887 1051
888 ir.Continuation joinContinuation; // Null if there is no join. 1052 JumpCollector join; // Null if there is no join.
889 if (thenBuilder.isOpen && elseBuilder.isOpen) { 1053 if (thenBuilder.isOpen && elseBuilder.isOpen) {
890 // There is a join-point continuation. Build the term 1054 // There is a join-point continuation. Build the term
891 // 'let cont join(x, ...) = [] in Result' and plug invocations of the 1055 // 'let cont join(x, ...) = [] in Result' and plug invocations of the
892 // join-point continuation into the then and else continuations. 1056 // join-point continuation into the then and else continuations.
893 JumpCollector jumps = new JumpCollector(null); 1057 join = new ForwardJumpCollector(environment);
894 jumps.addJump(thenBuilder); 1058 thenBuilder.jumpTo(join);
895 jumps.addJump(elseBuilder); 1059 elseBuilder.jumpTo(join);
896 joinContinuation = createJoin(environment.length, jumps); 1060 result = new ir.LetCont(join.continuation, result);
897 result = new ir.LetCont(joinContinuation, result);
898 } 1061 }
899 1062
900 // The then or else term root could be null, but not both. If there is 1063 // The then or else term root could be null, but not both. If there is
901 // a join then an InvokeContinuation was just added to both of them. If 1064 // a join then an InvokeContinuation was just added to both of them. If
902 // there is no join, then at least one of them is closed and thus has a 1065 // there is no join, then at least one of them is closed and thus has a
903 // non-null root by the definition of the predicate isClosed. In the 1066 // non-null root by the definition of the predicate isClosed. In the
904 // case that one of them is null, it must be the only one that is open 1067 // case that one of them is null, it must be the only one that is open
905 // and thus contains the new hole in the context. This case is handled 1068 // and thus contains the new hole in the context. This case is handled
906 // after the branch is plugged into the current hole. 1069 // after the branch is plugged into the current hole.
907 thenContinuation.body = thenBuilder._root; 1070 thenContinuation.body = thenBuilder._root;
908 elseContinuation.body = elseBuilder._root; 1071 elseContinuation.body = elseBuilder._root;
909 1072
910 add(result); 1073 add(result);
911 if (joinContinuation == null) { 1074 if (join == null) {
912 // At least one subexpression is closed. 1075 // At least one subexpression is closed.
913 if (thenBuilder.isOpen) { 1076 if (thenBuilder.isOpen) {
914 if (thenBuilder._root != null) _current = thenBuilder._current; 1077 if (thenBuilder._root != null) _current = thenBuilder._current;
915 environment = thenBuilder.environment; 1078 environment = thenBuilder.environment;
916 } else if (elseBuilder.isOpen) { 1079 } else if (elseBuilder.isOpen) {
917 if (elseBuilder._root != null) _current = elseBuilder._current; 1080 if (elseBuilder._root != null) _current = elseBuilder._current;
918 environment = elseBuilder.environment; 1081 environment = elseBuilder.environment;
919 } else { 1082 } else {
920 _current = null; 1083 _current = null;
921 } 1084 }
1085 } else {
1086 environment = join.environment;
922 } 1087 }
923 } 1088 }
924 1089
925 void jumpTo(ir.Continuation continuation) { 1090 void jumpTo(JumpCollector collector) {
926 assert(isOpen); 1091 collector.addJump(this);
927 assert(environment.length >= continuation.parameters.length);
928 ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized();
929 jump.continuation = new ir.Reference(continuation);
930 jump.arguments = new List<ir.Reference>.generate(
931 continuation.parameters.length, (i) {
932 return new ir.Reference(environment[i]);
933 });
934 add(jump);
935 _current = null;
936 } 1092 }
937 1093
938 /// Invoke a join-point continuation that contains arguments for all local 1094 void addRecursiveContinuation(BackwardJumpCollector collector) {
939 /// variables. 1095 assert(environment.length == collector.environment.length);
940 /// 1096 add(new ir.LetCont(collector.continuation,
941 /// Given the continuation and a list of uninitialized invocations, fill 1097 new ir.InvokeContinuation(collector.continuation,
942 /// in each invocation with the continuation and appropriate arguments. 1098 environment.index2value)));
943 void invokeFullJoin(ir.Continuation join, 1099 environment = collector.environment;
944 JumpCollector jumps,
945 {recursive: false}) {
946 // TODO(kmillikin): If the JumpCollector collected open IrBuilders instead
947 // of pairs of invocations and environments, we could use IrBuilder.jumpTo
948 // here --- the code is almost the same.
949 join.isRecursive = recursive;
950 for (int i = 0; i < jumps.length; ++i) {
951 Environment currentEnvironment = jumps.environments[i];
952 ir.InvokeContinuation invoke = jumps.invocations[i];
953 invoke.continuation = new ir.Reference(join);
954 invoke.arguments = new List<ir.Reference>.generate(
955 join.parameters.length,
956 (i) => new ir.Reference(currentEnvironment[i]));
957 invoke.isRecursive = recursive;
958 }
959 } 1100 }
960 1101
961 /// Creates a for loop in which the initializer, condition, body, update are 1102 /// Creates a for loop in which the initializer, condition, body, update are
962 /// created by [buildInitializer], [buildCondition], [buildBody] and 1103 /// created by [buildInitializer], [buildCondition], [buildBody] and
963 /// [buildUpdate], respectively. 1104 /// [buildUpdate], respectively.
964 /// 1105 ///
965 /// The jump [target] is used to identify which `break` and `continue` 1106 /// The jump [target] is used to identify which `break` and `continue`
966 /// statements that have this `for` statement as their target. 1107 /// statements that have this `for` statement as their target.
967 /// 1108 ///
968 /// The [closureScope] identifies variables that should be boxed in this loop. 1109 /// The [closureScope] identifies variables that should be boxed in this loop.
(...skipping 13 matching lines...) Expand all
982 1123
983 // For loops use four named continuations: the entry to the condition, 1124 // For loops use four named continuations: the entry to the condition,
984 // the entry to the body, the loop exit, and the loop successor (break). 1125 // the entry to the body, the loop exit, and the loop successor (break).
985 // The CPS translation of 1126 // The CPS translation of
986 // [[for (initializer; condition; update) body; successor]] is: 1127 // [[for (initializer; condition; update) body; successor]] is:
987 // 1128 //
988 // _enterForLoopInitializer(); 1129 // _enterForLoopInitializer();
989 // [[initializer]]; 1130 // [[initializer]];
990 // let cont loop(x, ...) = 1131 // let cont loop(x, ...) =
991 // let prim cond = [[condition]] in 1132 // let prim cond = [[condition]] in
992 // let cont break() = [[successor]] in 1133 // let cont break(x, ...) = [[successor]] in
993 // let cont exit() = break(v, ...) in 1134 // let cont exit() = break(v, ...) in
994 // let cont body() = 1135 // let cont body() =
995 // _enterForLoopBody(); 1136 // _enterForLoopBody();
996 // let cont continue(x, ...) = 1137 // let cont continue(x, ...) =
997 // _enterForLoopUpdate(); 1138 // _enterForLoopUpdate();
998 // [[update]]; 1139 // [[update]];
999 // loop(v, ...) in 1140 // loop(v, ...) in
1000 // [[body]]; 1141 // [[body]];
1001 // continue(v, ...) in 1142 // continue(v, ...) in
1002 // branch cond (body, exit) in 1143 // branch cond (body, exit) in
1003 // loop(v, ...) 1144 // loop(v, ...)
1004 // 1145 //
1005 // If there are no breaks in the body, the break continuation is inlined 1146 // If there are no breaks in the body, the break continuation is inlined
1006 // in the exit continuation (i.e., the translation of the successor 1147 // in the exit continuation (i.e., the translation of the successor
1007 // statement occurs in the exit continuation). If there is only one 1148 // statement occurs in the exit continuation). If there is only one
1008 // invocation of the continue continuation (i.e., no continues in the 1149 // invocation of the continue continuation (i.e., no continues in the
1009 // body), the continue continuation is inlined in the body. 1150 // body), the continue continuation is inlined in the body.
1010
1011 _enterForLoopInitializer(closureScope, loopVariables); 1151 _enterForLoopInitializer(closureScope, loopVariables);
1012
1013 buildInitializer(this); 1152 buildInitializer(this);
1014 1153
1015 IrBuilder condBuilder = makeRecursiveBuilder(); 1154 JumpCollector loop = new BackwardJumpCollector(environment);
1016 ir.Primitive condition = buildCondition(condBuilder); 1155 addRecursiveContinuation(loop);
1156
1157 ir.Primitive condition = buildCondition(this);
1017 if (condition == null) { 1158 if (condition == null) {
1018 // If the condition is empty then the body is entered unconditionally. 1159 // If the condition is empty then the body is entered unconditionally.
1019 condition = condBuilder.buildBooleanLiteral(true); 1160 condition = buildBooleanLiteral(true);
1020 } 1161 }
1162 JumpCollector breakCollector =
1163 new ForwardJumpCollector(environment, target: target);
1021 1164
1022 JumpCollector breakCollector = new JumpCollector(target); 1165 // Use a pair of builders for the body, one for the entry code if any
1023 JumpCollector continueCollector = new JumpCollector(target); 1166 // and one for the body itself. We only decide whether to insert a
1167 // continue continuation until after translating the body and there is no
1168 // way to insert such a continuation between the entry code and the body
1169 // if they are translated together.
1170 IrBuilder outerBodyBuilder = makeDelimitedBuilder();
1171 outerBodyBuilder._enterForLoopBody(closureScope, loopVariables);
1172 JumpCollector continueCollector =
1173 new ForwardJumpCollector(outerBodyBuilder.environment, target: target);
1174
1175 IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder();
1024 state.breakCollectors.add(breakCollector); 1176 state.breakCollectors.add(breakCollector);
1025 state.continueCollectors.add(continueCollector); 1177 state.continueCollectors.add(continueCollector);
1026
1027 IrBuilder outerBodyBuilder = condBuilder.makeDelimitedBuilder();
1028 outerBodyBuilder._enterForLoopBody(closureScope, loopVariables);
1029
1030 IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder();
1031
1032 buildBody(innerBodyBuilder); 1178 buildBody(innerBodyBuilder);
1033 assert(state.breakCollectors.last == breakCollector); 1179 assert(state.breakCollectors.last == breakCollector);
1034 assert(state.continueCollectors.last == continueCollector); 1180 assert(state.continueCollectors.last == continueCollector);
1035 state.breakCollectors.removeLast(); 1181 state.breakCollectors.removeLast();
1036 state.continueCollectors.removeLast(); 1182 state.continueCollectors.removeLast();
1037 1183
1038 // The binding of the continue continuation should occur as late as 1184 // The binding of the continue continuation should occur as late as
1039 // possible, that is, at the nearest common ancestor of all the continue 1185 // possible, that is, at the nearest common ancestor of all the continue
1040 // sites in the body. However, that is difficult to compute here, so it 1186 // sites in the body. However, that is difficult to compute here, so it
1041 // is instead placed just outside the body of the body continuation. 1187 // is instead placed just outside the translation of the loop body. In
1188 // the case where there are no continues in the body, the updates are
1189 // translated immediately after the body.
1042 bool hasContinues = !continueCollector.isEmpty; 1190 bool hasContinues = !continueCollector.isEmpty;
1043 IrBuilder updateBuilder = hasContinues 1191 IrBuilder updateBuilder;
1044 ? outerBodyBuilder.makeRecursiveBuilder() 1192 if (hasContinues) {
1045 : innerBodyBuilder; 1193 if (innerBodyBuilder.isOpen) innerBodyBuilder.jumpTo(continueCollector);
1194 updateBuilder = makeDelimitedBuilder(continueCollector.environment);
1195 } else {
1196 updateBuilder = innerBodyBuilder;
1197 }
1046 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); 1198 updateBuilder._enterForLoopUpdate(closureScope, loopVariables);
1047 buildUpdate(updateBuilder); 1199 buildUpdate(updateBuilder);
1200 if (updateBuilder.isOpen) updateBuilder.jumpTo(loop);
1201 // Connect the inner and outer body builders. This is done only after
1202 // it is guaranteed that the updateBuilder has a non-empty term.
1203 if (hasContinues) {
1204 outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation,
1205 innerBodyBuilder._root));
1206 continueCollector.continuation.body = updateBuilder._root;
1207 } else {
1208 outerBodyBuilder.add(innerBodyBuilder._root);
1209 }
1048 1210
1049 // Create body entry and loop exit continuations and a branch to them. 1211 // Create loop exit and body entry continuations and a branch to them.
1212 ir.Continuation exitContinuation = new ir.Continuation([]);
1050 ir.Continuation bodyContinuation = new ir.Continuation([]); 1213 ir.Continuation bodyContinuation = new ir.Continuation([]);
1051 ir.Continuation exitContinuation = new ir.Continuation([]); 1214 bodyContinuation.body = outerBodyBuilder._root;
1052 // Note the order of continuations: the first one is the one that will 1215 // Note the order of continuations: the first one is the one that will
1053 // be filled by LetCont.plug. 1216 // be filled by LetCont.plug.
1054 ir.LetCont branch = 1217 ir.LetCont branch =
1055 new ir.LetCont.many(<ir.Continuation>[exitContinuation, 1218 new ir.LetCont.many(<ir.Continuation>[exitContinuation,
1056 bodyContinuation], 1219 bodyContinuation],
1057 new ir.Branch(new ir.IsTrue(condition), 1220 new ir.Branch(new ir.IsTrue(condition),
1058 bodyContinuation, 1221 bodyContinuation,
1059 exitContinuation)); 1222 exitContinuation));
1060 // If there are breaks in the body, then there must be a join-point 1223 // If there are breaks in the body, then there must be a join-point
1061 // continuation for the normal exit and the breaks. 1224 // continuation for the normal exit and the breaks. Otherwise, the
1225 // successor is translated in the hole in the exit continuation.
1062 bool hasBreaks = !breakCollector.isEmpty; 1226 bool hasBreaks = !breakCollector.isEmpty;
1063 ir.LetCont letJoin; 1227 ir.LetCont letBreak;
1064 if (hasBreaks) { 1228 if (hasBreaks) {
1065 letJoin = new ir.LetCont(null, branch); 1229 IrBuilder exitBuilder = makeDelimitedBuilder();
1066 condBuilder.add(letJoin); 1230 exitBuilder.jumpTo(breakCollector);
1067 condBuilder._current = branch; 1231 exitContinuation.body = exitBuilder._root;
1232 letBreak = new ir.LetCont(breakCollector.continuation, branch);
1233 add(letBreak);
1234 environment = breakCollector.environment;
1068 } else { 1235 } else {
1069 condBuilder.add(branch); 1236 add(branch);
1070 }
1071 ir.Continuation continueContinuation;
1072 if (hasContinues) {
1073 // If there are continues in the body, we need a named continue
1074 // continuation as a join point.
1075 continueContinuation = new ir.Continuation(updateBuilder._parameters);
1076 if (innerBodyBuilder.isOpen) continueCollector.addJump(innerBodyBuilder);
1077 invokeFullJoin(continueContinuation, continueCollector);
1078 }
1079 ir.Continuation loopContinuation =
1080 new ir.Continuation(condBuilder._parameters);
1081 if (updateBuilder.isOpen) {
1082 JumpCollector backEdges = new JumpCollector(null);
1083 backEdges.addJump(updateBuilder);
1084 invokeFullJoin(loopContinuation, backEdges, recursive: true);
1085 }
1086
1087 // Fill in the body and possible continue continuation bodies. Do this
1088 // only after it is guaranteed that they are not empty.
1089 if (hasContinues) {
1090 continueContinuation.body = updateBuilder._root;
1091 outerBodyBuilder.add(new ir.LetCont(continueContinuation,
1092 innerBodyBuilder._root));
1093 } else {
1094 outerBodyBuilder.add(innerBodyBuilder._root);
1095 }
1096 bodyContinuation.body = outerBodyBuilder._root;
1097
1098 loopContinuation.body = condBuilder._root;
1099 add(new ir.LetCont(loopContinuation,
1100 new ir.InvokeContinuation(loopContinuation,
1101 environment.index2value)));
1102 if (hasBreaks) {
1103 _current = branch;
1104 environment = condBuilder.environment;
1105 breakCollector.addJump(this);
1106 letJoin.continuations =
1107 <ir.Continuation>[createJoin(environment.length, breakCollector)];
1108 _current = letJoin;
1109 } else {
1110 _current = condBuilder._current;
1111 environment = condBuilder.environment;
1112 } 1237 }
1113 } 1238 }
1114 1239
1115 /// Creates a for-in loop, `for (v in e) b`. 1240 /// Creates a for-in loop, `for (v in e) b`.
1116 /// 1241 ///
1117 /// [buildExpression] creates the expression, `e`. The variable, `v`, can 1242 /// [buildExpression] creates the expression, `e`. The variable, `v`, can
1118 /// take one of three forms: 1243 /// take one of three forms:
1119 /// 1) `v` can be declared within the for-in statement, like in 1244 /// 1) `v` can be declared within the for-in statement, like in
1120 /// `for (var v in e)`, in which case, [buildVariableDeclaration] 1245 /// `for (var v in e)`, in which case, [buildVariableDeclaration]
1121 /// creates its declaration and [variableElement] is the element for 1246 /// creates its declaration and [variableElement] is the element for
(...skipping 18 matching lines...) Expand all
1140 // for (a in e) s; 1265 // for (a in e) s;
1141 // 1266 //
1142 // Is compiled analogously to: 1267 // Is compiled analogously to:
1143 // 1268 //
1144 // it = e.iterator; 1269 // it = e.iterator;
1145 // while (it.moveNext()) { 1270 // while (it.moveNext()) {
1146 // var a = it.current; 1271 // var a = it.current;
1147 // s; 1272 // s;
1148 // } 1273 // }
1149 1274
1150 // The condition and body are delimited. 1275 // Fill the current hole with:
1151 IrBuilder condBuilder = makeRecursiveBuilder(); 1276 // let prim expressionReceiver = [[e]] in
1152 1277 // let cont iteratorInvoked(iterator) =
1278 // [ ]
1279 // in expressionReceiver.iterator () iteratorInvoked
1153 ir.Primitive expressionReceiver = buildExpression(this); 1280 ir.Primitive expressionReceiver = buildExpression(this);
1154 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); 1281 List<ir.Primitive> emptyArguments = <ir.Primitive>[];
1155
1156 ir.Parameter iterator = new ir.Parameter(null); 1282 ir.Parameter iterator = new ir.Parameter(null);
1157 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); 1283 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
1158 add(new ir.LetCont(iteratorInvoked, 1284 add(new ir.LetCont(iteratorInvoked,
1159 new ir.InvokeMethod(expressionReceiver, 1285 new ir.InvokeMethod(expressionReceiver,
1160 new Selector.getter("iterator", null), iteratorInvoked, 1286 new Selector.getter("iterator", null),
1287 iteratorInvoked,
1161 emptyArguments))); 1288 emptyArguments)));
1162 1289
1290 // Fill with:
1291 // let cont loop(x, ...) =
1292 // let cont moveNextInvoked(condition) =
1293 // [ ]
1294 // in iterator.moveNext () moveNextInvoked
1295 // in loop(v, ...)
1296 JumpCollector loop = new BackwardJumpCollector(environment, target: target);
1297 addRecursiveContinuation(loop);
1163 ir.Parameter condition = new ir.Parameter(null); 1298 ir.Parameter condition = new ir.Parameter(null);
1164 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); 1299 ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
1165 condBuilder.add(new ir.LetCont(moveNextInvoked, 1300 add(new ir.LetCont(moveNextInvoked,
1166 new ir.InvokeMethod(iterator, 1301 new ir.InvokeMethod(iterator,
1167 new Selector.call("moveNext", null, 0), 1302 new Selector.call("moveNext", null, 0),
1168 moveNextInvoked, emptyArguments))); 1303 moveNextInvoked,
1304 emptyArguments)));
1169 1305
1170 JumpCollector breakCollector = new JumpCollector(target); 1306 // As a delimited term, build:
1171 JumpCollector continueCollector = new JumpCollector(target); 1307 // <<BODY>> =
1172 state.breakCollectors.add(breakCollector); 1308 // _enterScope();
1173 state.continueCollectors.add(continueCollector); 1309 // [[variableDeclaration]]
1174 1310 // let cont currentInvoked(currentValue) =
1175 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); 1311 // [[a = currentValue]];
1312 // [ ]
1313 // in iterator.current () currentInvoked
1314 IrBuilder bodyBuilder = makeDelimitedBuilder();
1176 bodyBuilder._enterScope(closureScope); 1315 bodyBuilder._enterScope(closureScope);
1177 if (buildVariableDeclaration != null) { 1316 if (buildVariableDeclaration != null) {
1178 buildVariableDeclaration(bodyBuilder); 1317 buildVariableDeclaration(bodyBuilder);
1179 } 1318 }
1180
1181 ir.Parameter currentValue = new ir.Parameter(null); 1319 ir.Parameter currentValue = new ir.Parameter(null);
1182 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); 1320 ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
1183 bodyBuilder.add(new ir.LetCont(currentInvoked, 1321 bodyBuilder.add(new ir.LetCont(currentInvoked,
1184 new ir.InvokeMethod(iterator, new Selector.getter("current", null), 1322 new ir.InvokeMethod(iterator, new Selector.getter("current", null),
1185 currentInvoked, emptyArguments))); 1323 currentInvoked, emptyArguments)));
1186 // TODO(sra): Does this cover all cases? The general setter case include 1324 // TODO(sra): Does this cover all cases? The general setter case include
1187 // super. 1325 // super.
1188 if (Elements.isLocal(variableElement)) { 1326 if (Elements.isLocal(variableElement)) {
1189 bodyBuilder.buildLocalSet(variableElement, currentValue); 1327 bodyBuilder.buildLocalSet(variableElement, currentValue);
1190 } else if (Elements.isStaticOrTopLevel(variableElement) || 1328 } else if (Elements.isStaticOrTopLevel(variableElement) ||
1191 Elements.isErroneous(variableElement)) { 1329 Elements.isErroneous(variableElement)) {
1192 bodyBuilder.buildStaticSet(variableElement, currentValue); 1330 bodyBuilder.buildStaticSet(variableElement, currentValue);
1193 } else { 1331 } else {
1194 ir.Primitive receiver = bodyBuilder.buildThis(); 1332 ir.Primitive receiver = bodyBuilder.buildThis();
1195 assert(receiver != null); 1333 assert(receiver != null);
1196 bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue); 1334 bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue);
1197 } 1335 }
1198 1336
1337 // Translate the body in the hole in the delimited term above, and add
1338 // a jump to the loop if control flow is live after the body.
1339 JumpCollector breakCollector =
1340 new ForwardJumpCollector(environment, target: target);
1341 state.breakCollectors.add(breakCollector);
1342 state.continueCollectors.add(loop);
1199 buildBody(bodyBuilder); 1343 buildBody(bodyBuilder);
1200 assert(state.breakCollectors.last == breakCollector); 1344 assert(state.breakCollectors.last == breakCollector);
1201 assert(state.continueCollectors.last == continueCollector); 1345 assert(state.continueCollectors.last == loop);
1202 state.breakCollectors.removeLast(); 1346 state.breakCollectors.removeLast();
1203 state.continueCollectors.removeLast(); 1347 state.continueCollectors.removeLast();
1348 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
1204 1349
1205 // Create body entry and loop exit continuations and a branch to them. 1350 // Create body entry and loop exit continuations and a branch to them.
1351 //
1352 // let cont exit() = [ ]
1353 // and body() = <<BODY>>
1354 // in branch condition (body, exit)
1355 ir.Continuation exitContinuation = new ir.Continuation([]);
1206 ir.Continuation bodyContinuation = new ir.Continuation([]); 1356 ir.Continuation bodyContinuation = new ir.Continuation([]);
1207 ir.Continuation exitContinuation = new ir.Continuation([]); 1357 bodyContinuation.body = bodyBuilder._root;
1208 // Note the order of continuations: the first one is the one that will 1358 // Note the order of continuations: the first one is the one that will
1209 // be filled by LetCont.plug. 1359 // be filled by LetCont.plug.
1210 ir.LetCont branch = 1360 ir.LetCont branch =
1211 new ir.LetCont.many(<ir.Continuation>[exitContinuation, 1361 new ir.LetCont.many(<ir.Continuation>[exitContinuation,
1212 bodyContinuation], 1362 bodyContinuation],
1213 new ir.Branch(new ir.IsTrue(condition), 1363 new ir.Branch(new ir.IsTrue(condition),
1214 bodyContinuation, 1364 bodyContinuation,
1215 exitContinuation)); 1365 exitContinuation));
1216 // If there are breaks in the body, then there must be a join-point 1366 // If there are breaks in the body, then there must be a join-point
1217 // continuation for the normal exit and the breaks. 1367 // continuation for the normal exit and the breaks. Otherwise, the
1368 // successor is translated in the hole in the exit continuation.
1218 bool hasBreaks = !breakCollector.isEmpty; 1369 bool hasBreaks = !breakCollector.isEmpty;
1219 ir.LetCont letJoin; 1370 ir.LetCont letBreak;
1220 if (hasBreaks) { 1371 if (hasBreaks) {
1221 letJoin = new ir.LetCont(null, branch); 1372 IrBuilder exitBuilder = makeDelimitedBuilder();
1222 condBuilder.add(letJoin); 1373 exitBuilder.jumpTo(breakCollector);
1223 condBuilder._current = branch; 1374 exitContinuation.body = exitBuilder._root;
1375 letBreak = new ir.LetCont(breakCollector.continuation, branch);
1376 add(letBreak);
1377 environment = breakCollector.environment;
1224 } else { 1378 } else {
1225 condBuilder.add(branch); 1379 add(branch);
1226 }
1227 ir.Continuation loopContinuation =
1228 new ir.Continuation(condBuilder._parameters);
1229 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
1230 invokeFullJoin(
1231 loopContinuation, continueCollector, recursive: true);
1232 bodyContinuation.body = bodyBuilder._root;
1233
1234 loopContinuation.body = condBuilder._root;
1235 add(new ir.LetCont(loopContinuation,
1236 new ir.InvokeContinuation(loopContinuation,
1237 environment.index2value)));
1238 if (hasBreaks) {
1239 _current = branch;
1240 environment = condBuilder.environment;
1241 breakCollector.addJump(this);
1242 letJoin.continuations =
1243 <ir.Continuation>[createJoin(environment.length, breakCollector)];
1244 _current = letJoin;
1245 } else {
1246 _current = condBuilder._current;
1247 environment = condBuilder.environment;
1248 } 1380 }
1249 } 1381 }
1250 1382
1251 /// Creates a while loop in which the condition and body are created by 1383 /// Creates a while loop in which the condition and body are created by
1252 /// [buildCondition] and [buildBody], respectively. 1384 /// [buildCondition] and [buildBody], respectively.
1253 /// 1385 ///
1254 /// The jump [target] is used to identify which `break` and `continue` 1386 /// The jump [target] is used to identify which `break` and `continue`
1255 /// statements that have this `while` statement as their target. 1387 /// statements that have this `while` statement as their target.
1256 void buildWhile({SubbuildFunction buildCondition, 1388 void buildWhile({SubbuildFunction buildCondition,
1257 SubbuildFunction buildBody, 1389 SubbuildFunction buildBody,
1258 JumpTarget target, 1390 JumpTarget target,
1259 ClosureScope closureScope}) { 1391 ClosureScope closureScope}) {
1260 assert(isOpen); 1392 assert(isOpen);
1261 // While loops use four named continuations: the entry to the body, the 1393 // While loops use four named continuations: the entry to the body, the
1262 // loop exit, the loop back edge (continue), and the loop exit (break). 1394 // loop exit, the loop back edge (continue), and the loop exit (break).
1263 // The CPS translation of [[while (condition) body; successor]] is: 1395 // The CPS translation of [[while (condition) body; successor]] is:
1264 // 1396 //
1265 // let cont continue(x, ...) = 1397 // let cont continue(x, ...) =
1266 // let prim cond = [[condition]] in 1398 // let prim cond = [[condition]] in
1267 // let cont break(x, ...) = [[successor]] in 1399 // let cont break(x, ...) = [[successor]] in
1268 // let cont exit() = break(v, ...) 1400 // let cont exit() = break(v, ...)
1269 // and body() = [[body]]; continue(v, ...) 1401 // and body() =
1402 // _enterScope();
1403 // [[body]];
1404 // continue(v, ...)
1270 // in branch cond (body, exit) 1405 // in branch cond (body, exit)
1271 // in continue(v, ...) 1406 // in continue(v, ...)
1272 // 1407 //
1273 // If there are no breaks in the body, the break continuation is inlined 1408 // If there are no breaks in the body, the break continuation is inlined
1274 // in the exit continuation (i.e., the translation of the successor 1409 // in the exit continuation (i.e., the translation of the successor
1275 // statement occurs in the exit continuation). 1410 // statement occurs in the exit continuation).
1411 JumpCollector loop = new BackwardJumpCollector(environment, target: target);
1412 addRecursiveContinuation(loop);
1276 1413
1277 // The condition and body are delimited. 1414 ir.Primitive condition = buildCondition(this);
1278 IrBuilder condBuilder = makeRecursiveBuilder();
1279 ir.Primitive condition = buildCondition(condBuilder);
1280 1415
1281 JumpCollector breakCollector = new JumpCollector(target); 1416 JumpCollector breakCollector =
1282 JumpCollector continueCollector = new JumpCollector(target); 1417 new ForwardJumpCollector(environment, target: target);
1418
1419 IrBuilder bodyBuilder = makeDelimitedBuilder();
1420 bodyBuilder._enterScope(closureScope);
1283 state.breakCollectors.add(breakCollector); 1421 state.breakCollectors.add(breakCollector);
1284 state.continueCollectors.add(continueCollector); 1422 state.continueCollectors.add(loop);
1285
1286 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1287 bodyBuilder._enterScope(closureScope);
1288 buildBody(bodyBuilder); 1423 buildBody(bodyBuilder);
1289 assert(state.breakCollectors.last == breakCollector); 1424 assert(state.breakCollectors.last == breakCollector);
1290 assert(state.continueCollectors.last == continueCollector); 1425 assert(state.continueCollectors.last == loop);
1291 state.breakCollectors.removeLast(); 1426 state.breakCollectors.removeLast();
1292 state.continueCollectors.removeLast(); 1427 state.continueCollectors.removeLast();
1428 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop);
1293 1429
1294 // Create body entry and loop exit continuations and a branch to them. 1430 // Create body entry and loop exit continuations and a branch to them.
1431 ir.Continuation exitContinuation = new ir.Continuation([]);
1295 ir.Continuation bodyContinuation = new ir.Continuation([]); 1432 ir.Continuation bodyContinuation = new ir.Continuation([]);
1296 ir.Continuation exitContinuation = new ir.Continuation([]); 1433 bodyContinuation.body = bodyBuilder._root;
1297 // Note the order of continuations: the first one is the one that will 1434 // Note the order of continuations: the first one is the one that will
1298 // be filled by LetCont.plug. 1435 // be filled by LetCont.plug.
1299 ir.LetCont branch = 1436 ir.LetCont branch =
1300 new ir.LetCont.many(<ir.Continuation>[exitContinuation, 1437 new ir.LetCont.many(<ir.Continuation>[exitContinuation,
1301 bodyContinuation], 1438 bodyContinuation],
1302 new ir.Branch(new ir.IsTrue(condition), 1439 new ir.Branch(new ir.IsTrue(condition),
1303 bodyContinuation, 1440 bodyContinuation,
1304 exitContinuation)); 1441 exitContinuation));
1305 // If there are breaks in the body, then there must be a join-point 1442 // If there are breaks in the body, then there must be a join-point
1306 // continuation for the normal exit and the breaks. 1443 // continuation for the normal exit and the breaks. Otherwise, the
1444 // successor is translated in the hole in the exit continuation.
1307 bool hasBreaks = !breakCollector.isEmpty; 1445 bool hasBreaks = !breakCollector.isEmpty;
1308 ir.LetCont letJoin; 1446 ir.LetCont letBreak;
1309 if (hasBreaks) { 1447 if (hasBreaks) {
1310 letJoin = new ir.LetCont(null, branch); 1448 IrBuilder exitBuilder = makeDelimitedBuilder();
1311 condBuilder.add(letJoin); 1449 exitBuilder.jumpTo(breakCollector);
1312 condBuilder._current = branch; 1450 exitContinuation.body = exitBuilder._root;
1451 letBreak = new ir.LetCont(breakCollector.continuation, branch);
1452 add(letBreak);
1453 environment = breakCollector.environment;
1313 } else { 1454 } else {
1314 condBuilder.add(branch); 1455 add(branch);
1315 }
1316 ir.Continuation loopContinuation =
1317 new ir.Continuation(condBuilder._parameters);
1318 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder);
1319 invokeFullJoin(loopContinuation, continueCollector, recursive: true);
1320 bodyContinuation.body = bodyBuilder._root;
1321
1322 loopContinuation.body = condBuilder._root;
1323 add(new ir.LetCont(loopContinuation,
1324 new ir.InvokeContinuation(loopContinuation,
1325 environment.index2value)));
1326 if (hasBreaks) {
1327 _current = branch;
1328 environment = condBuilder.environment;
1329 breakCollector.addJump(this);
1330 letJoin.continuations =
1331 <ir.Continuation>[createJoin(environment.length, breakCollector)];
1332 _current = letJoin;
1333 } else {
1334 _current = condBuilder._current;
1335 environment = condBuilder.environment;
1336 } 1456 }
1337 } 1457 }
1338 1458
1339 1459
1340 /// Creates a do-while loop. 1460 /// Creates a do-while loop.
1341 /// 1461 ///
1342 /// The body and condition are created by [buildBody] and [buildCondition]. 1462 /// The body and condition are created by [buildBody] and [buildCondition].
1343 /// The jump target [target] is the target of `break` and `continue` 1463 /// The jump target [target] is the target of `break` and `continue`
1344 /// statements in the body that have the loop as their target. 1464 /// statements in the body that have the loop as their target.
1345 /// [closureScope] contains all the variables declared in the loop (but not 1465 /// [closureScope] contains all the variables declared in the loop (but not
1346 /// declared in some inner closure scope). 1466 /// declared in some inner closure scope).
1347 void buildDoWhile({SubbuildFunction buildBody, 1467 void buildDoWhile({SubbuildFunction buildBody,
1348 SubbuildFunction buildCondition, 1468 SubbuildFunction buildCondition,
1349 JumpTarget target, 1469 JumpTarget target,
1350 ClosureScope closureScope}) { 1470 ClosureScope closureScope}) {
1351 assert(isOpen); 1471 assert(isOpen);
1352 // The CPS translation of [[do body; while (condition); successor]] is: 1472 // The CPS translation of [[do body; while (condition); successor]] is:
1353 // 1473 //
1354 // let cont break(x, ...) = [[successor]] in 1474 // let cont break(x, ...) = [[successor]] in
1355 // let cont rec loop(x, ...) = 1475 // let cont rec loop(x, ...) =
1356 // let cont continue(x, ...) = 1476 // let cont continue(x, ...) =
1357 // let prim cond = [[condition]] in 1477 // let prim cond = [[condition]] in
1358 // let cont exit() = break(v, ...) 1478 // let cont exit() = break(v, ...)
1359 // and repeat() = loop(v, ...) 1479 // and repeat() = loop(v, ...)
1360 // in branch cond (repeat, exit) 1480 // in branch cond (repeat, exit)
1361 // in [[body]]; continue(v, ...) 1481 // in [[body]]; continue(v, ...)
1362 // in loop(v, ...) 1482 // in loop(v, ...)
1363 IrBuilder bodyBuilder = makeRecursiveBuilder(); 1483 IrBuilder loopBuilder = makeDelimitedBuilder();
1364 IrBuilder continueBuilder = bodyBuilder.makeRecursiveBuilder(); 1484 JumpCollector loop =
1485 new BackwardJumpCollector(loopBuilder.environment, target: target);
1486 loopBuilder.addRecursiveContinuation(loop);
1365 1487
1366 // Construct the continue continuation (i.e., the condition). 1488 // Translate the body.
1489 JumpCollector breakCollector =
1490 new ForwardJumpCollector(environment, target: target);
1491 JumpCollector continueCollector =
1492 new ForwardJumpCollector(loopBuilder.environment, target: target);
1493 IrBuilder bodyBuilder = loopBuilder.makeDelimitedBuilder();
1494 bodyBuilder._enterScope(closureScope);
1495 state.breakCollectors.add(breakCollector);
1496 state.continueCollectors.add(continueCollector);
1497 buildBody(bodyBuilder);
1498 assert(state.breakCollectors.last == breakCollector);
1499 assert(state.continueCollectors.last == continueCollector);
1500 state.breakCollectors.removeLast();
1501 state.continueCollectors.removeLast();
1502 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(continueCollector);
1503
1504 // Construct the body of the continue continuation (i.e., the condition).
1367 // <Continue> = 1505 // <Continue> =
1368 // let prim cond = [[condition]] in 1506 // let prim cond = [[condition]] in
1369 // let cont exit() = break(v, ...) 1507 // let cont exit() = break(v, ...)
1370 // and repeat() = loop(v, ...) 1508 // and repeat() = loop(v, ...)
1371 // in branch cond (repeat, exit) 1509 // in branch cond (repeat, exit)
1510 IrBuilder continueBuilder = loopBuilder.makeDelimitedBuilder();
1511 continueBuilder.environment = continueCollector.environment;
1372 ir.Primitive condition = buildCondition(continueBuilder); 1512 ir.Primitive condition = buildCondition(continueBuilder);
1373 // Use a delimited IrBuilder for the exit continuation's body so that 1513
1374 // we can capture the break with the body's break collector.
1375 ir.Continuation exitContinuation = new ir.Continuation([]); 1514 ir.Continuation exitContinuation = new ir.Continuation([]);
1376 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder(); 1515 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder();
1516 exitBuilder.jumpTo(breakCollector);
1517 exitContinuation.body = exitBuilder._root;
1377 ir.Continuation repeatContinuation = new ir.Continuation([]); 1518 ir.Continuation repeatContinuation = new ir.Continuation([]);
1378 ir.InvokeContinuation invokeLoop = 1519 IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder();
1379 new ir.InvokeContinuation.uninitialized(recursive: true); 1520 repeatBuilder.jumpTo(loop);
1380 invokeLoop.arguments = 1521 repeatContinuation.body = repeatBuilder._root;
1381 continueBuilder.environment.index2value.map( 1522
1382 (ir.Primitive value) => new ir.Reference(value)).toList();
1383 repeatContinuation.body = invokeLoop;
1384 continueBuilder.add( 1523 continueBuilder.add(
1385 new ir.LetCont.many(<ir.Continuation>[exitContinuation, 1524 new ir.LetCont.many(<ir.Continuation>[exitContinuation,
1386 repeatContinuation], 1525 repeatContinuation],
1387 new ir.Branch(new ir.IsTrue(condition), 1526 new ir.Branch(new ir.IsTrue(condition),
1388 repeatContinuation, 1527 repeatContinuation,
1389 exitContinuation))); 1528 exitContinuation)));
1390 ir.Continuation continueContinuation = 1529 continueCollector.continuation.body = continueBuilder._root;
1391 new ir.Continuation(continueBuilder._parameters);
1392 continueContinuation.body = continueBuilder._root;
1393 1530
1394 // Construct the loop continuation (i.e., the body and condition). 1531 // Construct the loop continuation (i.e., the body and condition).
1395 // <Loop> = 1532 // <Loop> =
1396 // let cont continue(x, ...) = 1533 // let cont continue(x, ...) =
1397 // <Continue> 1534 // <Continue>
1398 // in [[body]]; continue(v, ...) 1535 // in [[body]]; continue(v, ...)
1399 JumpCollector breakCollector = new JumpCollector(target); 1536 loopBuilder.add(
1400 JumpCollector continueCollector = new JumpCollector(target); 1537 new ir.LetCont(continueCollector.continuation,
1401 state.breakCollectors.add(breakCollector); 1538 bodyBuilder._root));
1402 state.continueCollectors.add(continueCollector);
1403 bodyBuilder._enterScope(closureScope);
1404 buildBody(bodyBuilder);
1405 assert(state.breakCollectors.last == breakCollector);
1406 assert(state.continueCollectors.last == continueCollector);
1407 state.breakCollectors.removeLast();
1408 state.continueCollectors.removeLast();
1409 // Add the jump from the loop's exit to the break condition. It is only
1410 // here where the exitBuilder's root is non-null and we can set the
1411 // exitContinuation's body.
1412 breakCollector.addJump(exitBuilder);
1413 exitContinuation.body = exitBuilder._root;
1414 if (bodyBuilder.isOpen) {
1415 continueCollector.addJump(bodyBuilder);
1416 }
1417 invokeFullJoin(continueContinuation, continueCollector, recursive: false);
1418 ir.Continuation loopContinuation =
1419 new ir.Continuation(bodyBuilder._parameters);
1420 loopContinuation.isRecursive = true;
1421 loopContinuation.body =
1422 new ir.LetCont(continueContinuation, bodyBuilder._root);
1423 invokeLoop.continuation =
1424 new ir.Reference<ir.Continuation>(loopContinuation);
1425 ir.LetCont letLoop =
1426 new ir.LetCont(loopContinuation,
1427 new ir.InvokeContinuation(loopContinuation,
1428 environment.index2value));
1429 1539
1430 // Add the break condition. 1540 // And tie it all together.
1431 ir.Continuation breakContinuation; 1541 add(new ir.LetCont(breakCollector.continuation, loopBuilder._root));
1432 if (breakCollector.length == 1) { 1542 environment = breakCollector.environment;
1433 // createJoin only works when there is more than one jump to a join-point
1434 // continuation. This is to potentially catch errors in the case that
1435 // a join was intended and at least one jump is missing. Unfortunately
1436 // we have the explicit code below for the (common?) case that the
1437 // only break from the do-while is the implicit one when the condition
1438 // is false.
1439 List<ir.Parameter> parameters = <ir.Parameter>[];
1440 List<ir.Reference> arguments = <ir.Reference>[];
1441 for (int i = 0; i < environment.length; ++i) {
1442 ir.Parameter parameter =
1443 new ir.Parameter(environment.index2variable[i]);
1444 parameters.add(parameter);
1445 environment.index2value[i] = parameter;
1446 arguments.add(new ir.Reference(breakCollector.environments.first[i]));
1447 }
1448 breakContinuation = new ir.Continuation(parameters);
1449 breakCollector.invocations.first.arguments = arguments;
1450 breakCollector.invocations.first.continuation =
1451 new ir.Reference(breakContinuation);
1452 } else {
1453 breakContinuation = createJoin(environment.length, breakCollector);
1454 }
1455 add(new ir.LetCont(breakContinuation, letLoop));
1456 } 1543 }
1457 1544
1458 /// Creates a try-statement. 1545 /// Creates a try-statement.
1459 /// 1546 ///
1460 /// [tryInfo] provides information on local variables declared and boxed 1547 /// [tryInfo] provides information on local variables declared and boxed
1461 /// within this try statement. 1548 /// within this try statement.
1462 /// [buildTryBlock] builds the try block. 1549 /// [buildTryBlock] builds the try block.
1463 /// [catchClauseInfos] provides access to the catch type, exception variable, 1550 /// [catchClauseInfos] provides access to the catch type, exception variable,
1464 /// and stack trace variable, and a function for building the catch block. 1551 /// and stack trace variable, and a function for building the catch block.
1465 void buildTry( 1552 void buildTry(
(...skipping 24 matching lines...) Expand all
1490 // 1577 //
1491 // In other words, both the try and catch block are in the scope of the 1578 // In other words, both the try and catch block are in the scope of the
1492 // join-point continuation, and they are both in the scope of a sequence 1579 // join-point continuation, and they are both in the scope of a sequence
1493 // of mutable bindings for the variables assigned in the try. The join- 1580 // of mutable bindings for the variables assigned in the try. The join-
1494 // point continuation is not in the scope of these mutable bindings. 1581 // point continuation is not in the scope of these mutable bindings.
1495 // The tryBlock is in the scope of a binding for the catch handler. Each 1582 // The tryBlock is in the scope of a binding for the catch handler. Each
1496 // instruction (specifically, each call) in the tryBlock is in the dynamic 1583 // instruction (specifically, each call) in the tryBlock is in the dynamic
1497 // scope of the handler. The mutable bindings are dereferenced at the end 1584 // scope of the handler. The mutable bindings are dereferenced at the end
1498 // of the try block and at the beginning of the catch block, so the 1585 // of the try block and at the beginning of the catch block, so the
1499 // variables are unboxed in the catch block and at the join point. 1586 // variables are unboxed in the catch block and at the join point.
1587 JumpCollector join = new ForwardJumpCollector(environment);
1588 IrBuilder tryCatchBuilder = makeDelimitedBuilder();
1500 1589
1501 IrBuilder tryCatchBuilder = makeDelimitedBuilder();
1502 // Variables that are boxed due to being captured in a closure are boxed 1590 // Variables that are boxed due to being captured in a closure are boxed
1503 // for their entire lifetime, and so they do not need to be boxed on 1591 // for their entire lifetime, and so they do not need to be boxed on
1504 // entry to any try block. We check for them here because we can not 1592 // entry to any try block. They are not filtered out before this because
1505 // identify all of them in the same pass where we identify the variables 1593 // we can not identify all of them in the same pass where we identify the
1506 // assigned in the try (the may be captured by a closure after the try 1594 // variables assigned in the try (they may be captured by a closure after
1507 // statement). 1595 // the try statement).
1508 Iterable<LocalVariableElement> boxedOnEntry = 1596 Iterable<LocalVariableElement> boxedOnEntry =
1509 tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) { 1597 tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) {
1510 return !tryCatchBuilder.mutableCapturedVariables.contains(variable); 1598 return !tryCatchBuilder.mutableCapturedVariables.contains(variable);
1511 }); 1599 });
1512 for (LocalVariableElement variable in boxedOnEntry) { 1600 for (LocalVariableElement variable in boxedOnEntry) {
1513 assert(!tryCatchBuilder.isInMutableVariable(variable)); 1601 assert(!tryCatchBuilder.isInMutableVariable(variable));
1514 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); 1602 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable);
1515 tryCatchBuilder.makeMutableVariable(variable); 1603 tryCatchBuilder.makeMutableVariable(variable);
1516 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); 1604 tryCatchBuilder.declareLocalVariable(variable, initialValue: value);
1517 } 1605 }
1518 1606
1519 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
1520 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); 1607 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder();
1521 List<ir.Parameter> joinParameters =
1522 new List<ir.Parameter>.generate(environment.length, (i) {
1523 return new ir.Parameter(environment.index2variable[i]);
1524 });
1525 ir.Continuation joinContinuation = new ir.Continuation(joinParameters);
1526 1608
1527 void interceptJumps(JumpCollector collector) { 1609 void interceptJumps(JumpCollector collector) {
1528 collector.enterTry(boxedOnEntry); 1610 collector.enterTry(boxedOnEntry);
1529 } 1611 }
1530 void restoreJumps(JumpCollector collector) { 1612 void restoreJumps(JumpCollector collector) {
1531 collector.leaveTry(); 1613 collector.leaveTry();
1532 } 1614 }
1533 tryBuilder.state.breakCollectors.forEach(interceptJumps); 1615 tryBuilder.state.breakCollectors.forEach(interceptJumps);
1534 tryBuilder.state.continueCollectors.forEach(interceptJumps); 1616 tryBuilder.state.continueCollectors.forEach(interceptJumps);
1535 buildTryBlock(tryBuilder); 1617 buildTryBlock(tryBuilder);
1618 if (tryBuilder.isOpen) {
1619 interceptJumps(join);
1620 tryBuilder.jumpTo(join);
1621 restoreJumps(join);
1622 }
1536 tryBuilder.state.breakCollectors.forEach(restoreJumps); 1623 tryBuilder.state.breakCollectors.forEach(restoreJumps);
1537 tryBuilder.state.continueCollectors.forEach(restoreJumps); 1624 tryBuilder.state.continueCollectors.forEach(restoreJumps);
1538 if (tryBuilder.isOpen) {
1539 for (LocalVariableElement variable in boxedOnEntry) {
1540 assert(tryBuilder.isInMutableVariable(variable));
1541 ir.Primitive value = tryBuilder.buildLocalGet(variable);
1542 tryBuilder.environment.update(variable, value);
1543 }
1544 tryBuilder.jumpTo(joinContinuation);
1545 }
1546 1625
1626 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder();
1547 for (LocalVariableElement variable in boxedOnEntry) { 1627 for (LocalVariableElement variable in boxedOnEntry) {
1548 assert(catchBuilder.isInMutableVariable(variable)); 1628 assert(catchBuilder.isInMutableVariable(variable));
1549 ir.Primitive value = catchBuilder.buildLocalGet(variable); 1629 ir.Primitive value = catchBuilder.buildLocalGet(variable);
1550 // Note that we remove the variable from the set of mutable variables 1630 // Note that we remove the variable from the set of mutable variables
1551 // here (and not above for the try body). This is because the set of 1631 // here (and not above for the try body). This is because the set of
1552 // mutable variables is global for the whole function and not local to 1632 // mutable variables is global for the whole function and not local to
1553 // a delimited builder. 1633 // a delimited builder.
1554 catchBuilder.removeMutableVariable(variable); 1634 catchBuilder.removeMutableVariable(variable);
1555 catchBuilder.environment.update(variable, value); 1635 catchBuilder.environment.update(variable, value);
1556 } 1636 }
(...skipping 11 matching lines...) Expand all
1568 if (stackTraceVariable != null) { 1648 if (stackTraceVariable != null) {
1569 traceParameter = new ir.Parameter(stackTraceVariable); 1649 traceParameter = new ir.Parameter(stackTraceVariable);
1570 catchBuilder.environment.extend(stackTraceVariable, traceParameter); 1650 catchBuilder.environment.extend(stackTraceVariable, traceParameter);
1571 } else { 1651 } else {
1572 // Use a dummy continuation parameter for the stack trace parameter. 1652 // Use a dummy continuation parameter for the stack trace parameter.
1573 // This will ensure that all handlers have two parameters and so they 1653 // This will ensure that all handlers have two parameters and so they
1574 // can be treated uniformly. 1654 // can be treated uniformly.
1575 traceParameter = new ir.Parameter(null); 1655 traceParameter = new ir.Parameter(null);
1576 } 1656 }
1577 catchClauseInfo.buildCatchBlock(catchBuilder); 1657 catchClauseInfo.buildCatchBlock(catchBuilder);
1578 if (catchBuilder.isOpen) { 1658 if (catchBuilder.isOpen) catchBuilder.jumpTo(join);
1579 catchBuilder.jumpTo(joinContinuation);
1580 }
1581 List<ir.Parameter> catchParameters = 1659 List<ir.Parameter> catchParameters =
1582 <ir.Parameter>[exceptionParameter, traceParameter]; 1660 <ir.Parameter>[exceptionParameter, traceParameter];
1583 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); 1661 ir.Continuation catchContinuation = new ir.Continuation(catchParameters);
1584 catchContinuation.body = catchBuilder._root; 1662 catchContinuation.body = catchBuilder._root;
1585 1663
1586 tryCatchBuilder.add( 1664 tryCatchBuilder.add(
1587 new ir.LetHandler(catchContinuation, tryBuilder._root)); 1665 new ir.LetHandler(catchContinuation, tryBuilder._root));
1588 tryCatchBuilder._current = null; 1666 tryCatchBuilder._current = null;
1589 } 1667 }
1590 1668
1591 add(new ir.LetCont(joinContinuation, tryCatchBuilder._root)); 1669 add(new ir.LetCont(join.continuation, tryCatchBuilder._root));
1592 for (int i = 0; i < environment.length; ++i) { 1670 environment = join.environment;
1593 environment.index2value[i] = joinParameters[i];
1594 }
1595 } 1671 }
1596 1672
1597 /// Create a return statement `return value;` or `return;` if [value] is 1673 /// Create a return statement `return value;` or `return;` if [value] is
1598 /// null. 1674 /// null.
1599 void buildReturn([ir.Primitive value]) { 1675 void buildReturn([ir.Primitive value]) {
1600 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] 1676 // Build(Return(e), C) = C'[InvokeContinuation(return, x)]
1601 // where (C', x) = Build(e, C) 1677 // where (C', x) = Build(e, C)
1602 // 1678 //
1603 // Return without a subexpression is translated as if it were return null. 1679 // Return without a subexpression is translated as if it were return null.
1604 assert(isOpen); 1680 assert(isOpen);
(...skipping 20 matching lines...) Expand all
1625 /// The first node in the sequence does not need to be reachable. 1701 /// The first node in the sequence does not need to be reachable.
1626 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses 1702 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses
1627 // `List` instead of `Link`. 1703 // `List` instead of `Link`.
1628 void buildSequence(var nodes, BuildFunction build) { 1704 void buildSequence(var nodes, BuildFunction build) {
1629 for (var node in nodes) { 1705 for (var node in nodes) {
1630 if (!isOpen) return; 1706 if (!isOpen) return;
1631 build(node); 1707 build(node);
1632 } 1708 }
1633 } 1709 }
1634 1710
1635
1636 /// Creates a labeled statement 1711 /// Creates a labeled statement
1637 void buildLabeledStatement({SubbuildFunction buildBody, 1712 void buildLabeledStatement({SubbuildFunction buildBody,
1638 JumpTarget target}) { 1713 JumpTarget target}) {
1639 JumpCollector jumps = new JumpCollector(target); 1714 JumpCollector join = new ForwardJumpCollector(environment, target: target);
1640 state.breakCollectors.add(jumps);
1641 IrBuilder innerBuilder = makeDelimitedBuilder(); 1715 IrBuilder innerBuilder = makeDelimitedBuilder();
1716 innerBuilder.state.breakCollectors.add(join);
1642 buildBody(innerBuilder); 1717 buildBody(innerBuilder);
1643 state.breakCollectors.removeLast(); 1718 innerBuilder.state.breakCollectors.removeLast();
1644 bool hasBreaks = !jumps.isEmpty; 1719 bool hasBreaks = !join.isEmpty;
1645 ir.Continuation joinContinuation;
1646 if (hasBreaks) { 1720 if (hasBreaks) {
1647 if (innerBuilder.isOpen) { 1721 if (innerBuilder.isOpen) innerBuilder.jumpTo(join);
1648 jumps.addJump(innerBuilder); 1722 add(new ir.LetCont(join.continuation, innerBuilder._root));
1649 } 1723 environment = join.environment;
1650 1724 } else if (innerBuilder._root != null) {
1651 // All jumps to the break continuation must be in the scope of the 1725 add(innerBuilder._root);
1652 // continuation's binding. The continuation is bound just outside the 1726 _current = innerBuilder._current;
1653 // body to satisfy this property without extra analysis. 1727 environment = innerBuilder.environment;
1654 // As a consequence, the break continuation needs parameters for all
1655 // local variables in scope at the exit from the body.
1656 List<ir.Parameter> parameters =
1657 new List<ir.Parameter>.generate(environment.length, (i) {
1658 return new ir.Parameter(environment.index2variable[i]);
1659 });
1660 joinContinuation = new ir.Continuation(parameters);
1661 invokeFullJoin(joinContinuation, jumps, recursive: false);
1662 add(new ir.LetCont(joinContinuation, innerBuilder._root));
1663 for (int i = 0; i < environment.length; ++i) {
1664 environment.index2value[i] = parameters[i];
1665 }
1666 } else { 1728 } else {
1667 if (innerBuilder._root != null) { 1729 // The translation of the body did not emit any CPS term.
1668 add(innerBuilder._root);
1669 _current = innerBuilder._current;
1670 environment = innerBuilder.environment;
1671 }
1672 } 1730 }
1673 return null;
1674 } 1731 }
1675 1732
1676
1677 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] 1733 // Build(BreakStatement L, C) = C[InvokeContinuation(...)]
1678 // 1734 //
1679 // The continuation and arguments are filled in later after translating 1735 // The continuation and arguments are filled in later after translating
1680 // the body containing the break. 1736 // the body containing the break.
1681 bool buildBreak(JumpTarget target) { 1737 bool buildBreak(JumpTarget target) {
1682 return buildJumpInternal(target, state.breakCollectors); 1738 return buildJumpInternal(target, state.breakCollectors);
1683 } 1739 }
1684 1740
1685 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] 1741 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)]
1686 // 1742 //
1687 // The continuation and arguments are filled in later after translating 1743 // The continuation and arguments are filled in later after translating
1688 // the body containing the continue. 1744 // the body containing the continue.
1689 bool buildContinue(JumpTarget target) { 1745 bool buildContinue(JumpTarget target) {
1690 return buildJumpInternal(target, state.continueCollectors); 1746 return buildJumpInternal(target, state.continueCollectors);
1691 } 1747 }
1692 1748
1693 bool buildJumpInternal(JumpTarget target, 1749 bool buildJumpInternal(JumpTarget target,
1694 Iterable<JumpCollector> collectors) { 1750 Iterable<JumpCollector> collectors) {
1695 assert(isOpen); 1751 assert(isOpen);
1696 for (JumpCollector collector in collectors) { 1752 for (JumpCollector collector in collectors) {
1697 if (target == collector.target) { 1753 if (target == collector.target) {
1698 collector.addJump(this); 1754 jumpTo(collector);
1699 return true; 1755 return true;
1700 } 1756 }
1701 } 1757 }
1702 return false; 1758 return false;
1703 } 1759 }
1704 1760
1705 /// Create a negation of [condition]. 1761 /// Create a negation of [condition].
1706 ir.Primitive buildNegation(ir.Primitive condition) { 1762 ir.Primitive buildNegation(ir.Primitive condition) {
1707 // ! e is translated as e ? false : true 1763 // ! e is translated as e ? false : true
1708 1764
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
1756 /// operand and [buildRightValue] is called to process the value of the right 1812 /// operand and [buildRightValue] is called to process the value of the right
1757 /// operand in the context of its own [IrBuilder]. 1813 /// operand in the context of its own [IrBuilder].
1758 ir.Primitive buildLogicalOperator( 1814 ir.Primitive buildLogicalOperator(
1759 ir.Primitive leftValue, 1815 ir.Primitive leftValue,
1760 ir.Primitive buildRightValue(IrBuilder builder), 1816 ir.Primitive buildRightValue(IrBuilder builder),
1761 {bool isLazyOr: false}) { 1817 {bool isLazyOr: false}) {
1762 // e0 && e1 is translated as if e0 ? (e1 == true) : false. 1818 // e0 && e1 is translated as if e0 ? (e1 == true) : false.
1763 // e0 || e1 is translated as if e0 ? true : (e1 == true). 1819 // e0 || e1 is translated as if e0 ? true : (e1 == true).
1764 // The translation must convert both e0 and e1 to booleans and handle 1820 // The translation must convert both e0 and e1 to booleans and handle
1765 // local variable assignments in e1. 1821 // local variable assignments in e1.
1766
1767 IrBuilder rightBuilder = makeDelimitedBuilder(); 1822 IrBuilder rightBuilder = makeDelimitedBuilder();
1768 ir.Primitive rightValue = buildRightValue(rightBuilder); 1823 ir.Primitive rightValue = buildRightValue(rightBuilder);
1769 // A dummy empty target for the branch on the left subexpression branch. 1824 // A dummy empty target for the branch on the left subexpression branch.
1770 // This enables using the same infrastructure for join-point continuations 1825 // This enables using the same infrastructure for join-point continuations
1771 // as in visitIf and visitConditional. It will hold a definition of the 1826 // as in visitIf and visitConditional. It will hold a definition of the
1772 // appropriate constant and an invocation of the join-point continuation. 1827 // appropriate constant and an invocation of the join-point continuation.
1773 IrBuilder emptyBuilder = makeDelimitedBuilder(); 1828 IrBuilder emptyBuilder = makeDelimitedBuilder();
1774 // Dummy empty targets for right true and right false. They hold 1829 // Dummy empty targets for right true and right false. They hold
1775 // definitions of the appropriate constant and an invocation of the 1830 // definitions of the appropriate constant and an invocation of the
1776 // join-point continuation. 1831 // join-point continuation.
1777 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder(); 1832 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
1778 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder(); 1833 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
1779 1834
1780 // If we don't evaluate the right subexpression, the value of the whole 1835 // If we don't evaluate the right subexpression, the value of the whole
1781 // expression is this constant. 1836 // expression is this constant.
1782 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); 1837 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr);
1783 // If we do evaluate the right subexpression, the value of the expression 1838 // If we do evaluate the right subexpression, the value of the expression
1784 // is a true or false constant. 1839 // is a true or false constant.
1785 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); 1840 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true);
1786 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); 1841 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false);
1787 1842
1788 // Treat the result values as named values in the environment, so they 1843 // Treat the result values as named values in the environment, so they
1789 // will be treated as arguments to the join-point continuation. 1844 // will be treated as arguments to the join-point continuation.
1790 assert(environment.length == emptyBuilder.environment.length); 1845 assert(environment.length == emptyBuilder.environment.length);
1791 assert(environment.length == rightTrueBuilder.environment.length); 1846 assert(environment.length == rightTrueBuilder.environment.length);
1792 assert(environment.length == rightFalseBuilder.environment.length); 1847 assert(environment.length == rightFalseBuilder.environment.length);
1848 // Treat the value of the expression as a local variable so it will get
1849 // a continuation parameter.
1850 environment.extend(null, null);
1793 emptyBuilder.environment.extend(null, leftBool); 1851 emptyBuilder.environment.extend(null, leftBool);
1794 rightTrueBuilder.environment.extend(null, rightTrue); 1852 rightTrueBuilder.environment.extend(null, rightTrue);
1795 rightFalseBuilder.environment.extend(null, rightFalse); 1853 rightFalseBuilder.environment.extend(null, rightFalse);
1796 1854
1797 // Wire up two continuations for the left subexpression, two continuations 1855 // Wire up two continuations for the left subexpression, two continuations
1798 // for the right subexpression, and a three-way join continuation. 1856 // for the right subexpression, and a three-way join continuation.
1799 JumpCollector jumps = new JumpCollector(null); 1857 JumpCollector join = new ForwardJumpCollector(environment);
1800 jumps.addJump(emptyBuilder); 1858 emptyBuilder.jumpTo(join);
1801 jumps.addJump(rightTrueBuilder); 1859 rightTrueBuilder.jumpTo(join);
1802 jumps.addJump(rightFalseBuilder); 1860 rightFalseBuilder.jumpTo(join);
1803 ir.Continuation joinContinuation =
1804 createJoin(environment.length + 1, jumps);
1805 ir.Continuation leftTrueContinuation = new ir.Continuation([]); 1861 ir.Continuation leftTrueContinuation = new ir.Continuation([]);
1806 ir.Continuation leftFalseContinuation = new ir.Continuation([]); 1862 ir.Continuation leftFalseContinuation = new ir.Continuation([]);
1807 ir.Continuation rightTrueContinuation = new ir.Continuation([]); 1863 ir.Continuation rightTrueContinuation = new ir.Continuation([]);
1808 ir.Continuation rightFalseContinuation = new ir.Continuation([]); 1864 ir.Continuation rightFalseContinuation = new ir.Continuation([]);
1809 rightTrueContinuation.body = rightTrueBuilder._root; 1865 rightTrueContinuation.body = rightTrueBuilder._root;
1810 rightFalseContinuation.body = rightFalseBuilder._root; 1866 rightFalseContinuation.body = rightFalseBuilder._root;
1811 // The right subexpression has two continuations. 1867 // The right subexpression has two continuations.
1812 rightBuilder.add( 1868 rightBuilder.add(
1813 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation, 1869 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation,
1814 rightFalseContinuation], 1870 rightFalseContinuation],
1815 new ir.Branch(new ir.IsTrue(rightValue), 1871 new ir.Branch(new ir.IsTrue(rightValue),
1816 rightTrueContinuation, 1872 rightTrueContinuation,
1817 rightFalseContinuation))); 1873 rightFalseContinuation)));
1818 // Depending on the operator, the left subexpression's continuations are 1874 // Depending on the operator, the left subexpression's continuations are
1819 // either the right subexpression or an invocation of the join-point 1875 // either the right subexpression or an invocation of the join-point
1820 // continuation. 1876 // continuation.
1821 if (isLazyOr) { 1877 if (isLazyOr) {
1822 leftTrueContinuation.body = emptyBuilder._root; 1878 leftTrueContinuation.body = emptyBuilder._root;
1823 leftFalseContinuation.body = rightBuilder._root; 1879 leftFalseContinuation.body = rightBuilder._root;
1824 } else { 1880 } else {
1825 leftTrueContinuation.body = rightBuilder._root; 1881 leftTrueContinuation.body = rightBuilder._root;
1826 leftFalseContinuation.body = emptyBuilder._root; 1882 leftFalseContinuation.body = emptyBuilder._root;
1827 } 1883 }
1828 1884
1829 add(new ir.LetCont(joinContinuation, 1885 add(new ir.LetCont(join.continuation,
1830 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation, 1886 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation,
1831 leftFalseContinuation], 1887 leftFalseContinuation],
1832 new ir.Branch(new ir.IsTrue(leftValue), 1888 new ir.Branch(new ir.IsTrue(leftValue),
1833 leftTrueContinuation, 1889 leftTrueContinuation,
1834 leftFalseContinuation)))); 1890 leftFalseContinuation))));
1891 environment = join.environment;
1892 environment.discard(1);
1835 // There is always a join parameter for the result value, because it 1893 // There is always a join parameter for the result value, because it
1836 // is different on at least two paths. 1894 // is different on at least two paths.
1837 return joinContinuation.parameters.last; 1895 return join.continuation.parameters.last;
1838 }
1839
1840 /// Create a non-recursive join-point continuation.
1841 ///
1842 /// Given the environment length at the join point and a list of
1843 /// jumps that should reach the join point, create a join-point
1844 /// continuation. The join-point continuation has a parameter for each
1845 /// variable that has different values reaching on different paths.
1846 ///
1847 /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
1848 /// They are filled in with the target continuation and appropriate
1849 /// arguments.
1850 ///
1851 /// As a side effect, the environment of this builder is updated to include
1852 /// the join-point continuation parameters.
1853 ir.Continuation createJoin(int environmentLength, JumpCollector jumps) {
1854 assert(jumps.length >= 2);
1855
1856 // Compute which values are identical on all paths reaching the join.
1857 // Handle the common case of a pair of contexts efficiently.
1858 Environment first = jumps.environments[0];
1859 Environment second = jumps.environments[1];
1860 assert(environmentLength <= first.length);
1861 assert(environmentLength <= second.length);
1862 assert(first.sameDomain(environmentLength, second));
1863 // A running count of the join-point parameters.
1864 int parameterCount = 0;
1865 // The null elements of common correspond to required parameters of the
1866 // join-point continuation.
1867 List<ir.Primitive> common =
1868 new List<ir.Primitive>.generate(environmentLength,
1869 (i) {
1870 ir.Primitive candidate = first[i];
1871 if (second[i] == candidate) {
1872 return candidate;
1873 } else {
1874 ++parameterCount;
1875 return null;
1876 }
1877 });
1878 // If there is already a parameter for each variable, the other
1879 // environments do not need to be considered.
1880 if (parameterCount < environmentLength) {
1881 for (int i = 0; i < environmentLength; ++i) {
1882 ir.Primitive candidate = common[i];
1883 if (candidate == null) continue;
1884 for (Environment current in jumps.environments.skip(2)) {
1885 assert(environmentLength <= current.length);
1886 assert(first.sameDomain(environmentLength, current));
1887 if (candidate != current[i]) {
1888 common[i] = null;
1889 ++parameterCount;
1890 break;
1891 }
1892 }
1893 if (parameterCount >= environmentLength) break;
1894 }
1895 }
1896
1897 // Create the join point continuation.
1898 List<ir.Parameter> parameters = <ir.Parameter>[];
1899 parameters.length = parameterCount;
1900 int index = 0;
1901 for (int i = 0; i < environmentLength; ++i) {
1902 if (common[i] == null) {
1903 parameters[index++] = new ir.Parameter(first.index2variable[i]);
1904 }
1905 }
1906 assert(index == parameterCount);
1907 ir.Continuation join = new ir.Continuation(parameters);
1908
1909 // Fill in all the continuation invocations.
1910 for (int i = 0; i < jumps.length; ++i) {
1911 Environment currentEnvironment = jumps.environments[i];
1912 ir.InvokeContinuation invoke = jumps.invocations[i];
1913 // Sharing this.environment with one of the invocations will not do
1914 // the right thing (this.environment has already been mutated).
1915 List<ir.Reference> arguments = <ir.Reference>[];
1916 arguments.length = parameterCount;
1917 int index = 0;
1918 for (int i = 0; i < environmentLength; ++i) {
1919 if (common[i] == null) {
1920 arguments[index++] = new ir.Reference(currentEnvironment[i]);
1921 }
1922 }
1923 invoke.continuation = new ir.Reference(join);
1924 invoke.arguments = arguments;
1925 }
1926
1927 // Mutate this.environment to be the environment at the join point. Do
1928 // this after adding the continuation invocations, because this.environment
1929 // might be collected by the jump collector and so the old environment
1930 // values are needed for the continuation invocation.
1931 //
1932 // Iterate to environment.length because environmentLength includes values
1933 // outside the environment which are 'phantom' variables used for the
1934 // values of expressions like &&, ||, and ?:.
1935 index = 0;
1936 for (int i = 0; i < environment.length; ++i) {
1937 if (common[i] == null) {
1938 environment.index2value[i] = parameters[index++];
1939 }
1940 }
1941
1942 return join;
1943 } 1896 }
1944 } 1897 }
1945 1898
1946 /// Shared state between DartIrBuilders within the same method. 1899 /// Shared state between DartIrBuilders within the same method.
1947 class DartIrBuilderSharedState { 1900 class DartIrBuilderSharedState {
1948 /// Maps local variables to their corresponding [MutableVariable] object. 1901 /// Maps local variables to their corresponding [MutableVariable] object.
1949 final Map<Local, ir.MutableVariable> local2mutable = 1902 final Map<Local, ir.MutableVariable> local2mutable =
1950 <Local, ir.MutableVariable>{}; 1903 <Local, ir.MutableVariable>{};
1951 1904
1952 // Move this to the IrBuilderVisitor. 1905 // Move this to the IrBuilderVisitor.
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after
2583 } 2536 }
2584 2537
2585 /// Synthetic parameter to a JavaScript factory method that takes the type 2538 /// Synthetic parameter to a JavaScript factory method that takes the type
2586 /// argument given for the type variable [variable]. 2539 /// argument given for the type variable [variable].
2587 class TypeInformationParameter implements Local { 2540 class TypeInformationParameter implements Local {
2588 final TypeVariableElement variable; 2541 final TypeVariableElement variable;
2589 final ExecutableElement executableContext; 2542 final ExecutableElement executableContext;
2590 TypeInformationParameter(this.variable, this.executableContext); 2543 TypeInformationParameter(this.variable, this.executableContext);
2591 String get name => variable.name; 2544 String get name => variable.name;
2592 } 2545 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698