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