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

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: Removed redundant null-check 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 '../io/source_file.dart'; 12 import '../io/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 _buildClosureEnvironmentSetup(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 _buildClosureScopeSetup(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 _buildClosureScopeSetup(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 _buildClosureEnvironmentSetup(closureEnvironment);
363 _buildClosureScopeSetup(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 // If the variables declared in the initializer must be boxed, we must
904 // create the box before entering the loop and renew the box at the end
905 // of the loop.
906 bool hasBoxedLoopVariables = closureScope != null &&
907 !closureScope.boxedLoopVariables.isEmpty;
908
909 // If a variable declared in the initializer must be boxed, we should
910 // create the box before initializing these variables.
911 // Otherwise, it is best to create the box inside the body so we don't have
912 // to create a box before the loop AND at the end of the loop.
913 if (hasBoxedLoopVariables) {
914 _buildClosureScopeSetup(closureScope);
915 }
916
945 buildInitializer(this); 917 buildInitializer(this);
946 918
947 IrBuilder condBuilder = new IrBuilder.recursive(this); 919 IrBuilder condBuilder = makeRecursiveBuilder();
948 ir.Primitive condition = buildCondition(condBuilder); 920 ir.Primitive condition = buildCondition(condBuilder);
949 if (condition == null) { 921 if (condition == null) {
950 // If the condition is empty then the body is entered unconditionally. 922 // If the condition is empty then the body is entered unconditionally.
951 condition = condBuilder.buildBooleanLiteral(true); 923 condition = condBuilder.buildBooleanLiteral(true);
952 } 924 }
953 925
954 JumpCollector breakCollector = new JumpCollector(target); 926 JumpCollector breakCollector = new JumpCollector(target);
955 JumpCollector continueCollector = new JumpCollector(target); 927 JumpCollector continueCollector = new JumpCollector(target);
956 state.breakCollectors.add(breakCollector); 928 state.breakCollectors.add(breakCollector);
957 state.continueCollectors.add(continueCollector); 929 state.continueCollectors.add(continueCollector);
958 930
959 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 931 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
932
933 // If we did not yet create a box for the boxed variables, we must create it
934 // here. This saves us from
935 if (!hasBoxedLoopVariables) {
936 bodyBuilder._buildClosureScopeSetup(closureScope);
937 }
938
960 buildBody(bodyBuilder); 939 buildBody(bodyBuilder);
961 assert(state.breakCollectors.last == breakCollector); 940 assert(state.breakCollectors.last == breakCollector);
962 assert(state.continueCollectors.last == continueCollector); 941 assert(state.continueCollectors.last == continueCollector);
963 state.breakCollectors.removeLast(); 942 state.breakCollectors.removeLast();
964 state.continueCollectors.removeLast(); 943 state.continueCollectors.removeLast();
965 944
966 // The binding of the continue continuation should occur as late as 945 // The binding of the continue continuation should occur as late as
967 // possible, that is, at the nearest common ancestor of all the continue 946 // 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 947 // 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. 948 // is instead placed just outside the body of the body continuation.
970 bool hasContinues = !continueCollector.isEmpty; 949 bool hasContinues = !continueCollector.isEmpty;
971 IrBuilder updateBuilder = hasContinues 950 IrBuilder updateBuilder = hasContinues
972 ? new IrBuilder.recursive(condBuilder) 951 ? condBuilder.makeRecursiveBuilder()
973 : bodyBuilder; 952 : bodyBuilder;
953 if (hasBoxedLoopVariables) {
954 updateBuilder._migrateLoopVariables(closureScope);
955 }
974 buildUpdate(updateBuilder); 956 buildUpdate(updateBuilder);
975 957
976 // Create body entry and loop exit continuations and a branch to them. 958 // Create body entry and loop exit continuations and a branch to them.
977 ir.Continuation bodyContinuation = new ir.Continuation([]); 959 ir.Continuation bodyContinuation = new ir.Continuation([]);
978 ir.Continuation exitContinuation = new ir.Continuation([]); 960 ir.Continuation exitContinuation = new ir.Continuation([]);
979 ir.LetCont branch = 961 ir.LetCont branch =
980 new ir.LetCont(exitContinuation, 962 new ir.LetCont(exitContinuation,
981 new ir.LetCont(bodyContinuation, 963 new ir.LetCont(bodyContinuation,
982 new ir.Branch(new ir.IsTrue(condition), 964 new ir.Branch(new ir.IsTrue(condition),
983 bodyContinuation, 965 bodyContinuation,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 /// 3) `v` is an instance variable in which case [variableSelector] 1031 /// 3) `v` is an instance variable in which case [variableSelector]
1050 /// defines its write access. 1032 /// defines its write access.
1051 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used 1033 /// [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 1034 /// to identify which `break` and `continue` statements that have this for-in
1053 /// statement as their target. 1035 /// statement as their target.
1054 void buildForIn({SubbuildFunction buildExpression, 1036 void buildForIn({SubbuildFunction buildExpression,
1055 SubbuildFunction buildVariableDeclaration, 1037 SubbuildFunction buildVariableDeclaration,
1056 Element variableElement, 1038 Element variableElement,
1057 Selector variableSelector, 1039 Selector variableSelector,
1058 SubbuildFunction buildBody, 1040 SubbuildFunction buildBody,
1059 JumpTarget target}) { 1041 JumpTarget target,
1042 ClosureScope closureScope}) {
1060 // The for-in loop 1043 // The for-in loop
1061 // 1044 //
1062 // for (a in e) s; 1045 // for (a in e) s;
1063 // 1046 //
1064 // Is compiled analogously to: 1047 // Is compiled analogously to:
1065 // 1048 //
1066 // a = e.iterator; 1049 // it = e.iterator;
1067 // while (a.moveNext()) { 1050 // while (it.moveNext()) {
1068 // var n0 = a.current; 1051 // var a = it.current;
1069 // s; 1052 // s;
1070 // } 1053 // }
1071 1054
1072 // The condition and body are delimited. 1055 // The condition and body are delimited.
1073 IrBuilder condBuilder = new IrBuilder.recursive(this); 1056 IrBuilder condBuilder = makeRecursiveBuilder();
1074 1057
1075 ir.Primitive expressionReceiver = buildExpression(this); 1058 ir.Primitive expressionReceiver = buildExpression(this);
1076 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); 1059 List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
1077 1060
1078 ir.Parameter iterator = new ir.Parameter(null); 1061 ir.Parameter iterator = new ir.Parameter(null);
1079 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); 1062 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
1080 add(new ir.LetCont(iteratorInvoked, 1063 add(new ir.LetCont(iteratorInvoked,
1081 new ir.InvokeMethod(expressionReceiver, 1064 new ir.InvokeMethod(expressionReceiver,
1082 new Selector.getter("iterator", null), iteratorInvoked, 1065 new Selector.getter("iterator", null), iteratorInvoked,
1083 emptyArguments))); 1066 emptyArguments)));
1084 1067
1085 ir.Parameter condition = new ir.Parameter(null); 1068 ir.Parameter condition = new ir.Parameter(null);
1086 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); 1069 ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
1087 condBuilder.add(new ir.LetCont(moveNextInvoked, 1070 condBuilder.add(new ir.LetCont(moveNextInvoked,
1088 new ir.InvokeMethod(iterator, 1071 new ir.InvokeMethod(iterator,
1089 new Selector.call("moveNext", null, 0), 1072 new Selector.call("moveNext", null, 0),
1090 moveNextInvoked, emptyArguments))); 1073 moveNextInvoked, emptyArguments)));
1091 1074
1092 JumpCollector breakCollector = new JumpCollector(target); 1075 JumpCollector breakCollector = new JumpCollector(target);
1093 JumpCollector continueCollector = new JumpCollector(target); 1076 JumpCollector continueCollector = new JumpCollector(target);
1094 state.breakCollectors.add(breakCollector); 1077 state.breakCollectors.add(breakCollector);
1095 state.continueCollectors.add(continueCollector); 1078 state.continueCollectors.add(continueCollector);
1096 1079
1097 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1080 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1081 bodyBuilder._buildClosureScopeSetup(closureScope);
1098 if (buildVariableDeclaration != null) { 1082 if (buildVariableDeclaration != null) {
1099 buildVariableDeclaration(bodyBuilder); 1083 buildVariableDeclaration(bodyBuilder);
1100 } 1084 }
1101 1085
1102 ir.Parameter currentValue = new ir.Parameter(null); 1086 ir.Parameter currentValue = new ir.Parameter(null);
1103 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); 1087 ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
1104 bodyBuilder.add(new ir.LetCont(currentInvoked, 1088 bodyBuilder.add(new ir.LetCont(currentInvoked,
1105 new ir.InvokeMethod(iterator, new Selector.getter("current", null), 1089 new ir.InvokeMethod(iterator, new Selector.getter("current", null),
1106 currentInvoked, emptyArguments))); 1090 currentInvoked, emptyArguments)));
1107 if (Elements.isLocal(variableElement)) { 1091 if (Elements.isLocal(variableElement)) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1163 } 1147 }
1164 } 1148 }
1165 1149
1166 /// Creates a while loop in which the condition and body are created by 1150 /// Creates a while loop in which the condition and body are created by
1167 /// [buildCondition] and [buildBody], respectively. 1151 /// [buildCondition] and [buildBody], respectively.
1168 /// 1152 ///
1169 /// The jump [target] is used to identify which `break` and `continue` 1153 /// The jump [target] is used to identify which `break` and `continue`
1170 /// statements that have this `while` statement as their target. 1154 /// statements that have this `while` statement as their target.
1171 void buildWhile({SubbuildFunction buildCondition, 1155 void buildWhile({SubbuildFunction buildCondition,
1172 SubbuildFunction buildBody, 1156 SubbuildFunction buildBody,
1173 JumpTarget target}) { 1157 JumpTarget target,
1158 ClosureScope closureScope}) {
1174 assert(isOpen); 1159 assert(isOpen);
1175 // While loops use four named continuations: the entry to the body, the 1160 // 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). 1161 // loop exit, the loop back edge (continue), and the loop exit (break).
1177 // The CPS translation of [[while (condition) body; successor]] is: 1162 // The CPS translation of [[while (condition) body; successor]] is:
1178 // 1163 //
1179 // let cont continue(x, ...) = 1164 // let cont continue(x, ...) =
1180 // let prim cond = [[condition]] in 1165 // let prim cond = [[condition]] in
1181 // let cont break() = [[successor]] in 1166 // let cont break() = [[successor]] in
1182 // let cont exit() = break(v, ...) in 1167 // let cont exit() = break(v, ...) in
1183 // let cont body() = [[body]]; continue(v, ...) in 1168 // let cont body() = [[body]]; continue(v, ...) in
1184 // branch cond (body, exit) in 1169 // branch cond (body, exit) in
1185 // continue(v, ...) 1170 // continue(v, ...)
1186 // 1171 //
1187 // If there are no breaks in the body, the break continuation is inlined 1172 // 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 1173 // in the exit continuation (i.e., the translation of the successor
1189 // statement occurs in the exit continuation). 1174 // statement occurs in the exit continuation).
1190 1175
1191 // The condition and body are delimited. 1176 // The condition and body are delimited.
1192 IrBuilder condBuilder = new IrBuilder.recursive(this); 1177 IrBuilder condBuilder = makeRecursiveBuilder();
1193 ir.Primitive condition = buildCondition(condBuilder); 1178 ir.Primitive condition = buildCondition(condBuilder);
1194 1179
1195 JumpCollector breakCollector = new JumpCollector(target); 1180 JumpCollector breakCollector = new JumpCollector(target);
1196 JumpCollector continueCollector = new JumpCollector(target); 1181 JumpCollector continueCollector = new JumpCollector(target);
1197 state.breakCollectors.add(breakCollector); 1182 state.breakCollectors.add(breakCollector);
1198 state.continueCollectors.add(continueCollector); 1183 state.continueCollectors.add(continueCollector);
1199 1184
1200 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1185 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1186 bodyBuilder._buildClosureScopeSetup(closureScope);
1201 buildBody(bodyBuilder); 1187 buildBody(bodyBuilder);
1202 assert(state.breakCollectors.last == breakCollector); 1188 assert(state.breakCollectors.last == breakCollector);
1203 assert(state.continueCollectors.last == continueCollector); 1189 assert(state.continueCollectors.last == continueCollector);
1204 state.breakCollectors.removeLast(); 1190 state.breakCollectors.removeLast();
1205 state.continueCollectors.removeLast(); 1191 state.continueCollectors.removeLast();
1206 1192
1207 // Create body entry and loop exit continuations and a branch to them. 1193 // Create body entry and loop exit continuations and a branch to them.
1208 ir.Continuation bodyContinuation = new ir.Continuation([]); 1194 ir.Continuation bodyContinuation = new ir.Continuation([]);
1209 ir.Continuation exitContinuation = new ir.Continuation([]); 1195 ir.Continuation exitContinuation = new ir.Continuation([]);
1210 ir.LetCont branch = 1196 ir.LetCont branch =
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 /// operand in the context of its own [IrBuilder]. 1354 /// operand in the context of its own [IrBuilder].
1369 ir.Primitive buildLogicalOperator( 1355 ir.Primitive buildLogicalOperator(
1370 ir.Primitive leftValue, 1356 ir.Primitive leftValue,
1371 ir.Primitive buildRightValue(IrBuilder builder), 1357 ir.Primitive buildRightValue(IrBuilder builder),
1372 {bool isLazyOr: false}) { 1358 {bool isLazyOr: false}) {
1373 // e0 && e1 is translated as if e0 ? (e1 == true) : false. 1359 // e0 && e1 is translated as if e0 ? (e1 == true) : false.
1374 // e0 || e1 is translated as if e0 ? true : (e1 == true). 1360 // e0 || e1 is translated as if e0 ? true : (e1 == true).
1375 // The translation must convert both e0 and e1 to booleans and handle 1361 // The translation must convert both e0 and e1 to booleans and handle
1376 // local variable assignments in e1. 1362 // local variable assignments in e1.
1377 1363
1378 IrBuilder rightBuilder = new IrBuilder.delimited(this); 1364 IrBuilder rightBuilder = makeDelimitedBuilder();
1379 ir.Primitive rightValue = buildRightValue(rightBuilder); 1365 ir.Primitive rightValue = buildRightValue(rightBuilder);
1380 // A dummy empty target for the branch on the left subexpression branch. 1366 // A dummy empty target for the branch on the left subexpression branch.
1381 // This enables using the same infrastructure for join-point continuations 1367 // This enables using the same infrastructure for join-point continuations
1382 // as in visitIf and visitConditional. It will hold a definition of the 1368 // as in visitIf and visitConditional. It will hold a definition of the
1383 // appropriate constant and an invocation of the join-point continuation. 1369 // appropriate constant and an invocation of the join-point continuation.
1384 IrBuilder emptyBuilder = new IrBuilder.delimited(this); 1370 IrBuilder emptyBuilder = makeDelimitedBuilder();
1385 // Dummy empty targets for right true and right false. They hold 1371 // Dummy empty targets for right true and right false. They hold
1386 // definitions of the appropriate constant and an invocation of the 1372 // definitions of the appropriate constant and an invocation of the
1387 // join-point continuation. 1373 // join-point continuation.
1388 IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); 1374 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
1389 IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); 1375 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
1390 1376
1391 // If we don't evaluate the right subexpression, the value of the whole 1377 // If we don't evaluate the right subexpression, the value of the whole
1392 // expression is this constant. 1378 // expression is this constant.
1393 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); 1379 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr);
1394 // If we do evaluate the right subexpression, the value of the expression 1380 // If we do evaluate the right subexpression, the value of the expression
1395 // is a true or false constant. 1381 // is a true or false constant.
1396 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); 1382 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true);
1397 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); 1383 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false);
1398 1384
1399 // Treat the result values as named values in the environment, so they 1385 // 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, 1427 new ir.LetCont(leftTrueContinuation,
1442 new ir.LetCont(leftFalseContinuation, 1428 new ir.LetCont(leftFalseContinuation,
1443 new ir.Branch(new ir.IsTrue(leftValue), 1429 new ir.Branch(new ir.IsTrue(leftValue),
1444 leftTrueContinuation, 1430 leftTrueContinuation,
1445 leftFalseContinuation))))); 1431 leftFalseContinuation)))));
1446 // There is always a join parameter for the result value, because it 1432 // There is always a join parameter for the result value, because it
1447 // is different on at least two paths. 1433 // is different on at least two paths.
1448 return joinContinuation.parameters.last; 1434 return joinContinuation.parameters.last;
1449 } 1435 }
1450 1436
1451 /// Creates an access to `this`. 1437 /// Creates an access to the receiver from the current (or enclosing) method.
1438 ///
1439 /// If inside a closure class, [buildThis] will redirect access through
1440 /// closure fields in order to access the receiver from the enclosing method.
1452 ir.Primitive buildThis() { 1441 ir.Primitive buildThis() {
1453 assert(isOpen); 1442 if (state.receiver != null) return state.receiver;
1454 ir.Primitive result = new ir.This(); 1443 ir.Primitive thisPrim = new ir.This();
1455 add(new ir.LetPrim(result)); 1444 add(new ir.LetPrim(thisPrim));
1456 return result; 1445 return thisPrim;
1457 } 1446 }
1458 1447
1459 /// Create a non-recursive join-point continuation. 1448 /// Create a non-recursive join-point continuation.
1460 /// 1449 ///
1461 /// Given the environment length at the join point and a list of 1450 /// Given the environment length at the join point and a list of
1462 /// jumps that should reach the join point, create a join-point 1451 /// jumps that should reach the join point, create a join-point
1463 /// continuation. The join-point continuation has a parameter for each 1452 /// continuation. The join-point continuation has a parameter for each
1464 /// variable that has different values reaching on different paths. 1453 /// variable that has different values reaching on different paths.
1465 /// 1454 ///
1466 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. 1455 /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1554 index = 0; 1543 index = 0;
1555 for (int i = 0; i < environment.length; ++i) { 1544 for (int i = 0; i < environment.length; ++i) {
1556 if (common[i] == null) { 1545 if (common[i] == null) {
1557 environment.index2value[i] = parameters[index++]; 1546 environment.index2value[i] = parameters[index++];
1558 } 1547 }
1559 } 1548 }
1560 1549
1561 return join; 1550 return join;
1562 } 1551 }
1563 } 1552 }
1553
1554 /// Dart-specific subclass of [IrBuilder].
1555 ///
1556 /// Inner functions are represented by a [FunctionDefinition] with the
1557 /// IR for the inner function nested inside.
1558 ///
1559 /// Captured variables are translated to ref cells (see [ClosureVariable])
1560 /// using [GetClosureVariable] and [SetClosureVariable].
1561 class DartIrBuilder extends IrBuilder {
1562 ClosureVariableInfo closureVariables;
1563
1564 IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables);
1565 DartIrBuilder._blank(this.closureVariables);
1566
1567 DartIrBuilder(ConstantSystem constantSystem,
1568 ExecutableElement currentElement,
1569 this.closureVariables) {
1570 _init(constantSystem, currentElement);
1571 closureVariables.capturedVariables.forEach(closure.makeClosureVariable);
1572 }
1573
1574 /// True if [local] is stored in a [ClosureVariable].
1575 bool isInClosureVariable(Local local) {
1576 return closure.local2closure.containsKey(local);
1577 }
1578
1579 /// Gets the [ClosureVariable] containing the value of [local].
1580 ir.ClosureVariable getClosureVariable(Local local) {
1581 return closure.local2closure[local];
1582 }
1583
1584 void _buildClosureScopeSetup(ClosureScope scope) {
1585 assert(scope == null);
1586 }
1587
1588 void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
1589 assert(env == null);
1590 }
1591
1592 void _migrateLoopVariables(ClosureScope scope) {
1593 assert(scope == null);
1594 }
1595
1596 void _createFunctionParameter(ParameterElement parameterElement) {
1597 ir.Parameter parameter = new ir.Parameter(parameterElement);
1598 _parameters.add(parameter);
1599 if (isInClosureVariable(parameterElement)) {
1600 state.functionParameters.add(getClosureVariable(parameterElement));
1601 } else {
1602 state.functionParameters.add(parameter);
1603 environment.extend(parameterElement, parameter);
1604 }
1605 }
1606
1607 void declareLocalVariable(LocalVariableElement variableElement,
1608 {ir.Primitive initialValue}) {
1609 assert(isOpen);
1610 if (initialValue == null) {
1611 initialValue = buildNullLiteral();
1612 }
1613 if (isInClosureVariable(variableElement)) {
1614 add(new ir.SetClosureVariable(getClosureVariable(variableElement),
1615 initialValue,
1616 isDeclaration: true));
1617 } else {
1618 initialValue.useElementAsHint(variableElement);
1619 environment.extend(variableElement, initialValue);
1620 }
1621 }
1622
1623 /// Add [functionElement] to the environment with provided [definition].
1624 void declareLocalFunction(LocalFunctionElement functionElement,
1625 ir.FunctionDefinition definition) {
1626 assert(isOpen);
1627 if (isInClosureVariable(functionElement)) {
1628 ir.ClosureVariable variable = getClosureVariable(functionElement);
1629 add(new ir.DeclareFunction(variable, definition));
1630 } else {
1631 ir.CreateFunction prim = new ir.CreateFunction(definition);
1632 add(new ir.LetPrim(prim));
1633 environment.extend(functionElement, prim);
1634 prim.useElementAsHint(functionElement);
1635 }
1636 }
1637
1638 /// Create a function expression from [definition].
1639 ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
1640 ir.CreateFunction prim = new ir.CreateFunction(definition);
1641 add(new ir.LetPrim(prim));
1642 return prim;
1643 }
1644
1645 /// Create a read access of [local].
1646 ir.Primitive buildLocalGet(LocalElement local) {
1647 assert(isOpen);
1648 if (isInClosureVariable(local)) {
1649 ir.Primitive result = new ir.GetClosureVariable(getClosureVariable(local)) ;
1650 result.useElementAsHint(local);
1651 add(new ir.LetPrim(result));
1652 return result;
1653 } else {
1654 return environment.lookup(local);
1655 }
1656 }
1657
1658 /// Create a write access to [local] with the provided [value].
1659 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1660 assert(isOpen);
1661 if (isInClosureVariable(local)) {
1662 add(new ir.SetClosureVariable(getClosureVariable(local), value));
1663 } else {
1664 value.useElementAsHint(local);
1665 environment.update(local, value);
1666 }
1667 return value;
1668 }
1669
1670
1671 }
1672
1673 /// JS-specific subclass of [IrBuilder].
1674 ///
1675 /// Inner functions are represented by a [ClosureClassElement], and captured
1676 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField].
1677 class JsIrBuilder extends IrBuilder {
1678 IrBuilder _makeInstance() => new JsIrBuilder._blank();
1679 JsIrBuilder._blank();
1680
1681 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) {
1682 _init(constantSystem, currentElement);
1683 }
1684
1685 void _buildClosureEnvironmentSetup(ClosureEnvironment env) {
1686 if (env == null) return;
1687
1688 // Obtain a reference to the function object (this).
1689 ir.Primitive thisPrim = new ir.This();
1690 add(new ir.LetPrim(thisPrim));
1691
1692 // Obtain access to the free variables.
1693 env.freeVariables.forEach((Local local, ClosureLocation location) {
1694 if (location.isBox) {
1695 // Boxed variables are loaded from their box on-demand.
1696 state.boxedVariables[local] = location;
1697 } else {
1698 // Unboxed variables are loaded from the function object immediately.
1699 // This includes BoxLocals which are themselves unboxed variables.
1700 ir.Primitive load = new ir.GetField(thisPrim, location.field);
1701 add(new ir.LetPrim(load));
1702 environment.extend(local, load);
1703 }
1704 });
1705
1706 // If the function captures a reference to the receiver from the
1707 // enclosing method, remember which primitive refers to the receiver object.
1708 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) {
1709 state.receiver = environment.lookup(env.thisLocal);
1710 }
1711
1712 // If the function has a self-reference, use the value of `this`.
1713 if (env.selfReference != null) {
1714 environment.extend(env.selfReference, thisPrim);
1715 }
1716 }
1717
1718 void _buildClosureScopeSetup(ClosureScope scope) {
1719 if (scope == null) return;
1720 ir.CreateBox boxPrim = new ir.CreateBox();
1721 add(new ir.LetPrim(boxPrim));
1722 environment.extend(scope.box, boxPrim);
1723 boxPrim.useElementAsHint(scope.box);
1724 scope.capturedVariables.forEach((Local local, ClosureLocation location) {
1725 assert(!state.boxedVariables.containsKey(local));
1726 if (location.isBox) {
1727 state.boxedVariables[local] = location;
1728 }
1729 });
1730 }
1731
1732 void _createFunctionParameter(ParameterElement parameterElement) {
1733 ir.Parameter parameter = new ir.Parameter(parameterElement);
1734 _parameters.add(parameter);
1735 state.functionParameters.add(parameter);
1736 ClosureLocation location = state.boxedVariables[parameterElement];
1737 if (location != null) {
1738 add(new ir.SetField(environment.lookup(location.box),
1739 location.field,
1740 parameter));
1741 } else {
1742 environment.extend(parameterElement, parameter);
1743 }
1744 }
1745
1746 void declareLocalVariable(LocalElement variableElement,
1747 {ir.Primitive initialValue}) {
1748 assert(isOpen);
1749 if (initialValue == null) {
1750 initialValue = buildNullLiteral();
1751 }
1752 ClosureLocation location = state.boxedVariables[variableElement];
1753 if (location != null) {
1754 add(new ir.SetField(environment.lookup(location.box),
1755 location.field,
1756 initialValue));
1757 } else {
1758 initialValue.useElementAsHint(variableElement);
1759 environment.extend(variableElement, initialValue);
1760 }
1761 }
1762
1763 /// Add [functionElement] to the environment with provided [definition].
1764 void declareLocalFunction(LocalFunctionElement functionElement,
1765 ClosureClassElement classElement) {
1766 ir.Primitive closure = buildFunctionExpression(classElement);
1767 declareLocalVariable(functionElement, initialValue: closure);
1768 }
1769
1770 ir.Primitive buildFunctionExpression(ClosureClassElement classElement) {
1771 List<ir.Primitive> arguments = <ir.Primitive>[];
1772 for (ClosureFieldElement field in classElement.closureFields) {
1773 arguments.add(environment.lookup(field.local));
1774 }
1775 ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments);
1776 add(new ir.LetPrim(closure));
1777 return closure;
1778 }
1779
1780 /// Create a read access of [local].
1781 ir.Primitive buildLocalGet(LocalElement local) {
1782 assert(isOpen);
1783 ClosureLocation location = state.boxedVariables[local];
1784 if (location != null) {
1785 ir.Primitive result = new ir.GetField(environment.lookup(location.box),
1786 location.field);
1787 result.useElementAsHint(local);
1788 add(new ir.LetPrim(result));
1789 return result;
1790 } else {
1791 return environment.lookup(local);
1792 }
1793 }
1794
1795 /// Create a write access to [local] with the provided [value].
1796 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1797 assert(isOpen);
1798 ClosureLocation location = state.boxedVariables[local];
1799 if (location != null) {
1800 add(new ir.SetField(environment.lookup(location.box),
1801 location.field,
1802 value));
1803 } else {
1804 value.useElementAsHint(local);
1805 environment.update(local, value);
1806 }
1807 return value;
1808 }
1809
1810 void _migrateLoopVariables(ClosureScope scope) {
1811 if (scope == null) return;
1812 ir.Primitive box = environment.lookup(scope.box);
1813 ir.Primitive newBox = new ir.CreateBox();
1814 newBox.useElementAsHint(scope.box);
1815 add(new ir.LetPrim(newBox));
1816 for (VariableElement loopVar in scope.boxedLoopVariables) {
1817 ClosureLocation location = scope.capturedVariables[loopVar];
1818 ir.Primitive get = new ir.GetField(box, location.field);
1819 add(new ir.LetPrim(get));
1820 add(new ir.SetField(newBox, location.field, get));
1821 }
1822 environment.update(scope.box, newBox);
1823 }
1824
1825 }
1826
1827
1828 /// Location of a variable relative to a given closure.
1829 class ClosureLocation {
1830 /// If not `null`, this location is [box].[field].
1831 /// The location of [box] can be obtained separately from an
1832 /// enclosing [ClosureEnvironment] or [ClosureScope].
1833 /// If `null`, then the location is [field] on the enclosing function object.
1834 final BoxLocal box;
1835
1836 /// The field in which the variable is stored.
1837 final Entity field;
1838
1839 bool get isBox => box != null;
1840
1841 ClosureLocation(this.box, this.field);
1842 }
1843
1844 /// Introduces a new box and binds local variables to this box.
1845 ///
1846 /// A [ClosureScope] may exist for each function and for each loop.
1847 /// Generally, one may pass `null` to the [IrBuilder] instead of a
1848 /// [ClosureScope] when a given scope has no boxed variables.
1849 class ClosureScope {
1850 /// This box is now in scope and [capturedVariables] may use it.
1851 final BoxLocal box;
1852
1853 /// Maps [LocalElement]s to their location.
1854 final Map<Local, ClosureLocation> capturedVariables;
1855
1856 /// If this is the scope of a for-loop, [boxedLoopVariables] is the list
1857 /// of boxed variables that are declared in the initializer.
1858 final List<VariableElement> boxedLoopVariables;
1859
1860 ClosureScope(this.box, this.capturedVariables, this.boxedLoopVariables);
1861 }
1862
1863 /// Environment passed when building a nested function, describing how
1864 /// to access variables from the enclosing scope.
1865 class ClosureEnvironment {
1866 /// References to this local should be treated as recursive self-reference.
1867 /// (This is *not* in [freeVariables]).
1868 final LocalFunctionElement selfReference;
1869
1870 /// If non-null, [thisLocal] has an entry in [freeVariables] describing where
1871 /// to find the captured value of `this`.
1872 final ThisLocal thisLocal;
1873
1874 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location.
1875 final Map<Local, ClosureLocation> freeVariables;
1876
1877 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables);
1878 }
1879
1880 /// Information about which variables are captured in a closure.
1881 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and
1882 /// [ClosureEnvironment].
1883 abstract class ClosureVariableInfo {
1884 Iterable<Local> get capturedVariables;
1885 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/closure.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698