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

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