Chromium Code Reviews| 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 |