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

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: 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 elements 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
171 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses 173 // TODO(johnniwinther): Type [nodes] as `Iterable<N>` when `NodeList` uses
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 {
floitsch 2015/01/08 18:29:35 Probably different CL, but I'm not sure the names
asgerf 2015/01/12 13:15:42 I completely agree, but I can't seem to think of b
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 in the enclosing method.
floitsch 2015/01/08 18:29:35 to the receiver (`this`) in ...
asgerf 2015/01/12 13:15:42 Done.
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, {ir.Primitive initialV alue});
floitsch 2015/01/08 18:29:36 long line.
242 void declareLocalFunction(LocalFunctionElement element, Object function);
243 ir.Primitive buildFunctionExpression(Object function);
244 ir.Primitive buildLocalGet(LocalElement element);
245 ir.Primitive buildLocalSet(LocalElement element, ir.Primitive value);
246
247 void _enterClosureEnvironment(ClosureEnvironment env);
floitsch 2015/01/08 18:29:36 comments!
248 void _enterScope(ClosureScope scope);
249 void _createFunctionParameter(ParameterElement parameterElement);
250 void _migrateLoopVariables(ClosureScope scope);
251
230 // TODO(johnniwinther): Make these field final and remove the default values 252 // TODO(johnniwinther): Make these field final and remove the default values
231 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin. 253 // when [IrBuilder] is a property of [IrBuilderVisitor] instead of a mixin.
232 254
233 final List<ir.Parameter> _parameters = <ir.Parameter>[]; 255 final List<ir.Parameter> _parameters = <ir.Parameter>[];
234 256
235 final IrBuilderSharedState state; 257 IrBuilderSharedState state;
236 258
237 final IrBuilderClosureState closure; 259 IrBuilderClosureState closure;
floitsch 2015/01/08 18:29:36 Again, probably different CL: closureState, or eve
238 260
239 /// A map from variable indexes to their values. 261 /// A map from variable indexes to their values.
262 /// [BoxLocal]s map to their box. [LocalElement]s that are boxed are not
floitsch 2015/01/08 18:29:35 New line before. (Otherwise markdown merges them).
263 /// in the map; look up their [BoxLocal] instead.
240 Environment environment; 264 Environment environment;
241 265
242 // The IR builder maintains a context, which is an expression with a hole in 266 // 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. 267 // 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 268 // 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. 269 // 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 270 // 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 271 // tail position, do not have a hole). Expressions with a hole have a plug
248 // method. 272 // method.
249 // 273 //
250 // Conceptually, visiting a statement takes a context as input and returns 274 // 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 275 // either a new context or else an expression without a hole if all
252 // control-flow paths through the statement have exited. An expression 276 // 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 277 // without a hole is represented by a (root, current) pair where root is the
254 // expression and current is null. 278 // expression and current is null.
255 // 279 //
256 // Conceptually again, visiting an expression takes a context as input and 280 // Conceptually again, visiting an expression takes a context as input and
257 // returns either a pair of a new context and a definition denoting 281 // 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 282 // the expression's value, or else an expression without a hole if all
259 // control-flow paths through the expression have exited. 283 // control-flow paths through the expression have exited.
260 // 284 //
261 // We do not pass contexts as arguments or return them. Rather we use the 285 // 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. 286 // current context (root, current) as the visitor state and mutate current.
263 // Visiting a statement returns null; visiting an expression returns the 287 // Visiting a statement returns null; visiting an expression returns the
264 // primitive denoting its value. 288 // primitive denoting its value.
265 289
266 ir.Expression _root = null; 290 ir.Expression _root = null;
267 ir.Expression _current = null; 291 ir.Expression _current = null;
268 292
269 IrBuilder(ConstantSystem constantSystem, 293 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) {
floitsch 2015/01/08 18:29:36 add comment. Could you keep this a constructor? B
asgerf 2015/01/12 13:15:42 Added comment. The subclasses have two constructo
270 ExecutableElement currentElement, 294 state = new IrBuilderSharedState(constantSystem, currentElement);
271 Iterable<Entity> closureLocals) 295 closure = new IrBuilderClosureState();
272 : this.state = new IrBuilderSharedState(constantSystem, currentElement), 296 environment = new Environment.empty();
273 this.closure = new IrBuilderClosureState(closureLocals), 297 }
274 this.environment = new Environment.empty();
275 298
276 /// Construct a delimited visitor for visiting a subtree. 299 /// Construct a delimited visitor for visiting a subtree.
277 /// 300 ///
278 /// The delimited visitor has its own compile-time environment mapping 301 /// The delimited visitor has its own compile-time environment mapping
279 /// local variables to their values, which is initially a copy of the parent 302 /// 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 303 /// environment. It has its own context for building an IR expression, so
281 /// the built expression is not plugged into the parent's context. 304 /// the built expression is not plugged into the parent's context.
282 IrBuilder.delimited(IrBuilder parent) 305 IrBuilder makeDelimitedBuilder() {
283 : this.state = parent.state, 306 return _makeInstance()
284 this.closure = parent.closure, 307 ..state = state
floitsch 2015/01/08 18:29:36 nit: indentation. (by 4).
285 this.environment = new Environment.from(parent.environment); 308 ..closure = closure
309 ..environment = new Environment.from(environment);
310 }
286 311
287 /// Construct a visitor for a recursive continuation. 312 /// Construct a visitor for a recursive continuation.
288 /// 313 ///
289 /// The recursive continuation builder has fresh parameters (i.e. SSA phis) 314 /// The recursive continuation builder has fresh parameters (i.e. SSA phis)
floitsch 2015/01/08 18:29:35 "i.e." doesn't seem right. It's more of a "like" n
asgerf 2015/01/12 13:15:42 Parameters are like SSA phis, but using "like" her
290 /// for all the local variables in the parent, because the invocation sites 315 /// 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 316 /// 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, 317 /// 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 318 /// which may be eliminated later if they are redundant---if they take on
294 /// the same value at all invocation sites. 319 /// the same value at all invocation sites.
295 IrBuilder.recursive(IrBuilder parent) 320 IrBuilder makeRecursiveBuilder() {
296 : this.state = parent.state, 321 IrBuilder inner = _makeInstance()
297 this.closure = parent.closure, 322 ..state = state
298 this.environment = new Environment.empty() { 323 ..closure = closure
299 parent.environment.index2variable.forEach(createLocalParameter); 324 ..environment = new Environment.empty();
325 environment.index2variable.forEach(inner.createLocalParameter);
326 return inner;
300 } 327 }
301 328
302 /// Construct a builder for an inner function. 329 /// Construct a builder for an inner function.
303 IrBuilder.innerFunction(IrBuilder parent, 330 IrBuilder makeInnerFunctionBuilder(ExecutableElement currentElement) {
304 ExecutableElement currentElement) 331 return _makeInstance()
305 : this.state = new IrBuilderSharedState(parent.state.constantSystem, 332 ..state = new IrBuilderSharedState(state.constantSystem, currentElement)
306 currentElement), 333 ..closure = closure
307 this.closure = parent.closure, 334 ..environment = new Environment.empty();
308 this.environment = new Environment.empty(); 335 }
309
310 336
311 bool get isOpen => _root == null || _current != null; 337 bool get isOpen => _root == null || _current != null;
312 338
313 /// True if [element] is a local variable, local function, or parameter that 339 void beginField({ ClosureScope closureScope }) {
floitsch 2015/01/08 18:29:36 nit: apparently we don't put spaces after "{" and
floitsch 2015/01/08 18:29:36 comment. Is this the rhs of a field-init?
asgerf 2015/01/12 13:15:43 Done.
314 /// is accessed from an inner function. Recursive self-references in a local 340 beginFunction([], closureScope: closureScope);
315 /// function count as closure accesses.
316 ///
317 /// If `true`, [element] is a [LocalElement].
318 bool isClosureVariable(Element element) {
319 return closure.closureLocals.contains(element);
320 } 341 }
321 342
322 /// Returns the [ClosureVariable] corresponding to the given variable. 343 void beginFunction(Iterable<ParameterElement> parameters,
floitsch 2015/01/08 18:29:36 Apparently this method is not just used for functi
asgerf 2015/01/12 13:15:43 Fixed. The only shared part was _enterScope, so I
323 /// Returns `null` for non-closure variables. 344 { ClosureScope closureScope,
324 ir.ClosureVariable getClosureVariable(LocalElement element) { 345 ClosureEnvironment closureEnvironment } ) {
325 return closure.local2closure[element]; 346 if (closureEnvironment != null) {
347 _enterClosureEnvironment(closureEnvironment);
floitsch 2015/01/08 18:29:35 unconditionally _enterClosureEnvironment(...) and
asgerf 2015/01/12 13:15:43 Done.
348 }
349 if (closureScope != null) {
350 _enterScope(closureScope);
floitsch 2015/01/08 18:29:35 ditto.
asgerf 2015/01/12 13:15:42 Done.
351 }
352 parameters.forEach(_createFunctionParameter);
326 } 353 }
327 354
328 /// Adds the given parameter to the function currently being built. 355 /// Create a parameter for [local] and add it to the current environment.
floitsch 2015/01/08 18:29:36 Creates ... adds ...
asgerf 2015/01/12 13:15:43 Done.
329 void createFunctionParameter(ParameterElement parameterElement) { 356 ir.Parameter createLocalParameter(Local local) {
330 if (isClosureVariable(parameterElement)) { 357 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); 358 _parameters.add(parameter);
342 environment.extend(parameterElement, parameter); 359 environment.extend(local, parameter);
343 return parameter; 360 return parameter;
344 } 361 }
345 362
346 /// Add the constant [variableElement] to the environment with [value] as its 363 /// Add the constant [variableElement] to the environment with [value] as its
floitsch 2015/01/08 18:29:35 Adds
asgerf 2015/01/12 13:15:42 Done.
347 /// constant value. 364 /// constant value.
348 void declareLocalConstant(LocalVariableElement variableElement, 365 void declareLocalConstant(LocalVariableElement variableElement,
349 ConstantExpression value) { 366 ConstantExpression value) {
350 state.localConstants.add(new ConstDeclaration(variableElement, value)); 367 state.localConstants.add(new ConstDeclaration(variableElement, value));
351 } 368 }
352 369
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 370 // 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 371 // 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, 372 // 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 373 // the new hole must be in the newly added expression---which becomes the
394 // new value of current. 374 // new value of current.
395 void add(ir.Expression expr) { 375 void add(ir.Expression expr) {
396 assert(isOpen); 376 assert(isOpen);
397 if (_root == null) { 377 if (_root == null) {
398 _root = _current = expr; 378 _root = _current = expr;
399 } else { 379 } else {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 /// then and else expression are created through the [buildThenExpression] and 495 /// then and else expression are created through the [buildThenExpression] and
516 /// [buildElseExpression] functions, respectively. 496 /// [buildElseExpression] functions, respectively.
517 ir.Primitive buildConditional( 497 ir.Primitive buildConditional(
518 ir.Primitive condition, 498 ir.Primitive condition,
519 ir.Primitive buildThenExpression(IrBuilder builder), 499 ir.Primitive buildThenExpression(IrBuilder builder),
520 ir.Primitive buildElseExpression(IrBuilder builder)) { 500 ir.Primitive buildElseExpression(IrBuilder builder)) {
521 501
522 assert(isOpen); 502 assert(isOpen);
523 503
524 // The then and else expressions are delimited. 504 // The then and else expressions are delimited.
525 IrBuilder thenBuilder = new IrBuilder.delimited(this); 505 IrBuilder thenBuilder = makeDelimitedBuilder();
526 IrBuilder elseBuilder = new IrBuilder.delimited(this); 506 IrBuilder elseBuilder = makeDelimitedBuilder();
527 ir.Primitive thenValue = buildThenExpression(thenBuilder); 507 ir.Primitive thenValue = buildThenExpression(thenBuilder);
528 ir.Primitive elseValue = buildElseExpression(elseBuilder); 508 ir.Primitive elseValue = buildElseExpression(elseBuilder);
529 509
530 // Treat the values of the subexpressions as named values in the 510 // Treat the values of the subexpressions as named values in the
531 // environment, so they will be treated as arguments to the join-point 511 // environment, so they will be treated as arguments to the join-point
532 // continuation. 512 // continuation.
533 assert(environment.length == thenBuilder.environment.length); 513 assert(environment.length == thenBuilder.environment.length);
534 assert(environment.length == elseBuilder.environment.length); 514 assert(environment.length == elseBuilder.environment.length);
535 thenBuilder.environment.extend(null, thenValue); 515 thenBuilder.environment.extend(null, thenValue);
536 elseBuilder.environment.extend(null, elseValue); 516 elseBuilder.environment.extend(null, elseValue);
(...skipping 17 matching lines...) Expand all
554 new ir.LetCont(elseContinuation, 534 new ir.LetCont(elseContinuation,
555 new ir.Branch(new ir.IsTrue(condition), 535 new ir.Branch(new ir.IsTrue(condition),
556 thenContinuation, 536 thenContinuation,
557 elseContinuation))))); 537 elseContinuation)))));
558 return (thenValue == elseValue) 538 return (thenValue == elseValue)
559 ? thenValue 539 ? thenValue
560 : joinContinuation.parameters.last; 540 : joinContinuation.parameters.last;
561 541
562 } 542 }
563 543
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 /** 544 /**
572 * Add an explicit `return null` for functions that don't have a return 545 * 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, 546 * statement on each branch. This includes functions with an empty body,
574 * such as `foo(){ }`. 547 * such as `foo(){ }`.
575 */ 548 */
576 void _ensureReturn() { 549 void _ensureReturn() {
577 if (!isOpen) return; 550 if (!isOpen) return;
578 ir.Constant constant = buildNullLiteral(); 551 ir.Constant constant = buildNullLiteral();
579 add(new ir.InvokeContinuation(state.returnContinuation, [constant])); 552 add(new ir.InvokeContinuation(state.returnContinuation, [constant]));
580 _current = null; 553 _current = null;
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments)); 732 (k) => new ir.InvokeConstructor(type, element, selector, k, arguments));
760 } 733 }
761 734
762 /// Create a string concatenation of the [arguments]. 735 /// Create a string concatenation of the [arguments].
763 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) { 736 ir.Primitive buildStringConcatenation(List<ir.Primitive> arguments) {
764 assert(isOpen); 737 assert(isOpen);
765 return _continueWithExpression( 738 return _continueWithExpression(
766 (k) => new ir.ConcatenateStrings(k, arguments)); 739 (k) => new ir.ConcatenateStrings(k, arguments));
767 } 740 }
768 741
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 742 /// Create an invocation of [local] where the argument structure is defined
795 /// by [selector] and the argument values are defined by [arguments]. 743 /// by [selector] and the argument values are defined by [arguments].
796 ir.Primitive buildLocalInvocation(LocalElement local, 744 ir.Primitive buildLocalInvocation(LocalElement local,
797 Selector selector, 745 Selector selector,
798 List<ir.Definition> arguments) { 746 List<ir.Definition> arguments) {
799 ir.Primitive receiver; 747 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 } 748 }
808 749
809 /// Create an invocation of the [functionExpression] where the argument 750 /// Create an invocation of the [functionExpression] where the argument
810 /// structure are defined by [selector] and the argument values are defined by 751 /// structure are defined by [selector] and the argument values are defined by
811 /// [arguments]. 752 /// [arguments].
812 ir.Primitive buildFunctionExpressionInvocation( 753 ir.Primitive buildFunctionExpressionInvocation(
813 ir.Primitive functionExpression, 754 ir.Primitive functionExpression,
814 Selector selector, 755 Selector selector,
815 List<ir.Definition> arguments) { 756 List<ir.Definition> arguments) {
816 return _buildInvokeCall(functionExpression, selector, arguments); 757 return _buildInvokeCall(functionExpression, selector, arguments);
817 } 758 }
818 759
819 /// Creates an if-then-else statement with the provided [condition] where the 760 /// Creates an if-then-else statement with the provided [condition] where the
820 /// then and else branches are created through the [buildThenPart] and 761 /// then and else branches are created through the [buildThenPart] and
821 /// [buildElsePart] functions, respectively. 762 /// [buildElsePart] functions, respectively.
822 /// 763 ///
823 /// An if-then statement is created if [buildElsePart] is a no-op. 764 /// An if-then statement is created if [buildElsePart] is a no-op.
824 // TODO(johnniwinther): Unify implementation with [buildConditional] and 765 // TODO(johnniwinther): Unify implementation with [buildConditional] and
825 // [_buildLogicalOperator]. 766 // [_buildLogicalOperator].
826 void buildIf(ir.Primitive condition, 767 void buildIf(ir.Primitive condition,
827 void buildThenPart(IrBuilder builder), 768 void buildThenPart(IrBuilder builder),
828 void buildElsePart(IrBuilder builder)) { 769 void buildElsePart(IrBuilder builder)) {
829 assert(isOpen); 770 assert(isOpen);
830 771
831 // The then and else parts are delimited. 772 // The then and else parts are delimited.
832 IrBuilder thenBuilder = new IrBuilder.delimited(this); 773 IrBuilder thenBuilder = makeDelimitedBuilder();
833 IrBuilder elseBuilder = new IrBuilder.delimited(this); 774 IrBuilder elseBuilder = makeDelimitedBuilder();
834 buildThenPart(thenBuilder); 775 buildThenPart(thenBuilder);
835 buildElsePart(elseBuilder); 776 buildElsePart(elseBuilder);
836 777
837 // Build the term 778 // Build the term
838 // (Result =) let cont then() = [[thenPart]] in 779 // (Result =) let cont then() = [[thenPart]] in
839 // let cont else() = [[elsePart]] in 780 // let cont else() = [[elsePart]] in
840 // if condition (then, else) 781 // if condition (then, else)
841 ir.Continuation thenContinuation = new ir.Continuation([]); 782 ir.Continuation thenContinuation = new ir.Continuation([]);
842 ir.Continuation elseContinuation = new ir.Continuation([]); 783 ir.Continuation elseContinuation = new ir.Continuation([]);
843 ir.Expression letElse = 784 ir.Expression letElse =
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 /// Creates a for loop in which the initializer, condition, body, update are 851 /// Creates a for loop in which the initializer, condition, body, update are
911 /// created by [buildInitializer], [buildCondition], [buildBody] and 852 /// created by [buildInitializer], [buildCondition], [buildBody] and
912 /// [buildUpdate], respectively. 853 /// [buildUpdate], respectively.
913 /// 854 ///
914 /// The jump [target] is used to identify which `break` and `continue` 855 /// The jump [target] is used to identify which `break` and `continue`
915 /// statements that have this `for` statement as their target. 856 /// statements that have this `for` statement as their target.
916 void buildFor({SubbuildFunction buildInitializer, 857 void buildFor({SubbuildFunction buildInitializer,
917 SubbuildFunction buildCondition, 858 SubbuildFunction buildCondition,
918 SubbuildFunction buildBody, 859 SubbuildFunction buildBody,
919 SubbuildFunction buildUpdate, 860 SubbuildFunction buildUpdate,
920 JumpTarget target}) { 861 JumpTarget target,
862 ClosureScope closureScope}) {
floitsch 2015/01/08 18:29:36 add comment about closureScope variable.
921 assert(isOpen); 863 assert(isOpen);
922 864
923 // For loops use four named continuations: the entry to the condition, 865 // 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). 866 // the entry to the body, the loop exit, and the loop successor (break).
925 // The CPS translation of 867 // The CPS translation of
926 // [[for (initializer; condition; update) body; successor]] is: 868 // [[for (initializer; condition; update) body; successor]] is:
927 // 869 //
928 // [[initializer]]; 870 // [[initializer]];
929 // let cont loop(x, ...) = 871 // let cont loop(x, ...) =
930 // let prim cond = [[condition]] in 872 // let prim cond = [[condition]] in
931 // let cont break() = [[successor]] in 873 // let cont break() = [[successor]] in
932 // let cont exit() = break(v, ...) in 874 // let cont exit() = break(v, ...) in
933 // let cont body() = 875 // let cont body() =
934 // let cont continue(x, ...) = [[update]]; loop(v, ...) in 876 // let cont continue(x, ...) = [[update]]; loop(v, ...) in
935 // [[body]]; continue(v, ...) in 877 // [[body]]; continue(v, ...) in
936 // branch cond (body, exit) in 878 // branch cond (body, exit) in
937 // loop(v, ...) 879 // loop(v, ...)
938 // 880 //
939 // If there are no breaks in the body, the break continuation is inlined 881 // 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 882 // in the exit continuation (i.e., the translation of the successor
941 // statement occurs in the exit continuation). If there is only one 883 // statement occurs in the exit continuation). If there is only one
942 // invocation of the continue continuation (i.e., no continues in the 884 // invocation of the continue continuation (i.e., no continues in the
943 // body), the continue continuation is inlined in the body. 885 // body), the continue continuation is inlined in the body.
944 886
887 if (closureScope != null) {
888 _enterScope(closureScope);
floitsch 2015/01/08 18:29:36 as above (and for the remaining ones): uncondition
889 }
890
945 buildInitializer(this); 891 buildInitializer(this);
946 892
947 IrBuilder condBuilder = new IrBuilder.recursive(this); 893 IrBuilder condBuilder = makeRecursiveBuilder();
948 ir.Primitive condition = buildCondition(condBuilder); 894 ir.Primitive condition = buildCondition(condBuilder);
949 if (condition == null) { 895 if (condition == null) {
950 // If the condition is empty then the body is entered unconditionally. 896 // If the condition is empty then the body is entered unconditionally.
951 condition = condBuilder.buildBooleanLiteral(true); 897 condition = condBuilder.buildBooleanLiteral(true);
952 } 898 }
953 899
954 JumpCollector breakCollector = new JumpCollector(target); 900 JumpCollector breakCollector = new JumpCollector(target);
955 JumpCollector continueCollector = new JumpCollector(target); 901 JumpCollector continueCollector = new JumpCollector(target);
956 state.breakCollectors.add(breakCollector); 902 state.breakCollectors.add(breakCollector);
957 state.continueCollectors.add(continueCollector); 903 state.continueCollectors.add(continueCollector);
958 904
959 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 905 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
960 buildBody(bodyBuilder); 906 buildBody(bodyBuilder);
961 assert(state.breakCollectors.last == breakCollector); 907 assert(state.breakCollectors.last == breakCollector);
962 assert(state.continueCollectors.last == continueCollector); 908 assert(state.continueCollectors.last == continueCollector);
963 state.breakCollectors.removeLast(); 909 state.breakCollectors.removeLast();
964 state.continueCollectors.removeLast(); 910 state.continueCollectors.removeLast();
965 911
966 // The binding of the continue continuation should occur as late as 912 // The binding of the continue continuation should occur as late as
967 // possible, that is, at the nearest common ancestor of all the continue 913 // 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 914 // 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. 915 // is instead placed just outside the body of the body continuation.
970 bool hasContinues = !continueCollector.isEmpty; 916 bool hasContinues = !continueCollector.isEmpty;
971 IrBuilder updateBuilder = hasContinues 917 IrBuilder updateBuilder = hasContinues
972 ? new IrBuilder.recursive(condBuilder) 918 ? condBuilder.makeRecursiveBuilder()
973 : bodyBuilder; 919 : bodyBuilder;
920 if (closureScope != null) {
921 updateBuilder._migrateLoopVariables(closureScope);
floitsch 2015/01/08 18:29:35 ditto
922 }
974 buildUpdate(updateBuilder); 923 buildUpdate(updateBuilder);
975 924
976 // Create body entry and loop exit continuations and a branch to them. 925 // Create body entry and loop exit continuations and a branch to them.
977 ir.Continuation bodyContinuation = new ir.Continuation([]); 926 ir.Continuation bodyContinuation = new ir.Continuation([]);
978 ir.Continuation exitContinuation = new ir.Continuation([]); 927 ir.Continuation exitContinuation = new ir.Continuation([]);
979 ir.LetCont branch = 928 ir.LetCont branch =
980 new ir.LetCont(exitContinuation, 929 new ir.LetCont(exitContinuation,
981 new ir.LetCont(bodyContinuation, 930 new ir.LetCont(bodyContinuation,
982 new ir.Branch(new ir.IsTrue(condition), 931 new ir.Branch(new ir.IsTrue(condition),
983 bodyContinuation, 932 bodyContinuation,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1049 /// 3) `v` is an instance variable in which case [variableSelector] 998 /// 3) `v` is an instance variable in which case [variableSelector]
1050 /// defines its write access. 999 /// defines its write access.
1051 /// [buildBody] creates the body, `b`, of the loop. The jump [target] is used 1000 /// [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 1001 /// to identify which `break` and `continue` statements that have this for-in
1053 /// statement as their target. 1002 /// statement as their target.
1054 void buildForIn({SubbuildFunction buildExpression, 1003 void buildForIn({SubbuildFunction buildExpression,
1055 SubbuildFunction buildVariableDeclaration, 1004 SubbuildFunction buildVariableDeclaration,
1056 Element variableElement, 1005 Element variableElement,
1057 Selector variableSelector, 1006 Selector variableSelector,
1058 SubbuildFunction buildBody, 1007 SubbuildFunction buildBody,
1059 JumpTarget target}) { 1008 JumpTarget target,
1009 ClosureScope closureScope}) {
1060 // The for-in loop 1010 // The for-in loop
1061 // 1011 //
1062 // for (a in e) s; 1012 // for (a in e) s;
1063 // 1013 //
1064 // Is compiled analogously to: 1014 // Is compiled analogously to:
1065 // 1015 //
1066 // a = e.iterator; 1016 // it = e.iterator;
1067 // while (a.moveNext()) { 1017 // while (it.moveNext()) {
1068 // var n0 = a.current; 1018 // var a = it.current;
1069 // s; 1019 // s;
1070 // } 1020 // }
1071 1021
1072 // The condition and body are delimited. 1022 // The condition and body are delimited.
1073 IrBuilder condBuilder = new IrBuilder.recursive(this); 1023 IrBuilder condBuilder = makeRecursiveBuilder();
1074 1024
1075 ir.Primitive expressionReceiver = buildExpression(this); 1025 ir.Primitive expressionReceiver = buildExpression(this);
1076 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); 1026 List<ir.Primitive> emptyArguments = new List<ir.Primitive>();
1077 1027
1078 ir.Parameter iterator = new ir.Parameter(null); 1028 ir.Parameter iterator = new ir.Parameter(null);
1079 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); 1029 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
1080 add(new ir.LetCont(iteratorInvoked, 1030 add(new ir.LetCont(iteratorInvoked,
1081 new ir.InvokeMethod(expressionReceiver, 1031 new ir.InvokeMethod(expressionReceiver,
1082 new Selector.getter("iterator", null), iteratorInvoked, 1032 new Selector.getter("iterator", null), iteratorInvoked,
1083 emptyArguments))); 1033 emptyArguments)));
1084 1034
1085 ir.Parameter condition = new ir.Parameter(null); 1035 ir.Parameter condition = new ir.Parameter(null);
1086 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); 1036 ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
1087 condBuilder.add(new ir.LetCont(moveNextInvoked, 1037 condBuilder.add(new ir.LetCont(moveNextInvoked,
1088 new ir.InvokeMethod(iterator, 1038 new ir.InvokeMethod(iterator,
1089 new Selector.call("moveNext", null, 0), 1039 new Selector.call("moveNext", null, 0),
1090 moveNextInvoked, emptyArguments))); 1040 moveNextInvoked, emptyArguments)));
1091 1041
1092 JumpCollector breakCollector = new JumpCollector(target); 1042 JumpCollector breakCollector = new JumpCollector(target);
1093 JumpCollector continueCollector = new JumpCollector(target); 1043 JumpCollector continueCollector = new JumpCollector(target);
1094 state.breakCollectors.add(breakCollector); 1044 state.breakCollectors.add(breakCollector);
1095 state.continueCollectors.add(continueCollector); 1045 state.continueCollectors.add(continueCollector);
1096 1046
1097 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1047 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1048 if (closureScope != null) {
1049 bodyBuilder._enterScope(closureScope);
1050 }
1098 if (buildVariableDeclaration != null) { 1051 if (buildVariableDeclaration != null) {
1099 buildVariableDeclaration(bodyBuilder); 1052 buildVariableDeclaration(bodyBuilder);
1100 } 1053 }
1101 1054
1102 ir.Parameter currentValue = new ir.Parameter(null); 1055 ir.Parameter currentValue = new ir.Parameter(null);
1103 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); 1056 ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
1104 bodyBuilder.add(new ir.LetCont(currentInvoked, 1057 bodyBuilder.add(new ir.LetCont(currentInvoked,
1105 new ir.InvokeMethod(iterator, new Selector.getter("current", null), 1058 new ir.InvokeMethod(iterator, new Selector.getter("current", null),
1106 currentInvoked, emptyArguments))); 1059 currentInvoked, emptyArguments)));
1107 if (Elements.isLocal(variableElement)) { 1060 if (Elements.isLocal(variableElement)) {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1163 } 1116 }
1164 } 1117 }
1165 1118
1166 /// Creates a while loop in which the condition and body are created by 1119 /// Creates a while loop in which the condition and body are created by
1167 /// [buildCondition] and [buildBody], respectively. 1120 /// [buildCondition] and [buildBody], respectively.
1168 /// 1121 ///
1169 /// The jump [target] is used to identify which `break` and `continue` 1122 /// The jump [target] is used to identify which `break` and `continue`
1170 /// statements that have this `while` statement as their target. 1123 /// statements that have this `while` statement as their target.
1171 void buildWhile({SubbuildFunction buildCondition, 1124 void buildWhile({SubbuildFunction buildCondition,
1172 SubbuildFunction buildBody, 1125 SubbuildFunction buildBody,
1173 JumpTarget target}) { 1126 JumpTarget target,
1127 ClosureScope closureScope}) {
1174 assert(isOpen); 1128 assert(isOpen);
1175 // While loops use four named continuations: the entry to the body, the 1129 // 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). 1130 // loop exit, the loop back edge (continue), and the loop exit (break).
1177 // The CPS translation of [[while (condition) body; successor]] is: 1131 // The CPS translation of [[while (condition) body; successor]] is:
1178 // 1132 //
1179 // let cont continue(x, ...) = 1133 // let cont continue(x, ...) =
1180 // let prim cond = [[condition]] in 1134 // let prim cond = [[condition]] in
1181 // let cont break() = [[successor]] in 1135 // let cont break() = [[successor]] in
1182 // let cont exit() = break(v, ...) in 1136 // let cont exit() = break(v, ...) in
1183 // let cont body() = [[body]]; continue(v, ...) in 1137 // let cont body() = [[body]]; continue(v, ...) in
1184 // branch cond (body, exit) in 1138 // branch cond (body, exit) in
1185 // continue(v, ...) 1139 // continue(v, ...)
1186 // 1140 //
1187 // If there are no breaks in the body, the break continuation is inlined 1141 // 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 1142 // in the exit continuation (i.e., the translation of the successor
1189 // statement occurs in the exit continuation). 1143 // statement occurs in the exit continuation).
1190 1144
1191 // The condition and body are delimited. 1145 // The condition and body are delimited.
1192 IrBuilder condBuilder = new IrBuilder.recursive(this); 1146 IrBuilder condBuilder = makeRecursiveBuilder();
1193 ir.Primitive condition = buildCondition(condBuilder); 1147 ir.Primitive condition = buildCondition(condBuilder);
1194 1148
1195 JumpCollector breakCollector = new JumpCollector(target); 1149 JumpCollector breakCollector = new JumpCollector(target);
1196 JumpCollector continueCollector = new JumpCollector(target); 1150 JumpCollector continueCollector = new JumpCollector(target);
1197 state.breakCollectors.add(breakCollector); 1151 state.breakCollectors.add(breakCollector);
1198 state.continueCollectors.add(continueCollector); 1152 state.continueCollectors.add(continueCollector);
1199 1153
1200 IrBuilder bodyBuilder = new IrBuilder.delimited(condBuilder); 1154 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder();
1155 if (closureScope != null) {
1156 bodyBuilder._enterScope(closureScope);
1157 }
1201 buildBody(bodyBuilder); 1158 buildBody(bodyBuilder);
1202 assert(state.breakCollectors.last == breakCollector); 1159 assert(state.breakCollectors.last == breakCollector);
1203 assert(state.continueCollectors.last == continueCollector); 1160 assert(state.continueCollectors.last == continueCollector);
1204 state.breakCollectors.removeLast(); 1161 state.breakCollectors.removeLast();
1205 state.continueCollectors.removeLast(); 1162 state.continueCollectors.removeLast();
1206 1163
1207 // Create body entry and loop exit continuations and a branch to them. 1164 // Create body entry and loop exit continuations and a branch to them.
1208 ir.Continuation bodyContinuation = new ir.Continuation([]); 1165 ir.Continuation bodyContinuation = new ir.Continuation([]);
1209 ir.Continuation exitContinuation = new ir.Continuation([]); 1166 ir.Continuation exitContinuation = new ir.Continuation([]);
1210 ir.LetCont branch = 1167 ir.LetCont branch =
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
1368 /// operand in the context of its own [IrBuilder]. 1325 /// operand in the context of its own [IrBuilder].
1369 ir.Primitive buildLogicalOperator( 1326 ir.Primitive buildLogicalOperator(
1370 ir.Primitive leftValue, 1327 ir.Primitive leftValue,
1371 ir.Primitive buildRightValue(IrBuilder builder), 1328 ir.Primitive buildRightValue(IrBuilder builder),
1372 {bool isLazyOr: false}) { 1329 {bool isLazyOr: false}) {
1373 // e0 && e1 is translated as if e0 ? (e1 == true) : false. 1330 // e0 && e1 is translated as if e0 ? (e1 == true) : false.
1374 // e0 || e1 is translated as if e0 ? true : (e1 == true). 1331 // e0 || e1 is translated as if e0 ? true : (e1 == true).
1375 // The translation must convert both e0 and e1 to booleans and handle 1332 // The translation must convert both e0 and e1 to booleans and handle
1376 // local variable assignments in e1. 1333 // local variable assignments in e1.
1377 1334
1378 IrBuilder rightBuilder = new IrBuilder.delimited(this); 1335 IrBuilder rightBuilder = makeDelimitedBuilder();
1379 ir.Primitive rightValue = buildRightValue(rightBuilder); 1336 ir.Primitive rightValue = buildRightValue(rightBuilder);
1380 // A dummy empty target for the branch on the left subexpression branch. 1337 // A dummy empty target for the branch on the left subexpression branch.
1381 // This enables using the same infrastructure for join-point continuations 1338 // This enables using the same infrastructure for join-point continuations
1382 // as in visitIf and visitConditional. It will hold a definition of the 1339 // as in visitIf and visitConditional. It will hold a definition of the
1383 // appropriate constant and an invocation of the join-point continuation. 1340 // appropriate constant and an invocation of the join-point continuation.
1384 IrBuilder emptyBuilder = new IrBuilder.delimited(this); 1341 IrBuilder emptyBuilder = makeDelimitedBuilder();
1385 // Dummy empty targets for right true and right false. They hold 1342 // Dummy empty targets for right true and right false. They hold
1386 // definitions of the appropriate constant and an invocation of the 1343 // definitions of the appropriate constant and an invocation of the
1387 // join-point continuation. 1344 // join-point continuation.
1388 IrBuilder rightTrueBuilder = new IrBuilder.delimited(rightBuilder); 1345 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder();
1389 IrBuilder rightFalseBuilder = new IrBuilder.delimited(rightBuilder); 1346 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder();
1390 1347
1391 // If we don't evaluate the right subexpression, the value of the whole 1348 // If we don't evaluate the right subexpression, the value of the whole
1392 // expression is this constant. 1349 // expression is this constant.
1393 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); 1350 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr);
1394 // If we do evaluate the right subexpression, the value of the expression 1351 // If we do evaluate the right subexpression, the value of the expression
1395 // is a true or false constant. 1352 // is a true or false constant.
1396 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); 1353 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true);
1397 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); 1354 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false);
1398 1355
1399 // Treat the result values as named values in the environment, so they 1356 // 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, 1398 new ir.LetCont(leftTrueContinuation,
1442 new ir.LetCont(leftFalseContinuation, 1399 new ir.LetCont(leftFalseContinuation,
1443 new ir.Branch(new ir.IsTrue(leftValue), 1400 new ir.Branch(new ir.IsTrue(leftValue),
1444 leftTrueContinuation, 1401 leftTrueContinuation,
1445 leftFalseContinuation))))); 1402 leftFalseContinuation)))));
1446 // There is always a join parameter for the result value, because it 1403 // There is always a join parameter for the result value, because it
1447 // is different on at least two paths. 1404 // is different on at least two paths.
1448 return joinContinuation.parameters.last; 1405 return joinContinuation.parameters.last;
1449 } 1406 }
1450 1407
1451 /// Creates an access to `this`. 1408 /// Creates an access to the receiver from the current (or enclosing) method.
1409 ///
1410 /// If inside a closure class, [buildThis] will redirect acess through closure
1411 /// fields in order to access the receiver from the enclosing method.
1452 ir.Primitive buildThis() { 1412 ir.Primitive buildThis() {
1453 assert(isOpen); 1413 if (state.receiver != null) return state.receiver;
1454 ir.Primitive result = new ir.This(); 1414 ir.Primitive thisPrim = new ir.This();
1455 add(new ir.LetPrim(result)); 1415 add(new ir.LetPrim(thisPrim));
1456 return result; 1416 return thisPrim;
1457 } 1417 }
1458 1418
1459 /// Create a non-recursive join-point continuation. 1419 /// Create a non-recursive join-point continuation.
1460 /// 1420 ///
1461 /// Given the environment length at the join point and a list of 1421 /// Given the environment length at the join point and a list of
1462 /// jumps that should reach the join point, create a join-point 1422 /// jumps that should reach the join point, create a join-point
1463 /// continuation. The join-point continuation has a parameter for each 1423 /// continuation. The join-point continuation has a parameter for each
1464 /// variable that has different values reaching on different paths. 1424 /// variable that has different values reaching on different paths.
1465 /// 1425 ///
1466 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. 1426 /// The jumps are uninitialized [ir.InvokeContinuation] expressions.
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1554 index = 0; 1514 index = 0;
1555 for (int i = 0; i < environment.length; ++i) { 1515 for (int i = 0; i < environment.length; ++i) {
1556 if (common[i] == null) { 1516 if (common[i] == null) {
1557 environment.index2value[i] = parameters[index++]; 1517 environment.index2value[i] = parameters[index++];
1558 } 1518 }
1559 } 1519 }
1560 1520
1561 return join; 1521 return join;
1562 } 1522 }
1563 } 1523 }
1524
1525 /// Dart-specific subclass of [IrBuilder].
1526 ///
1527 /// Inner functions are represented by an [ir.FunctionDefinition] with the
1528 /// IR for the inner function nested inside.
1529 ///
1530 /// Captured variables are translated to ref cells using [GetClosureVariable]
1531 /// and [SetClosureVariable].
1532 class DartIrBuilder extends IrBuilder {
1533 ClosureVariableInfo closureVariables;
1534
1535 IrBuilder _makeInstance() => new DartIrBuilder._blank(closureVariables);
1536 DartIrBuilder._blank(this.closureVariables);
1537
1538 DartIrBuilder(ConstantSystem constantSystem,
1539 ExecutableElement currentElement,
1540 this.closureVariables) {
1541 _init(constantSystem, currentElement);
1542 closureVariables.capturedVariables.forEach(closure.makeClosureVariable);
1543 }
1544
1545 /// True if [local] is stored in a ref cell.
floitsch 2015/01/08 18:29:35 What's a "ref cell" ? Explain more.
asgerf 2015/01/12 13:15:42 Changed to isInClosureVariable. I was thinking abo
1546 bool isInRefCell(Local local) {
1547 return closure.local2closure.containsKey(local);
1548 }
1549
1550 ir.ClosureVariable getRefCell(Local local) => closure.local2closure[local];
1551
1552 void _enterScope(ClosureScope scope) {
1553 throw 'Not supported';
1554 }
1555
1556 void _enterClosureEnvironment(ClosureEnvironment env) {
1557 throw 'Not supported';
1558 }
1559
1560 void _migrateLoopVariables(ClosureScope scope) {
1561 throw 'Not supported';
1562 }
1563
1564 void _createFunctionParameter(ParameterElement parameterElement) {
1565 ir.Parameter parameter = new ir.Parameter(parameterElement);
1566 _parameters.add(parameter);
1567 if (isInRefCell(parameterElement)) {
1568 state.functionParameters.add(getRefCell(parameterElement));
1569 } else {
1570 state.functionParameters.add(parameter);
1571 environment.extend(parameterElement, parameter);
1572 }
1573 }
1574
1575 void declareLocalVariable(LocalVariableElement variableElement,
1576 {ir.Primitive initialValue}) {
1577 assert(isOpen);
1578 if (initialValue == null) {
1579 initialValue = buildNullLiteral();
1580 }
1581 if (isInRefCell(variableElement)) {
1582 add(new ir.SetClosureVariable(getRefCell(variableElement),
1583 initialValue,
1584 isDeclaration: true));
1585 } else {
1586 initialValue.useElementAsHint(variableElement);
1587 environment.extend(variableElement, initialValue);
1588 }
1589 }
1590
1591 /// Add [functionElement] to the environment with provided [definition].
1592 void declareLocalFunction(LocalFunctionElement functionElement,
1593 ir.FunctionDefinition definition) {
1594 assert(isOpen);
1595 if (isInRefCell(functionElement)) {
1596 ir.ClosureVariable variable = getRefCell(functionElement);
1597 add(new ir.DeclareFunction(variable, definition));
1598 } else {
1599 ir.CreateFunction prim = new ir.CreateFunction(definition);
1600 add(new ir.LetPrim(prim));
1601 environment.extend(functionElement, prim);
1602 prim.useElementAsHint(functionElement);
1603 }
1604 }
1605
1606 /// Create a function expression from [definition].
1607 ir.Primitive buildFunctionExpression(ir.FunctionDefinition definition) {
1608 ir.CreateFunction prim = new ir.CreateFunction(definition);
1609 add(new ir.LetPrim(prim));
1610 return prim;
1611 }
1612
1613 /// Create a read access of [local].
1614 ir.Primitive buildLocalGet(LocalElement local) {
1615 assert(isOpen);
1616 if (isInRefCell(local)) {
1617 ir.Primitive result = new ir.GetClosureVariable(getRefCell(local));
1618 result.useElementAsHint(local);
1619 add(new ir.LetPrim(result));
1620 return result;
1621 } else {
1622 return environment.lookup(local);
1623 }
1624 }
1625
1626 /// Create a write access to [local] with the provided [value].
1627 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1628 assert(isOpen);
1629 if (isInRefCell(local)) {
1630 add(new ir.SetClosureVariable(getRefCell(local), value));
1631 } else {
1632 value.useElementAsHint(local);
1633 environment.update(local, value);
1634 }
1635 return value;
1636 }
1637
1638
1639 }
1640
1641 /// JS-specific subclass of [IrBuilder].
1642 ///
1643 /// Inner functions are repsented by a [ClosureClassElement], and captured
floitsch 2015/01/08 18:29:36 represented
asgerf 2015/01/12 13:15:42 Done.
1644 /// variables are boxed as necessary using [CreateBox], [GetField], [SetField].
1645 class JsIrBuilder extends IrBuilder {
1646 IrBuilder _makeInstance() => new JsIrBuilder._blank();
1647 JsIrBuilder._blank();
1648
1649 JsIrBuilder(ConstantSystem constantSystem, ExecutableElement currentElement) {
1650 _init(constantSystem, currentElement);
1651 }
1652
1653 void _enterClosureEnvironment(ClosureEnvironment env) {
1654 ir.Primitive thisPrim = new ir.This();
floitsch 2015/01/08 18:29:36 more comments.
asgerf 2015/01/12 13:15:42 Done.
1655 add(new ir.LetPrim(thisPrim));
1656 env.freeVariables.forEach((Local local, ClosureLocation location) {
1657 if (location.isBox) {
1658 state.boxedVariables[local] = location;
1659 } else {
1660 ir.Primitive load = new ir.GetField(thisPrim, location.field);
floitsch 2015/01/08 18:29:35 Add comment, that dead-code elimination will remov
asgerf 2015/01/12 13:15:43 Shrinking reductions will remove a dead GetField,
1661 add(new ir.LetPrim(load));
1662 environment.extend(local, load);
1663 }
1664 });
1665 if (env.thisLocal != null && env.freeVariables.containsKey(env.thisLocal)) {
1666 state.receiver = environment.lookup(env.thisLocal);
1667 }
1668 if (env.selfReference != null) {
1669 environment.extend(env.selfReference, thisPrim);
1670 }
1671 }
1672
1673 void _enterScope(ClosureScope scope) {
1674 if (scope.box != null) {
1675 ir.CreateBox boxPrim = new ir.CreateBox();
1676 add(new ir.LetPrim(boxPrim));
1677 environment.extend(scope.box, boxPrim);
1678 boxPrim.useElementAsHint(scope.box);
1679 }
1680 scope.capturedVariables.forEach((Local local, ClosureLocation location) {
1681 assert(!state.boxedVariables.containsKey(local));
1682 if (location.isBox) {
1683 state.boxedVariables[local] = location;
1684 }
1685 });
1686 }
1687
1688 void _createFunctionParameter(ParameterElement parameterElement) {
1689 ir.Parameter parameter = new ir.Parameter(parameterElement);
1690 _parameters.add(parameter);
1691 state.functionParameters.add(parameter);
1692 ClosureLocation location = state.boxedVariables[parameterElement];
1693 if (location != null) {
1694 add(new ir.SetField(environment.lookup(location.box),
1695 location.field,
1696 parameter));
1697 } else {
1698 environment.extend(parameterElement, parameter);
1699 }
1700 }
1701
1702 void declareLocalVariable(LocalElement variableElement,
1703 {ir.Primitive initialValue}) {
1704 assert(isOpen);
1705 if (initialValue == null) {
1706 initialValue = buildNullLiteral();
1707 }
1708 ClosureLocation location = state.boxedVariables[variableElement];
1709 if (location != null) {
1710 add(new ir.SetField(environment.lookup(location.box),
1711 location.field,
1712 initialValue));
1713 } else {
1714 initialValue.useElementAsHint(variableElement);
1715 environment.extend(variableElement, initialValue);
1716 }
1717 }
1718
1719 /// Add [functionElement] to the environment with provided [definition].
1720 void declareLocalFunction(LocalFunctionElement functionElement,
1721 ClosureClassElement classElement) {
1722 ir.Primitive closure = buildFunctionExpression(classElement);
1723 declareLocalVariable(functionElement, initialValue: closure);
1724 }
1725
1726 ir.Primitive buildFunctionExpression(ClosureClassElement classElement) {
1727 List<ir.Primitive> arguments = <ir.Primitive>[];
1728 for (ClosureFieldElement field in classElement.closureFields) {
1729 arguments.add(environment.lookup(field.local));
1730 }
1731 ir.Primitive closure = new ir.CreateClosureClass(classElement, arguments);
1732 add(new ir.LetPrim(closure));
1733 return closure;
1734 }
1735
1736 /// Create a read access of [local].
1737 ir.Primitive buildLocalGet(LocalElement local) {
1738 assert(isOpen);
1739 ClosureLocation location = state.boxedVariables[local];
1740 if (location != null) {
1741 ir.Primitive result = new ir.GetField(environment.lookup(location.box),
1742 location.field);
1743 result.useElementAsHint(local);
1744 add(new ir.LetPrim(result));
1745 return result;
1746 } else {
1747 return environment.lookup(local);
1748 }
1749 }
1750
1751 /// Create a write access to [local] with the provided [value].
1752 ir.Primitive buildLocalSet(LocalElement local, ir.Primitive value) {
1753 assert(isOpen);
1754 ClosureLocation location = state.boxedVariables[local];
1755 if (location != null) {
1756 add(new ir.SetField(environment.lookup(location.box),
1757 location.field,
1758 value));
1759 } else {
1760 value.useElementAsHint(local);
1761 environment.update(local, value);
1762 }
1763 return value;
1764 }
1765
1766 void _migrateLoopVariables(ClosureScope scope) {
1767 if (scope.boxedLoopVariables.isEmpty) return;
1768 ir.Primitive box = environment.lookup(scope.box);
1769 ir.Primitive newBox = new ir.CreateBox();
1770 newBox.useElementAsHint(scope.box);
1771 add(new ir.LetPrim(newBox));
1772 for (VariableElement loopVar in scope.boxedLoopVariables) {
1773 ClosureLocation location = scope.capturedVariables[loopVar];
1774 ir.Primitive get = new ir.GetField(box, location.field);
1775 add(new ir.LetPrim(get));
1776 add(new ir.SetField(newBox, location.field, get));
1777 }
1778 environment.update(scope.box, newBox);
1779 }
1780
1781 }
1782
1783
1784 /// Location of a variable relative to a given closure.
1785 class ClosureLocation {
1786 /// If not `null`, this location is [box].[field].
1787 /// The location of [box] can be obtained separately from an
1788 /// enclosing [ClosureEnvironment] or [ClosureScope].
1789 /// If `null`, then the location is [field] on the enclosing function object.
1790 final BoxLocal box;
1791
1792 /// The field in which the variable is stored.
1793 final Entity field;
1794
1795 bool get isBox => box != null;
1796
1797 ClosureLocation(this.box, this.field);
1798 }
1799
1800 /// Introduces a new box and binds local variables to this box.
1801 ///
1802 /// A [ClosureScope] may exist for each function and for each loop.
1803 /// Generally, one may pass `null` to the [IrBuilder] instead of a
1804 /// [ClosureScope] when a given scope has no boxed variables.
1805 class ClosureScope {
1806 /// This box is now in scope and [capturedVariables] may use it.
1807 final BoxLocal box;
1808
1809 /// Maps [LocalElement]s to their location.
1810 final Map<Local, ClosureLocation> capturedVariables;
1811
1812 /// If this is the scope of a for-loop, [boxedLoopVariables] is the list
1813 /// of boxed variables that are declared in the initializer.
1814 final List<VariableElement> boxedLoopVariables;
1815
1816 ClosureScope(this.box, this.capturedVariables, this.boxedLoopVariables);
1817 }
1818
1819 /// Environment passed when building a nested function, describing how
1820 /// to access variables from the enclosing scope.
1821 class ClosureEnvironment {
1822 /// References to this local should be treated as recursive self-reference.
1823 /// (This is *not* in [freeVariables]).
1824 final LocalFunctionElement selfReference;
1825
1826 /// If non-null, [thisLocal] has an entry in [freeVariables] describing where
1827 /// to find the captured value of `this`.
1828 final ThisLocal thisLocal;
1829
1830 /// Maps [LocalElement]s, [BoxLocal]s and [ThisLocal] to their location.
1831 final Map<Local, ClosureLocation> freeVariables;
1832
1833 ClosureEnvironment(this.selfReference, this.thisLocal, this.freeVariables);
1834 }
1835
1836 /// Information about which variables are captured in a closure.
1837 /// This is used by the [DartIrBuilder] instead of [ClosureScope] and
1838 /// [ClosureEnvironment].
1839 abstract class ClosureVariableInfo {
1840 Iterable<Local> get capturedVariables;
1841 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698