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