OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } | |
OLD | NEW |