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