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 |