| 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 '../compile_time_constants.dart' show BackendConstantEnvironment; | 7 import '../compile_time_constants.dart' show BackendConstantEnvironment; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/expressions.dart'; | 9 import '../constants/expressions.dart'; |
| 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; | 10 import '../constants/values.dart' show ConstantValue, PrimitiveConstantValue; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 index2value = other.index2variable.map((Local local) { | 61 index2value = other.index2variable.map((Local local) { |
| 62 return new ir.Parameter(local); | 62 return new ir.Parameter(local); |
| 63 }).toList(); | 63 }).toList(); |
| 64 | 64 |
| 65 get length => index2variable.length; | 65 get length => index2variable.length; |
| 66 | 66 |
| 67 ir.Primitive operator [](int index) => index2value[index]; | 67 ir.Primitive operator [](int index) => index2value[index]; |
| 68 | 68 |
| 69 void extend(Local element, ir.Primitive value) { | 69 void extend(Local element, ir.Primitive value) { |
| 70 // Assert that the name is not already in the environment. `null` is used | 70 // Assert that the name is not already in the environment. `null` is used |
| 71 // as the name of anonymous variables. Because the variable2index map is | 71 // as the name of anonymous variables. |
| 72 // shared, `null` can already occur. This is safe because such variables | 72 assert(!variable2index.containsKey(element)); |
| 73 // are not looked up by name. | 73 if (element != null) variable2index[element] = index2variable.length; |
| 74 // | |
| 75 // TODO(kmillikin): This is still kind of fishy. Refactor to not share | |
| 76 // name maps or else garbage collect unneeded names. | |
| 77 assert(element == null || !variable2index.containsKey(element)); | |
| 78 variable2index[element] = index2variable.length; | |
| 79 index2variable.add(element); | 74 index2variable.add(element); |
| 80 index2value.add(value); | 75 index2value.add(value); |
| 81 } | 76 } |
| 82 | 77 |
| 83 void discard(int count) { | 78 /// Drop [count] values from the environment. |
| 79 /// |
| 80 /// Return the previous last value in the environment for convenience. |
| 81 ir.Primitive discard(int count) { |
| 82 assert(count > 0); |
| 84 assert(count <= index2variable.length); | 83 assert(count <= index2variable.length); |
| 84 ir.Primitive value = index2value.last; |
| 85 // The map from variables to their index are shared, so we cannot remove | 85 // The map from variables to their index are shared, so we cannot remove |
| 86 // the mapping in `variable2index`. | 86 // the mapping in `variable2index`. |
| 87 index2variable.length -= count; | 87 index2variable.length -= count; |
| 88 index2value.length -= count; | 88 index2value.length -= count; |
| 89 return value; |
| 89 } | 90 } |
| 90 | 91 |
| 91 ir.Primitive lookup(Local element) { | 92 ir.Primitive lookup(Local element) { |
| 92 assert(invariant(element, variable2index.containsKey(element), | 93 assert(invariant(element, variable2index.containsKey(element), |
| 93 message: "Unknown variable: $element.")); | 94 message: "Unknown variable: $element.")); |
| 94 return index2value[variable2index[element]]; | 95 return index2value[variable2index[element]]; |
| 95 } | 96 } |
| 96 | 97 |
| 97 void update(Local element, ir.Primitive value) { | 98 void update(Local element, ir.Primitive value) { |
| 98 index2value[variable2index[element]] = value; | 99 index2value[variable2index[element]] = value; |
| 99 } | 100 } |
| 100 | 101 |
| 101 /// Verify that the variable2index and index2variable maps agree up to the | 102 /// Verify that the variable2index and index2variable maps agree up to the |
| 102 /// index [length] exclusive. | 103 /// index [length] exclusive. |
| 103 bool sameDomain(int length, Environment other) { | 104 bool sameDomain(int length, Environment other) { |
| 104 assert(this.length >= length); | 105 assert(this.length >= length); |
| 105 assert(other.length >= length); | 106 assert(other.length >= length); |
| 106 for (int i = 0; i < length; ++i) { | 107 for (int i = 0; i < length; ++i) { |
| 107 // An index maps to the same variable in both environments. | 108 // An index maps to the same variable in both environments. |
| 108 Local variable = index2variable[i]; | 109 Local variable = index2variable[i]; |
| 109 if (variable != other.index2variable[i]) return false; | 110 if (variable != other.index2variable[i]) return false; |
| 110 | 111 |
| 111 // The variable maps to the same index in both environments. | 112 // A named variable maps to the same index in both environments. |
| 112 int index = variable2index[variable]; | 113 if (variable != null) { |
| 113 if (index == null || index != other.variable2index[variable]) { | 114 int index = variable2index[variable]; |
| 114 return false; | 115 if (index == null || index != other.variable2index[variable]) { |
| 116 return false; |
| 117 } |
| 115 } | 118 } |
| 116 } | 119 } |
| 117 return true; | 120 return true; |
| 118 } | 121 } |
| 119 | 122 |
| 120 bool contains(Local local) => variable2index.containsKey(local); | 123 bool contains(Local local) => variable2index.containsKey(local); |
| 121 } | 124 } |
| 122 | 125 |
| 123 /// The abstract base class of objects that emit jumps to a continuation and | 126 /// The abstract base class of objects that emit jumps to a continuation and |
| 124 /// give a handle to the continuation and its environment. | 127 /// give a handle to the continuation and its environment. |
| 125 abstract class JumpCollector { | 128 abstract class JumpCollector { |
| 126 final JumpTarget target; | 129 final JumpTarget target; |
| 127 | 130 |
| 128 ir.Continuation _continuation = null; | 131 ir.Continuation _continuation = null; |
| 129 final Environment _continuationEnvironment; | 132 final Environment _continuationEnvironment; |
| 130 | 133 |
| 131 final List<Iterable<LocalVariableElement>> _boxedTryVariables = | 134 final List<Iterable<LocalVariableElement>> _boxedTryVariables = |
| 132 <Iterable<LocalVariableElement>>[]; | 135 <Iterable<LocalVariableElement>>[]; |
| 133 | 136 |
| 134 JumpCollector(this._continuationEnvironment, this.target); | 137 /// Construct a collector for a given environment and optionally a target. |
| 138 /// |
| 139 /// The environment is the one in effect at the point where the jump's |
| 140 /// continuation will be bound. Continuations can take an extra argument |
| 141 /// (see [addJump]). |
| 142 JumpCollector(this._continuationEnvironment, this.target, |
| 143 bool hasExtraArgument) { |
| 144 if (hasExtraArgument) _continuationEnvironment.extend(null, null); |
| 145 } |
| 135 | 146 |
| 136 /// True if the collector has not recorded any jumps to its continuation. | 147 /// True if the collector has not recorded any jumps to its continuation. |
| 137 bool get isEmpty; | 148 bool get isEmpty; |
| 138 | 149 |
| 139 /// The continuation encapsulated by this collector. | 150 /// The continuation encapsulated by this collector. |
| 140 ir.Continuation get continuation; | 151 ir.Continuation get continuation; |
| 141 | 152 |
| 142 /// The compile-time environment to be used for translating code in the body | 153 /// The compile-time environment to be used for translating code in the body |
| 143 /// of the continuation. | 154 /// of the continuation. |
| 144 Environment get environment; | 155 Environment get environment; |
| 145 | 156 |
| 146 /// Emit a jump to the continuation for a given [IrBuilder]. | 157 /// Emit a jump to the continuation for a given [IrBuilder]. |
| 147 void addJump(IrBuilder builder); | 158 /// |
| 159 /// Jumps can take a single extra argument. This is used to pass return |
| 160 /// values to finally blocks for returns inside try/finally and to pass |
| 161 /// values of expressions that have internal control flow to their join-point |
| 162 /// continuations. |
| 163 void addJump(IrBuilder builder, [ir.Primitive value]); |
| 148 | 164 |
| 149 /// Add a set of variables that were boxed on entry to a try block. | 165 /// Add a set of variables that were boxed on entry to a try block. |
| 150 /// | 166 /// |
| 151 /// All jumps from a try block to targets outside have to unbox the | 167 /// All jumps from a try block to targets outside have to unbox the |
| 152 /// variables that were boxed on entry before invoking the target | 168 /// variables that were boxed on entry before invoking the target |
| 153 /// continuation. Call this function before translating a try block and | 169 /// continuation. Call this function before translating a try block and |
| 154 /// call [leaveTry] after translating it. | 170 /// call [leaveTry] after translating it. |
| 155 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { | 171 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { |
| 156 // The boxed variables are maintained as a stack to make leaving easy. | 172 // The boxed variables are maintained as a stack to make leaving easy. |
| 157 _boxedTryVariables.add(boxedOnEntry); | 173 _boxedTryVariables.add(boxedOnEntry); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 class ForwardJumpCollector extends JumpCollector { | 215 class ForwardJumpCollector extends JumpCollector { |
| 200 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; | 216 final List<ir.InvokeContinuation> _invocations = <ir.InvokeContinuation>[]; |
| 201 final List<Environment> _invocationEnvironments = <Environment>[]; | 217 final List<Environment> _invocationEnvironments = <Environment>[]; |
| 202 | 218 |
| 203 /// Construct a collector with a given base environment. | 219 /// Construct a collector with a given base environment. |
| 204 /// | 220 /// |
| 205 /// The base environment is the one in scope at the site that the | 221 /// The base environment is the one in scope at the site that the |
| 206 /// continuation represented by this collector will be bound. The | 222 /// continuation represented by this collector will be bound. The |
| 207 /// environment is copied by the collector. Subsequent mutation of the | 223 /// environment is copied by the collector. Subsequent mutation of the |
| 208 /// original environment will not affect the collector. | 224 /// original environment will not affect the collector. |
| 209 ForwardJumpCollector(Environment environment, {JumpTarget target: null}) | 225 ForwardJumpCollector(Environment environment, |
| 210 : super(new Environment.from(environment), target); | 226 {JumpTarget target, bool hasExtraArgument: false}) |
| 227 : super(new Environment.from(environment), target, hasExtraArgument); |
| 211 | 228 |
| 212 bool get isEmpty => _invocations.isEmpty; | 229 bool get isEmpty => _invocations.isEmpty; |
| 213 | 230 |
| 214 ir.Continuation get continuation { | 231 ir.Continuation get continuation { |
| 215 if (_continuation == null) _setContinuation(); | 232 if (_continuation == null) _setContinuation(); |
| 216 return _continuation; | 233 return _continuation; |
| 217 } | 234 } |
| 218 | 235 |
| 219 Environment get environment { | 236 Environment get environment { |
| 220 if (_continuation == null) _setContinuation(); | 237 if (_continuation == null) _setContinuation(); |
| 221 return _continuationEnvironment; | 238 return _continuationEnvironment; |
| 222 } | 239 } |
| 223 | 240 |
| 224 void addJump(IrBuilder builder) { | 241 void addJump(IrBuilder builder, [ir.Primitive value]) { |
| 225 assert(_continuation == null); | 242 assert(_continuation == null); |
| 226 _buildTryExit(builder); | 243 _buildTryExit(builder); |
| 227 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); | 244 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized(); |
| 228 builder.add(invoke); | 245 builder.add(invoke); |
| 229 _invocations.add(invoke); | 246 _invocations.add(invoke); |
| 247 // Truncate the environment at the invocation site so it only includes |
| 248 // values that will be continuation arguments. If an extra value is passed |
| 249 // it will already be included in the continuation environment, but it is |
| 250 // not present in the invocation environment. |
| 251 int delta = builder.environment.length - _continuationEnvironment.length; |
| 252 if (value != null) ++delta; |
| 253 if (delta > 0) builder.environment.discard(delta); |
| 254 if (value != null) builder.environment.extend(null, value); |
| 230 _invocationEnvironments.add(builder.environment); | 255 _invocationEnvironments.add(builder.environment); |
| 231 builder._current = null; | 256 builder._current = null; |
| 232 // TODO(kmillikin): Can we set builder.environment to null to make it | 257 // TODO(kmillikin): Can we set builder.environment to null to make it |
| 233 // less likely to mutate it? | 258 // less likely to mutate it? |
| 234 } | 259 } |
| 235 | 260 |
| 236 void _setContinuation() { | 261 void _setContinuation() { |
| 237 assert(_continuation == null); | 262 assert(_continuation == null); |
| 238 // We have seen all invocations of this continuation, and recorded the | 263 // We have seen all invocations of this continuation, and recorded the |
| 239 // environment in effect at each invocation site. | 264 // environment in effect at each invocation site. |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 301 /// parameter for each variable in scope at the entry to the continuation, | 326 /// parameter for each variable in scope at the entry to the continuation, |
| 302 /// before emitting any jump to the continuation. When a jump is added, it | 327 /// before emitting any jump to the continuation. When a jump is added, it |
| 303 /// is given an argument for each continuation parameter. | 328 /// is given an argument for each continuation parameter. |
| 304 class BackwardJumpCollector extends JumpCollector { | 329 class BackwardJumpCollector extends JumpCollector { |
| 305 /// Construct a collector with a given base environment. | 330 /// Construct a collector with a given base environment. |
| 306 /// | 331 /// |
| 307 /// The base environment is the one in scope at the site that the | 332 /// The base environment is the one in scope at the site that the |
| 308 /// continuation represented by this collector will be bound. The | 333 /// continuation represented by this collector will be bound. The |
| 309 /// translation of the continuation body will use an environment with the | 334 /// translation of the continuation body will use an environment with the |
| 310 /// same shape, but with fresh continuation parameters for each variable. | 335 /// same shape, but with fresh continuation parameters for each variable. |
| 311 BackwardJumpCollector(Environment environment, {JumpTarget target: null}) | 336 BackwardJumpCollector(Environment environment, |
| 312 : super(new Environment.fresh(environment), target) { | 337 {JumpTarget target, bool hasExtraArgument: false}) |
| 338 : super(new Environment.fresh(environment), target, hasExtraArgument) { |
| 313 List<ir.Parameter> parameters = | 339 List<ir.Parameter> parameters = |
| 314 new List<ir.Parameter>.from(_continuationEnvironment.index2value); | 340 new List<ir.Parameter>.from(_continuationEnvironment.index2value); |
| 315 _continuation = new ir.Continuation(parameters, isRecursive: true); | 341 _continuation = new ir.Continuation(parameters, isRecursive: true); |
| 316 } | 342 } |
| 317 | 343 |
| 318 bool isEmpty = true; | 344 bool isEmpty = true; |
| 319 | 345 |
| 320 ir.Continuation get continuation => _continuation; | 346 ir.Continuation get continuation => _continuation; |
| 321 Environment get environment => _continuationEnvironment; | 347 Environment get environment => _continuationEnvironment; |
| 322 | 348 |
| 323 void addJump(IrBuilder builder) { | 349 void addJump(IrBuilder builder, [ir.Primitive value]) { |
| 324 assert(_continuation.parameters.length <= builder.environment.length); | 350 assert(_continuation.parameters.length <= builder.environment.length); |
| 325 isEmpty = false; | 351 isEmpty = false; |
| 326 _buildTryExit(builder); | 352 _buildTryExit(builder); |
| 353 // Truncate the environment at the invocation site so it only includes |
| 354 // values that will be continuation arguments. If an extra value is passed |
| 355 // it will already be included in the continuation environment, but it is |
| 356 // not present in the invocation environment. |
| 357 int delta = builder.environment.length - _continuationEnvironment.length; |
| 358 if (value != null) ++delta; |
| 359 if (delta > 0) builder.environment.discard(delta); |
| 360 if (value != null) builder.environment.extend(null, value); |
| 327 builder.add(new ir.InvokeContinuation(_continuation, | 361 builder.add(new ir.InvokeContinuation(_continuation, |
| 328 builder.environment.index2value.take(_continuation.parameters.length) | 362 builder.environment.index2value, |
| 329 .toList(), | |
| 330 isRecursive: true)); | 363 isRecursive: true)); |
| 331 builder._current = null; | 364 builder._current = null; |
| 332 } | 365 } |
| 333 } | 366 } |
| 334 | 367 |
| 335 /// Function for building a node in the context of the current builder. | 368 /// Function for building a node in the context of the current builder. |
| 336 typedef ir.Node BuildFunction(node); | 369 typedef ir.Node BuildFunction(node); |
| 337 | 370 |
| 338 /// Function for building nodes in the context of the provided [builder]. | 371 /// Function for building nodes in the context of the provided [builder]. |
| 339 typedef ir.Node SubbuildFunction(IrBuilder builder); | 372 typedef ir.Node SubbuildFunction(IrBuilder builder); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 } | 420 } |
| 388 } | 421 } |
| 389 | 422 |
| 390 /// Shared state between delimited IrBuilders within the same function. | 423 /// Shared state between delimited IrBuilders within the same function. |
| 391 class IrBuilderSharedState { | 424 class IrBuilderSharedState { |
| 392 final BackendConstantEnvironment constants; | 425 final BackendConstantEnvironment constants; |
| 393 | 426 |
| 394 ConstantSystem get constantSystem => constants.constantSystem; | 427 ConstantSystem get constantSystem => constants.constantSystem; |
| 395 | 428 |
| 396 /// A stack of collectors for breaks. | 429 /// A stack of collectors for breaks. |
| 397 final List<JumpCollector> breakCollectors = <JumpCollector>[]; | 430 List<JumpCollector> breakCollectors = <JumpCollector>[]; |
| 398 | 431 |
| 399 /// A stack of collectors for continues. | 432 /// A stack of collectors for continues. |
| 400 final List<JumpCollector> continueCollectors = <JumpCollector>[]; | 433 List<JumpCollector> continueCollectors = <JumpCollector>[]; |
| 401 | 434 |
| 402 final ExecutableElement currentElement; | 435 final ExecutableElement currentElement; |
| 403 | 436 |
| 404 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 437 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
| 438 |
| 439 /// The target of a return from the function. |
| 440 /// |
| 441 /// A null value indicates that the target is the function's return |
| 442 /// continuation. Otherwise, when inside the try block of try/finally |
| 443 /// a return is intercepted to give a place to generate the finally code. |
| 444 JumpCollector returnCollector = null; |
| 445 |
| 405 ir.Parameter _thisParameter; | 446 ir.Parameter _thisParameter; |
| 406 ir.Parameter enclosingMethodThisParameter; | 447 ir.Parameter enclosingMethodThisParameter; |
| 407 | 448 |
| 408 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; | 449 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
| 409 | 450 |
| 410 IrBuilderSharedState(this.constants, this.currentElement); | 451 IrBuilderSharedState(this.constants, this.currentElement); |
| 411 | 452 |
| 412 ir.Parameter get thisParameter => _thisParameter; | 453 ir.Parameter get thisParameter => _thisParameter; |
| 413 void set thisParameter(ir.Parameter value) { | 454 void set thisParameter(ir.Parameter value) { |
| 414 assert(_thisParameter == null); | 455 assert(_thisParameter == null); |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 IrBuilder elseBuilder = makeDelimitedBuilder(); | 784 IrBuilder elseBuilder = makeDelimitedBuilder(); |
| 744 ir.Primitive thenValue = buildThenExpression(thenBuilder); | 785 ir.Primitive thenValue = buildThenExpression(thenBuilder); |
| 745 ir.Primitive elseValue = buildElseExpression(elseBuilder); | 786 ir.Primitive elseValue = buildElseExpression(elseBuilder); |
| 746 | 787 |
| 747 // Treat the values of the subexpressions as named values in the | 788 // Treat the values of the subexpressions as named values in the |
| 748 // environment, so they will be treated as arguments to the join-point | 789 // environment, so they will be treated as arguments to the join-point |
| 749 // continuation. We know the environments are the right size because | 790 // continuation. We know the environments are the right size because |
| 750 // expressions cannot introduce variable bindings. | 791 // expressions cannot introduce variable bindings. |
| 751 assert(environment.length == thenBuilder.environment.length); | 792 assert(environment.length == thenBuilder.environment.length); |
| 752 assert(environment.length == elseBuilder.environment.length); | 793 assert(environment.length == elseBuilder.environment.length); |
| 753 // Extend the join-point environment with a placeholder for the value of | 794 JumpCollector join = |
| 754 // the expression. Optimistically assume that the value is the value of | 795 new ForwardJumpCollector(environment, hasExtraArgument: true); |
| 755 // the first subexpression. This value might noe even be in scope at the | 796 thenBuilder.jumpTo(join, thenValue); |
| 756 // join-point because it's bound in the first subexpression. However, if | 797 elseBuilder.jumpTo(join, elseValue); |
| 757 // that is the case, it will necessarily differ from the value of the | |
| 758 // other subexpression and cause the introduction of a join-point | |
| 759 // continuation parameter. If the two values do happen to be the same, | |
| 760 // this will avoid inserting a useless continuation parameter. | |
| 761 environment.extend(null, thenValue); | |
| 762 thenBuilder.environment.extend(null, thenValue); | |
| 763 elseBuilder.environment.extend(null, elseValue); | |
| 764 JumpCollector join = new ForwardJumpCollector(environment); | |
| 765 thenBuilder.jumpTo(join); | |
| 766 elseBuilder.jumpTo(join); | |
| 767 | 798 |
| 768 // Build the term | 799 // Build the term |
| 769 // let cont join(x, ..., result) = [] in | 800 // let cont join(x, ..., result) = [] in |
| 770 // let cont then() = [[thenPart]]; join(v, ...) | 801 // let cont then() = [[thenPart]]; join(v, ...) |
| 771 // and else() = [[elsePart]]; join(v, ...) | 802 // and else() = [[elsePart]]; join(v, ...) |
| 772 // in | 803 // in |
| 773 // if condition (then, else) | 804 // if condition (then, else) |
| 774 ir.Continuation thenContinuation = new ir.Continuation([]); | 805 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 775 ir.Continuation elseContinuation = new ir.Continuation([]); | 806 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 776 thenContinuation.body = thenBuilder._root; | 807 thenContinuation.body = thenBuilder._root; |
| 777 elseContinuation.body = elseBuilder._root; | 808 elseContinuation.body = elseBuilder._root; |
| 778 add(new ir.LetCont(join.continuation, | 809 add(new ir.LetCont(join.continuation, |
| 779 new ir.LetCont.many(<ir.Continuation>[thenContinuation, | 810 new ir.LetCont.many(<ir.Continuation>[thenContinuation, |
| 780 elseContinuation], | 811 elseContinuation], |
| 781 new ir.Branch(new ir.IsTrue(condition), | 812 new ir.Branch(new ir.IsTrue(condition), |
| 782 thenContinuation, | 813 thenContinuation, |
| 783 elseContinuation)))); | 814 elseContinuation)))); |
| 784 environment = join.environment; | 815 environment = join.environment; |
| 785 environment.discard(1); | 816 return environment.discard(1); |
| 786 return (thenValue == elseValue) | |
| 787 ? thenValue | |
| 788 : join.continuation.parameters.last; | |
| 789 } | 817 } |
| 790 | 818 |
| 791 /** | 819 /** |
| 792 * Add an explicit `return null` for functions that don't have a return | 820 * Add an explicit `return null` for functions that don't have a return |
| 793 * statement on each branch. This includes functions with an empty body, | 821 * statement on each branch. This includes functions with an empty body, |
| 794 * such as `foo(){ }`. | 822 * such as `foo(){ }`. |
| 795 */ | 823 */ |
| 796 void _ensureReturn() { | 824 void _ensureReturn() { |
| 797 if (!isOpen) return; | 825 if (!isOpen) return; |
| 798 ir.Constant constant = buildNullConstant(); | 826 ir.Constant constant = buildNullConstant(); |
| (...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1162 if (elseBuilder._root != null) _current = elseBuilder._current; | 1190 if (elseBuilder._root != null) _current = elseBuilder._current; |
| 1163 environment = elseBuilder.environment; | 1191 environment = elseBuilder.environment; |
| 1164 } else { | 1192 } else { |
| 1165 _current = null; | 1193 _current = null; |
| 1166 } | 1194 } |
| 1167 } else { | 1195 } else { |
| 1168 environment = join.environment; | 1196 environment = join.environment; |
| 1169 } | 1197 } |
| 1170 } | 1198 } |
| 1171 | 1199 |
| 1172 void jumpTo(JumpCollector collector) { | 1200 void jumpTo(JumpCollector collector, [ir.Primitive value]) { |
| 1173 collector.addJump(this); | 1201 collector.addJump(this, value); |
| 1174 } | 1202 } |
| 1175 | 1203 |
| 1176 void addRecursiveContinuation(BackwardJumpCollector collector) { | 1204 void addRecursiveContinuation(BackwardJumpCollector collector) { |
| 1177 assert(environment.length == collector.environment.length); | 1205 assert(environment.length == collector.environment.length); |
| 1178 add(new ir.LetCont(collector.continuation, | 1206 add(new ir.LetCont(collector.continuation, |
| 1179 new ir.InvokeContinuation(collector.continuation, | 1207 new ir.InvokeContinuation(collector.continuation, |
| 1180 environment.index2value))); | 1208 environment.index2value))); |
| 1181 environment = collector.environment; | 1209 environment = collector.environment; |
| 1182 } | 1210 } |
| 1183 | 1211 |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1708 /// | 1736 /// |
| 1709 /// [tryInfo] provides information on local variables declared and boxed | 1737 /// [tryInfo] provides information on local variables declared and boxed |
| 1710 /// within this try statement. | 1738 /// within this try statement. |
| 1711 /// [buildTryBlock] builds the try block. | 1739 /// [buildTryBlock] builds the try block. |
| 1712 /// [catchClauseInfos] provides access to the catch type, exception variable, | 1740 /// [catchClauseInfos] provides access to the catch type, exception variable, |
| 1713 /// and stack trace variable, and a function for building the catch block. | 1741 /// and stack trace variable, and a function for building the catch block. |
| 1714 void buildTry( | 1742 void buildTry( |
| 1715 {TryStatementInfo tryStatementInfo, | 1743 {TryStatementInfo tryStatementInfo, |
| 1716 SubbuildFunction buildTryBlock, | 1744 SubbuildFunction buildTryBlock, |
| 1717 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], | 1745 List<CatchClauseInfo> catchClauseInfos: const <CatchClauseInfo>[], |
| 1746 SubbuildFunction buildFinallyBlock, |
| 1718 ClosureClassMap closureClassMap}) { | 1747 ClosureClassMap closureClassMap}) { |
| 1719 assert(isOpen); | 1748 assert(isOpen); |
| 1720 | 1749 |
| 1721 // Catch handlers are in scope for their body. The CPS translation of | 1750 // Catch handlers are in scope for their body. The CPS translation of |
| 1722 // [[try tryBlock catch (e) catchBlock; successor]] is: | 1751 // [[try tryBlock catch (e) catchBlock; successor]] is: |
| 1723 // | 1752 // |
| 1724 // let cont join(v0, v1, ...) = [[successor]] in | 1753 // let cont join(v0, v1, ...) = [[successor]] in |
| 1725 // let mutable m0 = x0 in | 1754 // let mutable m0 = x0 in |
| 1726 // let mutable m1 = x1 in | 1755 // let mutable m1 = x1 in |
| 1727 // ... | 1756 // ... |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1740 // | 1769 // |
| 1741 // In other words, both the try and catch block are in the scope of the | 1770 // In other words, both the try and catch block are in the scope of the |
| 1742 // join-point continuation, and they are both in the scope of a sequence | 1771 // join-point continuation, and they are both in the scope of a sequence |
| 1743 // of mutable bindings for the variables assigned in the try. The join- | 1772 // of mutable bindings for the variables assigned in the try. The join- |
| 1744 // point continuation is not in the scope of these mutable bindings. | 1773 // point continuation is not in the scope of these mutable bindings. |
| 1745 // The tryBlock is in the scope of a binding for the catch handler. Each | 1774 // The tryBlock is in the scope of a binding for the catch handler. Each |
| 1746 // instruction (specifically, each call) in the tryBlock is in the dynamic | 1775 // instruction (specifically, each call) in the tryBlock is in the dynamic |
| 1747 // scope of the handler. The mutable bindings are dereferenced at the end | 1776 // scope of the handler. The mutable bindings are dereferenced at the end |
| 1748 // of the try block and at the beginning of the catch block, so the | 1777 // of the try block and at the beginning of the catch block, so the |
| 1749 // variables are unboxed in the catch block and at the join point. | 1778 // variables are unboxed in the catch block and at the join point. |
| 1750 JumpCollector join = new ForwardJumpCollector(environment); | 1779 if (catchClauseInfos.isNotEmpty) { |
| 1751 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); | 1780 JumpCollector join = new ForwardJumpCollector(environment); |
| 1752 | 1781 IrBuilder tryCatchBuilder = makeDelimitedBuilder(); |
| 1753 // Variables treated as mutable in a try are not mutable outside of it. | 1782 |
| 1754 // Work with a copy of the outer builder's mutable variables. | 1783 // Variables treated as mutable in a try are not mutable outside of it. |
| 1755 tryCatchBuilder.mutableVariables = | 1784 // Work with a copy of the outer builder's mutable variables. |
| 1756 new Map<Local, ir.MutableVariable>.from(mutableVariables); | 1785 tryCatchBuilder.mutableVariables = |
| 1757 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | 1786 new Map<Local, ir.MutableVariable>.from(mutableVariables); |
| 1758 assert(!tryCatchBuilder.isInMutableVariable(variable)); | 1787 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1759 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); | 1788 assert(!tryCatchBuilder.isInMutableVariable(variable)); |
| 1760 tryCatchBuilder.makeMutableVariable(variable); | 1789 ir.Primitive value = tryCatchBuilder.buildLocalVariableGet(variable); |
| 1761 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); | 1790 tryCatchBuilder.makeMutableVariable(variable); |
| 1791 tryCatchBuilder.declareLocalVariable(variable, initialValue: value); |
| 1792 } |
| 1793 |
| 1794 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1795 |
| 1796 void interceptJump(JumpCollector collector) { |
| 1797 collector.enterTry(tryStatementInfo.boxedOnEntry); |
| 1798 } |
| 1799 void restoreJump(JumpCollector collector) { |
| 1800 collector.leaveTry(); |
| 1801 } |
| 1802 tryBuilder.state.breakCollectors.forEach(interceptJump); |
| 1803 tryBuilder.state.continueCollectors.forEach(interceptJump); |
| 1804 buildTryBlock(tryBuilder); |
| 1805 if (tryBuilder.isOpen) { |
| 1806 interceptJump(join); |
| 1807 tryBuilder.jumpTo(join); |
| 1808 restoreJump(join); |
| 1809 } |
| 1810 tryBuilder.state.breakCollectors.forEach(restoreJump); |
| 1811 tryBuilder.state.continueCollectors.forEach(restoreJump); |
| 1812 |
| 1813 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); |
| 1814 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1815 assert(catchBuilder.isInMutableVariable(variable)); |
| 1816 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); |
| 1817 // After this point, the variables that were boxed on entry to the try |
| 1818 // are no longer treated as mutable. |
| 1819 catchBuilder.removeMutableVariable(variable); |
| 1820 catchBuilder.environment.update(variable, value); |
| 1821 } |
| 1822 |
| 1823 // Handlers are always translated as having both exception and stack trace |
| 1824 // parameters. Multiple clauses do not have to use the same names for |
| 1825 // them. Choose the first of each as the name hint for the respective |
| 1826 // handler parameter. |
| 1827 ir.Parameter exceptionParameter = |
| 1828 new ir.Parameter(catchClauseInfos.first.exceptionVariable); |
| 1829 LocalVariableElement traceVariable; |
| 1830 CatchClauseInfo catchAll; |
| 1831 for (int i = 0; i < catchClauseInfos.length; ++i) { |
| 1832 CatchClauseInfo info = catchClauseInfos[i]; |
| 1833 if (info.type == null) { |
| 1834 catchAll = info; |
| 1835 catchClauseInfos.length = i; |
| 1836 break; |
| 1837 } |
| 1838 if (traceVariable == null) { |
| 1839 traceVariable = info.stackTraceVariable; |
| 1840 } |
| 1841 } |
| 1842 ir.Parameter traceParameter = new ir.Parameter(traceVariable); |
| 1843 // Expand multiple catch clauses into an explicit if/then/else. Iterate |
| 1844 // them in reverse so the current block becomes the next else block. |
| 1845 ir.Expression catchBody; |
| 1846 if (catchAll == null) { |
| 1847 catchBody = new ir.Rethrow(); |
| 1848 } else { |
| 1849 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); |
| 1850 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable, |
| 1851 initialValue: exceptionParameter); |
| 1852 if (catchAll.stackTraceVariable != null) { |
| 1853 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable, |
| 1854 initialValue: traceParameter); |
| 1855 } |
| 1856 catchAll.buildCatchBlock(clauseBuilder); |
| 1857 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); |
| 1858 catchBody = clauseBuilder._root; |
| 1859 } |
| 1860 for (CatchClauseInfo clause in catchClauseInfos.reversed) { |
| 1861 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); |
| 1862 clauseBuilder.declareLocalVariable(clause.exceptionVariable, |
| 1863 initialValue: exceptionParameter); |
| 1864 if (clause.stackTraceVariable != null) { |
| 1865 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, |
| 1866 initialValue: traceParameter); |
| 1867 } |
| 1868 clause.buildCatchBlock(clauseBuilder); |
| 1869 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); |
| 1870 ir.Continuation thenContinuation = new ir.Continuation([]); |
| 1871 thenContinuation.body = clauseBuilder._root; |
| 1872 ir.Continuation elseContinuation = new ir.Continuation([]); |
| 1873 elseContinuation.body = catchBody; |
| 1874 |
| 1875 // Build the type test guarding this clause. We can share the |
| 1876 // environment with the nested builder because this part cannot mutate |
| 1877 // it. |
| 1878 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); |
| 1879 ir.Primitive typeMatches = |
| 1880 checkBuilder.buildTypeOperator(exceptionParameter, |
| 1881 clause.type, |
| 1882 isTypeTest: true); |
| 1883 checkBuilder.add(new ir.LetCont.many([thenContinuation, |
| 1884 elseContinuation], |
| 1885 new ir.Branch(new ir.IsTrue(typeMatches), |
| 1886 thenContinuation, |
| 1887 elseContinuation))); |
| 1888 catchBody = checkBuilder._root; |
| 1889 } |
| 1890 |
| 1891 List<ir.Parameter> catchParameters = |
| 1892 <ir.Parameter>[exceptionParameter, traceParameter]; |
| 1893 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); |
| 1894 catchBuilder.add(catchBody); |
| 1895 catchContinuation.body = catchBuilder._root; |
| 1896 |
| 1897 tryCatchBuilder.add( |
| 1898 new ir.LetHandler(catchContinuation, tryBuilder._root)); |
| 1899 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); |
| 1900 environment = join.environment; |
| 1901 } else { |
| 1902 // Try/finally. |
| 1903 JumpCollector join = new ForwardJumpCollector(environment); |
| 1904 IrBuilder tryFinallyBuilder = makeDelimitedBuilder(); |
| 1905 |
| 1906 tryFinallyBuilder.mutableVariables = |
| 1907 new Map<Local, ir.MutableVariable>.from(mutableVariables); |
| 1908 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1909 assert(!tryFinallyBuilder.isInMutableVariable(variable)); |
| 1910 ir.Primitive value = tryFinallyBuilder.buildLocalVariableGet(variable); |
| 1911 tryFinallyBuilder.makeMutableVariable(variable); |
| 1912 tryFinallyBuilder.declareLocalVariable(variable, initialValue: value); |
| 1913 } |
| 1914 |
| 1915 IrBuilder tryBuilder = tryFinallyBuilder.makeDelimitedBuilder(); |
| 1916 |
| 1917 JumpCollector interceptJump(JumpCollector collector) { |
| 1918 JumpCollector result = |
| 1919 new ForwardJumpCollector(environment, target: collector.target); |
| 1920 result.enterTry(tryStatementInfo.boxedOnEntry); |
| 1921 return result; |
| 1922 } |
| 1923 void restoreJump(JumpCollector collector) { |
| 1924 collector.leaveTry(); |
| 1925 } |
| 1926 List<JumpCollector> savedBreaks = tryBuilder.state.breakCollectors; |
| 1927 List<JumpCollector> savedContinues = tryBuilder.state.continueCollectors; |
| 1928 JumpCollector savedReturn = tryBuilder.state.returnCollector; |
| 1929 |
| 1930 List<JumpCollector> newBreaks = tryBuilder.state.breakCollectors = |
| 1931 savedBreaks.map(interceptJump).toList(); |
| 1932 List<JumpCollector> newContinues = tryBuilder.state.continueCollectors = |
| 1933 savedContinues.map(interceptJump).toList(); |
| 1934 JumpCollector newReturn = tryBuilder.state.returnCollector = |
| 1935 new ForwardJumpCollector(environment, hasExtraArgument: true); |
| 1936 newReturn.enterTry(tryStatementInfo.boxedOnEntry); |
| 1937 buildTryBlock(tryBuilder); |
| 1938 if (tryBuilder.isOpen) { |
| 1939 // To cover control falling off the end of the try block, the finally |
| 1940 // code is translated at the join point. This ensures that it is |
| 1941 // correctly outside the scope of the catch handler. |
| 1942 join.enterTry(tryStatementInfo.boxedOnEntry); |
| 1943 tryBuilder.jumpTo(join); |
| 1944 join.leaveTry(); |
| 1945 } |
| 1946 newBreaks.forEach(restoreJump); |
| 1947 newContinues.forEach(restoreJump); |
| 1948 newReturn.leaveTry(); |
| 1949 tryBuilder.state.breakCollectors = savedBreaks; |
| 1950 tryBuilder.state.continueCollectors = savedContinues; |
| 1951 tryBuilder.state.returnCollector = savedReturn; |
| 1952 |
| 1953 IrBuilder catchBuilder = tryFinallyBuilder.makeDelimitedBuilder(); |
| 1954 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { |
| 1955 assert(catchBuilder.isInMutableVariable(variable)); |
| 1956 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); |
| 1957 catchBuilder.removeMutableVariable(variable); |
| 1958 catchBuilder.environment.update(variable, value); |
| 1959 } |
| 1960 |
| 1961 buildFinallyBlock(catchBuilder); |
| 1962 if (catchBuilder.isOpen) { |
| 1963 catchBuilder.add(new ir.Rethrow()); |
| 1964 catchBuilder._current = null; |
| 1965 } |
| 1966 List<ir.Parameter> catchParameters = |
| 1967 <ir.Parameter>[new ir.Parameter(null), new ir.Parameter(null)]; |
| 1968 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); |
| 1969 catchContinuation.body = catchBuilder._root; |
| 1970 tryFinallyBuilder.add( |
| 1971 new ir.LetHandler(catchContinuation, tryBuilder._root)); |
| 1972 |
| 1973 // Build a list of continuations for jumps from the try block and |
| 1974 // duplicate the finally code before jumping to the actual target. |
| 1975 List<ir.Continuation> exits = <ir.Continuation>[join.continuation]; |
| 1976 void addJump(JumpCollector newCollector, |
| 1977 JumpCollector originalCollector) { |
| 1978 if (newCollector.isEmpty) return; |
| 1979 IrBuilder builder = makeDelimitedBuilder(newCollector.environment); |
| 1980 buildFinallyBlock(builder); |
| 1981 if (builder.isOpen) builder.jumpTo(originalCollector); |
| 1982 newCollector.continuation.body = builder._root; |
| 1983 exits.add(newCollector.continuation); |
| 1984 } |
| 1985 for (int i = 0; i < newBreaks.length; ++i) { |
| 1986 addJump(newBreaks[i], savedBreaks[i]); |
| 1987 } |
| 1988 for (int i = 0; i < newContinues.length; ++i) { |
| 1989 addJump(newContinues[i], savedContinues[i]); |
| 1990 } |
| 1991 if (!newReturn.isEmpty) { |
| 1992 IrBuilder builder = makeDelimitedBuilder(newReturn.environment); |
| 1993 ir.Primitive value = builder.environment.discard(1); |
| 1994 buildFinallyBlock(builder); |
| 1995 if (builder.isOpen) builder.buildReturn(value); |
| 1996 newReturn.continuation.body = builder._root; |
| 1997 exits.add(newReturn.continuation); |
| 1998 } |
| 1999 add(new ir.LetCont.many(exits, tryFinallyBuilder._root)); |
| 2000 environment = join.environment; |
| 2001 buildFinallyBlock(this); |
| 1762 } | 2002 } |
| 1763 | |
| 1764 IrBuilder tryBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1765 | |
| 1766 void interceptJumps(JumpCollector collector) { | |
| 1767 collector.enterTry(tryStatementInfo.boxedOnEntry); | |
| 1768 } | |
| 1769 void restoreJumps(JumpCollector collector) { | |
| 1770 collector.leaveTry(); | |
| 1771 } | |
| 1772 tryBuilder.state.breakCollectors.forEach(interceptJumps); | |
| 1773 tryBuilder.state.continueCollectors.forEach(interceptJumps); | |
| 1774 buildTryBlock(tryBuilder); | |
| 1775 if (tryBuilder.isOpen) { | |
| 1776 interceptJumps(join); | |
| 1777 tryBuilder.jumpTo(join); | |
| 1778 restoreJumps(join); | |
| 1779 } | |
| 1780 tryBuilder.state.breakCollectors.forEach(restoreJumps); | |
| 1781 tryBuilder.state.continueCollectors.forEach(restoreJumps); | |
| 1782 | |
| 1783 IrBuilder catchBuilder = tryCatchBuilder.makeDelimitedBuilder(); | |
| 1784 for (LocalVariableElement variable in tryStatementInfo.boxedOnEntry) { | |
| 1785 assert(catchBuilder.isInMutableVariable(variable)); | |
| 1786 ir.Primitive value = catchBuilder.buildLocalVariableGet(variable); | |
| 1787 // After this point, the variables that were boxed on entry to the try | |
| 1788 // are no longer treated as mutable. | |
| 1789 catchBuilder.removeMutableVariable(variable); | |
| 1790 catchBuilder.environment.update(variable, value); | |
| 1791 } | |
| 1792 | |
| 1793 // Handlers are always translated as having both exception and stack trace | |
| 1794 // parameters. Multiple clauses do not have to use the same names for | |
| 1795 // them. Choose the first of each as the name hint for the respective | |
| 1796 // handler parameter. | |
| 1797 ir.Parameter exceptionParameter = | |
| 1798 new ir.Parameter(catchClauseInfos.first.exceptionVariable); | |
| 1799 LocalVariableElement traceVariable; | |
| 1800 CatchClauseInfo catchAll; | |
| 1801 for (int i = 0; i < catchClauseInfos.length; ++i) { | |
| 1802 CatchClauseInfo info = catchClauseInfos[i]; | |
| 1803 if (info.type == null) { | |
| 1804 catchAll = info; | |
| 1805 catchClauseInfos.length = i; | |
| 1806 break; | |
| 1807 } | |
| 1808 if (traceVariable == null) { | |
| 1809 traceVariable = info.stackTraceVariable; | |
| 1810 } | |
| 1811 } | |
| 1812 ir.Parameter traceParameter = new ir.Parameter(traceVariable); | |
| 1813 // Expand multiple catch clauses into an explicit if/then/else. Iterate | |
| 1814 // them in reverse so the current block becomes the next else block. | |
| 1815 ir.Expression catchBody; | |
| 1816 if (catchAll == null) { | |
| 1817 catchBody = new ir.Rethrow(); | |
| 1818 } else { | |
| 1819 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1820 clauseBuilder.declareLocalVariable(catchAll.exceptionVariable, | |
| 1821 initialValue: exceptionParameter); | |
| 1822 if (catchAll.stackTraceVariable != null) { | |
| 1823 clauseBuilder.declareLocalVariable(catchAll.stackTraceVariable, | |
| 1824 initialValue: traceParameter); | |
| 1825 } | |
| 1826 catchAll.buildCatchBlock(clauseBuilder); | |
| 1827 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1828 catchBody = clauseBuilder._root; | |
| 1829 } | |
| 1830 for (CatchClauseInfo clause in catchClauseInfos.reversed) { | |
| 1831 IrBuilder clauseBuilder = catchBuilder.makeDelimitedBuilder(); | |
| 1832 clauseBuilder.declareLocalVariable(clause.exceptionVariable, | |
| 1833 initialValue: exceptionParameter); | |
| 1834 if (clause.stackTraceVariable != null) { | |
| 1835 clauseBuilder.declareLocalVariable(clause.stackTraceVariable, | |
| 1836 initialValue: traceParameter); | |
| 1837 } | |
| 1838 clause.buildCatchBlock(clauseBuilder); | |
| 1839 if (clauseBuilder.isOpen) clauseBuilder.jumpTo(join); | |
| 1840 ir.Continuation thenContinuation = new ir.Continuation([]); | |
| 1841 thenContinuation.body = clauseBuilder._root; | |
| 1842 ir.Continuation elseContinuation = new ir.Continuation([]); | |
| 1843 elseContinuation.body = catchBody; | |
| 1844 | |
| 1845 // Build the type test guarding this clause. We can share the environment | |
| 1846 // with the nested builder because this part cannot mutate it. | |
| 1847 IrBuilder checkBuilder = catchBuilder.makeDelimitedBuilder(environment); | |
| 1848 ir.Primitive typeMatches = | |
| 1849 checkBuilder.buildTypeOperator(exceptionParameter, | |
| 1850 clause.type, | |
| 1851 isTypeTest: true); | |
| 1852 checkBuilder.add(new ir.LetCont.many([thenContinuation, elseContinuation], | |
| 1853 new ir.Branch(new ir.IsTrue(typeMatches), | |
| 1854 thenContinuation, | |
| 1855 elseContinuation))); | |
| 1856 catchBody = checkBuilder._root; | |
| 1857 } | |
| 1858 | |
| 1859 List<ir.Parameter> catchParameters = | |
| 1860 <ir.Parameter>[exceptionParameter, traceParameter]; | |
| 1861 ir.Continuation catchContinuation = new ir.Continuation(catchParameters); | |
| 1862 catchBuilder.add(catchBody); | |
| 1863 catchContinuation.body = catchBuilder._root; | |
| 1864 | |
| 1865 tryCatchBuilder.add( | |
| 1866 new ir.LetHandler(catchContinuation, tryBuilder._root)); | |
| 1867 add(new ir.LetCont(join.continuation, tryCatchBuilder._root)); | |
| 1868 environment = join.environment; | |
| 1869 } | 2003 } |
| 1870 | 2004 |
| 1871 /// Create a return statement `return value;` or `return;` if [value] is | 2005 /// Create a return statement `return value;` or `return;` if [value] is |
| 1872 /// null. | 2006 /// null. |
| 1873 void buildReturn([ir.Primitive value]) { | 2007 void buildReturn([ir.Primitive value]) { |
| 1874 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 2008 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
| 1875 // where (C', x) = Build(e, C) | 2009 // where (C', x) = Build(e, C) |
| 1876 // | 2010 // |
| 1877 // Return without a subexpression is translated as if it were return null. | 2011 // Return without a subexpression is translated as if it were return null. |
| 1878 assert(isOpen); | 2012 assert(isOpen); |
| 1879 if (value == null) { | 2013 if (value == null) { |
| 1880 value = buildNullConstant(); | 2014 value = buildNullConstant(); |
| 1881 } | 2015 } |
| 1882 add(new ir.InvokeContinuation(state.returnContinuation, [value])); | 2016 if (state.returnCollector == null) { |
| 1883 _current = null; | 2017 add(new ir.InvokeContinuation(state.returnContinuation, [value])); |
| 2018 _current = null; |
| 2019 } else { |
| 2020 // Inside the try block of try/finally, all returns go to a join-point |
| 2021 // continuation that contains the finally code. The return value is |
| 2022 // passed as an extra argument. |
| 2023 jumpTo(state.returnCollector, value); |
| 2024 } |
| 1884 } | 2025 } |
| 1885 | 2026 |
| 1886 /// Create a blocks of [statements] by applying [build] to all reachable | 2027 /// Create a blocks of [statements] by applying [build] to all reachable |
| 1887 /// statements. The first statement is assumed to be reachable. | 2028 /// statements. The first statement is assumed to be reachable. |
| 1888 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses | 2029 // TODO(johnniwinther): Type [statements] as `Iterable` when `NodeList` uses |
| 1889 // `List` instead of `Link`. | 2030 // `List` instead of `Link`. |
| 1890 void buildBlock(var statements, BuildFunction build) { | 2031 void buildBlock(var statements, BuildFunction build) { |
| 1891 // Build(Block(stamements), C) = C' | 2032 // Build(Block(stamements), C) = C' |
| 1892 // where C' = statements.fold(Build, C) | 2033 // where C' = statements.fold(Build, C) |
| 1893 assert(isOpen); | 2034 assert(isOpen); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2030 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder(); | 2171 IrBuilder rightFalseBuilder = rightBuilder.makeDelimitedBuilder(); |
| 2031 | 2172 |
| 2032 // If we don't evaluate the right subexpression, the value of the whole | 2173 // If we don't evaluate the right subexpression, the value of the whole |
| 2033 // expression is this constant. | 2174 // expression is this constant. |
| 2034 ir.Constant leftBool = emptyBuilder.buildBooleanConstant(isLazyOr); | 2175 ir.Constant leftBool = emptyBuilder.buildBooleanConstant(isLazyOr); |
| 2035 // If we do evaluate the right subexpression, the value of the expression | 2176 // If we do evaluate the right subexpression, the value of the expression |
| 2036 // is a true or false constant. | 2177 // is a true or false constant. |
| 2037 ir.Constant rightTrue = rightTrueBuilder.buildBooleanConstant(true); | 2178 ir.Constant rightTrue = rightTrueBuilder.buildBooleanConstant(true); |
| 2038 ir.Constant rightFalse = rightFalseBuilder.buildBooleanConstant(false); | 2179 ir.Constant rightFalse = rightFalseBuilder.buildBooleanConstant(false); |
| 2039 | 2180 |
| 2040 // Treat the result values as named values in the environment, so they | 2181 // Result values are passed as continuation arguments, which are |
| 2041 // will be treated as arguments to the join-point continuation. | 2182 // constructed based on environments. These assertions are a sanity check. |
| 2042 assert(environment.length == emptyBuilder.environment.length); | 2183 assert(environment.length == emptyBuilder.environment.length); |
| 2043 assert(environment.length == rightTrueBuilder.environment.length); | 2184 assert(environment.length == rightTrueBuilder.environment.length); |
| 2044 assert(environment.length == rightFalseBuilder.environment.length); | 2185 assert(environment.length == rightFalseBuilder.environment.length); |
| 2045 // Treat the value of the expression as a local variable so it will get | |
| 2046 // a continuation parameter. | |
| 2047 environment.extend(null, null); | |
| 2048 emptyBuilder.environment.extend(null, leftBool); | |
| 2049 rightTrueBuilder.environment.extend(null, rightTrue); | |
| 2050 rightFalseBuilder.environment.extend(null, rightFalse); | |
| 2051 | 2186 |
| 2052 // Wire up two continuations for the left subexpression, two continuations | 2187 // Wire up two continuations for the left subexpression, two continuations |
| 2053 // for the right subexpression, and a three-way join continuation. | 2188 // for the right subexpression, and a three-way join continuation. |
| 2054 JumpCollector join = new ForwardJumpCollector(environment); | 2189 JumpCollector join = |
| 2055 emptyBuilder.jumpTo(join); | 2190 new ForwardJumpCollector(environment, hasExtraArgument: true); |
| 2056 rightTrueBuilder.jumpTo(join); | 2191 emptyBuilder.jumpTo(join, leftBool); |
| 2057 rightFalseBuilder.jumpTo(join); | 2192 rightTrueBuilder.jumpTo(join, rightTrue); |
| 2193 rightFalseBuilder.jumpTo(join, rightFalse); |
| 2058 ir.Continuation leftTrueContinuation = new ir.Continuation([]); | 2194 ir.Continuation leftTrueContinuation = new ir.Continuation([]); |
| 2059 ir.Continuation leftFalseContinuation = new ir.Continuation([]); | 2195 ir.Continuation leftFalseContinuation = new ir.Continuation([]); |
| 2060 ir.Continuation rightTrueContinuation = new ir.Continuation([]); | 2196 ir.Continuation rightTrueContinuation = new ir.Continuation([]); |
| 2061 ir.Continuation rightFalseContinuation = new ir.Continuation([]); | 2197 ir.Continuation rightFalseContinuation = new ir.Continuation([]); |
| 2062 rightTrueContinuation.body = rightTrueBuilder._root; | 2198 rightTrueContinuation.body = rightTrueBuilder._root; |
| 2063 rightFalseContinuation.body = rightFalseBuilder._root; | 2199 rightFalseContinuation.body = rightFalseBuilder._root; |
| 2064 // The right subexpression has two continuations. | 2200 // The right subexpression has two continuations. |
| 2065 rightBuilder.add( | 2201 rightBuilder.add( |
| 2066 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation, | 2202 new ir.LetCont.many(<ir.Continuation>[rightTrueContinuation, |
| 2067 rightFalseContinuation], | 2203 rightFalseContinuation], |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2079 leftFalseContinuation.body = emptyBuilder._root; | 2215 leftFalseContinuation.body = emptyBuilder._root; |
| 2080 } | 2216 } |
| 2081 | 2217 |
| 2082 add(new ir.LetCont(join.continuation, | 2218 add(new ir.LetCont(join.continuation, |
| 2083 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation, | 2219 new ir.LetCont.many(<ir.Continuation>[leftTrueContinuation, |
| 2084 leftFalseContinuation], | 2220 leftFalseContinuation], |
| 2085 new ir.Branch(new ir.IsTrue(leftValue), | 2221 new ir.Branch(new ir.IsTrue(leftValue), |
| 2086 leftTrueContinuation, | 2222 leftTrueContinuation, |
| 2087 leftFalseContinuation)))); | 2223 leftFalseContinuation)))); |
| 2088 environment = join.environment; | 2224 environment = join.environment; |
| 2089 environment.discard(1); | 2225 return environment.discard(1); |
| 2090 // There is always a join parameter for the result value, because it | |
| 2091 // is different on at least two paths. | |
| 2092 return join.continuation.parameters.last; | |
| 2093 } | 2226 } |
| 2094 | 2227 |
| 2095 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) { | 2228 ir.Primitive buildIdentical(ir.Primitive x, ir.Primitive y) { |
| 2096 return addPrimitive(new ir.ApplyBuiltinOperator( | 2229 return addPrimitive(new ir.ApplyBuiltinOperator( |
| 2097 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y])); | 2230 ir.BuiltinOperator.Identical, <ir.Primitive>[x, y])); |
| 2098 } | 2231 } |
| 2099 } | 2232 } |
| 2100 | 2233 |
| 2101 /// State shared between JsIrBuilders within the same function. | 2234 /// State shared between JsIrBuilders within the same function. |
| 2102 /// | 2235 /// |
| (...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2623 this.buildCatchBlock}); | 2756 this.buildCatchBlock}); |
| 2624 } | 2757 } |
| 2625 | 2758 |
| 2626 class SwitchCaseInfo { | 2759 class SwitchCaseInfo { |
| 2627 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2760 final List<ir.Primitive> constants = <ir.Primitive>[]; |
| 2628 final SubbuildFunction buildBody; | 2761 final SubbuildFunction buildBody; |
| 2629 | 2762 |
| 2630 SwitchCaseInfo(this.buildBody); | 2763 SwitchCaseInfo(this.buildBody); |
| 2631 | 2764 |
| 2632 void addConstant(ir.Primitive constant) => constants.add(constant); | 2765 void addConstant(ir.Primitive constant) => constants.add(constant); |
| 2633 } | 2766 } |
| OLD | NEW |