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

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

Issue 831133004: Use closure conversion in new dart2js backend. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase Created 5 years, 11 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
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';
11 import '../elements/elements.dart'; 11 import '../elements/elements.dart';
12 import '../source_file.dart'; 12 import '../source_file.dart';
13 import '../tree/tree.dart' as ast; 13 import '../tree/tree.dart' as ast;
14 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator; 14 import '../scanner/scannerlib.dart' show Token, isUserDefinableOperator;
15 import '../universe/universe.dart' show SelectorKind; 15 import '../universe/universe.dart' show SelectorKind;
16 import 'cps_ir_nodes.dart' as ir; 16 import 'cps_ir_nodes.dart' as ir;
17 import '../elements/modelx.dart' show SynthesizedConstructorElementX; 17 import '../elements/modelx.dart' show SynthesizedConstructorElementX;
18 import '../closure.dart';
19 import '../closure.dart' as closurelib;
20 import '../js_backend/js_backend.dart' show JavaScriptBackend;
18 21
19 part 'cps_ir_builder_visitor.dart'; 22 part 'cps_ir_builder_visitor.dart';
20 23
21 /// A mapping from variable elements to their compile-time values. 24 /// A mapping from variable elements to their compile-time values.
22 /// 25 ///
23 /// Map elements denoted by parameters and local variables to the 26 /// Map elements denoted by parameters and local variables to the
24 /// [ir.Primitive] that is their value. Parameters and locals are 27 /// [ir.Primitive] that is their value. Parameters and locals are
25 /// assigned indexes which can be used to refer to them. 28 /// assigned indexes which can be used to refer to them.
26 class Environment { 29 class Environment {
27 /// A map from elements to their environment index. 30 /// A map from locals to their environment index.
28 final Map<Element, int> variable2index; 31 final Map<Local, int> variable2index;
29 32
30 /// A reverse map from environment indexes to the variable. 33 /// A reverse map from environment indexes to the variable.
31 final List<Element> index2variable; 34 final List<Local> index2variable;
32 35
33 /// A map from environment indexes to their value. 36 /// A map from environment indexes to their value.
34 final List<ir.Primitive> index2value; 37 final List<ir.Primitive> index2value;
35 38
36 Environment.empty() 39 Environment.empty()
37 : variable2index = <Element, int>{}, 40 : variable2index = <Local, int>{},
38 index2variable = <Element>[], 41 index2variable = <Local>[],
39 index2value = <ir.Primitive>[]; 42 index2value = <ir.Primitive>[];
40 43
41 /// Construct an environment that is a copy of another one. 44 /// Construct an environment that is a copy of another one.
42 /// 45 ///
43 /// The mapping from elements to indexes is shared, not copied. 46 /// The mapping from elements to indexes is shared, not copied.
44 Environment.from(Environment other) 47 Environment.from(Environment other)
45 : variable2index = other.variable2index, 48 : variable2index = other.variable2index,
46 index2variable = new List<Element>.from(other.index2variable), 49 index2variable = new List<Local>.from(other.index2variable),
47 index2value = new List<ir.Primitive>.from(other.index2value); 50 index2value = new List<ir.Primitive>.from(other.index2value);
48 51
49 get length => index2variable.length; 52 get length => index2variable.length;
50 53
51 ir.Primitive operator [](int index) => index2value[index]; 54 ir.Primitive operator [](int index) => index2value[index];
52 55
53 void extend(Element element, ir.Primitive value) { 56 void extend(Local element, ir.Primitive value) {
54 // Assert that the name is not already in the environment. `null` is used 57 // Assert that the name is not already in the environment. `null` is used
55 // as the name of anonymous variables. Because the variable2index map is 58 // as the name of anonymous variables. Because the variable2index map is
56 // shared, `null` can already occur. This is safe because such variables 59 // shared, `null` can already occur. This is safe because such variables
57 // are not looked up by name. 60 // are not looked up by name.
58 // 61 //
59 // TODO(kmillikin): This is still kind of fishy. Refactor to not share 62 // TODO(kmillikin): This is still kind of fishy. Refactor to not share
60 // name maps or else garbage collect unneeded names. 63 // name maps or else garbage collect unneeded names.
61 assert(element == null || !variable2index.containsKey(element)); 64 assert(element == null || !variable2index.containsKey(element));
62 variable2index[element] = index2variable.length; 65 variable2index[element] = index2variable.length;
63 index2variable.add(element); 66 index2variable.add(element);
64 index2value.add(value); 67 index2value.add(value);
65 } 68 }
66 69
67 ir.Primitive lookup(Element element) { 70 ir.Primitive lookup(Local element) {
68 assert(!element.isConst);
69 assert(invariant(element, variable2index.containsKey(element), 71 assert(invariant(element, variable2index.containsKey(element),
70 message: "Unknown variable: $element.")); 72 message: "Unknown variable: $element."));
71 return index2value[variable2index[element]]; 73 return index2value[variable2index[element]];
72 } 74 }
73 75
74 void update(Element element, ir.Primitive value) { 76 void update(Local element, ir.Primitive value) {
75 index2value[variable2index[element]] = value; 77 index2value[variable2index[element]] = value;
76 } 78 }
77 79
78 /// Verify that the variable2index and index2variable maps agree up to the 80 /// Verify that the variable2index and index2variable maps agree up to the
79 /// index [length] exclusive. 81 /// index [length] exclusive.
80 bool sameDomain(int length, Environment other) { 82 bool sameDomain(int length, Environment other) {
81 assert(this.length >= length); 83 assert(this.length >= length);
82 assert(other.length >= length); 84 assert(other.length >= length);
83 for (int i = 0; i < length; ++i) { 85 for (int i = 0; i < length; ++i) {
84 // An index maps to the same variable in both environments. 86 // An index maps to the same variable in both environments.
85 Element variable = index2variable[i]; 87 Local variable = index2variable[i];
86 if (variable != other.index2variable[i]) return false; 88 if (variable != other.index2variable[i]) return false;
87 89
88 // The variable maps to the same index in both environments. 90 // The variable maps to the same index in both environments.
89 int index = variable2index[variable]; 91 int index = variable2index[variable];
90 if (index == null || index != other.variable2index[variable]) { 92 if (index == null || index != other.variable2index[variable]) {
91 return false; 93 return false;
92 } 94 }
93 } 95 }
94 return true; 96 return true;
95 } 97 }
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 // `List` instead of `Link`. 174 // `List` instead of `Link`.
173 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) { 175 SubbuildFunction subbuildSequence(/*Iterable<N>*/ nodes) {
174 return (IrBuilder builder) { 176 return (IrBuilder builder) {
175 return withBuilder(builder, () => builder.buildSequence(nodes, build)); 177 return withBuilder(builder, () => builder.buildSequence(nodes, build));
176 }; 178 };
177 } 179 }
178 } 180 }
179 181
180 /// Shared state between IrBuilders of nested functions. 182 /// Shared state between IrBuilders of nested functions.
181 class IrBuilderClosureState { 183 class IrBuilderClosureState {
182 final Iterable<Entity> closureLocals;
183
184 /// Maps local variables to their corresponding [ClosureVariable] object. 184 /// Maps local variables to their corresponding [ClosureVariable] object.
185 final Map<Local, ir.ClosureVariable> local2closure = 185 final Map<Local, ir.ClosureVariable> local2closure =
186 <Local, ir.ClosureVariable>{}; 186 <Local, ir.ClosureVariable>{};
187 187
188 /// Maps functions to the list of closure variables declared in that function. 188 /// Maps functions to the list of closure variables declared in that function.
189 final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures = 189 final Map<ExecutableElement, List<ir.ClosureVariable>> function2closures =
190 <ExecutableElement, List<ir.ClosureVariable>>{}; 190 <ExecutableElement, List<ir.ClosureVariable>>{};
191 191
192 /// Returns the closure variables declared in the given function. 192 /// Returns the closure variables declared in the given function.
193 List<ir.ClosureVariable> getClosureList(ExecutableElement element) { 193 List<ir.ClosureVariable> getClosureList(ExecutableElement element) {
194 return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]); 194 return function2closures.putIfAbsent(element, () => <ir.ClosureVariable>[]);
195 } 195 }
196 196
197 IrBuilderClosureState(this.closureLocals) { 197 /// Creates a closure variable for the given local.
198 for (Local local in closureLocals) { 198 void makeClosureVariable(Local local) {
199 ExecutableElement context = local.executableContext; 199 ir.ClosureVariable variable =
200 ir.ClosureVariable variable = new ir.ClosureVariable(context, local); 200 new ir.ClosureVariable(local.executableContext, local);
201 local2closure[local] = variable; 201 local2closure[local] = variable;
202 getClosureList(context).add(variable); 202 getClosureList(local.executableContext).add(variable);
203 }
204 } 203 }
205 } 204 }
206 205
207 /// Shared state between delimited IrBuilders within the same function. 206 /// Shared state between delimited IrBuilders within the same function.
208 class IrBuilderSharedState { 207 class IrBuilderSharedState {
209 final ConstantSystem constantSystem; 208 final ConstantSystem constantSystem;
210 209
211 /// A stack of collectors for breaks. 210 /// A stack of collectors for breaks.
212 final List<JumpCollector> breakCollectors = <JumpCollector>[]; 211 final List<JumpCollector> breakCollectors = <JumpCollector>[];
213 212
214 /// A stack of collectors for continues. 213 /// A stack of collectors for continues.
215 final List<JumpCollector> continueCollectors = <JumpCollector>[]; 214 final List<JumpCollector> continueCollectors = <JumpCollector>[];
216 215
217 final List<ConstDeclaration> localConstants = <ConstDeclaration>[]; 216 final List<ConstDeclaration> localConstants = <ConstDeclaration>[];
218 217
219 final ExecutableElement currentElement; 218 final ExecutableElement currentElement;
220 219
221 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); 220 final ir.Continuation returnContinuation = new ir.Continuation.retrn();
222 221
223 final List<ir.Definition> functionParameters = <ir.Definition>[]; 222 final List<ir.Definition> functionParameters = <ir.Definition>[];
224 223
224 /// Maps boxed locals to their location. These locals are not part of
225 /// the environment.
226 final Map<Local, ClosureLocation> boxedVariables = {};
227
228 /// If non-null, this refers to the receiver (`this`) in the enclosing method.
229 ir.Primitive receiver;
230
225 IrBuilderSharedState(this.constantSystem, this.currentElement); 231 IrBuilderSharedState(this.constantSystem, this.currentElement);
226 } 232 }
227 233
228 /// A factory for building the cps IR. 234 /// A factory for building the cps IR.
229 class IrBuilder { 235 ///
236 /// [DartIrBuilder] and [JsIrBuilder] implement nested functions and captured
237 /// variables in different ways.
238 abstract class IrBuilder {
239 IrBuilder _makeInstance();
240
241 void declareLocalVariable(LocalVariableElement element,
242 {ir.Primitive initialValue});
243 void declareLocalFunction(LocalFunctionElement element, Object function);
244 ir.Primitive buildFunctionExpression(Object function);
245 ir.Primitive buildLocalGet(LocalElement element);
246 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value);
247
248 /// Called when entering a nested function with free variables.
249 /// The free variables should subsequently be accessible using [buildLocalGet]
250 /// and [buildLocalSet].
251 void _enterClosureEnvironment(ClosureEnvironment env);
252
253 /// Enter a scope that declares boxed variables. The boxed variables must
254 /// subsequently be accessible using [buildLocalGet], [buildLocalSet], etc.
255 void _enterScope(ClosureScope scope);
256
257 /// Add the given function parameter to the IR, and bind it in the environment
258 /// or put it in its box, if necessary.
259 void _createFunctionParameter(ParameterElement parameterElement);
260
261 /// Called before the update expression of a for-loop. A new box should be
262 /// created for [scope] and the values from the old box should be copied over.
263 void _migrateLoopVariables(ClosureScope scope);
264
230 // TODO(johnniwinther): Make these field final and remove the default values 265 // TODO(johnniwinther): Make these field final and remove the default values
231 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. 266 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin.
232 267
233 final List<ir.Parameter> _parameters = <ir.Parameter>[]; 268 final List<ir.Parameter> _parameters = <ir.Parameter>[];
234 269
235 final IrBuilderSharedState state; 270 IrBuilderSharedState state;
236 271
237 final IrBuilderClosureState closure; 272 IrBuilderClosureState closure;
238 273
239 /// A map from variable indexes to their values. 274 /// A map from variable indexes to their values.
275 ///
276 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not
277 /// in the map; look up their [BoxLocal] instead.
240 Environment environment; 278 Environment environment;
241 279
242 // The IR builder maintains a context, which is an expression with a hole in 280 // The IR builder maintains a context, which is an expression with a hole in
243 // it. The hole represents the focus where new expressions can be added. 281 // it. The hole represents the focus where new expressions can be added.
244 // The context is implemented by 'root' which is the root of the expression 282 // The context is implemented by 'root' which is the root of the expression
245 // and 'current' which is the expression that immediately contains the hole. 283 // and 'current' which is the expression that immediately contains the hole.
246 // Not all expressions have a hole (e.g., invocations, which always occur in 284 // Not all expressions have a hole (e.g., invocations, which always occur in
247 // tail position, do not have a hole). Expressions with a hole have a plug 285 // tail position, do not have a hole). Expressions with a hole have a plug
248 // method. 286 // method.
249 // 287 //
250 // Conceptually, visiting a statement takes a context as input and returns 288 // Conceptually, visiting a statement takes a context as input and returns
251 // either a new context or else an expression without a hole if all 289 // either a new context or else an expression without a hole if all
252 // control-flow paths through the statement have exited. An expression 290 // control-flow paths through the statement have exited. An expression
253 // without a hole is represented by a (root, current) pair where root is the 291 // without a hole is represented by a (root, current) pair where root is the
254 // expression and current is null. 292 // expression and current is null.
255 // 293 //
256 // Conceptually again, visiting an expression takes a context as input and 294 // Conceptually again, visiting an expression takes a context as input and
257 // returns either a pair of a new context and a definition denoting 295 // returns either a pair of a new context and a definition denoting
258 // the expression's value, or else an expression without a hole if all 296 // the expression's value, or else an expression without a hole if all
259 // control-flow paths through the expression have exited. 297 // control-flow paths through the expression have exited.
260 // 298 //
261 // We do not pass contexts as arguments or return them. Rather we use the 299 // We do not pass contexts as arguments or return them. Rather we use the
262 // current context (root, current) as the visitor state and mutate current. 300 // current context (root, current) as the visitor state and mutate current.
263 // Visiting a statement returns null; visiting an expression returns the 301 // Visiting a statement returns null; visiting an expression returns the
264 // primitive denoting its value. 302 // primitive denoting its value.
265 303
266 ir.Expression _root = null; 304 ir.Expression _root = null;
267 ir.Expression _current = null; 305 ir.Expression _current = null;
268 306
269 IrBuilder(ConstantSystem constantSystem, 307 /// Initialize a new top-level IR builder.
270 ExecutableElement currentElement, 308 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
271 Iterable<Entity> closureLocals) 309 state = new IrBuilderSharedState(constantSystem, currentElement);
272 : this.state = new IrBuilderSharedState(constantSystem, currentElement), 310 closure = new IrBuilderClosureState();
273 this.closure = new IrBuilderClosureState(closureLocals), 311 environment = new Environment.empty();
274 this.environment = new Environment.empty(); 312 }
275 313
276 /// Construct a delimited visitor for visiting a subtree. 314 /// Construct a delimited visitor for visiting a subtree.
277 /// 315 ///
278 /// The delimited visitor has its own compile-time environment mapping 316 /// The delimited visitor has its own compile-time environment mapping
279 /// local variables to their values, which is initially a copy of the parent 317 /// local variables to their values, which is initially a copy of the parent
280 /// environment. It has its own context for building an IR expression, so 318 /// environment. It has its own context for building an IR expression, so
281 /// the built expression is not plugged into the parent's context. 319 /// the built expression is not plugged into the parent's context.
282 IrBuilder.delimited(IrBuilder parent) 320 IrBuilder makeDelimitedBuilder() {
283 : this.state = parent.state, 321 return _makeInstance()
284 this.closure = parent.closure, 322 ..state = state
285 this.environment = new Environment.from(parent.environment); 323 ..closure = closure
324 ..environment = new Environment.from(environment);
325 }
286 326
287 /// Construct a visitor for a recursive continuation. 327 /// Construct a visitor for a recursive continuation.
288 /// 328 ///
289 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) 329 /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
290 /// for all the local variables in the parent, because the invocation sites 330 /// for all the local variables in the parent, because the invocation sites
291 /// of the continuation are not all known when the builder is created. The 331 /// of the continuation are not all known when the builder is created. The
292 /// recursive invocations will be passed values for all the local variables, 332 /// recursive invocations will be passed values for all the local variables,
293 /// which may be eliminated later if they are redundant---if they take on 333 /// which may be eliminated later if they are redundant---if they take on
294 /// the same value at all invocation sites. 334 /// the same value at all invocation sites.
295 IrBuilder.recursive(IrBuilder parent) 335 IrBuilder makeRecursiveBuilder() {
296 : this.state = parent.state, 336 IrBuilder inner = _makeInstance()
297 this.closure = parent.closure, 337 ..state = state
298 this.environment = new Environment.empty() { 338 ..closure = closure
299 parent.environment.index2variable.forEach(createLocalParameter); 339 ..environment = new Environment.empty();
340 environment.index2variable.forEach(inner.createLocalParameter);
341 return inner;
300 } 342 }
301 343
302 /// Construct a builder for an inner function. 344 /// Construct a builder for an inner function.
303 IrBuilder.innerFunction(IrBuilder parent, 345 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
304 ExecutableElement currentElement) 346 return _makeInstance()
305 : this.state = new IrBuilderSharedState(parent.state.constantSystem, 347 ..state = new IrBuilderSharedState(state.constantSystem, currentElement)
306 currentElement), 348 ..closure = closure
307 this.closure = parent.closure, 349 ..environment = new Environment.empty();
308 this.environment = new Environment.empty(); 350 }
309
310 351
311 bool get isOpen => _root == null || _current != null; 352 bool get isOpen => _root == null || _current != null;
312 353
313 /// True if [element] is a local variable, local function, or parameter that 354
314 /// is accessed from an inner function. Recursive self-references in a local 355 void buildFieldInitializerHeader({ClosureScope closureScope}) {
315 /// function count as closure accesses. 356 _enterScope(closureScope);
316 ///
317 /// If `true`, [element] is a [LocalElement].
318 bool isClosureVariable(Element element) {
319 return closure.closureLocals.contains(element);
320 } 357 }
321 358
322 /// Returns the [ClosureVariable] corresponding to the given variable. 359 void buildFunctionHeader(Iterable<ParameterElement> parameters,
323 /// Returns `null` for non-closure variables. 360 {ClosureScope closureScope,
324 ir.ClosureVariable getClosureVariable(LocalElement element) { 361 ClosureEnvironment closureEnvironment} ) {
325 return closure.local2closure[element]; 362 _enterClosureEnvironment(closureEnvironment);
363 _enterScope(closureScope);
364 parameters.forEach(_createFunctionParameter);
326 } 365 }
327 366
328 /// Adds the given parameter to the function currently being built. 367 /// Creates a parameter for [local] and adds it to the current environment.
329 void createFunctionParameter(ParameterElement parameterElement) { 368 ir.Parameter createLocalParameter(Local local) {
330 if (isClosureVariable(parameterElement)) { 369 ir.Parameter parameter = new ir.Parameter(local);
331 state.functionParameters.add(getClosureVariable(parameterElement));
332 } else {
333 state.functionParameters.add(createLocalParameter(parameterElement));
334 }
335 }
336
337 /// Create a parameter for [parameterElement] and add it to the current
338 /// environment.
339 ir.Parameter createLocalParameter(LocalElement parameterElement) {
340 ir.Parameter parameter = new ir.Parameter(parameterElement);
341 _parameters.add(parameter); 370 _parameters.add(parameter);
342 environment.extend(parameterElement, parameter); 371 environment.extend(local, parameter);
343 return parameter; 372 return parameter;
344 } 373 }
345 374
346 /// Add the constant [variableElement] to the environment with [value] as its 375 /// Adds the constant [variableElement] to the environment with [value] as its
347 /// constant value. 376 /// constant value.
348 void declareLocalConstant(LocalVariableElement variableElement, 377 void declareLocalConstant(LocalVariableElement variableElement,
349 ConstantExpression value) { 378 ConstantExpression value) {
350 state.localConstants.add(new ConstDeclaration(variableElement, value)); 379 state.localConstants.add(new ConstDeclaration(variableElement, value));
351 } 380 }
352 381
353 /// Add [variableElement] to the environment with [initialValue] as its
354 /// initial value.
355 void declareLocalVariable(LocalVariableElement variableElement,
356 {ir.Primitive initialValue}) {
357 assert(isOpen);
358 if (initialValue == null) {
359 // TODO(kmillikin): Consider pooling constants.
360 // The initial value is null.
361 initialValue = buildNullLiteral();
362 }
363 if (isClosureVariable(variableElement)) {
364 add(new ir.SetClosureVariable(getClosureVariable(variableElement),
365 initialValue,
366 isDeclaration: true));
367 } else {
368 // In case a primitive was introduced for the initializer expression,
369 // use this variable element to help derive a good name for it.
370 initialValue.useElementAsHint(variableElement);
371 environment.extend(variableElement, initialValue);
372 }
373 }
374
375 /// Add [functionElement] to the environment with provided [definition].
376 void declareLocalFunction(LocalFunctionElement functionElement,
377 ir.FunctionDefinition definition) {
378 assert(isOpen);
379 if (isClosureVariable(functionElement)) {
380 ir.ClosureVariable variable = getClosureVariable(functionElement);
381 add(new ir.DeclareFunction(variable, definition));
382 } else {
383 ir.CreateFunction prim = new ir.CreateFunction(definition);
384 add(new ir.LetPrim(prim));
385 environment.extend(functionElement, prim);
386 prim.useElementAsHint(functionElement);
387 }
388 }
389
390 // Plug an expression into the 'hole' in the context being accumulated. The 382 // Plug an expression into the 'hole' in the context being accumulated. The
391 // empty context (just a hole) is represented by root (and current) being 383 // empty context (just a hole) is represented by root (and current) being
392 // null. Since the hole in the current context is filled by this function, 384 // null. Since the hole in the current context is filled by this function,
393 // the new hole must be in the newly added expression---which becomes the 385 // the new hole must be in the newly added expression---which becomes the
394 // new value of current. 386 // new value of current.
395 void add(ir.Expression expr) { 387 void add(ir.Expression expr) {
396 assert(isOpen); 388 assert(isOpen);
397 if (_root == null) { 389 if (_root == null) {
398 _root = _current = expr; 390 _root = _current = expr;
399 } else { 391 } else {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 /// then and else expression are created through the [buildThenExpression] and 507 /// then and else expression are created through the [buildThenExpression] and
516 /// [buildElseExpression] functions, respectively. 508 /// [buildElseExpression] functions, respectively.
517 ir.Primitive buildConditional( 509 ir.Primitive buildConditional(
518 ir.Primitive condition, 510 ir.Primitive condition,
519 ir.Primitive buildThenExpression(IrBuilder builder), 511 ir.Primitive buildThenExpression(IrBuilder builder),
520 ir.Primitive buildElseExpression(IrBuilder builder)) { 512 ir.Primitive buildElseExpression(IrBuilder builder)) {
521 513
522 assert(isOpen); 514 assert(isOpen);
523 515
524 // The then and else expressions are delimited. 516 // The then and else expressions are delimited.
525 IrBuilder thenBuilder = new IrBuilder.delimited(this); 517 IrBuilder thenBuilder = makeDelimitedBuilder();
526 IrBuilder elseBuilder = new IrBuilder.delimited(this); 518 IrBuilder elseBuilder = makeDelimitedBuilder();
527 ir.Primitive thenValue = buildThenExpression(thenBuilder); 519 ir.Primitive thenValue = buildThenExpression(thenBuilder);
528 ir.Primitive elseValue = buildElseExpression(elseBuilder); 520 ir.Primitive elseValue = buildElseExpression(elseBuilder);
529 521
530 // Treat the values of the subexpressions as named values in the 522 // Treat the values of the subexpressions as named values in the
531 // environment, so they will be treated as arguments to the join-point 523 // environment, so they will be treated as arguments to the join-point
532 // continuation. 524 // continuation.
533 assert(environment.length == thenBuilder.environment.length); 525 assert(environment.length == thenBuilder.environment.length);
534 assert(environment.length == elseBuilder.environment.length); 526 assert(environment.length == elseBuilder.environment.length);
535 thenBuilder.environment.extend(null, thenValue); 527 thenBuilder.environment.extend(null, thenValue);
536 elseBuilder.environment.extend(null, elseValue); 528 elseBuilder.environment.extend(null, elseValue);
(...skipping 17 matching lines...) Expand all
554 new ir.LetCont(elseContinuation, 546 new ir.LetCont(elseContinuation,
555 new ir.Branch(new ir.IsTrue(condition), 547 new ir.Branch(new ir.IsTrue(condition),
556 thenContinuation, 548 thenContinuation,
557 elseContinuation))))); 549 elseContinuation)))));
558 return (thenValue == elseValue) 550 return (thenValue == elseValue)
559 ? thenValue 551 ? thenValue
560 : joinContinuation.parameters.last; 552 : joinContinuation.parameters.last;
561 553
562 } 554 }
563 555
564 /// Create a function expression from [definition].
565 ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
566 ir.CreateFunction prim = new ir.CreateFunction(definition);
567 add(new ir.LetPrim(prim));
568 return prim;
569 }
570
571 /** 556 /**
572 * Add an explicit `return null` for functions that don't have a return 557 * Add an explicit `return null` for functions that don't have a return
573 * statement on each branch. This includes functions with an empty body, 558 * statement on each branch. This includes functions with an empty body,
574 * such as `foo(){ }`. 559 * such as `foo(){ }`.
575 */ 560 */
576 void _ensureReturn() { 561 void _ensureReturn() {
577 if (!isOpen) return; 562 if (!isOpen) return;
578 ir.Constant constant = buildNullLiteral(); 563 ir.Constant constant = buildNullLiteral();
579 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); 564 add(new ir.InvokeContinuation(state.returnContinuation, [constant]));
580 _current = null; 565 _current = null;
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments)); 744 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments));
760 } 745 }
761 746
762 /// Create a string concatenation of the [arguments]. 747 /// Create a string concatenation of the [arguments].
763 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { 748 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) {
764 assert(isOpen); 749 assert(isOpen);
765 return _continueWithExpression( 750 return _continueWithExpression(
766 (k) => new ir.ConcatenateStrings(k, arguments)); 751 (k) => new ir.ConcatenateStrings(k, arguments));
767 } 752 }
768 753
769 /// Create a read access of [local].
770 ir.Primitive buildLocalGet(LocalElement local) {
771 assert(isOpen);
772 if (isClosureVariable(local)) {
773 ir.Primitive result =
774 new ir.GetClosureVariable(getClosureVariable(local));
775 add(new ir.LetPrim(result));
776 return result;
777 } else {
778 return environment.lookup(local);
779 }
780 }
781
782 /// Create a write access to [local] with the provided [value].
783 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
784 assert(isOpen);
785 if (isClosureVariable(local)) {
786 add(new ir.SetClosureVariable(getClosureVariable(local), value));
787 } else {
788 value.useElementAsHint(local);
789 environment.update(local, value);
790 }
791 return value;
792 }
793
794 /// Create an invocation of [local] where the argument structure is defined 754 /// Create an invocation of [local] where the argument structure is defined
795 /// by [selector] and the argument values are defined by [arguments]. 755 /// by [selector] and the argument values are defined by [arguments].
796 ir.Primitive buildLocalInvocation(LocalElement local, 756 ir.Primitive buildLocalInvocation(LocalElement local,
797 Selector selector, 757 Selector selector,
798 List<ir.Definition> arguments) { 758 List<ir.Definition> arguments) {
799 ir.Primitive receiver; 759 return _buildInvokeCall(buildLocalGet(local), selector, arguments);
800 if (isClosureVariable(local)) {
801 receiver = new ir.GetClosureVariable(getClosureVariable(local));
802 add(new ir.LetPrim(receiver));
803 } else {
804 receiver = environment.lookup(local);
805 }
806 return _buildInvokeCall(receiver, selector, arguments);
807 } 760 }
808 761
809 /// Create an invocation of the [functionExpression] where the argument 762 /// Create an invocation of the [functionExpression] where the argument
810 /// structure are defined by [selector] and the argument values are defined by 763 /// structure are defined by [selector] and the argument values are defined by
811 /// [arguments]. 764 /// [arguments].
812 ir.Primitive buildFunctionExpressionInvocation( 765 ir.Primitive buildFunctionExpressionInvocation(
813 ir.Primitive functionExpression, 766 ir.Primitive functionExpression,
814 Selector selector, 767 Selector selector,
815 List<ir.Definition> arguments) { 768 List<ir.Definition> arguments) {
816 return _buildInvokeCall(functionExpression, selector, arguments); 769 return _buildInvokeCall(functionExpression, selector, arguments);
817 } 770 }
818 771
819 /// Creates an if-then-else statement with the provided [condition] where the 772 /// Creates an if-then-else statement with the provided [condition] where the
820 /// then and else branches are created through the [buildThenPart] and 773 /// then and else branches are created through the [buildThenPart] and
821 /// [buildElsePart] functions, respectively. 774 /// [buildElsePart] functions, respectively.
822 /// 775 ///
823 /// An if-then statement is created if [buildElsePart] is a no-op. 776 /// An if-then statement is created if [buildElsePart] is a no-op.
824 // TODO(johnniwinther): Unify implementation with [buildConditional] and 777 // TODO(johnniwinther): Unify implementation with [buildConditional] and
825 // [_buildLogicalOperator]. 778 // [_buildLogicalOperator].
826 void buildIf(ir.Primitive condition, 779 void buildIf(ir.Primitive condition,
827 void buildThenPart(IrBuilder builder), 780 void buildThenPart(IrBuilder builder),
828 void buildElsePart(IrBuilder builder)) { 781 void buildElsePart(IrBuilder builder)) {
829 assert(isOpen); 782 assert(isOpen);
830 783
831 // The then and else parts are delimited. 784 // The then and else parts are delimited.
832 IrBuilder thenBuilder = new IrBuilder.delimited(this); 785 IrBuilder thenBuilder = makeDelimitedBuilder();
833 IrBuilder elseBuilder = new IrBuilder.delimited(this); 786 IrBuilder elseBuilder = makeDelimitedBuilder();
834 buildThenPart(thenBuilder); 787 buildThenPart(thenBuilder);
835 buildElsePart(elseBuilder); 788 buildElsePart(elseBuilder);
836 789
837 // Build the term 790 // Build the term
838 // (Result =) let cont then() = [[thenPart]] in 791 // (Result =) let cont then() = [[thenPart]] in
839 // let cont else() = [[elsePart]] in 792 // let cont else() = [[elsePart]] in
840 // if condition (then, else) 793 // if condition (then, else)
841 ir.Continuation thenContinuation = new ir.Continuation([]); 794 ir.Continuation thenContinuation = new ir.Continuation([]);
842 ir.Continuation elseContinuation = new ir.Continuation([]); 795 ir.Continuation elseContinuation = new ir.Continuation([]);
843 ir.Expression letElse = 796 ir.Expression letElse =
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 invoke.isRecursive = recursive; 859 invoke.isRecursive = recursive;
907 } 860 }
908 } 861 }
909 862
910 /// Creates a for loop in which the initializer, condition, body, update are 863 /// Creates a for loop in which the initializer, condition, body, update are
911 /// created by [buildInitializer], [buildCondition], [buildBody] and 864 /// created by [buildInitializer], [buildCondition], [buildBody] and
912 /// [buildUpdate], respectively. 865 /// [buildUpdate], respectively.
913 /// 866 ///
914 /// The jump [target] is used to identify which `break` and `continue` 867 /// The jump [target] is used to identify which `break` and `continue`
915 /// statements that have this `for` statement as their target. 868 /// statements that have this `for` statement as their target.
869 ///
870 /// The [closureScope] identifies variables that should be boxed in this loop.
871 /// This includes variables declared inside the body of the loop as well as
872 /// in the for-loop initializer.
916 void buildFor({SubbuildFunction buildInitializer, 873 void buildFor({SubbuildFunction buildInitializer,
917 SubbuildFunction buildCondition, 874 SubbuildFunction buildCondition,
918 SubbuildFunction buildBody, 875 SubbuildFunction buildBody,
919 SubbuildFunction buildUpdate, 876 SubbuildFunction buildUpdate,
920 JumpTarget target}) { 877 JumpTarget target,
878 ClosureScope closureScope}) {
921 assert(isOpen); 879 assert(isOpen);
922 880
923 // For loops use four named continuations: the entry to the condition, 881 // For loops use four named continuations: the entry to the condition,
924 // the entry to the body, the loop exit, and the loop successor (break). 882 // the entry to the body, the loop exit, and the loop successor (break).
925 // The CPS translation of 883 // The CPS translation of
926 // [[for (initializer; condition; update) body; successor]] is: 884 // [[for (initializer; condition; update) body; successor]] is:
927 // 885 //
928 // [[initializer]]; 886 // [[initializer]];
929 // let cont loop(x, ...) = 887 // let cont loop(x, ...) =
930 // let prim cond = [[condition]] in 888 // let prim cond = [[condition]] in
931 // let cont break() = [[successor]] in 889 // let cont break() = [[successor]] in
932 // let cont exit() = break(v, ...) in 890 // let cont exit() = break(v, ...) in
933 // let cont body() = 891 // let cont body() =
934 // let cont continue(x, ...) = [[update]]; loop(v, ...) in 892 // let cont continue(x, ...) = [[update]]; loop(v, ...) in
935 // [[body]]; continue(v, ...) in 893 // [[body]]; continue(v, ...) in
936 // branch cond (body, exit) in 894 // branch cond (body, exit) in
937 // loop(v, ...) 895 // loop(v, ...)
938 // 896 //
939 // If there are no breaks in the body, the break continuation is inlined 897 // If there are no breaks in the body, the break continuation is inlined
940 // in the exit continuation (i.e., the translation of the successor 898 // in the exit continuation (i.e., the translation of the successor
941 // statement occurs in the exit continuation). If there is only one 899 // statement occurs in the exit continuation). If there is only one
942 // invocation of the continue continuation (i.e., no continues in the 900 // invocation of the continue continuation (i.e., no continues in the
943 // body), the continue continuation is inlined in the body. 901 // body), the continue continuation is inlined in the body.
944 902
903 _enterScope(closureScope);
904
945 buildInitializer(this); 905 buildInitializer(this);
946 906
947 IrBuilder condBuilder = new IrBuilder.recursive(this); 907 IrBuilder condBuilder = makeRecursiveBuilder();
948 ir.Primitive condition = buildCondition(condBuilder); 908 ir.Primitive condition = buildCondition(condBuilder);
949 if (condition == null) { 909 if (condition == null) {
950 // If the condition is empty then the body is entered unconditionally. 910 // If the condition is empty then the body is entered unconditionally.
951 condition = condBuilder.buildBooleanLiteral(true); 911 condition = condBuilder.buildBooleanLiteral(true);
952 } 912 }
953 913
954 JumpCollector breakCollector = new JumpCollector(target); 914 JumpCollector breakCollector = new JumpCollector(target);
955 JumpCollector continueCollector = new JumpCollector(target); 915 JumpCollector continueCollector = new JumpCollector(target);
956 state.breakCollectors.add(breakCollector); 916 state.breakCollectors.add(breakCollector);
957 state.continueCollectors.add(continueCollector); 917 state.continueCollectors.add(continueCollector);
958 918
959 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 919 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
960 buildBody(bodyBuilder); 920 buildBody(bodyBuilder);
961 assert(state.breakCollectors.last == breakCollector); 921 assert(state.breakCollectors.last == breakCollector);
962 assert(state.continueCollectors.last == continueCollector); 922 assert(state.continueCollectors.last == continueCollector);
963 state.breakCollectors.removeLast(); 923 state.breakCollectors.removeLast();
964 state.continueCollectors.removeLast(); 924 state.continueCollectors.removeLast();
965 925
966 // The binding of the continue continuation should occur as late as 926 // The binding of the continue continuation should occur as late as
967 // possible, that is, at the nearest common ancestor of all the continue 927 // possible, that is, at the nearest common ancestor of all the continue
968 // sites in the body. However, that is difficult to compute here, so it 928 // sites in the body. However, that is difficult to compute here, so it
969 // is instead placed just outside the body of the body continuation. 929 // is instead placed just outside the body of the body continuation.
970 bool hasContinues = !continueCollector.isEmpty; 930 bool hasContinues = !continueCollector.isEmpty;
971 IrBuilder updateBuilder = hasContinues 931 IrBuilder updateBuilder = hasContinues
972 ? new IrBuilder.recursive(condBuilder) 932 ? condBuilder.makeRecursiveBuilder()
973 : bodyBuilder; 933 : bodyBuilder;
934 updateBuilder._migrateLoopVariables(closureScope);
974 buildUpdate(updateBuilder); 935 buildUpdate(updateBuilder);
975 936
976 // Create body entry and loop exit continuations and a branch to them. 937 // Create body entry and loop exit continuations and a branch to them.
977 ir.Continuation bodyContinuation = new ir.Continuation([]); 938 ir.Continuation bodyContinuation = new ir.Continuation([]);
978 ir.Continuation exitContinuation = new ir.Continuation([]); 939 ir.Continuation exitContinuation = new ir.Continuation([]);
979 ir.LetCont branch = 940 ir.LetCont branch =
980 new ir.LetCont(exitContinuation, 941 new ir.LetCont(exitContinuation,
981 new ir.LetCont(bodyContinuation, 942 new ir.LetCont(bodyContinuation,
982 new ir.Branch(new ir.IsTrue(condition), 943 new ir.Branch(new ir.IsTrue(condition),
983 bodyContinuation, 944 bodyContinuation,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 /// 3) `v` is an instance variable in which case [variableSelector] 1010 /// 3) `v` is an instance variable in which case [variableSelector]
1050 /// defines its write access. 1011 /// defines its write access.
1051 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used 1012 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used
1052 /// to identify which `break` and `continue` statements that have this for-in 1013 /// to identify which `break` and `continue` statements that have this for-in
1053 /// statement as their target. 1014 /// statement as their target.
1054 void buildForIn({SubbuildFunction buildExpression, 1015 void buildForIn({SubbuildFunction buildExpression,
1055 SubbuildFunction buildVariableDeclaration, 1016 SubbuildFunction buildVariableDeclaration,
1056 Element variableElement, 1017 Element variableElement,
1057 Selector variableSelector, 1018 Selector variableSelector,
1058 SubbuildFunction buildBody, 1019 SubbuildFunction buildBody,
1059 JumpTarget target}) { 1020 JumpTarget target,
1021 ClosureScope closureScope}) {
1060 // The for-in loop 1022 // The for-in loop
1061 // 1023 //
1062 // for (a in e) s; 1024 // for (a in e) s;
1063 // 1025 //
1064 // Is compiled analogously to: 1026 // Is compiled analogously to:
1065 // 1027 //
1066 // a = e.iterator; 1028 // it = e.iterator;
1067 // while (a.moveNext()) { 1029 // while (it.moveNext()) {
1068 // var n0 = a.current; 1030 // var a = it.current;
1069 // s; 1031 // s;
1070 // } 1032 // }
1071 1033
1072 // The condition and body are delimited. 1034 // The condition and body are delimited.
1073 IrBuilder condBuilder = new IrBuilder.recursive(this); 1035 IrBuilder condBuilder = makeRecursiveBuilder();
1074 1036
1075 ir.Primitive expressionReceiver = buildExpression(this); 1037 ir.Primitive expressionReceiver = buildExpression(this);
1076 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); 1038 List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
1077 1039
1078 ir.Parameter iterator = new ir.Parameter(null); 1040 ir.Parameter iterator = new ir.Parameter(null);
1079 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); 1041 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
1080 add(new ir.LetCont(iteratorInvoked, 1042 add(new ir.LetCont(iteratorInvoked,
1081 new ir.InvokeMethod(expressionReceiver, 1043 new ir.InvokeMethod(expressionReceiver,
1082 new Selector.getter("iterator", null), iteratorInvoked, 1044 new Selector.getter("iterator", null), iteratorInvoked,
1083 emptyArguments))); 1045 emptyArguments)));
1084 1046
1085 ir.Parameter condition = new ir.Parameter(null); 1047 ir.Parameter condition = new ir.Parameter(null);
1086 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); 1048 ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
1087 condBuilder.add(new ir.LetCont(moveNextInvoked, 1049 condBuilder.add(new ir.LetCont(moveNextInvoked,
1088 new ir.InvokeMethod(iterator, 1050 new ir.InvokeMethod(iterator,
1089 new Selector.call("moveNext", null, 0), 1051 new Selector.call("moveNext", null, 0),
1090 moveNextInvoked, emptyArguments))); 1052 moveNextInvoked, emptyArguments)));
1091 1053
1092 JumpCollector breakCollector = new JumpCollector(target); 1054 JumpCollector breakCollector = new JumpCollector(target);
1093 JumpCollector continueCollector = new JumpCollector(target); 1055 JumpCollector continueCollector = new JumpCollector(target);
1094 state.breakCollectors.add(breakCollector); 1056 state.breakCollectors.add(breakCollector);
1095 state.continueCollectors.add(continueCollector); 1057 state.continueCollectors.add(continueCollector);
1096 1058
1097 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1059 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1060 bodyBuilder._enterScope(closureScope);
1098 if (buildVariableDeclaration != null) { 1061 if (buildVariableDeclaration != null) {
1099 buildVariableDeclaration(bodyBuilder); 1062 buildVariableDeclaration(bodyBuilder);
1100 } 1063 }
1101 1064
1102 ir.Parameter currentValue = new ir.Parameter(null); 1065 ir.Parameter currentValue = new ir.Parameter(null);
1103 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); 1066 ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
1104 bodyBuilder.add(new ir.LetCont(currentInvoked, 1067 bodyBuilder.add(new ir.LetCont(currentInvoked,
1105 new ir.InvokeMethod(iterator, new Selector.getter("current", null), 1068 new ir.InvokeMethod(iterator, new Selector.getter("current", null),
1106 currentInvoked, emptyArguments))); 1069 currentInvoked, emptyArguments)));
1107 if (Elements.isLocal(variableElement)) { 1070 if (Elements.isLocal(variableElement)) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1163 } 1126 }
1164 } 1127 }
1165 1128
1166 /// Creates a while loop in which the condition and body are created by 1129 /// Creates a while loop in which the condition and body are created by
1167 /// [buildCondition] and [buildBody], respectively. 1130 /// [buildCondition] and [buildBody], respectively.
1168 /// 1131 ///
1169 /// The jump [target] is used to identify which `break` and `continue` 1132 /// The jump [target] is used to identify which `break` and `continue`
1170 /// statements that have this `while` statement as their target. 1133 /// statements that have this `while` statement as their target.
1171 void buildWhile({SubbuildFunction buildCondition, 1134 void buildWhile({SubbuildFunction buildCondition,
1172 SubbuildFunction buildBody, 1135 SubbuildFunction buildBody,
1173 JumpTarget target}) { 1136 JumpTarget target,
1137 ClosureScope closureScope}) {
1174 assert(isOpen); 1138 assert(isOpen);
1175 // While loops use four named continuations: the entry to the body, the 1139 // While loops use four named continuations: the entry to the body, the
1176 // loop exit, the loop back edge (continue), and the loop exit (break). 1140 // loop exit, the loop back edge (continue), and the loop exit (break).
1177 // The CPS translation of [[while (condition) body; successor]] is: 1141 // The CPS translation of [[while (condition) body; successor]] is:
1178 // 1142 //
1179 // let cont continue(x, ...) = 1143 // let cont continue(x, ...) =
1180 // let prim cond = [[condition]] in 1144 // let prim cond = [[condition]] in
1181 // let cont break() = [[successor]] in 1145 // let cont break() = [[successor]] in
1182 // let cont exit() = break(v, ...) in 1146 // let cont exit() = break(v, ...) in
1183 // let cont body() = [[body]]; continue(v, ...) in 1147 // let cont body() = [[body]]; continue(v, ...) in
1184 // branch cond (body, exit) in 1148 // branch cond (body, exit) in
1185 // continue(v, ...) 1149 // continue(v, ...)
1186 // 1150 //
1187 // If there are no breaks in the body, the break continuation is inlined 1151 // If there are no breaks in the body, the break continuation is inlined
1188 // in the exit continuation (i.e., the translation of the successor 1152 // in the exit continuation (i.e., the translation of the successor
1189 // statement occurs in the exit continuation). 1153 // statement occurs in the exit continuation).
1190 1154
1191 // The condition and body are delimited. 1155 // The condition and body are delimited.
1192 IrBuilder condBuilder = new IrBuilder.recursive(this); 1156 IrBuilder condBuilder = makeRecursiveBuilder();
1193 ir.Primitive condition = buildCondition(condBuilder); 1157 ir.Primitive condition = buildCondition(condBuilder);
1194 1158
1195 JumpCollector breakCollector = new JumpCollector(target); 1159 JumpCollector breakCollector = new JumpCollector(target);
1196 JumpCollector continueCollector = new JumpCollector(target); 1160 JumpCollector continueCollector = new JumpCollector(target);
1197 state.breakCollectors.add(breakCollector); 1161 state.breakCollectors.add(breakCollector);
1198 state.continueCollectors.add(continueCollector); 1162 state.continueCollectors.add(continueCollector);
1199 1163
1200 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1164 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1165 bodyBuilder._enterScope(closureScope);
1201 buildBody(bodyBuilder); 1166 buildBody(bodyBuilder);
1202 assert(state.breakCollectors.last == breakCollector); 1167 assert(state.breakCollectors.last == breakCollector);
1203 assert(state.continueCollectors.last == continueCollector); 1168 assert(state.continueCollectors.last == continueCollector);
1204 state.breakCollectors.removeLast(); 1169 state.breakCollectors.removeLast();
1205 state.continueCollectors.removeLast(); 1170 state.continueCollectors.removeLast();
1206 1171
1207 // Create body entry and loop exit continuations and a branch to them. 1172 // Create body entry and loop exit continuations and a branch to them.
1208 ir.Continuation bodyContinuation = new ir.Continuation([]); 1173 ir.Continuation bodyContinuation = new ir.Continuation([]);
1209 ir.Continuation exitContinuation = new ir.Continuation([]); 1174 ir.Continuation exitContinuation = new ir.Continuation([]);
1210 ir.LetCont branch = 1175 ir.LetCont branch =
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 /// operand in the context of its own [IrBuilder]. 1333 /// operand in the context of its own [IrBuilder].
1369 ir.Primitive buildLogicalOperator( 1334 ir.Primitive buildLogicalOperator(
1370 ir.Primitive leftValue, 1335 ir.Primitive leftValue,
1371 ir.Primitive buildRightValue(IrBuilder builder), 1336 ir.Primitive buildRightValue(IrBuilder builder),
1372 {bool isLazyOr: false}) { 1337 {bool isLazyOr: false}) {
1373 // e0 && e1 is translated as if e0 ? (e1 == true) : false. 1338 // e0 && e1 is translated as if e0 ? (e1 == true) : false.
1374 // e0 || e1 is translated as if e0 ? true : (e1 == true). 1339 // e0 || e1 is translated as if e0 ? true : (e1 == true).
1375 // The translation must convert both e0 and e1 to booleans and handle 1340 // The translation must convert both e0 and e1 to booleans and handle
1376 // local variable assignments in e1. 1341 // local variable assignments in e1.
1377 1342
1378 IrBuilder rightBuilder = new IrBuilder.delimited(this); 1343 IrBuilder rightBuilder = makeDelimitedBuilder();
1379 ir.Primitive rightValue = buildRightValue(rightBuilder); 1344 ir.Primitive rightValue = buildRightValue(rightBuilder);
1380 // A dummy empty target for the branch on the left subexpression branch. 1345 // A dummy empty target for the branch on the left subexpression branch.
1381 // This enables using the same infrastructure for join-point continuations 1346 // This enables using the same infrastructure for join-point continuations
1382 // as in visitIf and visitConditional. It will hold a definition of the 1347 // as in visitIf and visitConditional. It will hold a definition of the
1383 // appropriate constant and an invocation of the join-point continuation. 1348 // appropriate constant and an invocation of the join-point continuation.
1384 IrBuilder emptyBuilder = new IrBuilder.delimited(this); 1349 IrBuilder emptyBuilder = makeDelimitedBuilder();
1385 // Dummy empty targets for right true and right false. They hold 1350 // Dummy empty targets for right true and right false. They hold
1386 // definitions of the appropriate constant and an invocation of the 1351 // definitions of the appropriate constant and an invocation of the
1387 // join-point continuation. 1352 // join-point continuation.
1388 IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); 1353 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
1389 IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); 1354 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
1390 1355
1391 // If we don't evaluate the right subexpression, the value of the whole 1356 // If we don't evaluate the right subexpression, the value of the whole
1392 // expression is this constant. 1357 // expression is this constant.
1393 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); 1358 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr);
1394 // If we do evaluate the right subexpression, the value of the expression 1359 // If we do evaluate the right subexpression, the value of the expression
1395 // is a true or false constant. 1360 // is a true or false constant.
1396 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); 1361 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true);
1397 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); 1362 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false);
1398 1363
1399 // Treat the result values as named values in the environment, so they 1364 // Treat the result values as named values in the environment, so they
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1441 new ir.LetCont(leftTrueContinuation, 1406 new ir.LetCont(leftTrueContinuation,
1442 new ir.LetCont(leftFalseContinuation, 1407 new ir.LetCont(leftFalseContinuation,
1443 new ir.Branch(new ir.IsTrue(leftValue), 1408 new ir.Branch(new ir.IsTrue(leftValue),
1444 leftTrueContinuation, 1409 leftTrueContinuation,
1445 leftFalseContinuation))))); 1410 leftFalseContinuation)))));
1446 // There is always a join parameter for the result value, because it 1411 // There is always a join parameter for the result value, because it
1447 // is different on at least two paths. 1412 // is different on at least two paths.
1448 return joinContinuation.parameters.last; 1413 return joinContinuation.parameters.last;
1449 } 1414 }
1450 1415
1451 /// Creates an access to `this`. 1416 /// Creates an access to the receiver from the current (or enclosing) method.
1417 ///
1418 /// If inside a closure class, [buildThis] will redirect access through
1419 /// closure fields in order to access the receiver from the enclosing method.
1452 ir.Primitive buildThis() { 1420 ir.Primitive buildThis() {
1453 assert(isOpen); 1421 if (state.receiver != null) return state.receiver;
1454 ir.Primitive result = new ir.This(); 1422 ir.Primitive thisPrim = new ir.This();
1455 add(new ir.LetPrim(result)); 1423 add(new ir.LetPrim(thisPrim));
1456 return result; 1424 return thisPrim;
1457 } 1425 }
1458 1426
1459 /// Create a non-recursive join-point continuation. 1427 /// Create a non-recursive join-point continuation.
1460 /// 1428 ///
1461 /// Given the environment length at the join point and a list of 1429 /// Given the environment length at the join point and a list of
1462 /// jumps that should reach the join point, create a join-point 1430 /// jumps that should reach the join point, create a join-point
1463 /// continuation. The join-point continuation has a parameter for each 1431 /// continuation. The join-point continuation has a parameter for each
1464 /// variable that has different values reaching on different paths. 1432 /// variable that has different values reaching on different paths.
1465 /// 1433 ///
1466 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. 1434 /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1554 index = 0; 1522 index = 0;
1555 for (int i = 0; i < environment.length; ++i) { 1523 for (int i = 0; i < environment.length; ++i) {
1556 if (common[i] == null) { 1524 if (common[i] == null) {
1557 environment.index2value[i] = parameters[index++]; 1525 environment.index2value[i] = parameters[index++];
1558 } 1526 }
1559 } 1527 }
1560 1528
1561 return join; 1529 return join;
1562 } 1530 }
1563 } 1531 }
1532
1533 /// Dart-specific subclass of [IrBuilder].
1534 ///
1535 /// Inner functions are represented by a [FunctionDefinition] with the
1536 /// IR for the inner function nested inside.
1537 ///
1538 /// Captured variables are translated to ref cells (see [ClosureVariable])
1539 /// using [GetClosureVariable] and [SetClosureVariable].
1540 class DartIrBuilder extends IrBuilder {
1541 ClosureVariableInfo closureVariables;
1542
1543 IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables);
1544 DartIrBuilder._blank(this.closureVariables);
1545
1546 DartIrBuilder(ConstantSystem constantSystem,
1547 ExecutableElement currentElement,
1548 this.closureVariables) {
1549 _init(constantSystem, currentElement);
1550 closureVariables.capturedVariables.forEach(closure.makeClosureVariable);
1551 }
1552
1553 /// True if [local] is stored in a [ClosureVariable].
1554 bool isInClosureVariable(Local local) {
1555 return closure.local2closure.containsKey(local);
1556 }
1557
1558 /// Gets the [ClosureVariable] containing the value of [local].
1559 ir.ClosureVariable getClosureVariable(Local local) {
1560 return closure.local2closure[local];
1561 }
1562
1563 void _enterScope(ClosureScope scope) {
1564 assert(scope == null);
1565 }
1566
1567 void _enterClosureEnvironment(ClosureEnvironment env) {
1568 assert(env == null);
1569 }
1570
1571 void _migrateLoopVariables(ClosureScope scope) {
1572 assert(scope == null);
1573 }
1574
1575 void _createFunctionParameter(ParameterElement parameterElement) {
1576 ir.Parameter parameter = new ir.Parameter(parameterElement);
1577 _parameters.add(parameter);
1578 if (isInClosureVariable(parameterElement)) {
1579 state.functionParameters.add(getClosureVariable(parameterElement));
1580 } else {
1581 state.functionParameters.add(parameter);
1582 environment.extend(parameterElement, parameter);
1583 }
1584 }
1585
1586 void declareLocalVariable(LocalVariableElement variableElement,
1587 {ir.Primitive initialValue}) {
1588 assert(isOpen);
1589 if (initialValue == null) {
1590 initialValue = buildNullLiteral();
1591 }
1592 if (isInClosureVariable(variableElement)) {
1593 add(new ir.SetClosureVariable(getClosureVariable(variableElement),
1594 initialValue,
1595 isDeclaration: true));
1596 } else {
1597 initialValue.useElementAsHint(variableElement);
1598 environment.extend(variableElement, initialValue);
1599 }
1600 }
1601
1602 /// Add [functionElement] to the environment with provided [definition].
1603 void declareLocalFunction(LocalFunctionElement functionElement,
1604 ir.FunctionDefinition definition) {
1605 assert(isOpen);
1606 if (isInClosureVariable(functionElement)) {
1607 ir.ClosureVariable variable = getClosureVariable(functionElement);
1608 add(new ir.DeclareFunction(variable, definition));
1609 } else {
1610 ir.CreateFunction prim = new ir.CreateFunction(definition);
1611 add(new ir.LetPrim(prim));
1612 environment.extend(functionElement, prim);
1613 prim.useElementAsHint(functionElement);
1614 }
1615 }
1616
1617 /// Create a function expression from [definition].
1618 ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
1619 ir.CreateFunction prim = new ir.CreateFunction(definition);
1620 add(new ir.LetPrim(prim));
1621 return prim;
1622 }
1623
1624 /// Create a read access of [local].
1625 ir.Primitive buildLocalGet(LocalElement local) {
1626 assert(isOpen);
1627 if (isInClosureVariable(local)) {
1628 ir.Primitive result = new ir.GetClosureVariable(getClosureVariable(local)) ;
1629 result.useElementAsHint(local);
1630 add(new ir.LetPrim(result));
1631 return result;
1632 } else {
1633 return environment.lookup(local);
1634 }
1635 }
1636
1637 /// Create a write access to [local] with the provided [value].
1638 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1639 assert(isOpen);
1640 if (isInClosureVariable(local)) {
1641 add(new ir.SetClosureVariable(getClosureVariable(local), value));
1642 } else {
1643 value.useElementAsHint(local);
1644 environment.update(local, value);
1645 }
1646 return value;
1647 }
1648
1649
1650 }
1651
1652 /// JS-specific subclass of [IrBuilder].
1653 ///
1654 /// Inner functions are represented by a [ClosureClassElement], and captured
1655 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField].
1656 class JsIrBuilder extends IrBuilder {
1657 IrBuilder _makeInstance() => new JsIrBuilder._blank();
1658 JsIrBuilder._blank();
1659
1660 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) {
1661 _init(constantSystem, currentElement);
1662 }
1663
1664 void _enterClosureEnvironment(ClosureEnvironment env) {
1665 if (env == null) return;
1666
1667 // Obtain a reference to the function object (this).
1668 ir.Primitive thisPrim = new ir.This();
1669 add(new ir.LetPrim(thisPrim));
1670
1671 // Obtain access to the free variables.
1672 env.freeVariables.forEach((Local local, ClosureLocation location) {
1673 if (location.isBox) {
1674 // Boxed variables are loaded from their box on-demand.
1675 state.boxedVariables[local] = location;
1676 } else {
1677 // Unboxed variables are loaded from the function object immediately.
1678 // This includes BoxLocals which are themselves unboxed variables.
1679 ir.Primitive load = new ir.GetField(thisPrim, location.field);
1680 add(new ir.LetPrim(load));
1681 environment.extend(local, load);
1682 }
1683 });
1684
1685 // If the function captures a reference to the receiver from the
1686 // enclosing method, remember which primitive refers to the receiver object.
1687 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) {
1688 state.receiver = environment.lookup(env.thisLocal);
1689 }
1690
1691 // If the function has a self-reference, use the value of `this`.
1692 if (env.selfReference != null) {
1693 environment.extend(env.selfReference, thisPrim);
1694 }
1695 }
1696
1697 void _enterScope(ClosureScope scope) {
1698 if (scope == null) return;
1699 if (scope.box != null) {
1700 ir.CreateBox boxPrim = new ir.CreateBox();
1701 add(new ir.LetPrim(boxPrim));
1702 environment.extend(scope.box, boxPrim);
1703 boxPrim.useElementAsHint(scope.box);
1704 }
1705 scope.capturedVariables.forEach((Local local, ClosureLocation location) {
1706 assert(!state.boxedVariables.containsKey(local));
1707 if (location.isBox) {
1708 state.boxedVariables[local] = location;
1709 }
1710 });
1711 }
1712
1713 void _createFunctionParameter(ParameterElement parameterElement) {
1714 ir.Parameter parameter = new ir.Parameter(parameterElement);
1715 _parameters.add(parameter);
1716 state.functionParameters.add(parameter);
1717 ClosureLocation location = state.boxedVariables[parameterElement];
1718 if (location != null) {
1719 add(new ir.SetField(environment.lookup(location.box),
1720 location.field,
1721 parameter));
1722 } else {
1723 environment.extend(parameterElement, parameter);
1724 }
1725 }
1726
1727 void declareLocalVariable(LocalElement variableElement,
1728 {ir.Primitive initialValue}) {
1729 assert(isOpen);
1730 if (initialValue == null) {
1731 initialValue = buildNullLiteral();
1732 }
1733 ClosureLocation location = state.boxedVariables[variableElement];
1734 if (location != null) {
1735 add(new ir.SetField(environment.lookup(location.box),
1736 location.field,
1737 initialValue));
1738 } else {
1739 initialValue.useElementAsHint(variableElement);
1740 environment.extend(variableElement, initialValue);
1741 }
1742 }
1743
1744 /// Add [functionElement] to the environment with provided [definition].
1745 void declareLocalFunction(LocalFunctionElement functionElement,
1746 ClosureClassElement classElement) {
1747 ir.Primitive closure = buildFunctionExpression(classElement);
1748 declareLocalVariable(functionElement, initialValue: closure);
1749 }
1750
1751 ir.Primitive buildFunctionExpression(ClosureClassElement classElement) {
1752 List<ir.Primitive> arguments = <ir.Primitive>[];
1753 for (ClosureFieldElement field in classElement.closureFields) {
1754 arguments.add(environment.lookup(field.local));
1755 }
1756 ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments);
1757 add(new ir.LetPrim(closure));
1758 return closure;
1759 }
1760
1761 /// Create a read access of [local].
1762 ir.Primitive buildLocalGet(LocalElement local) {
1763 assert(isOpen);
1764 ClosureLocation location = state.boxedVariables[local];
1765 if (location != null) {
1766 ir.Primitive result = new ir.GetField(environment.lookup(location.box),
1767 location.field);
1768 result.useElementAsHint(local);
1769 add(new ir.LetPrim(result));
1770 return result;
1771 } else {
1772 return environment.lookup(local);
1773 }
1774 }
1775
1776 /// Create a write access to [local] with the provided [value].
1777 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1778 assert(isOpen);
1779 ClosureLocation location = state.boxedVariables[local];
1780 if (location != null) {
1781 add(new ir.SetField(environment.lookup(location.box),
1782 location.field,
1783 value));
1784 } else {
1785 value.useElementAsHint(local);
1786 environment.update(local, value);
1787 }
1788 return value;
1789 }
1790
1791 void _migrateLoopVariables(ClosureScope scope) {
1792 if (scope.boxedLoopVariables.isEmpty) return;
1793 ir.Primitive box = environment.lookup(scope.box);
1794 ir.Primitive newBox = new ir.CreateBox();
1795 newBox.useElementAsHint(scope.box);
1796 add(new ir.LetPrim(newBox));
1797 for (VariableElement loopVar in scope.boxedLoopVariables) {
1798 ClosureLocation location = scope.capturedVariables[loopVar];
1799 ir.Primitive get = new ir.GetField(box, location.field);
1800 add(new ir.LetPrim(get));
1801 add(new ir.SetField(newBox, location.field, get));
1802 }
1803 environment.update(scope.box, newBox);
1804 }
1805
1806 }
1807
1808
1809 /// Location of a variable relative to a given closure.
1810 class ClosureLocation {
1811 /// If not `null`, this location is [box].[field].
1812 /// The location of [box] can be obtained separately from an
1813 /// enclosing [ClosureEnvironment] or [ClosureScope].
1814 /// If `null`, then the location is [field] on the enclosing function object.
1815 final BoxLocal box;
1816
1817 /// The field in which the variable is stored.
1818 final Entity field;
1819
1820 bool get isBox => box != null;
1821
1822 ClosureLocation(this.box, this.field);
1823 }
1824
1825 /// Introduces a new box and binds local variables to this box.
1826 ///
1827 /// A [ClosureScope] may exist for each function and for each loop.
1828 /// Generally, one may pass `null` to the [IrBuilder] instead of a
1829 /// [ClosureScope] when a given scope has no boxed variables.
1830 class ClosureScope {
1831 /// This box is now in scope and [capturedVariables] may use it.
1832 final BoxLocal box;
1833
1834 /// Maps [LocalElement]s to their location.
1835 final Map<Local, ClosureLocation> capturedVariables;
1836
1837 /// If this is the scope of a for-loop, [boxedLoopVariables] is the list
1838 /// of boxed variables that are declared in the initializer.
1839 final List<VariableElement> boxedLoopVariables;
1840
1841 ClosureScope(this.box, this.capturedVariables, this.boxedLoopVariables);
1842 }
1843
1844 /// Environment passed when building a nested function, describing how
1845 /// to access variables from the enclosing scope.
1846 class ClosureEnvironment {
1847 /// References to this local should be treated as recursive self-reference.
1848 /// (This is *not* in [freeVariables]).
1849 final LocalFunctionElement selfReference;
1850
1851 /// If non-null, [thisLocal] has an entry in [freeVariables] describing where
1852 /// to find the captured value of `this`.
1853 final ThisLocal thisLocal;
1854
1855 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location.
1856 final Map<Local, ClosureLocation> freeVariables;
1857
1858 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables);
1859 }
1860
1861 /// Information about which variables are captured in a closure.
1862 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and
1863 /// [ClosureEnvironment].
1864 abstract class ClosureVariableInfo {
1865 Iterable<Local> get capturedVariables;
1866 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698