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 '../closure.dart' hide ClosureScope; | 7 import '../closure.dart' hide ClosureScope; |
8 import '../common.dart'; | 8 import '../common.dart'; |
9 import '../common/names.dart' show | 9 import '../common/names.dart' show |
10 Names, | 10 Names, |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
152 /// Construct a collector for a given environment and optionally a target. | 152 /// Construct a collector for a given environment and optionally a target. |
153 /// | 153 /// |
154 /// The environment is the one in effect at the point where the jump's | 154 /// The environment is the one in effect at the point where the jump's |
155 /// continuation will be bound. Continuations can take an extra argument | 155 /// continuation will be bound. Continuations can take an extra argument |
156 /// (see [addJump]). | 156 /// (see [addJump]). |
157 JumpCollector(this._continuationEnvironment, this.target, | 157 JumpCollector(this._continuationEnvironment, this.target, |
158 bool hasExtraArgument) { | 158 bool hasExtraArgument) { |
159 if (hasExtraArgument) _continuationEnvironment.extend(null, null); | 159 if (hasExtraArgument) _continuationEnvironment.extend(null, null); |
160 } | 160 } |
161 | 161 |
| 162 /// Construct a collector for collecting only return jumps. |
| 163 /// |
| 164 /// There is no jump target, it is implicitly the exit from the function. |
| 165 /// There is no environment at the destination. |
| 166 JumpCollector.retrn(this._continuation) |
| 167 : _continuationEnvironment = null, target = null; |
| 168 |
162 /// True if the collector has not recorded any jumps to its continuation. | 169 /// True if the collector has not recorded any jumps to its continuation. |
163 bool get isEmpty; | 170 bool get isEmpty; |
164 | 171 |
165 /// The continuation encapsulated by this collector. | 172 /// The continuation encapsulated by this collector. |
166 ir.Continuation get continuation; | 173 ir.Continuation get continuation; |
167 | 174 |
168 /// The compile-time environment to be used for translating code in the body | 175 /// The compile-time environment to be used for translating code in the body |
169 /// of the continuation. | 176 /// of the continuation. |
170 Environment get environment; | 177 Environment get environment; |
171 | 178 |
172 /// Emit a jump to the continuation for a given [IrBuilder]. | 179 /// Emit a jump to the continuation for a given [IrBuilder]. |
173 /// | 180 /// |
174 /// Jumps can take a single extra argument. This is used to pass return | 181 /// Jumps can take a single extra argument. This is used to pass return |
175 /// values to finally blocks for returns inside try/finally and to pass | 182 /// values to finally blocks for returns inside try/finally and to pass |
176 /// values of expressions that have internal control flow to their join-point | 183 /// values of expressions that have internal control flow to their join-point |
177 /// continuations. | 184 /// continuations. |
178 void addJump(IrBuilder builder, [ir.Primitive value]); | 185 void addJump(IrBuilder builder, |
| 186 [ir.Primitive value, SourceInformation sourceInformation]); |
179 | 187 |
180 /// Add a set of variables that were boxed on entry to a try block. | 188 /// Add a set of variables that were boxed on entry to a try block. |
181 /// | 189 /// |
182 /// All jumps from a try block to targets outside have to unbox the | 190 /// All jumps from a try block to targets outside have to unbox the |
183 /// variables that were boxed on entry before invoking the target | 191 /// variables that were boxed on entry before invoking the target |
184 /// continuation. Call this function before translating a try block and | 192 /// continuation. Call this function before translating a try block and |
185 /// call [leaveTry] after translating it. | 193 /// call [leaveTry] after translating it. |
186 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { | 194 void enterTry(Iterable<LocalVariableElement> boxedOnEntry) { |
187 // The boxed variables are maintained as a stack to make leaving easy. | 195 // The boxed variables are maintained as a stack to make leaving easy. |
188 _boxedTryVariables.add(boxedOnEntry); | 196 _boxedTryVariables.add(boxedOnEntry); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 ir.Continuation get continuation { | 260 ir.Continuation get continuation { |
253 if (_continuation == null) _setContinuation(); | 261 if (_continuation == null) _setContinuation(); |
254 return _continuation; | 262 return _continuation; |
255 } | 263 } |
256 | 264 |
257 Environment get environment { | 265 Environment get environment { |
258 if (_continuation == null) _setContinuation(); | 266 if (_continuation == null) _setContinuation(); |
259 return _continuationEnvironment; | 267 return _continuationEnvironment; |
260 } | 268 } |
261 | 269 |
262 void addJump(IrBuilder builder, [ir.Primitive value]) { | 270 void addJump(IrBuilder builder, |
| 271 [ir.Primitive value, SourceInformation sourceInformation]) { |
263 assert(_continuation == null); | 272 assert(_continuation == null); |
264 _buildTryExit(builder); | 273 _buildTryExit(builder); |
265 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized( | 274 ir.InvokeContinuation invoke = new ir.InvokeContinuation.uninitialized( |
266 isEscapingTry: isEscapingTry); | 275 isEscapingTry: isEscapingTry); |
267 builder.add(invoke); | 276 builder.add(invoke); |
268 _invocations.add(invoke); | 277 _invocations.add(invoke); |
269 // Truncate the environment at the invocation site so it only includes | 278 // Truncate the environment at the invocation site so it only includes |
270 // values that will be continuation arguments. If an extra value is passed | 279 // values that will be continuation arguments. If an extra value is passed |
271 // it will already be included in the continuation environment, but it is | 280 // it will already be included in the continuation environment, but it is |
272 // not present in the invocation environment. | 281 // not present in the invocation environment. |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 List<ir.Parameter> parameters = | 370 List<ir.Parameter> parameters = |
362 new List<ir.Parameter>.from(_continuationEnvironment.index2value); | 371 new List<ir.Parameter>.from(_continuationEnvironment.index2value); |
363 _continuation = new ir.Continuation(parameters, isRecursive: true); | 372 _continuation = new ir.Continuation(parameters, isRecursive: true); |
364 } | 373 } |
365 | 374 |
366 bool isEmpty = true; | 375 bool isEmpty = true; |
367 | 376 |
368 ir.Continuation get continuation => _continuation; | 377 ir.Continuation get continuation => _continuation; |
369 Environment get environment => _continuationEnvironment; | 378 Environment get environment => _continuationEnvironment; |
370 | 379 |
371 void addJump(IrBuilder builder, [ir.Primitive value]) { | 380 void addJump(IrBuilder builder, |
| 381 [ir.Primitive value, SourceInformation sourceInformation]) { |
372 assert(_continuation.parameters.length <= builder.environment.length); | 382 assert(_continuation.parameters.length <= builder.environment.length); |
373 isEmpty = false; | 383 isEmpty = false; |
374 _buildTryExit(builder); | 384 _buildTryExit(builder); |
375 // Truncate the environment at the invocation site so it only includes | 385 // Truncate the environment at the invocation site so it only includes |
376 // values that will be continuation arguments. If an extra value is passed | 386 // values that will be continuation arguments. If an extra value is passed |
377 // it will already be included in the continuation environment, but it is | 387 // it will already be included in the continuation environment, but it is |
378 // not present in the invocation environment. | 388 // not present in the invocation environment. |
379 int delta = builder.environment.length - _continuationEnvironment.length; | 389 int delta = builder.environment.length - _continuationEnvironment.length; |
380 if (value != null) ++delta; | 390 if (value != null) ++delta; |
381 if (delta > 0) builder.environment.discard(delta); | 391 if (delta > 0) builder.environment.discard(delta); |
382 if (value != null) builder.environment.extend(null, value); | 392 if (value != null) builder.environment.extend(null, value); |
383 builder.add(new ir.InvokeContinuation(_continuation, | 393 builder.add(new ir.InvokeContinuation(_continuation, |
384 builder.environment.index2value, | 394 builder.environment.index2value, |
385 isRecursive: true, | 395 isRecursive: true, |
386 isEscapingTry: isEscapingTry)); | 396 isEscapingTry: isEscapingTry)); |
387 builder._current = null; | 397 builder._current = null; |
388 } | 398 } |
389 } | 399 } |
390 | 400 |
| 401 /// Collect 'return' jumps. |
| 402 /// |
| 403 /// A return jump is one that targets the return continuation of a function. |
| 404 /// Thus, returns from inside try/finally are not return jumps because they are |
| 405 /// intercepted by a block that contains the finally handler code. |
| 406 class ReturnJumpCollector extends JumpCollector { |
| 407 bool isEmpty = true; |
| 408 ir.Continuation get continuation => _continuation; |
| 409 Environment environment = null; |
| 410 |
| 411 /// Construct a return jump collector for a given return continuation. |
| 412 ReturnJumpCollector(ir.Continuation continuation) : super.retrn(continuation); |
| 413 |
| 414 void addJump(IrBuilder builder, |
| 415 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 416 isEmpty = false; |
| 417 builder.add(new ir.InvokeContinuation(continuation, <ir.Primitive>[value], |
| 418 isEscapingTry: isEscapingTry, |
| 419 sourceInformation: sourceInformation)); |
| 420 builder._current = null; |
| 421 } |
| 422 } |
| 423 |
391 /// Function for building a node in the context of the current builder. | 424 /// Function for building a node in the context of the current builder. |
392 typedef ir.Node BuildFunction(node); | 425 typedef ir.Node BuildFunction(node); |
393 | 426 |
394 /// Function for building nodes in the context of the provided [builder]. | 427 /// Function for building nodes in the context of the provided [builder]. |
395 typedef ir.Node SubbuildFunction(IrBuilder builder); | 428 typedef ir.Node SubbuildFunction(IrBuilder builder); |
396 | 429 |
397 /// Mixin that provides encapsulated access to nested builders. | 430 /// Mixin that provides encapsulated access to nested builders. |
398 abstract class IrBuilderMixin<N> { | 431 abstract class IrBuilderMixin<N> { |
399 IrBuilder _irBuilder; | 432 IrBuilder _irBuilder; |
400 | 433 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 | 492 |
460 final ExecutableElement currentElement; | 493 final ExecutableElement currentElement; |
461 | 494 |
462 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); | 495 final ir.Continuation returnContinuation = new ir.Continuation.retrn(); |
463 | 496 |
464 /// The target of a return from the function. | 497 /// The target of a return from the function. |
465 /// | 498 /// |
466 /// A null value indicates that the target is the function's return | 499 /// A null value indicates that the target is the function's return |
467 /// continuation. Otherwise, when inside the try block of try/finally | 500 /// continuation. Otherwise, when inside the try block of try/finally |
468 /// a return is intercepted to give a place to generate the finally code. | 501 /// a return is intercepted to give a place to generate the finally code. |
469 JumpCollector returnCollector = null; | 502 JumpCollector returnCollector; |
470 | 503 |
471 /// Parameter holding the internal value of 'this' passed to the function. | 504 /// Parameter holding the internal value of 'this' passed to the function. |
472 /// | 505 /// |
473 /// For nested functions, this is *not* captured receiver, but the function | 506 /// For nested functions, this is *not* captured receiver, but the function |
474 /// object itself. | 507 /// object itself. |
475 ir.Parameter thisParameter; | 508 ir.Parameter thisParameter; |
476 | 509 |
477 /// If non-null, this refers to the receiver (`this`) in the enclosing method. | 510 /// If non-null, this refers to the receiver (`this`) in the enclosing method. |
478 ir.Primitive enclosingThis; | 511 ir.Primitive enclosingThis; |
479 | 512 |
480 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; | 513 final List<ir.Parameter> functionParameters = <ir.Parameter>[]; |
481 | 514 |
482 /// Maps boxed locals to their location. These locals are not part of | 515 /// Maps boxed locals to their location. These locals are not part of |
483 /// the environment. | 516 /// the environment. |
484 final Map<Local, ClosureLocation> boxedVariables = {}; | 517 final Map<Local, ClosureLocation> boxedVariables = {}; |
485 | 518 |
486 IrBuilderSharedState(this.program, this.constants, this.currentElement); | 519 IrBuilderSharedState(this.program, this.constants, this.currentElement) { |
| 520 returnCollector = new ReturnJumpCollector(returnContinuation); |
| 521 } |
487 } | 522 } |
488 | 523 |
489 class ThisParameterLocal implements Local { | 524 class ThisParameterLocal implements Local { |
490 final ExecutableElement executableContext; | 525 final ExecutableElement executableContext; |
491 ThisParameterLocal(this.executableContext); | 526 ThisParameterLocal(this.executableContext); |
492 String get name => 'this'; | 527 String get name => 'this'; |
493 toString() => 'ThisParameterLocal($executableContext)'; | 528 toString() => 'ThisParameterLocal($executableContext)'; |
494 } | 529 } |
495 | 530 |
496 /// The IR builder maintains an environment and an IR fragment. | 531 /// The IR builder maintains an environment and an IR fragment. |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 if (elseBuilder._root != null) _current = elseBuilder._current; | 1188 if (elseBuilder._root != null) _current = elseBuilder._current; |
1154 environment = elseBuilder.environment; | 1189 environment = elseBuilder.environment; |
1155 } else { | 1190 } else { |
1156 _current = null; | 1191 _current = null; |
1157 } | 1192 } |
1158 } else { | 1193 } else { |
1159 environment = join.environment; | 1194 environment = join.environment; |
1160 } | 1195 } |
1161 } | 1196 } |
1162 | 1197 |
1163 void jumpTo(JumpCollector collector, [ir.Primitive value]) { | 1198 void jumpTo(JumpCollector collector, |
1164 collector.addJump(this, value); | 1199 [ir.Primitive value, SourceInformation sourceInformation]) { |
| 1200 collector.addJump(this, value, sourceInformation); |
1165 } | 1201 } |
1166 | 1202 |
1167 void addRecursiveContinuation(BackwardJumpCollector collector) { | 1203 void addRecursiveContinuation(BackwardJumpCollector collector) { |
1168 assert(environment.length == collector.environment.length); | 1204 assert(environment.length == collector.environment.length); |
1169 add(new ir.LetCont(collector.continuation, | 1205 add(new ir.LetCont(collector.continuation, |
1170 new ir.InvokeContinuation(collector.continuation, | 1206 new ir.InvokeContinuation(collector.continuation, |
1171 environment.index2value))); | 1207 environment.index2value))); |
1172 environment = collector.environment; | 1208 environment = collector.environment; |
1173 } | 1209 } |
1174 | 1210 |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1804 // variables are unboxed in the catch block and at the join point. | 1840 // variables are unboxed in the catch block and at the join point. |
1805 | 1841 |
1806 void enterTry(IrBuilder builder) { | 1842 void enterTry(IrBuilder builder) { |
1807 // On entry to try of try/catch, update the builder's state to reflect the | 1843 // On entry to try of try/catch, update the builder's state to reflect the |
1808 // variables that have been boxed. | 1844 // variables that have been boxed. |
1809 void interceptJump(JumpCollector collector) { | 1845 void interceptJump(JumpCollector collector) { |
1810 collector.enterTry(variables.boxedOnEntry); | 1846 collector.enterTry(variables.boxedOnEntry); |
1811 } | 1847 } |
1812 builder.state.breakCollectors.forEach(interceptJump); | 1848 builder.state.breakCollectors.forEach(interceptJump); |
1813 builder.state.continueCollectors.forEach(interceptJump); | 1849 builder.state.continueCollectors.forEach(interceptJump); |
| 1850 interceptJump(builder.state.returnCollector); |
1814 } | 1851 } |
1815 | 1852 |
1816 void leaveTry(IrBuilder builder) { | 1853 void leaveTry(IrBuilder builder) { |
1817 // On exit from try of try/catch, update the builder's state to reflect | 1854 // On exit from try of try/catch, update the builder's state to reflect |
1818 // the variables that are no longer boxed. | 1855 // the variables that are no longer boxed. |
1819 void restoreJump(JumpCollector collector) { | 1856 void restoreJump(JumpCollector collector) { |
1820 collector.leaveTry(); | 1857 collector.leaveTry(); |
1821 } | 1858 } |
1822 builder.state.breakCollectors.forEach(restoreJump); | 1859 builder.state.breakCollectors.forEach(restoreJump); |
1823 builder.state.continueCollectors.forEach(restoreJump); | 1860 builder.state.continueCollectors.forEach(restoreJump); |
| 1861 restoreJump(builder.state.returnCollector); |
1824 } | 1862 } |
1825 | 1863 |
1826 List<ir.Parameter> buildCatch(IrBuilder builder, | 1864 List<ir.Parameter> buildCatch(IrBuilder builder, |
1827 JumpCollector join) { | 1865 JumpCollector join) { |
1828 // Translate the catch clauses. Multiple clauses are translated as if | 1866 // Translate the catch clauses. Multiple clauses are translated as if |
1829 // they were explicitly cascaded if/else type tests. | 1867 // they were explicitly cascaded if/else type tests. |
1830 | 1868 |
1831 // Handlers are always translated as having both exception and stack trace | 1869 // Handlers are always translated as having both exception and stack trace |
1832 // parameters. Multiple clauses do not have to use the same names for | 1870 // parameters. Multiple clauses do not have to use the same names for |
1833 // them. Choose the first of each as the name hint for the respective | 1871 // them. Choose the first of each as the name hint for the respective |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2022 /// null. | 2060 /// null. |
2023 void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) { | 2061 void buildReturn({ir.Primitive value, SourceInformation sourceInformation}) { |
2024 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] | 2062 // Build(Return(e), C) = C'[InvokeContinuation(return, x)] |
2025 // where (C', x) = Build(e, C) | 2063 // where (C', x) = Build(e, C) |
2026 // | 2064 // |
2027 // Return without a subexpression is translated as if it were return null. | 2065 // Return without a subexpression is translated as if it were return null. |
2028 assert(isOpen); | 2066 assert(isOpen); |
2029 if (value == null) { | 2067 if (value == null) { |
2030 value = buildNullConstant(); | 2068 value = buildNullConstant(); |
2031 } | 2069 } |
2032 if (state.returnCollector == null) { | 2070 jumpTo(state.returnCollector, value, sourceInformation); |
2033 add(new ir.InvokeContinuation(state.returnContinuation, [value], | |
2034 sourceInformation: sourceInformation)); | |
2035 _current = null; | |
2036 } else { | |
2037 // Inside the try block of try/finally, all returns go to a join-point | |
2038 // continuation that contains the finally code. The return value is | |
2039 // passed as an extra argument. | |
2040 jumpTo(state.returnCollector, value); | |
2041 } | |
2042 } | 2071 } |
2043 | 2072 |
2044 /// Build a call to the closure conversion helper for the [Function] typed | 2073 /// Build a call to the closure conversion helper for the [Function] typed |
2045 /// value in [value]. | 2074 /// value in [value]. |
2046 ir.Primitive _convertDartClosure(ir.Primitive value, FunctionType type) { | 2075 ir.Primitive _convertDartClosure(ir.Primitive value, FunctionType type) { |
2047 ir.Constant arity = buildIntegerConstant(type.computeArity()); | 2076 ir.Constant arity = buildIntegerConstant(type.computeArity()); |
2048 return buildStaticFunctionInvocation( | 2077 return buildStaticFunctionInvocation( |
2049 program.closureConverter, | 2078 program.closureConverter, |
2050 CallStructure.TWO_ARGS, | 2079 CallStructure.TWO_ARGS, |
2051 <ir.Primitive>[value, arity]); | 2080 <ir.Primitive>[value, arity]); |
(...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2889 } | 2918 } |
2890 | 2919 |
2891 class SwitchCaseInfo { | 2920 class SwitchCaseInfo { |
2892 final List<ir.Primitive> constants = <ir.Primitive>[]; | 2921 final List<ir.Primitive> constants = <ir.Primitive>[]; |
2893 final SubbuildFunction buildBody; | 2922 final SubbuildFunction buildBody; |
2894 | 2923 |
2895 SwitchCaseInfo(this.buildBody); | 2924 SwitchCaseInfo(this.buildBody); |
2896 | 2925 |
2897 void addConstant(ir.Primitive constant) => constants.add(constant); | 2926 void addConstant(ir.Primitive constant) => constants.add(constant); |
2898 } | 2927 } |
OLD | NEW |