Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.ir_builder; | 5 library dart2js.ir_builder; |
| 6 | 6 |
| 7 import '../constants/expressions.dart'; | 7 import '../constants/expressions.dart'; |
| 8 import '../constants/values.dart' show PrimitiveConstantValue; | 8 import '../constants/values.dart' show PrimitiveConstantValue; |
| 9 import '../dart_types.dart'; | 9 import '../dart_types.dart'; |
| 10 import '../dart2jslib.dart'; | 10 import '../dart2jslib.dart'; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 37 index2value = <ir.Primitive>[]; | 37 index2value = <ir.Primitive>[]; |
| 38 | 38 |
| 39 /// Construct an environment that is a copy of another one. | 39 /// Construct an environment that is a copy of another one. |
| 40 /// | 40 /// |
| 41 /// The mapping from elements to indexes is shared, not copied. | 41 /// The mapping from elements to indexes is shared, not copied. |
| 42 Environment.from(Environment other) | 42 Environment.from(Environment other) |
| 43 : variable2index = other.variable2index, | 43 : variable2index = other.variable2index, |
| 44 index2variable = new List<Local>.from(other.index2variable), | 44 index2variable = new List<Local>.from(other.index2variable), |
| 45 index2value = new List<ir.Primitive>.from(other.index2value); | 45 index2value = new List<ir.Primitive>.from(other.index2value); |
| 46 | 46 |
| 47 /// Construct an environment that is shaped like another one but with a | |
| 48 /// fresh parameter for each variable. | |
| 49 /// | |
| 50 /// The mapping from elements to indexes is shared, not copied. | |
| 51 Environment.fresh(Environment other, List<ir.Parameter> parameters) | |
|
Kevin Millikin (Google)
2015/04/07 09:14:55
`parameters` is an output parameter here: the call
asgerf
2015/04/07 13:42:42
But it's a copy of index2value. Could you just cop
Kevin Millikin (Google)
2015/04/08 10:56:59
Yeah, I can do that. I was trying to make it enfo
| |
| 52 : variable2index = other.variable2index, | |
| 53 index2variable = new List<Local>.from(other.index2variable), | |
| 54 index2value = other.index2variable.map((Local local) { | |
| 55 return new ir.Parameter(local); | |
| 56 }).toList() { | |
| 57 assert(parameters.isEmpty); | |
| 58 index2value.forEach(parameters.add); | |
| 59 } | |
| 60 | |
| 47 get length => index2variable.length; | 61 get length => index2variable.length; |
| 48 | 62 |
| 49 ir.Primitive operator [](int index) => index2value[index]; | 63 ir.Primitive operator [](int index) => index2value[index]; |
| 50 | 64 |
| 51 void extend(Local element, ir.Primitive value) { | 65 void extend(Local element, ir.Primitive value) { |
| 52 // Assert that the name is not already in the environment. `null` is used | 66 // Assert that the name is not already in the environment. `null` is used |
| 53 // as the name of anonymous variables. Because the variable2index map is | 67 // as the name of anonymous variables. Because the variable2index map is |
| 54 // shared, `null` can already occur. This is safe because such variables | 68 // shared, `null` can already occur. This is safe because such variables |
| 55 // are not looked up by name. | 69 // are not looked up by name. |
| 56 // | 70 // |
| 57 // TODO(kmillikin): This is still kind of fishy. Refactor to not share | 71 // TODO(kmillikin): This is still kind of fishy. Refactor to not share |
| 58 // name maps or else garbage collect unneeded names. | 72 // name maps or else garbage collect unneeded names. |
| 59 assert(element == null || !variable2index.containsKey(element)); | 73 assert(element == null || !variable2index.containsKey(element)); |
| 60 variable2index[element] = index2variable.length; | 74 variable2index[element] = index2variable.length; |
| 61 index2variable.add(element); | 75 index2variable.add(element); |
| 62 index2value.add(value); | 76 index2value.add(value); |
| 63 } | 77 } |
| 64 | 78 |
| 79 void discard(int count) { | |
| 80 assert(count <= index2variable.length); | |
| 81 // The map from variables to their index are shared, so we cannot remove | |
| 82 // the mapping in `variable2index`. | |
| 83 index2variable.length -= count; | |
| 84 index2value.length -= count; | |
| 85 } | |
| 86 | |
| 65 ir.Primitive lookup(Local element) { | 87 ir.Primitive lookup(Local element) { |
| 66 assert(invariant(element, variable2index.containsKey(element), | 88 assert(invariant(element, variable2index.containsKey(element), |
| 67 message: "Unknown variable: $element.")); | 89 message: "Unknown variable: $element.")); |
| 68 return index2value[variable2index[element]]; | 90 return index2value[variable2index[element]]; |
| 69 } | 91 } |
| 70 | 92 |
| 71 void update(Local element, ir.Primitive value) { | 93 void update(Local element, ir.Primitive value) { |
| 72 index2value[variable2index[element]] = value; | 94 index2value[variable2index[element]] = value; |
| 73 } | 95 } |
| 74 | 96 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 85 // The variable maps to the same index in both environments. | 107 // The variable maps to the same index in both environments. |
| 86 int index = variable2index[variable]; | 108 int index = variable2index[variable]; |
| 87 if (index == null || index != other.variable2index[variable]) { | 109 if (index == null || index != other.variable2index[variable]) { |
| 88 return false; | 110 return false; |
| 89 } | 111 } |
| 90 } | 112 } |
| 91 return true; | 113 return true; |
| 92 } | 114 } |
| 93 } | 115 } |
| 94 | 116 |
| 95 /// A class to collect breaks or continues. | 117 /// The abstract base class of objects that emit jumps to a continuation and |
| 96 /// | 118 /// give a handle to the continuation and its environment. |
| 97 /// When visiting a potential target of breaks or continues, any breaks or | 119 abstract class JumpCollector { |
| 98 /// continues are collected by a JumpCollector and processed later, on demand. | |
| 99 /// The site of the break or continue is represented by a continuation | |
| 100 /// invocation that will have its target and arguments filled in later. | |
| 101 /// | |
| 102 /// The environment of the builder at that point is captured and should not | |
| 103 /// be subsequently mutated until the jump is resolved. | |
| 104 class JumpCollector { | |
| 105 final JumpTarget target; | 120 final JumpTarget target; |
| 106 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; | 121 |
| 107 final List<Environment> _environments = <Environment>[]; | 122 ir.Continuation _continuation = null; |
| 108 final List<Iterable<LocalVariableElement>> boxedTryVariables = | 123 final Environment _environment; |
| 124 | |
| 125 final List<Iterable<LocalVariableElement>> _boxedTryVariables = | |
| 109 <Iterable<LocalVariableElement>>[]; | 126 <Iterable<LocalVariableElement>>[]; |
| 110 | 127 |
| 111 JumpCollector(this.target); | 128 JumpCollector(this._environment, this.target); |
| 112 | 129 |
| 113 bool get isEmpty => _invocations.isEmpty; | 130 /// True if the collector has recorded any jumps to its continuation. |
|
asgerf
2015/04/07 13:42:42
has *not* recorded
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 114 int get length => _invocations.length; | 131 bool get isEmpty; |
| 115 List<ir.InvokeContinuation> get invocations => _invocations; | |
| 116 List<Environment> get environments => _environments; | |
| 117 | 132 |
| 118 void addJump(IrBuilder builder) { | 133 /// The continuation encapsulated by this collector. |
| 119 // Unbox all variables that were boxed on entry to try blocks between the | 134 ir.Continuation get continuation; |
| 120 // jump and the target. | 135 |
| 121 for (Iterable<LocalVariableElement> boxedOnEntry in boxedTryVariables) { | 136 /// The compile-time environment to be used for translating code in the body |
| 137 /// of the continuation. | |
| 138 Environment get environment; | |
| 139 | |
| 140 /// Emit a jump to the continuation for a given [IrBuilder]. | |
| 141 void addJump(IrBuilder builder); | |
| 142 | |
| 143 /// Add a set of variables that were boxed on entry to a try block. | |
| 144 /// | |
| 145 /// Jumps from a try block to targets outside have to unbox the variables | |
| 146 /// that were boxed on entry before invoking the target continuation. Call | |
| 147 /// this function before translating a try block and call [leaveTry] after | |
| 148 /// translating it. | |
|
asgerf
2015/04/07 13:42:41
Could you start the comment with "All jumps" inste
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 149 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { | |
| 150 // The boxed variables are maintained as a stack to make leaving easy. | |
| 151 _boxedTryVariables.add(boxedOnEntry); | |
| 152 } | |
| 153 | |
| 154 /// Remove the most recently added set of variables boxed on entry to a try | |
| 155 /// block. | |
| 156 /// | |
| 157 /// Call [enterTry] before translating a try block and call this function | |
| 158 /// after translating it. | |
| 159 void leaveTry() { | |
| 160 _boxedTryVariables.removeLast(); | |
| 161 } | |
| 162 | |
| 163 void _buildTryExit(IrBuilder builder) { | |
| 164 for (Iterable<LocalVariableElement> boxedOnEntry in _boxedTryVariables) { | |
| 122 for (LocalVariableElement variable in boxedOnEntry) { | 165 for (LocalVariableElement variable in boxedOnEntry) { |
| 123 assert(builder.isInMutableVariable(variable)); | 166 assert(builder.isInMutableVariable(variable)); |
| 124 ir.Primitive value = builder.buildLocalGet(variable); | 167 ir.Primitive value = builder.buildLocalGet(variable); |
| 125 builder.environment.update(variable, value); | 168 builder.environment.update(variable, value); |
| 126 } | 169 } |
| 127 } | 170 } |
| 171 } | |
| 172 } | |
| 173 | |
| 174 /// A class to collect 'forward' jumps. | |
| 175 /// | |
| 176 /// A forward jump to a continuation in the sense of the CPS translation is | |
| 177 /// a jump where the jump is emitted before any code in the body of the | |
| 178 /// continuation is translated. They have the property that continuation | |
| 179 /// parameters and the environment for the translation of the body can be | |
| 180 /// determined based on the invocations, before translating the body. A | |
| 181 /// [ForwardJumpCollector] can encapsulate a continuation where all the | |
| 182 /// jumps are forward ones. | |
| 183 /// | |
| 184 /// Examples of forward jumps in the translation are join points of | |
| 185 /// if-then-else and breaks from loops. | |
| 186 /// | |
| 187 /// The implementation strategy is that the collector collects invocation | |
| 188 /// sites and the environments at those sites. Then it constructs a | |
| 189 /// continuation 'on demand' after all the jumps are seen. It determines | |
| 190 /// continuation parameters, the environment for the translation of code in | |
| 191 /// the continuation body, and the arguments at the invocation site only | |
| 192 /// after all the jumps to the continuation are seen. | |
| 193 class ForwardJumpCollector extends JumpCollector { | |
| 194 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; | |
| 195 final List<Environment> _environments = <Environment>[]; | |
|
asgerf
2015/04/07 13:42:42
Could we rename this to _invocationEnvironments?
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 196 | |
| 197 /// Construct a collector with a given base environment. | |
| 198 /// | |
| 199 /// The base environment is the one in scope at the site that the | |
| 200 /// continuation represented by this collector will be bound. The | |
| 201 /// environment is copied by the collector. Subsequent mutation of the | |
| 202 /// original environment will not effect the collector. | |
|
asgerf
2015/04/07 13:42:41
affect
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 203 ForwardJumpCollector(Environment environment, {JumpTarget target: null}) | |
| 204 : super(new Environment.from(environment), target); | |
| 205 | |
| 206 bool get isEmpty => _invocations.isEmpty; | |
| 207 | |
| 208 ir.Continuation get continuation { | |
| 209 if (_continuation == null) _setContinuation(); | |
| 210 return _continuation; | |
| 211 } | |
| 212 | |
| 213 Environment get environment { | |
| 214 if (_continuation == null) _setContinuation(); | |
| 215 return _environment; | |
| 216 } | |
| 217 | |
| 218 void addJump(IrBuilder builder) { | |
| 219 assert(_continuation == null); | |
| 220 _buildTryExit(builder); | |
| 128 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); | 221 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); |
| 129 builder.add(invoke); | 222 builder.add(invoke); |
| 130 _invocations.add(invoke); | 223 _invocations.add(invoke); |
| 131 _environments.add(builder.environment); | 224 _environments.add(builder.environment); |
| 132 builder._current = null; | 225 builder._current = null; |
| 133 // TODO(kmillikin): Can we set builder.environment to null to make it | 226 // TODO(kmillikin): Can we set builder.environment to null to make it |
| 134 // less likely to mutate it? | 227 // less likely to mutate it? |
| 135 } | 228 } |
| 136 | 229 |
| 137 /// Add a set of variables that were boxed on entry to a try block. | 230 void _setContinuation() { |
| 138 /// | 231 assert(_continuation == null); |
| 139 /// Jumps from a try block to targets outside have to unbox the variables | 232 // We have seen all invocations of this continuation, and recorded the |
| 140 /// that were boxed on entry before invoking the target continuation. Call | 233 // environment in effect at each invocation site. |
| 141 /// this function before translating a try block and call [leaveTry] after | |
| 142 /// translating it. | |
| 143 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { | |
| 144 // The boxed variables are maintained as a stack to make leaving easy. | |
| 145 boxedTryVariables.add(boxedOnEntry); | |
| 146 } | |
| 147 | 234 |
| 148 /// Remove the most recently added set of variables boxed on entry to a try | 235 // Compute the union of the assigned variables reaching the continuation. |
| 149 /// block. | 236 // |
| 150 /// | 237 // There is a continuation parameter for each environment variable |
| 151 /// Call [enterTry] before translating a try block and call this function | 238 // that has a different value (from the environment in scope at the |
| 152 /// after translating it. | 239 // continuation binding) on some path. `_environment` is initially a copy |
| 153 void leaveTry() { | 240 // of the environment in scope at the continuation binding. Compute the |
| 154 boxedTryVariables.removeLast(); | 241 // continuation parameters and add them to `_environment` so it will become |
| 242 // the one in scope for the continuation body. | |
|
asgerf
2015/04/07 13:42:41
'_environment' and 'env' (below) are bad names whe
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 243 List<ir.Parameter> parameters = <ir.Parameter>[]; | |
| 244 if (_environments.isNotEmpty) { | |
| 245 for (int varIndex = 0; varIndex < _environment.length; ++varIndex) { | |
| 246 for (Environment env in _environments) { | |
| 247 if (env[varIndex] != _environment[varIndex]) { | |
| 248 ir.Parameter parameter = | |
| 249 new ir.Parameter(_environment.index2variable[varIndex]); | |
| 250 _environment.index2value[varIndex] = parameter; | |
| 251 parameters.add(parameter); | |
| 252 break; | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 _continuation = new ir.Continuation(parameters); | |
| 258 | |
| 259 // Compute the intersection of the parameters with the environments at | |
| 260 // each continuation invocation. Initialize the invocations. | |
| 261 for (int jumpIndex = 0; jumpIndex < _invocations.length; ++jumpIndex) { | |
| 262 Environment currentEnvironment = _environments[jumpIndex]; | |
|
asgerf
2015/04/07 13:42:42
Again, something like 'jumpEnvironment' would be b
| |
| 263 List<ir.Reference> arguments = <ir.Reference>[]; | |
| 264 if (parameters.isNotEmpty) { | |
|
asgerf
2015/04/07 13:42:42
I think we should make 'parameters' the outer loop
Kevin Millikin (Google)
2015/04/08 10:56:59
Done. It is probably better, though not simpler,
| |
| 265 arguments.length = parameters.length; | |
| 266 int argIndex = 0; | |
| 267 for (int varIndex = 0; varIndex < _environment.length; ++varIndex) { | |
| 268 if (_environment[varIndex] == parameters[argIndex]) { | |
| 269 arguments[argIndex++] = | |
| 270 new ir.Reference(currentEnvironment[varIndex]); | |
| 271 if (argIndex == parameters.length) break; | |
| 272 } | |
| 273 } | |
| 274 } | |
| 275 ir.InvokeContinuation invocation = _invocations[jumpIndex]; | |
| 276 invocation.continuation = new ir.Reference(_continuation); | |
| 277 invocation.arguments = arguments; | |
| 278 } | |
| 155 } | 279 } |
| 156 } | 280 } |
| 157 | 281 |
| 282 /// A class to collect 'backward' jumps. | |
| 283 /// | |
| 284 /// A backward jump to a continuation in the sense of the CPS translation is | |
| 285 /// a jump where some code in the body of the continuation is translated | |
| 286 /// before the jump is emitted. They have the property that the | |
| 287 /// continuation parameters and the environment for the translation of the | |
| 288 /// body must be determined before emitting all the invocations. A | |
| 289 /// [BackwardJumpCollector] can ecapsulate a continuation where some jumps | |
| 290 /// are backward ones. | |
| 291 /// | |
| 292 /// Examples of backward jumps in the translation are the recursive | |
| 293 /// invocations of loop continuations. | |
| 294 /// | |
| 295 /// The implementation strategy is that the collector inserts a continuation | |
| 296 /// parameter for each variable in scope at the entry to the continuation, | |
| 297 /// before emitting any jump to the continuation. When a jump is added, it | |
| 298 /// is given an argument for each continuation parameter. | |
| 299 class BackwardJumpCollector extends JumpCollector { | |
| 300 List<ir.Parameter> _parameters; | |
| 301 | |
| 302 /// Construct a collector with a given base environment. | |
| 303 /// | |
| 304 /// The base environment is the one in scope at the site that the | |
| 305 /// continuation represented by this collector will be bound. The | |
| 306 /// translation of the continuation body will use an environment with the | |
| 307 /// same shape, but with fresh continuation parameters for each variable. | |
| 308 factory BackwardJumpCollector(Environment environment, | |
| 309 {JumpTarget target: null}) { | |
| 310 List<ir.Parameter> parameters = <ir.Parameter>[]; | |
| 311 Environment fresh = new Environment.fresh(environment, parameters); | |
| 312 return new BackwardJumpCollector._internal(fresh, parameters, target); | |
| 313 } | |
| 314 | |
| 315 BackwardJumpCollector._internal(Environment environment, | |
| 316 this._parameters, | |
| 317 JumpTarget target) | |
| 318 : super(environment, target) { | |
| 319 _continuation = new ir.Continuation(_parameters, isRecursive: true); | |
| 320 } | |
| 321 | |
| 322 bool isEmpty = true; | |
| 323 | |
| 324 ir.Continuation get continuation => _continuation; | |
| 325 Environment get environment => _environment; | |
| 326 | |
| 327 void addJump(IrBuilder builder) { | |
| 328 assert(_parameters.length <= builder.environment.length); | |
| 329 isEmpty = false; | |
| 330 _buildTryExit(builder); | |
| 331 builder.add(new ir.InvokeContinuation(_continuation, | |
| 332 builder.environment.index2value.take(_parameters.length).toList(), | |
| 333 isRecursive: true)); | |
| 334 builder._current = null; | |
| 335 } | |
| 336 } | |
| 337 | |
| 158 /// Function for building a node in the context of the current builder. | 338 /// Function for building a node in the context of the current builder. |
| 159 typedef ir.Node BuildFunction(node); | 339 typedef ir.Node BuildFunction(node); |
| 160 | 340 |
| 161 /// Function for building nodes in the context of the provided [builder]. | 341 /// Function for building nodes in the context of the provided [builder]. |
| 162 typedef ir.Node SubbuildFunction(IrBuilder builder); | 342 typedef ir.Node SubbuildFunction(IrBuilder builder); |
| 163 | 343 |
| 164 /// Mixin that provides encapsulated access to nested builders. | 344 /// Mixin that provides encapsulated access to nested builders. |
| 165 abstract class IrBuilderMixin<N> { | 345 abstract class IrBuilderMixin<N> { |
| 166 IrBuilder _irBuilder; | 346 IrBuilder _irBuilder; |
| 167 | 347 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 ir.Expression _current = null; | 539 ir.Expression _current = null; |
| 360 | 540 |
| 361 /// Initialize a new top-level IR builder. | 541 /// Initialize a new top-level IR builder. |
| 362 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { | 542 void _init(ConstantSystem constantSystem, ExecutableElement currentElement) { |
| 363 state = new IrBuilderDelimitedState(constantSystem, currentElement); | 543 state = new IrBuilderDelimitedState(constantSystem, currentElement); |
| 364 environment = new Environment.empty(); | 544 environment = new Environment.empty(); |
| 365 } | 545 } |
| 366 | 546 |
| 367 /// Construct a delimited visitor for visiting a subtree. | 547 /// Construct a delimited visitor for visiting a subtree. |
| 368 /// | 548 /// |
| 369 /// The delimited visitor has its own compile-time environment mapping | 549 /// Build a subterm that is not (yet) connected to the CPS term. The |
| 370 /// local variables to their values, which is initially a copy of the parent | 550 /// delimited visitor has its own has its own context for building an IR |
| 371 /// environment. It has its own context for building an IR expression, so | 551 /// expression, so the built expression is not plugged into the parent's |
| 372 /// the built expression is not plugged into the parent's context. | 552 /// context. It has its own compile-time environment mapping local |
| 373 IrBuilder makeDelimitedBuilder() { | 553 /// variables to their values. If an optional environment argument is |
| 554 /// supplied, it is used as the builder's initial environment. Otherwise | |
| 555 /// the environment is initially a copy of the parent builder's environment. | |
| 556 IrBuilder makeDelimitedBuilder([Environment env = null]) { | |
| 374 return _makeInstance() | 557 return _makeInstance() |
| 375 ..state = state | 558 ..state = state |
| 376 ..environment = new Environment.from(environment); | 559 ..environment = env != null ? env : new Environment.from(environment); |
| 377 } | 560 } |
| 378 | 561 |
| 379 /// Construct a builder for making constructor field initializers. | 562 /// Construct a builder for making constructor field initializers. |
| 380 IrBuilder makeInitializerBuilder() { | 563 IrBuilder makeInitializerBuilder() { |
| 381 return _makeInstance() | 564 return _makeInstance() |
| 382 ..state = new IrBuilderDelimitedState(state.constantSystem, | 565 ..state = new IrBuilderDelimitedState(state.constantSystem, |
| 383 state.currentElement) | 566 state.currentElement) |
| 384 ..environment = new Environment.from(environment); | 567 ..environment = new Environment.from(environment); |
| 385 } | 568 } |
| 386 | 569 |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 return addPrimitive(new ir.LiteralMap(type, entries)); | 756 return addPrimitive(new ir.LiteralMap(type, entries)); |
| 574 } | 757 } |
| 575 | 758 |
| 576 /// Creates a conditional expression with the provided [condition] where the | 759 /// Creates a conditional expression with the provided [condition] where the |
| 577 /// then and else expression are created through the [buildThenExpression] and | 760 /// then and else expression are created through the [buildThenExpression] and |
| 578 /// [buildElseExpression] functions, respectively. | 761 /// [buildElseExpression] functions, respectively. |
| 579 ir.Primitive buildConditional( | 762 ir.Primitive buildConditional( |
| 580 ir.Primitive condition, | 763 ir.Primitive condition, |
| 581 ir.Primitive buildThenExpression(IrBuilder builder), | 764 ir.Primitive buildThenExpression(IrBuilder builder), |
| 582 ir.Primitive buildElseExpression(IrBuilder builder)) { | 765 ir.Primitive buildElseExpression(IrBuilder builder)) { |
| 583 | |
| 584 assert(isOpen); | 766 assert(isOpen); |
| 585 | 767 |
| 586 // The then and else expressions are delimited. | 768 // The then and else expressions are delimited. |
| 587 IrBuilder thenBuilder = makeDelimitedBuilder(); | 769 IrBuilder thenBuilder = makeDelimitedBuilder(); |
| 588 IrBuilder elseBuilder = makeDelimitedBuilder(); | 770 IrBuilder elseBuilder = makeDelimitedBuilder(); |
| 589 ir.Primitive thenValue = buildThenExpression(thenBuilder); | 771 ir.Primitive thenValue = buildThenExpression(thenBuilder); |
| 590 ir.Primitive elseValue = buildElseExpression(elseBuilder); | 772 ir.Primitive elseValue = buildElseExpression(elseBuilder); |
| 591 | 773 |
| 592 // Treat the values of the subexpressions as named values in the | 774 // Treat the values of the subexpressions as named values in the |
| 593 // environment, so they will be treated as arguments to the join-point | 775 // environment, so they will be treated as arguments to the join-point |
| 594 // continuation. | 776 // continuation. We know the environments are the right size because |
| 777 // expressions cannot introduce variable bindings. | |
| 595 assert(environment.length == thenBuilder.environment.length); | 778 assert(environment.length == thenBuilder.environment.length); |
| 596 assert(environment.length == elseBuilder.environment.length); | 779 assert(environment.length == elseBuilder.environment.length); |
| 780 // Optimistically assume that the value in the incoming environment is the | |
| 781 // value of the first subexpression, which might not even be in scope | |
| 782 // because it's bound in the first subexpression. However, if that is the | |
| 783 // case, it will necessarily differ from the value of the other | |
| 784 // subexpression and cause the introduction of a join-point continuation | |
| 785 // parameter. If the two values do happen to be the same, this will | |
| 786 // avoid inserting a useless continuation parameter. | |
|
asgerf
2015/04/07 13:42:42
I really like using the environment like this. Bef
Kevin Millikin (Google)
2015/04/08 10:56:59
I've mentioned that first, though I thought the co
asgerf
2015/04/08 11:10:21
You are right, I overlooked the comment before the
| |
| 787 environment.extend(null, thenValue); | |
| 597 thenBuilder.environment.extend(null, thenValue); | 788 thenBuilder.environment.extend(null, thenValue); |
| 598 elseBuilder.environment.extend(null, elseValue); | 789 elseBuilder.environment.extend(null, elseValue); |
| 599 JumpCollector jumps = new JumpCollector(null); | 790 JumpCollector join = new ForwardJumpCollector(environment); |
| 600 jumps.addJump(thenBuilder); | 791 thenBuilder.jumpTo(join); |
| 601 jumps.addJump(elseBuilder); | 792 elseBuilder.jumpTo(join); |
| 602 ir.Continuation joinContinuation = | |
| 603 createJoin(environment.length + 1, jumps); | |
| 604 | 793 |
| 605 // Build the term | 794 // Build the term |
| 606 // let cont join(x, ..., result) = [] in | 795 // let cont join(x, ..., result) = [] in |
| 607 // let cont then() = [[thenPart]]; join(v, ...) | 796 // let cont then() = [[thenPart]]; join(v, ...) |
| 608 // and else() = [[elsePart]]; join(v, ...) | 797 // and else() = [[elsePart]]; join(v, ...) |
| 609 // in | 798 // in |
| 610 // if condition (then, else) | 799 // if condition (then, else) |
| 611 ir.Continuation thenContinuation = new ir.Continuation([]); | 800 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 612 ir.Continuation elseContinuation = new ir.Continuation([]); | 801 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 613 thenContinuation.body = thenBuilder._root; | 802 thenContinuation.body = thenBuilder._root; |
| 614 elseContinuation.body = elseBuilder._root; | 803 elseContinuation.body = elseBuilder._root; |
| 615 add(new ir.LetCont(joinContinuation, | 804 add(new ir.LetCont(join.continuation, |
| 616 new ir.LetCont.many(<ir.Continuation>[thenContinuation, | 805 new ir.LetCont.many(<ir.Continuation>[thenContinuation, |
| 617 elseContinuation], | 806 elseContinuation], |
| 618 new ir.Branch(new ir.IsTrue(condition), | 807 new ir.Branch(new ir.IsTrue(condition), |
| 619 thenContinuation, | 808 thenContinuation, |
| 620 elseContinuation)))); | 809 elseContinuation)))); |
| 810 environment = join.environment; | |
| 811 environment.discard(1); | |
| 621 return (thenValue == elseValue) | 812 return (thenValue == elseValue) |
| 622 ? thenValue | 813 ? thenValue |
| 623 : joinContinuation.parameters.last; | 814 : join.continuation.parameters.last; |
| 624 } | 815 } |
| 625 | 816 |
| 626 /** | 817 /** |
| 627 * Add an explicit `return null` for functions that don't have a return | 818 * Add an explicit `return null` for functions that don't have a return |
| 628 * statement on each branch. This includes functions with an empty body, | 819 * statement on each branch. This includes functions with an empty body, |
| 629 * such as `foo(){ }`. | 820 * such as `foo(){ }`. |
| 630 */ | 821 */ |
| 631 void _ensureReturn() { | 822 void _ensureReturn() { |
| 632 if (!isOpen) return; | 823 if (!isOpen) return; |
| 633 ir.Constant constant = buildNullLiteral(); | 824 ir.Constant constant = buildNullLiteral(); |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 880 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen | 1071 List<ir.Continuation> arms = !thenBuilder.isOpen && elseBuilder.isOpen |
| 881 ? <ir.Continuation>[elseContinuation, thenContinuation] | 1072 ? <ir.Continuation>[elseContinuation, thenContinuation] |
| 882 : <ir.Continuation>[thenContinuation, elseContinuation]; | 1073 : <ir.Continuation>[thenContinuation, elseContinuation]; |
| 883 | 1074 |
| 884 ir.Expression result = | 1075 ir.Expression result = |
| 885 new ir.LetCont.many(arms, | 1076 new ir.LetCont.many(arms, |
| 886 new ir.Branch(new ir.IsTrue(condition), | 1077 new ir.Branch(new ir.IsTrue(condition), |
| 887 thenContinuation, | 1078 thenContinuation, |
| 888 elseContinuation)); | 1079 elseContinuation)); |
| 889 | 1080 |
| 890 ir.Continuation joinContinuation; // Null if there is no join. | 1081 JumpCollector join; // Null if there is no join. |
| 891 if (thenBuilder.isOpen && elseBuilder.isOpen) { | 1082 if (thenBuilder.isOpen && elseBuilder.isOpen) { |
| 892 // There is a join-point continuation. Build the term | 1083 // There is a join-point continuation. Build the term |
| 893 // 'let cont join(x, ...) = [] in Result' and plug invocations of the | 1084 // 'let cont join(x, ...) = [] in Result' and plug invocations of the |
| 894 // join-point continuation into the then and else continuations. | 1085 // join-point continuation into the then and else continuations. |
| 895 JumpCollector jumps = new JumpCollector(null); | 1086 join = new ForwardJumpCollector(environment); |
| 896 jumps.addJump(thenBuilder); | 1087 thenBuilder.jumpTo(join); |
| 897 jumps.addJump(elseBuilder); | 1088 elseBuilder.jumpTo(join); |
| 898 joinContinuation = createJoin(environment.length, jumps); | 1089 result = new ir.LetCont(join.continuation, result); |
| 899 result = new ir.LetCont(joinContinuation, result); | |
| 900 } | 1090 } |
| 901 | 1091 |
| 902 // The then or else term root could be null, but not both. If there is | 1092 // The then or else term root could be null, but not both. If there is |
| 903 // a join then an InvokeContinuation was just added to both of them. If | 1093 // a join then an InvokeContinuation was just added to both of them. If |
| 904 // there is no join, then at least one of them is closed and thus has a | 1094 // there is no join, then at least one of them is closed and thus has a |
| 905 // non-null root by the definition of the predicate isClosed. In the | 1095 // non-null root by the definition of the predicate isClosed. In the |
| 906 // case that one of them is null, it must be the only one that is open | 1096 // case that one of them is null, it must be the only one that is open |
| 907 // and thus contains the new hole in the context. This case is handled | 1097 // and thus contains the new hole in the context. This case is handled |
| 908 // after the branch is plugged into the current hole. | 1098 // after the branch is plugged into the current hole. |
| 909 thenContinuation.body = thenBuilder._root; | 1099 thenContinuation.body = thenBuilder._root; |
| 910 elseContinuation.body = elseBuilder._root; | 1100 elseContinuation.body = elseBuilder._root; |
| 911 | 1101 |
| 912 add(result); | 1102 add(result); |
| 913 if (joinContinuation == null) { | 1103 if (join == null) { |
| 914 // At least one subexpression is closed. | 1104 // At least one subexpression is closed. |
| 915 if (thenBuilder.isOpen) { | 1105 if (thenBuilder.isOpen) { |
| 916 if (thenBuilder._root != null) _current = thenBuilder._current; | 1106 if (thenBuilder._root != null) _current = thenBuilder._current; |
| 917 environment = thenBuilder.environment; | 1107 environment = thenBuilder.environment; |
| 918 } else if (elseBuilder.isOpen) { | 1108 } else if (elseBuilder.isOpen) { |
| 919 if (elseBuilder._root != null) _current = elseBuilder._current; | 1109 if (elseBuilder._root != null) _current = elseBuilder._current; |
| 920 environment = elseBuilder.environment; | 1110 environment = elseBuilder.environment; |
| 921 } else { | 1111 } else { |
| 922 _current = null; | 1112 _current = null; |
| 923 } | 1113 } |
| 1114 } else { | |
| 1115 environment = join.environment; | |
| 924 } | 1116 } |
| 925 } | 1117 } |
| 926 | 1118 |
| 927 void jumpTo(ir.Continuation continuation) { | 1119 void jumpTo(JumpCollector collector) { |
| 928 assert(isOpen); | 1120 collector.addJump(this); |
| 929 assert(environment.length >= continuation.parameters.length); | |
| 930 ir.InvokeContinuation jump = new ir.InvokeContinuation.uninitialized(); | |
| 931 jump.continuation = new ir.Reference(continuation); | |
| 932 jump.arguments = new List<ir.Reference>.generate( | |
| 933 continuation.parameters.length, (i) { | |
| 934 return new ir.Reference(environment[i]); | |
| 935 }); | |
| 936 add(jump); | |
| 937 _current = null; | |
| 938 } | 1121 } |
| 939 | 1122 |
| 940 /// Invoke a join-point continuation that contains arguments for all local | 1123 void addRecursiveContinuation(BackwardJumpCollector collector) { |
| 941 /// variables. | 1124 assert(environment.length == collector.environment.length); |
| 942 /// | 1125 add(new ir.LetCont(collector.continuation, |
| 943 /// Given the continuation and a list of uninitialized invocations, fill | 1126 new ir.InvokeContinuation(collector.continuation, |
| 944 /// in each invocation with the continuation and appropriate arguments. | 1127 environment.index2value))); |
| 945 void invokeFullJoin(ir.Continuation join, | 1128 environment = collector.environment; |
| 946 JumpCollector jumps, | |
| 947 {recursive: false}) { | |
| 948 // TODO(kmillikin): If the JumpCollector collected open IrBuilders instead | |
| 949 // of pairs of invocations and environments, we could use IrBuilder.jumpTo | |
| 950 // here --- the code is almost the same. | |
| 951 join.isRecursive = recursive; | |
| 952 for (int i = 0; i < jumps.length; ++i) { | |
| 953 Environment currentEnvironment = jumps.environments[i]; | |
| 954 ir.InvokeContinuation invoke = jumps.invocations[i]; | |
| 955 invoke.continuation = new ir.Reference(join); | |
| 956 invoke.arguments = new List<ir.Reference>.generate( | |
| 957 join.parameters.length, | |
| 958 (i) => new ir.Reference(currentEnvironment[i])); | |
| 959 invoke.isRecursive = recursive; | |
| 960 } | |
| 961 } | 1129 } |
| 962 | 1130 |
| 963 /// Creates a for loop in which the initializer, condition, body, update are | 1131 /// Creates a for loop in which the initializer, condition, body, update are |
| 964 /// created by [buildInitializer], [buildCondition], [buildBody] and | 1132 /// created by [buildInitializer], [buildCondition], [buildBody] and |
| 965 /// [buildUpdate], respectively. | 1133 /// [buildUpdate], respectively. |
| 966 /// | 1134 /// |
| 967 /// The jump [target] is used to identify which `break` and `continue` | 1135 /// The jump [target] is used to identify which `break` and `continue` |
| 968 /// statements that have this `for` statement as their target. | 1136 /// statements that have this `for` statement as their target. |
| 969 /// | 1137 /// |
| 970 /// The [closureScope] identifies variables that should be boxed in this loop. | 1138 /// The [closureScope] identifies variables that should be boxed in this loop. |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 984 | 1152 |
| 985 // For loops use four named continuations: the entry to the condition, | 1153 // For loops use four named continuations: the entry to the condition, |
| 986 // the entry to the body, the loop exit, and the loop successor (break). | 1154 // the entry to the body, the loop exit, and the loop successor (break). |
| 987 // The CPS translation of | 1155 // The CPS translation of |
| 988 // [[for (initializer; condition; update) body; successor]] is: | 1156 // [[for (initializer; condition; update) body; successor]] is: |
| 989 // | 1157 // |
| 990 // _enterForLoopInitializer(); | 1158 // _enterForLoopInitializer(); |
| 991 // [[initializer]]; | 1159 // [[initializer]]; |
| 992 // let cont loop(x, ...) = | 1160 // let cont loop(x, ...) = |
| 993 // let prim cond = [[condition]] in | 1161 // let prim cond = [[condition]] in |
| 994 // let cont break() = [[successor]] in | 1162 // let cont break(x, ...) = [[successor]] in |
| 995 // let cont exit() = break(v, ...) in | 1163 // let cont exit() = break(v, ...) in |
| 996 // let cont body() = | 1164 // let cont body() = |
| 997 // _enterForLoopBody(); | 1165 // _enterForLoopBody(); |
| 998 // let cont continue(x, ...) = | 1166 // let cont continue(x, ...) = |
| 999 // _enterForLoopUpdate(); | 1167 // _enterForLoopUpdate(); |
| 1000 // [[update]]; | 1168 // [[update]]; |
| 1001 // loop(v, ...) in | 1169 // loop(v, ...) in |
| 1002 // [[body]]; | 1170 // [[body]]; |
| 1003 // continue(v, ...) in | 1171 // continue(v, ...) in |
| 1004 // branch cond (body, exit) in | 1172 // branch cond (body, exit) in |
| 1005 // loop(v, ...) | 1173 // loop(v, ...) |
| 1006 // | 1174 // |
| 1007 // If there are no breaks in the body, the break continuation is inlined | 1175 // If there are no breaks in the body, the break continuation is inlined |
| 1008 // in the exit continuation (i.e., the translation of the successor | 1176 // in the exit continuation (i.e., the translation of the successor |
| 1009 // statement occurs in the exit continuation). If there is only one | 1177 // statement occurs in the exit continuation). If there is only one |
| 1010 // invocation of the continue continuation (i.e., no continues in the | 1178 // invocation of the continue continuation (i.e., no continues in the |
| 1011 // body), the continue continuation is inlined in the body. | 1179 // body), the continue continuation is inlined in the body. |
| 1012 | |
| 1013 _enterForLoopInitializer(closureScope, loopVariables); | 1180 _enterForLoopInitializer(closureScope, loopVariables); |
| 1014 | |
| 1015 buildInitializer(this); | 1181 buildInitializer(this); |
| 1016 | 1182 |
| 1017 IrBuilder condBuilder = makeRecursiveBuilder(); | 1183 JumpCollector loop = new BackwardJumpCollector(environment); |
| 1018 ir.Primitive condition = buildCondition(condBuilder); | 1184 addRecursiveContinuation(loop); |
| 1185 | |
| 1186 ir.Primitive condition = buildCondition(this); | |
| 1019 if (condition == null) { | 1187 if (condition == null) { |
| 1020 // If the condition is empty then the body is entered unconditionally. | 1188 // If the condition is empty then the body is entered unconditionally. |
| 1021 condition = condBuilder.buildBooleanLiteral(true); | 1189 condition = buildBooleanLiteral(true); |
| 1022 } | 1190 } |
| 1191 JumpCollector breakCollector = | |
| 1192 new ForwardJumpCollector(environment, target: target); | |
| 1023 | 1193 |
| 1024 JumpCollector breakCollector = new JumpCollector(target); | 1194 // Use a pair of builders for the body, one for the entry code if any |
| 1025 JumpCollector continueCollector = new JumpCollector(target); | 1195 // and one for the body itself. We only decide whether to insert a |
| 1196 // continue continuation until after translating the body and there is no | |
| 1197 // way to insert such a continuation between the entry code and the body | |
| 1198 // if they are translated together. | |
| 1199 IrBuilder outerBodyBuilder = makeDelimitedBuilder(); | |
| 1200 outerBodyBuilder._enterForLoopBody(closureScope, loopVariables); | |
| 1201 JumpCollector continueCollector = | |
| 1202 new ForwardJumpCollector(outerBodyBuilder.environment, target: target); | |
| 1203 | |
| 1204 IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder(); | |
| 1026 state.breakCollectors.add(breakCollector); | 1205 state.breakCollectors.add(breakCollector); |
| 1027 state.continueCollectors.add(continueCollector); | 1206 state.continueCollectors.add(continueCollector); |
| 1028 | |
| 1029 IrBuilder outerBodyBuilder = condBuilder.makeDelimitedBuilder(); | |
| 1030 outerBodyBuilder._enterForLoopBody(closureScope, loopVariables); | |
| 1031 | |
| 1032 IrBuilder innerBodyBuilder = outerBodyBuilder.makeDelimitedBuilder(); | |
| 1033 | |
| 1034 buildBody(innerBodyBuilder); | 1207 buildBody(innerBodyBuilder); |
| 1035 assert(state.breakCollectors.last == breakCollector); | 1208 assert(state.breakCollectors.last == breakCollector); |
| 1036 assert(state.continueCollectors.last == continueCollector); | 1209 assert(state.continueCollectors.last == continueCollector); |
| 1037 state.breakCollectors.removeLast(); | 1210 state.breakCollectors.removeLast(); |
| 1038 state.continueCollectors.removeLast(); | 1211 state.continueCollectors.removeLast(); |
| 1039 | 1212 |
| 1040 // The binding of the continue continuation should occur as late as | 1213 // The binding of the continue continuation should occur as late as |
| 1041 // possible, that is, at the nearest common ancestor of all the continue | 1214 // possible, that is, at the nearest common ancestor of all the continue |
| 1042 // sites in the body. However, that is difficult to compute here, so it | 1215 // sites in the body. However, that is difficult to compute here, so it |
| 1043 // is instead placed just outside the body of the body continuation. | 1216 // is instead placed just outside the translation of the loop body. In |
| 1217 // the case where there are no continues in the body, the updates are | |
| 1218 // translated immediately after the body. | |
| 1044 bool hasContinues = !continueCollector.isEmpty; | 1219 bool hasContinues = !continueCollector.isEmpty; |
| 1045 IrBuilder updateBuilder = hasContinues | 1220 IrBuilder updateBuilder; |
| 1046 ? outerBodyBuilder.makeRecursiveBuilder() | 1221 if (hasContinues) { |
| 1047 : innerBodyBuilder; | 1222 if (innerBodyBuilder.isOpen) innerBodyBuilder.jumpTo(continueCollector); |
| 1223 updateBuilder = makeDelimitedBuilder(continueCollector.environment); | |
| 1224 } else { | |
| 1225 updateBuilder = innerBodyBuilder; | |
| 1226 } | |
| 1048 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); | 1227 updateBuilder._enterForLoopUpdate(closureScope, loopVariables); |
| 1049 buildUpdate(updateBuilder); | 1228 buildUpdate(updateBuilder); |
| 1229 if (updateBuilder.isOpen) updateBuilder.jumpTo(loop); | |
| 1230 // Connect the inner and outer body builders. This is done only after | |
| 1231 // it is guaranteed that the updateBuilder has a non-empty term. | |
| 1232 if (hasContinues) { | |
| 1233 outerBodyBuilder.add(new ir.LetCont(continueCollector.continuation, | |
| 1234 innerBodyBuilder._root)); | |
| 1235 continueCollector.continuation.body = updateBuilder._root; | |
| 1236 } else { | |
| 1237 outerBodyBuilder.add(innerBodyBuilder._root); | |
| 1238 } | |
| 1050 | 1239 |
| 1051 // Create body entry and loop exit continuations and a branch to them. | 1240 // Create loop exit and body entry continuations and a branch to them. |
| 1241 ir.Continuation exitContinuation = new ir.Continuation([]); | |
| 1052 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1242 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1053 ir.Continuation exitContinuation = new ir.Continuation([]); | 1243 bodyContinuation.body = outerBodyBuilder._root; |
| 1054 // Note the order of continuations: the first one is the one that will | 1244 // Note the order of continuations: the first one is the one that will |
| 1055 // be filled by LetCont.plug. | 1245 // be filled by LetCont.plug. |
| 1056 ir.LetCont branch = | 1246 ir.LetCont branch = |
| 1057 new ir.LetCont.many(<ir.Continuation>[exitContinuation, | 1247 new ir.LetCont.many(<ir.Continuation>[exitContinuation, |
| 1058 bodyContinuation], | 1248 bodyContinuation], |
| 1059 new ir.Branch(new ir.IsTrue(condition), | 1249 new ir.Branch(new ir.IsTrue(condition), |
| 1060 bodyContinuation, | 1250 bodyContinuation, |
| 1061 exitContinuation)); | 1251 exitContinuation)); |
| 1062 // If there are breaks in the body, then there must be a join-point | 1252 // If there are breaks in the body, then there must be a join-point |
| 1063 // continuation for the normal exit and the breaks. | 1253 // continuation for the normal exit and the breaks. Otherwise, the |
| 1254 // successor is translated in the hole in the exit continuation. | |
| 1064 bool hasBreaks = !breakCollector.isEmpty; | 1255 bool hasBreaks = !breakCollector.isEmpty; |
| 1065 ir.LetCont letJoin; | 1256 ir.LetCont letBreak; |
| 1066 if (hasBreaks) { | 1257 if (hasBreaks) { |
| 1067 letJoin = new ir.LetCont(null, branch); | 1258 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1068 condBuilder.add(letJoin); | 1259 exitBuilder.jumpTo(breakCollector); |
| 1069 condBuilder._current = branch; | 1260 exitContinuation.body = exitBuilder._root; |
| 1261 letBreak = new ir.LetCont(breakCollector.continuation, branch); | |
| 1262 add(letBreak); | |
| 1263 environment = breakCollector.environment; | |
| 1070 } else { | 1264 } else { |
| 1071 condBuilder.add(branch); | 1265 add(branch); |
| 1072 } | |
| 1073 ir.Continuation continueContinuation; | |
| 1074 if (hasContinues) { | |
| 1075 // If there are continues in the body, we need a named continue | |
| 1076 // continuation as a join point. | |
| 1077 continueContinuation = new ir.Continuation(updateBuilder._parameters); | |
| 1078 if (innerBodyBuilder.isOpen) continueCollector.addJump(innerBodyBuilder); | |
| 1079 invokeFullJoin(continueContinuation, continueCollector); | |
| 1080 } | |
| 1081 ir.Continuation loopContinuation = | |
| 1082 new ir.Continuation(condBuilder._parameters); | |
| 1083 if (updateBuilder.isOpen) { | |
| 1084 JumpCollector backEdges = new JumpCollector(null); | |
| 1085 backEdges.addJump(updateBuilder); | |
| 1086 invokeFullJoin(loopContinuation, backEdges, recursive: true); | |
| 1087 } | |
| 1088 | |
| 1089 // Fill in the body and possible continue continuation bodies. Do this | |
| 1090 // only after it is guaranteed that they are not empty. | |
| 1091 if (hasContinues) { | |
| 1092 continueContinuation.body = updateBuilder._root; | |
| 1093 outerBodyBuilder.add(new ir.LetCont(continueContinuation, | |
| 1094 innerBodyBuilder._root)); | |
| 1095 } else { | |
| 1096 outerBodyBuilder.add(innerBodyBuilder._root); | |
| 1097 } | |
| 1098 bodyContinuation.body = outerBodyBuilder._root; | |
| 1099 | |
| 1100 loopContinuation.body = condBuilder._root; | |
| 1101 add(new ir.LetCont(loopContinuation, | |
| 1102 new ir.InvokeContinuation(loopContinuation, | |
| 1103 environment.index2value))); | |
| 1104 if (hasBreaks) { | |
| 1105 _current = branch; | |
| 1106 environment = condBuilder.environment; | |
| 1107 breakCollector.addJump(this); | |
| 1108 letJoin.continuations = | |
| 1109 <ir.Continuation>[createJoin(environment.length, breakCollector)]; | |
| 1110 _current = letJoin; | |
| 1111 } else { | |
| 1112 _current = condBuilder._current; | |
| 1113 environment = condBuilder.environment; | |
| 1114 } | 1266 } |
| 1115 } | 1267 } |
| 1116 | 1268 |
| 1117 /// Creates a for-in loop, `for (v in e) b`. | 1269 /// Creates a for-in loop, `for (v in e) b`. |
| 1118 /// | 1270 /// |
| 1119 /// [buildExpression] creates the expression, `e`. The variable, `v`, can | 1271 /// [buildExpression] creates the expression, `e`. The variable, `v`, can |
| 1120 /// take one of three forms: | 1272 /// take one of three forms: |
| 1121 /// 1) `v` can be declared within the for-in statement, like in | 1273 /// 1) `v` can be declared within the for-in statement, like in |
| 1122 /// `for (var v in e)`, in which case, [buildVariableDeclaration] | 1274 /// `for (var v in e)`, in which case, [buildVariableDeclaration] |
| 1123 /// creates its declaration and [variableElement] is the element for | 1275 /// creates its declaration and [variableElement] is the element for |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1142 // for (a in e) s; | 1294 // for (a in e) s; |
| 1143 // | 1295 // |
| 1144 // Is compiled analogously to: | 1296 // Is compiled analogously to: |
| 1145 // | 1297 // |
| 1146 // it = e.iterator; | 1298 // it = e.iterator; |
| 1147 // while (it.moveNext()) { | 1299 // while (it.moveNext()) { |
| 1148 // var a = it.current; | 1300 // var a = it.current; |
| 1149 // s; | 1301 // s; |
| 1150 // } | 1302 // } |
| 1151 | 1303 |
| 1152 // The condition and body are delimited. | 1304 // Fill the current hole with: |
| 1153 IrBuilder condBuilder = makeRecursiveBuilder(); | 1305 // let prim expressionReceiver = [[e]] in |
| 1154 | 1306 // let cont iteratorInvoked(iterator) = |
| 1307 // [ ] | |
| 1308 // in expressionReceiver.iterator () iteratorInvoked | |
| 1155 ir.Primitive expressionReceiver = buildExpression(this); | 1309 ir.Primitive expressionReceiver = buildExpression(this); |
| 1156 List<ir.Primitive> emptyArguments = new List<ir.Primitive>(); | 1310 List<ir.Primitive> emptyArguments = <ir.Primitive>[]; |
| 1157 | |
| 1158 ir.Parameter iterator = new ir.Parameter(null); | 1311 ir.Parameter iterator = new ir.Parameter(null); |
| 1159 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); | 1312 ir.Continuation iteratorInvoked = new ir.Continuation([iterator]); |
| 1160 add(new ir.LetCont(iteratorInvoked, | 1313 add(new ir.LetCont(iteratorInvoked, |
| 1161 new ir.InvokeMethod(expressionReceiver, | 1314 new ir.InvokeMethod(expressionReceiver, |
| 1162 new Selector.getter("iterator", null), iteratorInvoked, | 1315 new Selector.getter("iterator", null), |
| 1316 iteratorInvoked, | |
| 1163 emptyArguments))); | 1317 emptyArguments))); |
| 1164 | 1318 |
| 1319 // Fill with: | |
| 1320 // let cont loop(x, ...) = | |
| 1321 // let cont moveNextInvoked(condition) = | |
| 1322 // [ ] | |
| 1323 // in iterator.moveNext () moveNextInvoked | |
| 1324 // in loop(v, ...) | |
| 1325 JumpCollector loop = new BackwardJumpCollector(environment, target: target); | |
| 1326 addRecursiveContinuation(loop); | |
| 1165 ir.Parameter condition = new ir.Parameter(null); | 1327 ir.Parameter condition = new ir.Parameter(null); |
| 1166 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); | 1328 ir.Continuation moveNextInvoked = new ir.Continuation([condition]); |
| 1167 condBuilder.add(new ir.LetCont(moveNextInvoked, | 1329 add(new ir.LetCont(moveNextInvoked, |
| 1168 new ir.InvokeMethod(iterator, | 1330 new ir.InvokeMethod(iterator, |
| 1169 new Selector.call("moveNext", null, 0), | 1331 new Selector.call("moveNext", null, 0), |
| 1170 moveNextInvoked, emptyArguments))); | 1332 moveNextInvoked, |
| 1333 emptyArguments))); | |
| 1171 | 1334 |
| 1172 JumpCollector breakCollector = new JumpCollector(target); | 1335 // As a delimited term, build: |
| 1173 JumpCollector continueCollector = new JumpCollector(target); | 1336 // <<BODY>> = |
| 1174 state.breakCollectors.add(breakCollector); | 1337 // _enterScope(); |
| 1175 state.continueCollectors.add(continueCollector); | 1338 // [[variableDeclaration]] |
| 1176 | 1339 // let cont currentInvoked(currentValue) = |
| 1177 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); | 1340 // [[a = currentValue]]; |
| 1341 // [ ] | |
| 1342 // in iterator.current () currentInvoked | |
| 1343 IrBuilder bodyBuilder = makeDelimitedBuilder(); | |
| 1178 bodyBuilder._enterScope(closureScope); | 1344 bodyBuilder._enterScope(closureScope); |
| 1179 if (buildVariableDeclaration != null) { | 1345 if (buildVariableDeclaration != null) { |
| 1180 buildVariableDeclaration(bodyBuilder); | 1346 buildVariableDeclaration(bodyBuilder); |
| 1181 } | 1347 } |
| 1182 | |
| 1183 ir.Parameter currentValue = new ir.Parameter(null); | 1348 ir.Parameter currentValue = new ir.Parameter(null); |
| 1184 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); | 1349 ir.Continuation currentInvoked = new ir.Continuation([currentValue]); |
| 1185 bodyBuilder.add(new ir.LetCont(currentInvoked, | 1350 bodyBuilder.add(new ir.LetCont(currentInvoked, |
| 1186 new ir.InvokeMethod(iterator, new Selector.getter("current", null), | 1351 new ir.InvokeMethod(iterator, new Selector.getter("current", null), |
| 1187 currentInvoked, emptyArguments))); | 1352 currentInvoked, emptyArguments))); |
| 1188 // TODO(sra): Does this cover all cases? The general setter case include | 1353 // TODO(sra): Does this cover all cases? The general setter case include |
| 1189 // super. | 1354 // super. |
| 1190 if (Elements.isLocal(variableElement)) { | 1355 if (Elements.isLocal(variableElement)) { |
| 1191 bodyBuilder.buildLocalSet(variableElement, currentValue); | 1356 bodyBuilder.buildLocalSet(variableElement, currentValue); |
| 1192 } else if (Elements.isStaticOrTopLevel(variableElement) || | 1357 } else if (Elements.isStaticOrTopLevel(variableElement) || |
| 1193 Elements.isErroneous(variableElement)) { | 1358 Elements.isErroneous(variableElement)) { |
| 1194 bodyBuilder.buildStaticSet(variableElement, currentValue); | 1359 bodyBuilder.buildStaticSet(variableElement, currentValue); |
| 1195 } else { | 1360 } else { |
| 1196 ir.Primitive receiver = bodyBuilder.buildThis(); | 1361 ir.Primitive receiver = bodyBuilder.buildThis(); |
| 1197 assert(receiver != null); | 1362 assert(receiver != null); |
| 1198 bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue); | 1363 bodyBuilder.buildDynamicSet(receiver, variableSelector, currentValue); |
| 1199 } | 1364 } |
| 1200 | 1365 |
| 1366 // Translate the body in the hole in the delimited term above, and add | |
| 1367 // a jump to the loop if control flow is live after the body. | |
| 1368 JumpCollector breakCollector = | |
| 1369 new ForwardJumpCollector(environment, target: target); | |
| 1370 state.breakCollectors.add(breakCollector); | |
| 1371 state.continueCollectors.add(loop); | |
| 1201 buildBody(bodyBuilder); | 1372 buildBody(bodyBuilder); |
| 1202 assert(state.breakCollectors.last == breakCollector); | 1373 assert(state.breakCollectors.last == breakCollector); |
| 1203 assert(state.continueCollectors.last == continueCollector); | 1374 assert(state.continueCollectors.last == loop); |
| 1204 state.breakCollectors.removeLast(); | 1375 state.breakCollectors.removeLast(); |
| 1205 state.continueCollectors.removeLast(); | 1376 state.continueCollectors.removeLast(); |
| 1377 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); | |
| 1206 | 1378 |
| 1207 // Create body entry and loop exit continuations and a branch to them. | 1379 // Create body entry and loop exit continuations and a branch to them. |
| 1380 // | |
| 1381 // let cont exit() = [ ] | |
| 1382 // and body() = <<BODY>> | |
| 1383 // in branch condition (body, exit) | |
| 1384 ir.Continuation exitContinuation = new ir.Continuation([]); | |
| 1208 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1385 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1209 ir.Continuation exitContinuation = new ir.Continuation([]); | 1386 bodyContinuation.body = bodyBuilder._root; |
| 1210 // Note the order of continuations: the first one is the one that will | 1387 // Note the order of continuations: the first one is the one that will |
| 1211 // be filled by LetCont.plug. | 1388 // be filled by LetCont.plug. |
| 1212 ir.LetCont branch = | 1389 ir.LetCont branch = |
| 1213 new ir.LetCont.many(<ir.Continuation>[exitContinuation, | 1390 new ir.LetCont.many(<ir.Continuation>[exitContinuation, |
| 1214 bodyContinuation], | 1391 bodyContinuation], |
| 1215 new ir.Branch(new ir.IsTrue(condition), | 1392 new ir.Branch(new ir.IsTrue(condition), |
| 1216 bodyContinuation, | 1393 bodyContinuation, |
| 1217 exitContinuation)); | 1394 exitContinuation)); |
| 1218 // If there are breaks in the body, then there must be a join-point | 1395 // If there are breaks in the body, then there must be a join-point |
| 1219 // continuation for the normal exit and the breaks. | 1396 // continuation for the normal exit and the breaks. Otherwise, the |
| 1397 // successor is translated in the hole in the exit continuation. | |
| 1220 bool hasBreaks = !breakCollector.isEmpty; | 1398 bool hasBreaks = !breakCollector.isEmpty; |
| 1221 ir.LetCont letJoin; | 1399 ir.LetCont letBreak; |
| 1222 if (hasBreaks) { | 1400 if (hasBreaks) { |
| 1223 letJoin = new ir.LetCont(null, branch); | 1401 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1224 condBuilder.add(letJoin); | 1402 exitBuilder.jumpTo(breakCollector); |
| 1225 condBuilder._current = branch; | 1403 exitContinuation.body = exitBuilder._root; |
| 1404 letBreak = new ir.LetCont(breakCollector.continuation, branch); | |
| 1405 add(letBreak); | |
| 1406 environment = breakCollector.environment; | |
| 1226 } else { | 1407 } else { |
| 1227 condBuilder.add(branch); | 1408 add(branch); |
| 1228 } | |
| 1229 ir.Continuation loopContinuation = | |
| 1230 new ir.Continuation(condBuilder._parameters); | |
| 1231 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); | |
| 1232 invokeFullJoin( | |
| 1233 loopContinuation, continueCollector, recursive: true); | |
| 1234 bodyContinuation.body = bodyBuilder._root; | |
| 1235 | |
| 1236 loopContinuation.body = condBuilder._root; | |
| 1237 add(new ir.LetCont(loopContinuation, | |
| 1238 new ir.InvokeContinuation(loopContinuation, | |
| 1239 environment.index2value))); | |
| 1240 if (hasBreaks) { | |
| 1241 _current = branch; | |
| 1242 environment = condBuilder.environment; | |
| 1243 breakCollector.addJump(this); | |
| 1244 letJoin.continuations = | |
| 1245 <ir.Continuation>[createJoin(environment.length, breakCollector)]; | |
| 1246 _current = letJoin; | |
| 1247 } else { | |
| 1248 _current = condBuilder._current; | |
| 1249 environment = condBuilder.environment; | |
| 1250 } | 1409 } |
| 1251 } | 1410 } |
| 1252 | 1411 |
| 1253 /// Creates a while loop in which the condition and body are created by | 1412 /// Creates a while loop in which the condition and body are created by |
| 1254 /// [buildCondition] and [buildBody], respectively. | 1413 /// [buildCondition] and [buildBody], respectively. |
| 1255 /// | 1414 /// |
| 1256 /// The jump [target] is used to identify which `break` and `continue` | 1415 /// The jump [target] is used to identify which `break` and `continue` |
| 1257 /// statements that have this `while` statement as their target. | 1416 /// statements that have this `while` statement as their target. |
| 1258 void buildWhile({SubbuildFunction buildCondition, | 1417 void buildWhile({SubbuildFunction buildCondition, |
| 1259 SubbuildFunction buildBody, | 1418 SubbuildFunction buildBody, |
| 1260 JumpTarget target, | 1419 JumpTarget target, |
| 1261 ClosureScope closureScope}) { | 1420 ClosureScope closureScope}) { |
| 1262 assert(isOpen); | 1421 assert(isOpen); |
| 1263 // While loops use four named continuations: the entry to the body, the | 1422 // While loops use four named continuations: the entry to the body, the |
| 1264 // loop exit, the loop back edge (continue), and the loop exit (break). | 1423 // loop exit, the loop back edge (continue), and the loop exit (break). |
| 1265 // The CPS translation of [[while (condition) body; successor]] is: | 1424 // The CPS translation of [[while (condition) body; successor]] is: |
| 1266 // | 1425 // |
| 1267 // let cont continue(x, ...) = | 1426 // let cont continue(x, ...) = |
| 1268 // let prim cond = [[condition]] in | 1427 // let prim cond = [[condition]] in |
| 1269 // let cont break(x, ...) = [[successor]] in | 1428 // let cont break(x, ...) = [[successor]] in |
| 1270 // let cont exit() = break(v, ...) | 1429 // let cont exit() = break(v, ...) |
| 1271 // and body() = [[body]]; continue(v, ...) | 1430 // and body() = |
| 1431 // _enterScope(); | |
| 1432 // [[body]]; | |
| 1433 // continue(v, ...) | |
| 1272 // in branch cond (body, exit) | 1434 // in branch cond (body, exit) |
| 1273 // in continue(v, ...) | 1435 // in continue(v, ...) |
| 1274 // | 1436 // |
| 1275 // If there are no breaks in the body, the break continuation is inlined | 1437 // If there are no breaks in the body, the break continuation is inlined |
| 1276 // in the exit continuation (i.e., the translation of the successor | 1438 // in the exit continuation (i.e., the translation of the successor |
| 1277 // statement occurs in the exit continuation). | 1439 // statement occurs in the exit continuation). |
| 1440 JumpCollector loop = new BackwardJumpCollector(environment, target: target); | |
| 1441 addRecursiveContinuation(loop); | |
| 1278 | 1442 |
| 1279 // The condition and body are delimited. | 1443 ir.Primitive condition = buildCondition(this); |
| 1280 IrBuilder condBuilder = makeRecursiveBuilder(); | |
| 1281 ir.Primitive condition = buildCondition(condBuilder); | |
| 1282 | 1444 |
| 1283 JumpCollector breakCollector = new JumpCollector(target); | 1445 JumpCollector breakCollector = |
| 1284 JumpCollector continueCollector = new JumpCollector(target); | 1446 new ForwardJumpCollector(environment, target: target); |
| 1447 | |
| 1448 IrBuilder bodyBuilder = makeDelimitedBuilder(); | |
| 1449 bodyBuilder._enterScope(closureScope); | |
| 1285 state.breakCollectors.add(breakCollector); | 1450 state.breakCollectors.add(breakCollector); |
| 1286 state.continueCollectors.add(continueCollector); | 1451 state.continueCollectors.add(loop); |
| 1287 | |
| 1288 IrBuilder bodyBuilder = condBuilder.makeDelimitedBuilder(); | |
| 1289 bodyBuilder._enterScope(closureScope); | |
| 1290 buildBody(bodyBuilder); | 1452 buildBody(bodyBuilder); |
| 1291 assert(state.breakCollectors.last == breakCollector); | 1453 assert(state.breakCollectors.last == breakCollector); |
| 1292 assert(state.continueCollectors.last == continueCollector); | 1454 assert(state.continueCollectors.last == loop); |
| 1293 state.breakCollectors.removeLast(); | 1455 state.breakCollectors.removeLast(); |
| 1294 state.continueCollectors.removeLast(); | 1456 state.continueCollectors.removeLast(); |
| 1457 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(loop); | |
| 1295 | 1458 |
| 1296 // Create body entry and loop exit continuations and a branch to them. | 1459 // Create body entry and loop exit continuations and a branch to them. |
| 1460 ir.Continuation exitContinuation = new ir.Continuation([]); | |
| 1297 ir.Continuation bodyContinuation = new ir.Continuation([]); | 1461 ir.Continuation bodyContinuation = new ir.Continuation([]); |
| 1298 ir.Continuation exitContinuation = new ir.Continuation([]); | 1462 bodyContinuation.body = bodyBuilder._root; |
| 1299 // Note the order of continuations: the first one is the one that will | 1463 // Note the order of continuations: the first one is the one that will |
| 1300 // be filled by LetCont.plug. | 1464 // be filled by LetCont.plug. |
| 1301 ir.LetCont branch = | 1465 ir.LetCont branch = |
| 1302 new ir.LetCont.many(<ir.Continuation>[exitContinuation, | 1466 new ir.LetCont.many(<ir.Continuation>[exitContinuation, |
| 1303 bodyContinuation], | 1467 bodyContinuation], |
| 1304 new ir.Branch(new ir.IsTrue(condition), | 1468 new ir.Branch(new ir.IsTrue(condition), |
| 1305 bodyContinuation, | 1469 bodyContinuation, |
| 1306 exitContinuation)); | 1470 exitContinuation)); |
| 1307 // If there are breaks in the body, then there must be a join-point | 1471 // If there are breaks in the body, then there must be a join-point |
| 1308 // continuation for the normal exit and the breaks. | 1472 // continuation for the normal exit and the breaks. Otherwise, the |
| 1473 // successor is translated in the hole in the exit continuation. | |
| 1309 bool hasBreaks = !breakCollector.isEmpty; | 1474 bool hasBreaks = !breakCollector.isEmpty; |
| 1310 ir.LetCont letJoin; | 1475 ir.LetCont letBreak; |
| 1311 if (hasBreaks) { | 1476 if (hasBreaks) { |
| 1312 letJoin = new ir.LetCont(null, branch); | 1477 IrBuilder exitBuilder = makeDelimitedBuilder(); |
| 1313 condBuilder.add(letJoin); | 1478 exitBuilder.jumpTo(breakCollector); |
| 1314 condBuilder._current = branch; | 1479 exitContinuation.body = exitBuilder._root; |
| 1480 letBreak = new ir.LetCont(breakCollector.continuation, branch); | |
| 1481 add(letBreak); | |
| 1482 environment = breakCollector.environment; | |
| 1315 } else { | 1483 } else { |
| 1316 condBuilder.add(branch); | 1484 add(branch); |
| 1317 } | |
| 1318 ir.Continuation loopContinuation = | |
| 1319 new ir.Continuation(condBuilder._parameters); | |
| 1320 if (bodyBuilder.isOpen) continueCollector.addJump(bodyBuilder); | |
| 1321 invokeFullJoin(loopContinuation, continueCollector, recursive: true); | |
| 1322 bodyContinuation.body = bodyBuilder._root; | |
| 1323 | |
| 1324 loopContinuation.body = condBuilder._root; | |
| 1325 add(new ir.LetCont(loopContinuation, | |
| 1326 new ir.InvokeContinuation(loopContinuation, | |
| 1327 environment.index2value))); | |
| 1328 if (hasBreaks) { | |
| 1329 _current = branch; | |
| 1330 environment = condBuilder.environment; | |
| 1331 breakCollector.addJump(this); | |
| 1332 letJoin.continuations = | |
| 1333 <ir.Continuation>[createJoin(environment.length, breakCollector)]; | |
| 1334 _current = letJoin; | |
| 1335 } else { | |
| 1336 _current = condBuilder._current; | |
| 1337 environment = condBuilder.environment; | |
| 1338 } | 1485 } |
| 1339 } | 1486 } |
| 1340 | 1487 |
| 1341 | 1488 |
| 1342 /// Creates a do-while loop. | 1489 /// Creates a do-while loop. |
| 1343 /// | 1490 /// |
| 1344 /// The body and condition are created by [buildBody] and [buildCondition]. | 1491 /// The body and condition are created by [buildBody] and [buildCondition]. |
| 1345 /// The jump target [target] is the target of `break` and `continue` | 1492 /// The jump target [target] is the target of `break` and `continue` |
| 1346 /// statements in the body that have the loop as their target. | 1493 /// statements in the body that have the loop as their target. |
| 1347 /// [closureScope] contains all the variables declared in the loop (but not | 1494 /// [closureScope] contains all the variables declared in the loop (but not |
| 1348 /// declared in some inner closure scope). | 1495 /// declared in some inner closure scope). |
| 1349 void buildDoWhile({SubbuildFunction buildBody, | 1496 void buildDoWhile({SubbuildFunction buildBody, |
| 1350 SubbuildFunction buildCondition, | 1497 SubbuildFunction buildCondition, |
| 1351 JumpTarget target, | 1498 JumpTarget target, |
| 1352 ClosureScope closureScope}) { | 1499 ClosureScope closureScope}) { |
| 1353 assert(isOpen); | 1500 assert(isOpen); |
| 1354 // The CPS translation of [[do body; while (condition); successor]] is: | 1501 // The CPS translation of [[do body; while (condition); successor]] is: |
| 1355 // | 1502 // |
| 1356 // let cont break(x, ...) = [[successor]] in | 1503 // let cont break(x, ...) = [[successor]] in |
| 1357 // let cont rec loop(x, ...) = | 1504 // let cont rec loop(x, ...) = |
| 1358 // let cont continue(x, ...) = | 1505 // let cont continue(x, ...) = |
| 1359 // let prim cond = [[condition]] in | 1506 // let prim cond = [[condition]] in |
| 1360 // let cont exit() = break(v, ...) | 1507 // let cont exit() = break(v, ...) |
| 1361 // and repeat() = loop(v, ...) | 1508 // and repeat() = loop(v, ...) |
| 1362 // in branch cond (repeat, exit) | 1509 // in branch cond (repeat, exit) |
| 1363 // in [[body]]; continue(v, ...) | 1510 // in [[body]]; continue(v, ...) |
| 1364 // in loop(v, ...) | 1511 // in loop(v, ...) |
| 1365 IrBuilder bodyBuilder = makeRecursiveBuilder(); | 1512 IrBuilder loopBuilder = makeDelimitedBuilder(); |
| 1366 IrBuilder continueBuilder = bodyBuilder.makeRecursiveBuilder(); | 1513 JumpCollector loop = |
| 1514 new BackwardJumpCollector(loopBuilder.environment, target: target); | |
| 1515 loopBuilder.addRecursiveContinuation(loop); | |
| 1367 | 1516 |
| 1368 // Construct the continue continuation (i.e., the condition). | 1517 // Translate the body. |
| 1518 JumpCollector breakCollector = | |
| 1519 new ForwardJumpCollector(environment, target: target); | |
| 1520 JumpCollector continueCollector = | |
| 1521 new ForwardJumpCollector(loopBuilder.environment, target: target); | |
| 1522 IrBuilder bodyBuilder = loopBuilder.makeDelimitedBuilder(); | |
| 1523 bodyBuilder._enterScope(closureScope); | |
| 1524 state.breakCollectors.add(breakCollector); | |
| 1525 state.continueCollectors.add(continueCollector); | |
| 1526 buildBody(bodyBuilder); | |
| 1527 assert(state.breakCollectors.last == breakCollector); | |
| 1528 assert(state.continueCollectors.last == continueCollector); | |
| 1529 state.breakCollectors.removeLast(); | |
| 1530 state.continueCollectors.removeLast(); | |
| 1531 if (bodyBuilder.isOpen) bodyBuilder.jumpTo(continueCollector); | |
| 1532 | |
| 1533 // Construct the body of the continue continuation (i.e., the condition). | |
| 1369 // <Continue> = | 1534 // <Continue> = |
| 1370 // let prim cond = [[condition]] in | 1535 // let prim cond = [[condition]] in |
| 1371 // let cont exit() = break(v, ...) | 1536 // let cont exit() = break(v, ...) |
| 1372 // and repeat() = loop(v, ...) | 1537 // and repeat() = loop(v, ...) |
| 1373 // in branch cond (repeat, exit) | 1538 // in branch cond (repeat, exit) |
| 1539 IrBuilder continueBuilder = loopBuilder.makeDelimitedBuilder(); | |
| 1540 continueBuilder.environment = continueCollector.environment; | |
| 1374 ir.Primitive condition = buildCondition(continueBuilder); | 1541 ir.Primitive condition = buildCondition(continueBuilder); |
| 1375 // Use a delimited IrBuilder for the exit continuation's body so that | 1542 |
| 1376 // we can capture the break with the body's break collector. | |
| 1377 ir.Continuation exitContinuation = new ir.Continuation([]); | 1543 ir.Continuation exitContinuation = new ir.Continuation([]); |
| 1378 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder(); | 1544 IrBuilder exitBuilder = continueBuilder.makeDelimitedBuilder(); |
| 1545 exitBuilder.jumpTo(breakCollector); | |
| 1546 exitContinuation.body = exitBuilder._root; | |
| 1379 ir.Continuation repeatContinuation = new ir.Continuation([]); | 1547 ir.Continuation repeatContinuation = new ir.Continuation([]); |
| 1380 ir.InvokeContinuation invokeLoop = | 1548 IrBuilder repeatBuilder = continueBuilder.makeDelimitedBuilder(); |
| 1381 new ir.InvokeContinuation.uninitialized(recursive: true); | 1549 repeatBuilder.jumpTo(loop); |
| 1382 invokeLoop.arguments = | 1550 repeatContinuation.body = repeatBuilder._root; |
| 1383 continueBuilder.environment.index2value.map( | 1551 |
| 1384 (ir.Primitive value) => new ir.Reference(value)).toList(); | |
| 1385 repeatContinuation.body = invokeLoop; | |
| 1386 continueBuilder.add( | 1552 continueBuilder.add( |
| 1387 new ir.LetCont.many(<ir.Continuation>[exitContinuation, | 1553 new ir.LetCont.many(<ir.Continuation>[exitContinuation, |
| 1388 repeatContinuation], | 1554 repeatContinuation], |
| 1389 new ir.Branch(new ir.IsTrue(condition), | 1555 new ir.Branch(new ir.IsTrue(condition), |
| 1390 repeatContinuation, | 1556 repeatContinuation, |
| 1391 exitContinuation))); | 1557 exitContinuation))); |
| 1392 ir.Continuation continueContinuation = | 1558 continueCollector.continuation.body = continueBuilder._root; |
| 1393 new ir.Continuation(continueBuilder._parameters); | |
| 1394 continueContinuation.body = continueBuilder._root; | |
| 1395 | 1559 |
| 1396 // Construct the loop continuation (i.e., the body and condition). | 1560 // Construct the loop continuation (i.e., the body and condition). |
| 1397 // <Loop> = | 1561 // <Loop> = |
| 1398 // let cont continue(x, ...) = | 1562 // let cont continue(x, ...) = |
| 1399 // <Continue> | 1563 // <Continue> |
| 1400 // in [[body]]; continue(v, ...) | 1564 // in [[body]]; continue(v, ...) |
| 1401 JumpCollector breakCollector = new JumpCollector(target); | 1565 loopBuilder.add( |
| 1402 JumpCollector continueCollector = new JumpCollector(target); | 1566 new ir.LetCont(continueCollector.continuation, |
| 1403 state.breakCollectors.add(breakCollector); | 1567 bodyBuilder._root)); |
| 1404 state.continueCollectors.add(continueCollector); | |
| 1405 bodyBuilder._enterScope(closureScope); | |
| 1406 buildBody(bodyBuilder); | |
| 1407 assert(state.breakCollectors.last == breakCollector); | |
| 1408 assert(state.continueCollectors.last == continueCollector); | |
| 1409 state.breakCollectors.removeLast(); | |
| 1410 state.continueCollectors.removeLast(); | |
| 1411 // Add the jump from the loop's exit to the break condition. It is only | |
| 1412 // here where the exitBuilder's root is non-null and we can set the | |
| 1413 // exitContinuation's body. | |
| 1414 breakCollector.addJump(exitBuilder); | |
| 1415 exitContinuation.body = exitBuilder._root; | |
| 1416 if (bodyBuilder.isOpen) { | |
| 1417 continueCollector.addJump(bodyBuilder); | |
| 1418 } | |
| 1419 invokeFullJoin(continueContinuation, continueCollector, recursive: false); | |
| 1420 ir.Continuation loopContinuation = | |
| 1421 new ir.Continuation(bodyBuilder._parameters); | |
| 1422 loopContinuation.isRecursive = true; | |
| 1423 loopContinuation.body = | |
| 1424 new ir.LetCont(continueContinuation, bodyBuilder._root); | |
| 1425 invokeLoop.continuation = | |
| 1426 new ir.Reference<ir.Continuation>(loopContinuation); | |
| 1427 ir.LetCont letLoop = | |
| 1428 new ir.LetCont(loopContinuation, | |
| 1429 new ir.InvokeContinuation(loopContinuation, | |
| 1430 environment.index2value)); | |
| 1431 | 1568 |
| 1432 // Add the break condition. | 1569 // And tie it all together. |
| 1433 ir.Continuation breakContinuation; | 1570 add(new ir.LetCont(breakCollector.continuation, loopBuilder._root)); |
| 1434 if (breakCollector.length == 1) { | 1571 environment = breakCollector.environment; |
| 1435 // createJoin only works when there is more than one jump to a join-point | |
| 1436 // continuation. This is to potentially catch errors in the case that | |
| 1437 // a join was intended and at least one jump is missing. Unfortunately | |
| 1438 // we have the explicit code below for the (common?) case that the | |
| 1439 // only break from the do-while is the implicit one when the condition | |
| 1440 // is false. | |
| 1441 List<ir.Parameter> parameters = <ir.Parameter>[]; | |
| 1442 List<ir.Reference> arguments = <ir.Reference>[]; | |
| 1443 for (int i = 0; i < environment.length; ++i) { | |
| 1444 ir.Parameter parameter = | |
| 1445 new ir.Parameter(environment.index2variable[i]); | |
| 1446 parameters.add(parameter); | |
| 1447 environment.index2value[i] = parameter; | |
| 1448 arguments.add(new ir.Reference(breakCollector.environments.first[i])); | |
| 1449 } | |
| 1450 breakContinuation = new ir.Continuation(parameters); | |
| 1451 breakCollector.invocations.first.arguments = arguments; | |
| 1452 breakCollector.invocations.first.continuation = | |
| 1453 new ir.Reference(breakContinuation); | |
| 1454 } else { | |
| 1455 breakContinuation = createJoin(environment.length, breakCollector); | |
| 1456 } | |
| 1457 add(new ir.LetCont(breakContinuation, letLoop)); | |
| 1458 } | 1572 } |
| 1459 | 1573 |
| 1460 /// Creates a try-statement. | 1574 /// Creates a try-statement. |
| 1461 /// | 1575 /// |
| 1462 /// [tryInfo] provides information on local variables declared and boxed | 1576 /// [tryInfo] provides information on local variables declared and boxed |
| 1463 /// within this try statement. | 1577 /// within this try statement. |
| 1464 /// [buildTryBlock] builds the try block. | 1578 /// [buildTryBlock] builds the try block. |
| 1465 /// [catchClauseInfos] provides access to the catch type, exception variable, | 1579 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1466 /// and stack trace variable, and a function for building the catch block. | 1580 /// and stack trace variable, and a function for building the catch block. |
| 1467 void buildTry( | 1581 void buildTry( |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1492 // | 1606 // |
| 1493 // In other words, both the try and catch block are in the scope of the | 1607 // In other words, both the try and catch block are in the scope of the |
| 1494 // join-point continuation, and they are both in the scope of a sequence | 1608 // join-point continuation, and they are both in the scope of a sequence |
| 1495 // of mutable bindings for the variables assigned in the try. The join- | 1609 // of mutable bindings for the variables assigned in the try. The join- |
| 1496 // point continuation is not in the scope of these mutable bindings. | 1610 // point continuation is not in the scope of these mutable bindings. |
| 1497 // The tryBlock is in the scope of a binding for the catch handler. Each | 1611 // The tryBlock is in the scope of a binding for the catch handler. Each |
| 1498 // instruction (specifically, each call) in the tryBlock is in the dynamic | 1612 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1499 // scope of the handler. The mutable bindings are dereferenced at the end | 1613 // scope of the handler. The mutable bindings are dereferenced at the end |
| 1500 // of the try block and at the beginning of the catch block, so the | 1614 // of the try block and at the beginning of the catch block, so the |
| 1501 // variables are unboxed in the catch block and at the join point. | 1615 // variables are unboxed in the catch block and at the join point. |
| 1616 JumpCollector join = new ForwardJumpCollector(environment); | |
| 1617 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | |
| 1502 | 1618 |
| 1503 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | |
| 1504 // Variables that are boxed due to being captured in a closure are boxed | 1619 // Variables that are boxed due to being captured in a closure are boxed |
| 1505 // for their entire lifetime, and so they do not need to be boxed on | 1620 // for their entire lifetime, and so they do not need to be boxed on |
| 1506 // entry to any try block. We check for them here because we can not | 1621 // entry to any try block. They are not filtered out before this because |
| 1507 // identify all of them in the same pass where we identify the variables | 1622 // we can not identify all of them in the same pass where we identify the |
| 1508 // assigned in the try (the may be captured by a closure after the try | 1623 // variables assigned in the try (they may be captured by a closure after |
| 1509 // statement). | 1624 // the try statement). |
| 1510 Iterable<LocalVariableElement> boxedOnEntry = | 1625 Iterable<LocalVariableElement> boxedOnEntry = |
| 1511 tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) { | 1626 tryStatementInfo.boxedOnEntry.where((LocalVariableElement variable) { |
| 1512 return !tryCatchBuilder.mutableCapturedVariables.contains(variable); | 1627 return !tryCatchBuilder.mutableCapturedVariables.contains(variable); |
| 1513 }); | 1628 }); |
| 1514 for (LocalVariableElement variable in boxedOnEntry) { | 1629 for (LocalVariableElement variable in boxedOnEntry) { |
| 1515 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1630 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1516 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); | 1631 ir.Primitive value = tryCatchBuilder.buildLocalGet(variable); |
| 1517 tryCatchBuilder.makeMutableVariable(variable); | 1632 tryCatchBuilder.makeMutableVariable(variable); |
| 1518 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); | 1633 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1519 } | 1634 } |
| 1520 | 1635 |
| 1521 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1522 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | 1636 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1523 List<ir.Parameter> joinParameters = | |
| 1524 new List<ir.Parameter>.generate(environment.length, (i) { | |
| 1525 return new ir.Parameter(environment.index2variable[i]); | |
| 1526 }); | |
| 1527 ir.Continuation joinContinuation = new ir.Continuation(joinParameters); | |
| 1528 | 1637 |
| 1529 void interceptJumps(JumpCollector collector) { | 1638 void interceptJumps(JumpCollector collector) { |
| 1530 collector.enterTry(boxedOnEntry); | 1639 collector.enterTry(boxedOnEntry); |
| 1531 } | 1640 } |
| 1641 tryBuilder.state.breakCollectors.forEach(interceptJumps); | |
| 1642 tryBuilder.state.continueCollectors.forEach(interceptJumps); | |
| 1643 buildTryBlock(tryBuilder); | |
| 1532 void restoreJumps(JumpCollector collector) { | 1644 void restoreJumps(JumpCollector collector) { |
| 1533 collector.leaveTry(); | 1645 collector.leaveTry(); |
| 1534 } | 1646 } |
| 1535 tryBuilder.state.breakCollectors.forEach(interceptJumps); | |
| 1536 tryBuilder.state.continueCollectors.forEach(interceptJumps); | |
| 1537 buildTryBlock(tryBuilder); | |
| 1538 tryBuilder.state.breakCollectors.forEach(restoreJumps); | 1647 tryBuilder.state.breakCollectors.forEach(restoreJumps); |
| 1539 tryBuilder.state.continueCollectors.forEach(restoreJumps); | 1648 tryBuilder.state.continueCollectors.forEach(restoreJumps); |
| 1540 if (tryBuilder.isOpen) { | 1649 if (tryBuilder.isOpen) { |
| 1541 for (LocalVariableElement variable in boxedOnEntry) { | 1650 interceptJumps(join); |
| 1542 assert(tryBuilder.isInMutableVariable(variable)); | 1651 tryBuilder.jumpTo(join); |
| 1543 ir.Primitive value = tryBuilder.buildLocalGet(variable); | 1652 restoreJumps(join); |
| 1544 tryBuilder.environment.update(variable, value); | |
| 1545 } | |
| 1546 tryBuilder.jumpTo(joinContinuation); | |
| 1547 } | 1653 } |
|
asgerf
2015/04/07 13:42:42
I may be nitpicking now, but could we please resto
Kevin Millikin (Google)
2015/04/08 10:56:59
That's fine. I can even restore the break and con
asgerf
2015/04/08 11:10:21
Just don't do breakCollectors.reversed.forEach(res
| |
| 1548 | 1654 |
| 1655 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1549 for (LocalVariableElement variable in boxedOnEntry) { | 1656 for (LocalVariableElement variable in boxedOnEntry) { |
| 1550 assert(catchBuilder.isInMutableVariable(variable)); | 1657 assert(catchBuilder.isInMutableVariable(variable)); |
| 1551 ir.Primitive value = catchBuilder.buildLocalGet(variable); | 1658 ir.Primitive value = catchBuilder.buildLocalGet(variable); |
| 1552 // Note that we remove the variable from the set of mutable variables | 1659 // Note that we remove the variable from the set of mutable variables |
| 1553 // here (and not above for the try body). This is because the set of | 1660 // here (and not above for the try body). This is because the set of |
| 1554 // mutable variables is global for the whole function and not local to | 1661 // mutable variables is global for the whole function and not local to |
| 1555 // a delimited builder. | 1662 // a delimited builder. |
| 1556 catchBuilder.removeMutableVariable(variable); | 1663 catchBuilder.removeMutableVariable(variable); |
| 1557 catchBuilder.environment.update(variable, value); | 1664 catchBuilder.environment.update(variable, value); |
| 1558 } | 1665 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 1570 if (stackTraceVariable != null) { | 1677 if (stackTraceVariable != null) { |
| 1571 traceParameter = new ir.Parameter(stackTraceVariable); | 1678 traceParameter = new ir.Parameter(stackTraceVariable); |
| 1572 catchBuilder.environment.extend(stackTraceVariable, traceParameter); | 1679 catchBuilder.environment.extend(stackTraceVariable, traceParameter); |
| 1573 } else { | 1680 } else { |
| 1574 // Use a dummy continuation parameter for the stack trace parameter. | 1681 // Use a dummy continuation parameter for the stack trace parameter. |
| 1575 // This will ensure that all handlers have two parameters and so they | 1682 // This will ensure that all handlers have two parameters and so they |
| 1576 // can be treated uniformly. | 1683 // can be treated uniformly. |
| 1577 traceParameter = new ir.Parameter(null); | 1684 traceParameter = new ir.Parameter(null); |
| 1578 } | 1685 } |
| 1579 catchClauseInfo.buildCatchBlock(catchBuilder); | 1686 catchClauseInfo.buildCatchBlock(catchBuilder); |
| 1580 if (catchBuilder.isOpen) { | 1687 if (catchBuilder.isOpen) catchBuilder.jumpTo(join); |
| 1581 catchBuilder.jumpTo(joinContinuation); | |
| 1582 } | |
| 1583 List<ir.Parameter> catchParameters = | 1688 List<ir.Parameter> catchParameters = |
| 1584 <ir.Parameter>[exceptionParameter, traceParameter]; | 1689 <ir.Parameter>[exceptionParameter, traceParameter]; |
| 1585 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | 1690 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); |
| 1586 catchContinuation.body = catchBuilder._root; | 1691 catchContinuation.body = catchBuilder._root; |
| 1587 | 1692 |
| 1588 tryCatchBuilder.add( | 1693 tryCatchBuilder.add( |
| 1589 new ir.LetHandler(catchContinuation, tryBuilder._root)); | 1694 new ir.LetHandler(catchContinuation, tryBuilder._root)); |
| 1590 tryCatchBuilder._current = null; | 1695 tryCatchBuilder._current = null; |
| 1591 } | 1696 } |
| 1592 | 1697 |
| 1593 add(new ir.LetCont(joinContinuation, tryCatchBuilder._root)); | 1698 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); |
| 1594 for (int i = 0; i < environment.length; ++i) { | 1699 environment = join.environment; |
| 1595 environment.index2value[i] = joinParameters[i]; | |
| 1596 } | |
| 1597 } | 1700 } |
| 1598 | 1701 |
| 1599 /// Create a return statement `return value;` or `return;` if [value] is | 1702 /// Create a return statement `return value;` or `return;` if [value] is |
| 1600 /// null. | 1703 /// null. |
| 1601 void buildReturn([ir.Primitive value]) { | 1704 void buildReturn([ir.Primitive value]) { |
| 1602 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 1705 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1603 // where (C', x) = Build(e, C) | 1706 // where (C', x) = Build(e, C) |
| 1604 // | 1707 // |
| 1605 // Return without a subexpression is translated as if it were return null. | 1708 // Return without a subexpression is translated as if it were return null. |
| 1606 assert(isOpen); | 1709 assert(isOpen); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 1627 /// The first node in the sequence does not need to be reachable. | 1730 /// The first node in the sequence does not need to be reachable. |
| 1628 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses | 1731 // TODO(johnniwinther): Type [nodes] as `Iterable` when `NodeList` uses |
| 1629 // `List` instead of `Link`. | 1732 // `List` instead of `Link`. |
| 1630 void buildSequence(var nodes, BuildFunction build) { | 1733 void buildSequence(var nodes, BuildFunction build) { |
| 1631 for (var node in nodes) { | 1734 for (var node in nodes) { |
| 1632 if (!isOpen) return; | 1735 if (!isOpen) return; |
| 1633 build(node); | 1736 build(node); |
| 1634 } | 1737 } |
| 1635 } | 1738 } |
| 1636 | 1739 |
| 1637 | |
| 1638 /// Creates a labeled statement | 1740 /// Creates a labeled statement |
| 1639 void buildLabeledStatement({SubbuildFunction buildBody, | 1741 void buildLabeledStatement({SubbuildFunction buildBody, |
| 1640 JumpTarget target}) { | 1742 JumpTarget target}) { |
| 1641 JumpCollector jumps = new JumpCollector(target); | 1743 JumpCollector join = new ForwardJumpCollector(environment, target: target); |
| 1642 state.breakCollectors.add(jumps); | |
| 1643 IrBuilder innerBuilder = makeDelimitedBuilder(); | 1744 IrBuilder innerBuilder = makeDelimitedBuilder(); |
| 1745 innerBuilder.state.breakCollectors.add(join); | |
| 1644 buildBody(innerBuilder); | 1746 buildBody(innerBuilder); |
| 1645 state.breakCollectors.removeLast(); | 1747 innerBuilder.state.breakCollectors.removeLast(); |
| 1646 bool hasBreaks = !jumps.isEmpty; | 1748 bool hasBreaks = !join.isEmpty; |
| 1647 ir.Continuation joinContinuation; | |
| 1648 if (hasBreaks) { | 1749 if (hasBreaks) { |
| 1649 if (innerBuilder.isOpen) { | 1750 if (innerBuilder.isOpen) innerBuilder.jumpTo(join); |
| 1650 jumps.addJump(innerBuilder); | 1751 add(new ir.LetCont(join.continuation, innerBuilder._root)); |
| 1651 } | 1752 environment = join.environment; |
| 1652 | 1753 } else if (innerBuilder._root != null) { |
| 1653 // All jumps to the break continuation must be in the scope of the | 1754 add(innerBuilder._root); |
| 1654 // continuation's binding. The continuation is bound just outside the | 1755 _current = innerBuilder._current; |
| 1655 // body to satisfy this property without extra analysis. | 1756 environment = innerBuilder.environment; |
| 1656 // As a consequence, the break continuation needs parameters for all | |
| 1657 // local variables in scope at the exit from the body. | |
| 1658 List<ir.Parameter> parameters = | |
| 1659 new List<ir.Parameter>.generate(environment.length, (i) { | |
| 1660 return new ir.Parameter(environment.index2variable[i]); | |
| 1661 }); | |
| 1662 joinContinuation = new ir.Continuation(parameters); | |
| 1663 invokeFullJoin(joinContinuation, jumps, recursive: false); | |
| 1664 add(new ir.LetCont(joinContinuation, innerBuilder._root)); | |
| 1665 for (int i = 0; i < environment.length; ++i) { | |
| 1666 environment.index2value[i] = parameters[i]; | |
| 1667 } | |
| 1668 } else { | |
| 1669 if (innerBuilder._root != null) { | |
| 1670 add(innerBuilder._root); | |
| 1671 _current = innerBuilder._current; | |
| 1672 environment = innerBuilder.environment; | |
| 1673 } | |
| 1674 } | 1757 } |
|
asgerf
2015/04/07 13:42:41
Could we have an else with a comment saying that t
Kevin Millikin (Google)
2015/04/08 10:56:59
Done.
| |
| 1675 return null; | |
| 1676 } | 1758 } |
| 1677 | 1759 |
| 1678 | |
| 1679 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] | 1760 // Build(BreakStatement L, C) = C[InvokeContinuation(...)] |
| 1680 // | 1761 // |
| 1681 // The continuation and arguments are filled in later after translating | 1762 // The continuation and arguments are filled in later after translating |
| 1682 // the body containing the break. | 1763 // the body containing the break. |
| 1683 bool buildBreak(JumpTarget target) { | 1764 bool buildBreak(JumpTarget target) { |
| 1684 return buildJumpInternal(target, state.breakCollectors); | 1765 return buildJumpInternal(target, state.breakCollectors); |
| 1685 } | 1766 } |
| 1686 | 1767 |
| 1687 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] | 1768 // Build(ContinueStatement L, C) = C[InvokeContinuation(...)] |
| 1688 // | 1769 // |
| 1689 // The continuation and arguments are filled in later after translating | 1770 // The continuation and arguments are filled in later after translating |
| 1690 // the body containing the continue. | 1771 // the body containing the continue. |
| 1691 bool buildContinue(JumpTarget target) { | 1772 bool buildContinue(JumpTarget target) { |
| 1692 return buildJumpInternal(target, state.continueCollectors); | 1773 return buildJumpInternal(target, state.continueCollectors); |
| 1693 } | 1774 } |
| 1694 | 1775 |
| 1695 bool buildJumpInternal(JumpTarget target, | 1776 bool buildJumpInternal(JumpTarget target, |
| 1696 Iterable<JumpCollector> collectors) { | 1777 Iterable<JumpCollector> collectors) { |
| 1697 assert(isOpen); | 1778 assert(isOpen); |
| 1698 for (JumpCollector collector in collectors) { | 1779 for (JumpCollector collector in collectors) { |
| 1699 if (target == collector.target) { | 1780 if (target == collector.target) { |
| 1700 collector.addJump(this); | 1781 jumpTo(collector); |
| 1701 return true; | 1782 return true; |
| 1702 } | 1783 } |
| 1703 } | 1784 } |
| 1704 return false; | 1785 return false; |
| 1705 } | 1786 } |
| 1706 | 1787 |
| 1707 /// Create a negation of [condition]. | 1788 /// Create a negation of [condition]. |
| 1708 ir.Primitive buildNegation(ir.Primitive condition) { | 1789 ir.Primitive buildNegation(ir.Primitive condition) { |
| 1709 // ! e is translated as e ? false : true | 1790 // ! e is translated as e ? false : true |
| 1710 | 1791 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1758 /// operand and [buildRightValue] is called to process the value of the right | 1839 /// operand and [buildRightValue] is called to process the value of the right |
| 1759 /// operand in the context of its own [IrBuilder]. | 1840 /// operand in the context of its own [IrBuilder]. |
| 1760 ir.Primitive buildLogicalOperator( | 1841 ir.Primitive buildLogicalOperator( |
| 1761 ir.Primitive leftValue, | 1842 ir.Primitive leftValue, |
| 1762 ir.Primitive buildRightValue(IrBuilder builder), | 1843 ir.Primitive buildRightValue(IrBuilder builder), |
| 1763 {bool isLazyOr: false}) { | 1844 {bool isLazyOr: false}) { |
| 1764 // e0 && e1 is translated as if e0 ? (e1 == true) : false. | 1845 // e0 && e1 is translated as if e0 ? (e1 == true) : false. |
| 1765 // e0 || e1 is translated as if e0 ? true : (e1 == true). | 1846 // e0 || e1 is translated as if e0 ? true : (e1 == true). |
| 1766 // The translation must convert both e0 and e1 to booleans and handle | 1847 // The translation must convert both e0 and e1 to booleans and handle |
| 1767 // local variable assignments in e1. | 1848 // local variable assignments in e1. |
| 1768 | |
| 1769 IrBuilder rightBuilder = makeDelimitedBuilder(); | 1849 IrBuilder rightBuilder = makeDelimitedBuilder(); |
| 1770 ir.Primitive rightValue = buildRightValue(rightBuilder); | 1850 ir.Primitive rightValue = buildRightValue(rightBuilder); |
| 1771 // A dummy empty target for the branch on the left subexpression branch. | 1851 // A dummy empty target for the branch on the left subexpression branch. |
| 1772 // This enables using the same infrastructure for join-point continuations | 1852 // This enables using the same infrastructure for join-point continuations |
| 1773 // as in visitIf and visitConditional. It will hold a definition of the | 1853 // as in visitIf and visitConditional. It will hold a definition of the |
| 1774 // appropriate constant and an invocation of the join-point continuation. | 1854 // appropriate constant and an invocation of the join-point continuation. |
| 1775 IrBuilder emptyBuilder = makeDelimitedBuilder(); | 1855 IrBuilder emptyBuilder = makeDelimitedBuilder(); |
| 1776 // Dummy empty targets for right true and right false. They hold | 1856 // Dummy empty targets for right true and right false. They hold |
| 1777 // definitions of the appropriate constant and an invocation of the | 1857 // definitions of the appropriate constant and an invocation of the |
| 1778 // join-point continuation. | 1858 // join-point continuation. |
| 1779 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder(); | 1859 IrBuilder rightTrueBuilder = rightBuilder.makeDelimitedBuilder(); |
| 1780 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder(); | 1860 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder(); |
| 1781 | 1861 |
| 1782 // If we don't evaluate the right subexpression, the value of the whole | 1862 // If we don't evaluate the right subexpression, the value of the whole |
| 1783 // expression is this constant. | 1863 // expression is this constant. |
| 1784 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); | 1864 ir.Constant leftBool = emptyBuilder.buildBooleanLiteral(isLazyOr); |
| 1785 // If we do evaluate the right subexpression, the value of the expression | 1865 // If we do evaluate the right subexpression, the value of the expression |
| 1786 // is a true or false constant. | 1866 // is a true or false constant. |
| 1787 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); | 1867 ir.Constant rightTrue = rightTrueBuilder.buildBooleanLiteral(true); |
| 1788 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); | 1868 ir.Constant rightFalse = rightFalseBuilder.buildBooleanLiteral(false); |
| 1789 | 1869 |
| 1790 // Treat the result values as named values in the environment, so they | 1870 // Treat the result values as named values in the environment, so they |
| 1791 // will be treated as arguments to the join-point continuation. | 1871 // will be treated as arguments to the join-point continuation. |
| 1792 assert(environment.length == emptyBuilder.environment.length); | 1872 assert(environment.length == emptyBuilder.environment.length); |
| 1793 assert(environment.length == rightTrueBuilder.environment.length); | 1873 assert(environment.length == rightTrueBuilder.environment.length); |
| 1794 assert(environment.length == rightFalseBuilder.environment.length); | 1874 assert(environment.length == rightFalseBuilder.environment.length); |
| 1875 // Treat the value of the expression as a local variable so it will get | |
| 1876 // a continuation parameter. | |
| 1877 environment.extend(null, null); | |
|
asgerf
2015/04/07 13:42:42
I love this!
| |
| 1795 emptyBuilder.environment.extend(null, leftBool); | 1878 emptyBuilder.environment.extend(null, leftBool); |
| 1796 rightTrueBuilder.environment.extend(null, rightTrue); | 1879 rightTrueBuilder.environment.extend(null, rightTrue); |
| 1797 rightFalseBuilder.environment.extend(null, rightFalse); | 1880 rightFalseBuilder.environment.extend(null, rightFalse); |
| 1798 | 1881 |
| 1799 // Wire up two continuations for the left subexpression, two continuations | 1882 // Wire up two continuations for the left subexpression, two continuations |
| 1800 // for the right subexpression, and a three-way join continuation. | 1883 // for the right subexpression, and a three-way join continuation. |
| 1801 JumpCollector jumps = new JumpCollector(null); | 1884 JumpCollector join = new ForwardJumpCollector(environment); |
| 1802 jumps.addJump(emptyBuilder); | 1885 emptyBuilder.jumpTo(join); |
| 1803 jumps.addJump(rightTrueBuilder); | 1886 rightTrueBuilder.jumpTo(join); |
| 1804 jumps.addJump(rightFalseBuilder); | 1887 rightFalseBuilder.jumpTo(join); |
| 1805 ir.Continuation joinContinuation = | |
| 1806 createJoin(environment.length + 1, jumps); | |
| 1807 ir.Continuation leftTrueContinuation = new ir.Continuation([]); | 1888 ir.Continuation leftTrueContinuation = new ir.Continuation([]); |
| 1808 ir.Continuation leftFalseContinuation = new ir.Continuation([]); | 1889 ir.Continuation leftFalseContinuation = new ir.Continuation([]); |
| 1809 ir.Continuation rightTrueContinuation = new ir.Continuation([]); | 1890 ir.Continuation rightTrueContinuation = new ir.Continuation([]); |
| 1810 ir.Continuation rightFalseContinuation = new ir.Continuation([]); | 1891 ir.Continuation rightFalseContinuation = new ir.Continuation([]); |
| 1811 rightTrueContinuation.body = rightTrueBuilder._root; | 1892 rightTrueContinuation.body = rightTrueBuilder._root; |
| 1812 rightFalseContinuation.body = rightFalseBuilder._root; | 1893 rightFalseContinuation.body = rightFalseBuilder._root; |
| 1813 // The right subexpression has two continuations. | 1894 // The right subexpression has two continuations. |
| 1814 rightBuilder.add( | 1895 rightBuilder.add( |
| 1815 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation, | 1896 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation, |
| 1816 rightFalseContinuation], | 1897 rightFalseContinuation], |
| 1817 new ir.Branch(new ir.IsTrue(rightValue), | 1898 new ir.Branch(new ir.IsTrue(rightValue), |
| 1818 rightTrueContinuation, | 1899 rightTrueContinuation, |
| 1819 rightFalseContinuation))); | 1900 rightFalseContinuation))); |
| 1820 // Depending on the operator, the left subexpression's continuations are | 1901 // Depending on the operator, the left subexpression's continuations are |
| 1821 // either the right subexpression or an invocation of the join-point | 1902 // either the right subexpression or an invocation of the join-point |
| 1822 // continuation. | 1903 // continuation. |
| 1823 if (isLazyOr) { | 1904 if (isLazyOr) { |
| 1824 leftTrueContinuation.body = emptyBuilder._root; | 1905 leftTrueContinuation.body = emptyBuilder._root; |
| 1825 leftFalseContinuation.body = rightBuilder._root; | 1906 leftFalseContinuation.body = rightBuilder._root; |
| 1826 } else { | 1907 } else { |
| 1827 leftTrueContinuation.body = rightBuilder._root; | 1908 leftTrueContinuation.body = rightBuilder._root; |
| 1828 leftFalseContinuation.body = emptyBuilder._root; | 1909 leftFalseContinuation.body = emptyBuilder._root; |
| 1829 } | 1910 } |
| 1830 | 1911 |
| 1831 add(new ir.LetCont(joinContinuation, | 1912 add(new ir.LetCont(join.continuation, |
| 1832 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation, | 1913 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation, |
| 1833 leftFalseContinuation], | 1914 leftFalseContinuation], |
| 1834 new ir.Branch(new ir.IsTrue(leftValue), | 1915 new ir.Branch(new ir.IsTrue(leftValue), |
| 1835 leftTrueContinuation, | 1916 leftTrueContinuation, |
| 1836 leftFalseContinuation)))); | 1917 leftFalseContinuation)))); |
| 1918 environment = join.environment; | |
| 1919 environment.discard(1); | |
| 1837 // There is always a join parameter for the result value, because it | 1920 // There is always a join parameter for the result value, because it |
| 1838 // is different on at least two paths. | 1921 // is different on at least two paths. |
| 1839 return joinContinuation.parameters.last; | 1922 return join.continuation.parameters.last; |
| 1840 } | |
| 1841 | |
| 1842 /// Create a non-recursive join-point continuation. | |
| 1843 /// | |
| 1844 /// Given the environment length at the join point and a list of | |
| 1845 /// jumps that should reach the join point, create a join-point | |
| 1846 /// continuation. The join-point continuation has a parameter for each | |
| 1847 /// variable that has different values reaching on different paths. | |
| 1848 /// | |
| 1849 /// The jumps are uninitialized [ir.InvokeContinuation] expressions. | |
| 1850 /// They are filled in with the target continuation and appropriate | |
| 1851 /// arguments. | |
| 1852 /// | |
| 1853 /// As a side effect, the environment of this builder is updated to include | |
| 1854 /// the join-point continuation parameters. | |
| 1855 ir.Continuation createJoin(int environmentLength, JumpCollector jumps) { | |
| 1856 assert(jumps.length >= 2); | |
| 1857 | |
| 1858 // Compute which values are identical on all paths reaching the join. | |
| 1859 // Handle the common case of a pair of contexts efficiently. | |
| 1860 Environment first = jumps.environments[0]; | |
| 1861 Environment second = jumps.environments[1]; | |
| 1862 assert(environmentLength <= first.length); | |
| 1863 assert(environmentLength <= second.length); | |
| 1864 assert(first.sameDomain(environmentLength, second)); | |
| 1865 // A running count of the join-point parameters. | |
| 1866 int parameterCount = 0; | |
| 1867 // The null elements of common correspond to required parameters of the | |
| 1868 // join-point continuation. | |
| 1869 List<ir.Primitive> common = | |
| 1870 new List<ir.Primitive>.generate(environmentLength, | |
| 1871 (i) { | |
| 1872 ir.Primitive candidate = first[i]; | |
| 1873 if (second[i] == candidate) { | |
| 1874 return candidate; | |
| 1875 } else { | |
| 1876 ++parameterCount; | |
| 1877 return null; | |
| 1878 } | |
| 1879 }); | |
| 1880 // If there is already a parameter for each variable, the other | |
| 1881 // environments do not need to be considered. | |
| 1882 if (parameterCount < environmentLength) { | |
| 1883 for (int i = 0; i < environmentLength; ++i) { | |
| 1884 ir.Primitive candidate = common[i]; | |
| 1885 if (candidate == null) continue; | |
| 1886 for (Environment current in jumps.environments.skip(2)) { | |
| 1887 assert(environmentLength <= current.length); | |
| 1888 assert(first.sameDomain(environmentLength, current)); | |
| 1889 if (candidate != current[i]) { | |
| 1890 common[i] = null; | |
| 1891 ++parameterCount; | |
| 1892 break; | |
| 1893 } | |
| 1894 } | |
| 1895 if (parameterCount >= environmentLength) break; | |
| 1896 } | |
| 1897 } | |
| 1898 | |
| 1899 // Create the join point continuation. | |
| 1900 List<ir.Parameter> parameters = <ir.Parameter>[]; | |
| 1901 parameters.length = parameterCount; | |
| 1902 int index = 0; | |
| 1903 for (int i = 0; i < environmentLength; ++i) { | |
| 1904 if (common[i] == null) { | |
| 1905 parameters[index++] = new ir.Parameter(first.index2variable[i]); | |
| 1906 } | |
| 1907 } | |
| 1908 assert(index == parameterCount); | |
| 1909 ir.Continuation join = new ir.Continuation(parameters); | |
| 1910 | |
| 1911 // Fill in all the continuation invocations. | |
| 1912 for (int i = 0; i < jumps.length; ++i) { | |
| 1913 Environment currentEnvironment = jumps.environments[i]; | |
| 1914 ir.InvokeContinuation invoke = jumps.invocations[i]; | |
| 1915 // Sharing this.environment with one of the invocations will not do | |
| 1916 // the right thing (this.environment has already been mutated). | |
| 1917 List<ir.Reference> arguments = <ir.Reference>[]; | |
| 1918 arguments.length = parameterCount; | |
| 1919 int index = 0; | |
| 1920 for (int i = 0; i < environmentLength; ++i) { | |
| 1921 if (common[i] == null) { | |
| 1922 arguments[index++] = new ir.Reference(currentEnvironment[i]); | |
| 1923 } | |
| 1924 } | |
| 1925 invoke.continuation = new ir.Reference(join); | |
| 1926 invoke.arguments = arguments; | |
| 1927 } | |
| 1928 | |
| 1929 // Mutate this.environment to be the environment at the join point. Do | |
| 1930 // this after adding the continuation invocations, because this.environment | |
| 1931 // might be collected by the jump collector and so the old environment | |
| 1932 // values are needed for the continuation invocation. | |
| 1933 // | |
| 1934 // Iterate to environment.length because environmentLength includes values | |
| 1935 // outside the environment which are 'phantom' variables used for the | |
| 1936 // values of expressions like &&, ||, and ?:. | |
| 1937 index = 0; | |
| 1938 for (int i = 0; i < environment.length; ++i) { | |
| 1939 if (common[i] == null) { | |
| 1940 environment.index2value[i] = parameters[index++]; | |
| 1941 } | |
| 1942 } | |
| 1943 | |
|
asgerf
2015/04/07 13:42:42
I think red is my new favorite color.
| |
| 1944 return join; | |
| 1945 } | 1923 } |
| 1946 } | 1924 } |
| 1947 | 1925 |
| 1948 /// Shared state between DartIrBuilders within the same method. | 1926 /// Shared state between DartIrBuilders within the same method. |
| 1949 class DartIrBuilderSharedState { | 1927 class DartIrBuilderSharedState { |
| 1950 /// Maps local variables to their corresponding [MutableVariable] object. | 1928 /// Maps local variables to their corresponding [MutableVariable] object. |
| 1951 final Map<Local, ir.MutableVariable> local2mutable = | 1929 final Map<Local, ir.MutableVariable> local2mutable = |
| 1952 <Local, ir.MutableVariable>{}; | 1930 <Local, ir.MutableVariable>{}; |
| 1953 | 1931 |
| 1954 // Move this to the IrBuilderVisitor. | 1932 // Move this to the IrBuilderVisitor. |
| (...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2585 } | 2563 } |
| 2586 | 2564 |
| 2587 /// Synthetic parameter to a JavaScript factory method that takes the type | 2565 /// Synthetic parameter to a JavaScript factory method that takes the type |
| 2588 /// argument given for the type variable [variable]. | 2566 /// argument given for the type variable [variable]. |
| 2589 class TypeInformationParameter implements Local { | 2567 class TypeInformationParameter implements Local { |
| 2590 final TypeVariableElement variable; | 2568 final TypeVariableElement variable; |
| 2591 final ExecutableElement executableContext; | 2569 final ExecutableElement executableContext; |
| 2592 TypeInformationParameter(this.variable, this.executableContext); | 2570 TypeInformationParameter(this.variable, this.executableContext); |
| 2593 String get name => variable.name; | 2571 String get name => variable.name; |
| 2594 } | 2572 } |
| OLD | NEW |