| 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 |