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