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 library dart2js.ir_nodes; | 4 library dart2js.ir_nodes; |
5 | 5 |
6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 import 'cps_fragment.dart' show CpsFragment; |
7 import '../constants/values.dart' as values; | 8 import '../constants/values.dart' as values; |
8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 9 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
9 import '../elements/elements.dart'; | 10 import '../elements/elements.dart'; |
10 import '../io/source_information.dart' show SourceInformation; | 11 import '../io/source_information.dart' show SourceInformation; |
11 import '../types/types.dart' show TypeMask; | 12 import '../types/types.dart' show TypeMask; |
12 import '../universe/selector.dart' show Selector; | 13 import '../universe/selector.dart' show Selector; |
13 | 14 |
14 import 'builtin_operator.dart'; | 15 import 'builtin_operator.dart'; |
15 export 'builtin_operator.dart'; | 16 export 'builtin_operator.dart'; |
16 | 17 |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); | 197 EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); |
197 } | 198 } |
198 | 199 |
199 /// A named value. | 200 /// A named value. |
200 /// | 201 /// |
201 /// The identity of the [Primitive] object is the name of the value. | 202 /// The identity of the [Primitive] object is the name of the value. |
202 /// The subclass describes how to compute the value. | 203 /// The subclass describes how to compute the value. |
203 /// | 204 /// |
204 /// All primitives except [Parameter] must be bound by a [LetPrim]. | 205 /// All primitives except [Parameter] must be bound by a [LetPrim]. |
205 abstract class Primitive extends Variable<Primitive> { | 206 abstract class Primitive extends Variable<Primitive> { |
206 /// The [VariableElement] or [ParameterElement] from which the primitive | 207 Primitive() : super(null); |
207 /// binding originated. | |
208 Entity hint; | |
209 | |
210 /// Use the given element as a hint for naming this primitive. | |
211 /// | |
212 /// Has no effect if this primitive already has a non-null [element]. | |
213 void useElementAsHint(Entity hint) { | |
214 if (this.hint == null) { | |
215 this.hint = hint; | |
216 } | |
217 } | |
218 | 208 |
219 /// True if this primitive has a value that can be used by other expressions. | 209 /// True if this primitive has a value that can be used by other expressions. |
220 bool get hasValue; | 210 bool get hasValue; |
221 | 211 |
222 /// True if the primitive can be removed, assuming it has no uses | 212 /// True if the primitive can be removed, assuming it has no uses |
223 /// (this getter does not check if there are any uses). | 213 /// (this getter does not check if there are any uses). |
224 /// | 214 /// |
225 /// False must be returned for primitives that may throw, diverge, or have | 215 /// False must be returned for primitives that may throw, diverge, or have |
226 /// observable side-effects. | 216 /// observable side-effects. |
227 bool get isSafeForElimination; | 217 bool get isSafeForElimination; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 assert(this is! Parameter); | 278 assert(this is! Parameter); |
289 assert(newDefinition is! Parameter); | 279 assert(newDefinition is! Parameter); |
290 assert(newDefinition.parent == null); | 280 assert(newDefinition.parent == null); |
291 replaceUsesWith(newDefinition); | 281 replaceUsesWith(newDefinition); |
292 destroy(); | 282 destroy(); |
293 LetPrim let = parent; | 283 LetPrim let = parent; |
294 let.primitive = newDefinition; | 284 let.primitive = newDefinition; |
295 newDefinition.parent = let; | 285 newDefinition.parent = let; |
296 newDefinition.useElementAsHint(hint); | 286 newDefinition.useElementAsHint(hint); |
297 } | 287 } |
| 288 |
| 289 /// Replaces this definition with a CPS fragment (a term with a hole in it), |
| 290 /// given the value to replace the uses of the definition with. |
| 291 /// |
| 292 /// This can be thought of as substituting: |
| 293 /// |
| 294 /// let x = OLD in BODY |
| 295 /// ==> |
| 296 /// FRAGMENT[BODY{newPrimitive/x}] |
| 297 void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) { |
| 298 assert(this is! Parameter); |
| 299 replaceUsesWith(newPrimitive); |
| 300 destroy(); |
| 301 LetPrim let = parent; |
| 302 fragment.insertBelow(let); |
| 303 let.remove(); |
| 304 } |
298 } | 305 } |
299 | 306 |
300 /// A primitive that is generally not safe for elimination, but may be marked | 307 /// A primitive that is generally not safe for elimination, but may be marked |
301 /// as safe by type propagation | 308 /// as safe by type propagation |
302 // | 309 // |
303 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this | 310 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this |
304 // class. | 311 // class. |
305 abstract class UnsafePrimitive extends Primitive { | 312 abstract class UnsafePrimitive extends Primitive { |
306 bool isSafeForElimination = false; | 313 bool isSafeForElimination = false; |
307 bool isSafeForReordering = false; | 314 bool isSafeForReordering = false; |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 | 464 |
458 accept(Visitor visitor) => visitor.visitLetMutable(this); | 465 accept(Visitor visitor) => visitor.visitLetMutable(this); |
459 | 466 |
460 void setParentPointers() { | 467 void setParentPointers() { |
461 variable.parent = this; | 468 variable.parent = this; |
462 value.parent = this; | 469 value.parent = this; |
463 if (body != null) body.parent = this; | 470 if (body != null) body.parent = this; |
464 } | 471 } |
465 } | 472 } |
466 | 473 |
| 474 enum CallingConvention { |
| 475 /// JS receiver is the Dart receiver, there are no extra arguments. |
| 476 /// |
| 477 /// This includes cases (e.g., static functions, constructors) where there |
| 478 /// is no receiver. |
| 479 /// |
| 480 /// For example: `foo.bar$1(x)` |
| 481 Normal, |
| 482 |
| 483 /// JS receiver is an interceptor, the first argument is the Dart receiver. |
| 484 /// |
| 485 /// For example: `getInterceptor(foo).bar$1(foo, x)` |
| 486 Intercepted, |
| 487 |
| 488 /// JS receiver is the Dart receiver, the first argument is a dummy value. |
| 489 /// |
| 490 /// For example: `foo.bar$1(0, x)` |
| 491 DummyIntercepted, |
| 492 |
| 493 /// JS receiver is the Dart receiver, there are no extra arguments. |
| 494 /// |
| 495 /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)` |
| 496 OneShotIntercepted, |
| 497 } |
| 498 |
| 499 /// Base class of function invocations. |
| 500 /// |
| 501 /// This class defines the common interface of function invocations. |
| 502 abstract class InvocationPrimitive extends UnsafePrimitive { |
| 503 Reference<Primitive> get receiver => null; |
| 504 List<Reference<Primitive>> get arguments; |
| 505 SourceInformation get sourceInformation; |
| 506 |
| 507 Reference<Primitive> get dartReceiverReference => null; |
| 508 CallingConvention get callingConvention => CallingConvention.Normal; |
| 509 } |
| 510 |
467 /// Invoke a static function. | 511 /// Invoke a static function. |
468 /// | 512 /// |
469 /// All optional arguments declared by [target] are passed in explicitly, and | 513 /// All optional arguments declared by [target] are passed in explicitly, and |
470 /// occur at the end of [arguments] list, in normalized order. | 514 /// occur at the end of [arguments] list, in normalized order. |
471 /// | 515 /// |
472 /// Discussion: | 516 /// Discussion: |
473 /// All information in the [selector] is technically redundant; it will likely | 517 /// All information in the [selector] is technically redundant; it will likely |
474 /// be removed. | 518 /// be removed. |
475 class InvokeStatic extends UnsafePrimitive { | 519 class InvokeStatic extends InvocationPrimitive { |
476 final FunctionElement target; | 520 final FunctionElement target; |
477 final Selector selector; | 521 final Selector selector; |
478 final List<Reference<Primitive>> arguments; | 522 final List<Reference<Primitive>> arguments; |
479 final SourceInformation sourceInformation; | 523 final SourceInformation sourceInformation; |
480 | 524 |
481 InvokeStatic(this.target, | 525 InvokeStatic(this.target, |
482 this.selector, | 526 this.selector, |
483 List<Primitive> args, | 527 List<Primitive> args, |
484 [this.sourceInformation]) | 528 [this.sourceInformation]) |
485 : arguments = _referenceList(args); | 529 : arguments = _referenceList(args); |
486 | 530 |
487 InvokeStatic.byReference(this.target, | 531 InvokeStatic.byReference(this.target, |
488 this.selector, | 532 this.selector, |
489 this.arguments, | 533 this.arguments, |
490 [this.sourceInformation]); | 534 [this.sourceInformation]); |
491 | 535 |
492 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 536 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
493 | 537 |
494 bool get hasValue => true; | 538 bool get hasValue => true; |
495 | 539 |
496 void setParentPointers() { | 540 void setParentPointers() { |
497 _setParentsOnList(arguments, this); | 541 _setParentsOnList(arguments, this); |
498 } | 542 } |
499 } | 543 } |
500 | 544 |
501 enum CallingConvention { | |
502 /// JS receiver is the Dart receiver, there are no extra arguments. | |
503 /// | |
504 /// For example: `foo.bar$1(x)` | |
505 Normal, | |
506 | |
507 /// JS receiver is an interceptor, the first argument is the Dart receiver. | |
508 /// | |
509 /// For example: `getInterceptor(foo).bar$1(foo, x)` | |
510 Intercepted, | |
511 | |
512 /// JS receiver is the Dart receiver, the first argument is a dummy value. | |
513 /// | |
514 /// For example: `foo.bar$1(0, x)` | |
515 DummyIntercepted, | |
516 | |
517 /// JS receiver is the Dart receiver, there are no extra arguments. | |
518 /// | |
519 /// Compiles to a one-shot interceptor, e.g: `J.bar$1(foo, x)` | |
520 OneShotIntercepted, | |
521 } | |
522 | |
523 /// Invoke a method on an object. | 545 /// Invoke a method on an object. |
524 /// | 546 /// |
525 /// This includes getters, setters, operators, and index getter/setters. | 547 /// This includes getters, setters, operators, and index getter/setters. |
526 /// | 548 /// |
527 /// Tearing off a method is treated like a getter invocation (getters and | 549 /// Tearing off a method is treated like a getter invocation (getters and |
528 /// tear-offs cannot be distinguished at compile-time). | 550 /// tear-offs cannot be distinguished at compile-time). |
529 /// | 551 /// |
530 /// The [selector] records the names of named arguments. The value of named | 552 /// The [selector] records the names of named arguments. The value of named |
531 /// arguments occur at the end of the [arguments] list, in normalized order. | 553 /// arguments occur at the end of the [arguments] list, in normalized order. |
532 class InvokeMethod extends UnsafePrimitive { | 554 class InvokeMethod extends InvocationPrimitive { |
533 Reference<Primitive> receiver; | 555 Reference<Primitive> receiver; |
534 Selector selector; | 556 Selector selector; |
535 TypeMask mask; | 557 TypeMask mask; |
536 final List<Reference<Primitive>> arguments; | 558 final List<Reference<Primitive>> arguments; |
537 final SourceInformation sourceInformation; | 559 final SourceInformation sourceInformation; |
538 | 560 |
539 CallingConvention callingConvention = CallingConvention.Normal; | 561 CallingConvention callingConvention = CallingConvention.Normal; |
540 | 562 |
541 Reference<Primitive> get dartReceiverReference { | 563 Reference<Primitive> get dartReceiverReference { |
542 return callingConvention == CallingConvention.Intercepted | 564 return callingConvention == CallingConvention.Intercepted |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 /// If it is known that [target] does not use its receiver argument, then | 621 /// If it is known that [target] does not use its receiver argument, then |
600 /// [receiver] may refer to a null constant primitive. This happens for direct | 622 /// [receiver] may refer to a null constant primitive. This happens for direct |
601 /// invocations to intercepted methods, where the effective receiver is instead | 623 /// invocations to intercepted methods, where the effective receiver is instead |
602 /// passed as a formal parameter. | 624 /// passed as a formal parameter. |
603 /// | 625 /// |
604 /// TODO(sra): Review. A direct call to a method that is mixed into a native | 626 /// TODO(sra): Review. A direct call to a method that is mixed into a native |
605 /// class will still require an explicit argument. | 627 /// class will still require an explicit argument. |
606 /// | 628 /// |
607 /// All optional arguments declared by [target] are passed in explicitly, and | 629 /// All optional arguments declared by [target] are passed in explicitly, and |
608 /// occur at the end of [arguments] list, in normalized order. | 630 /// occur at the end of [arguments] list, in normalized order. |
609 class InvokeMethodDirectly extends UnsafePrimitive { | 631 class InvokeMethodDirectly extends InvocationPrimitive { |
610 Reference<Primitive> receiver; | 632 Reference<Primitive> receiver; |
611 final FunctionElement target; | 633 final FunctionElement target; |
612 final Selector selector; | 634 final Selector selector; |
613 final List<Reference<Primitive>> arguments; | 635 final List<Reference<Primitive>> arguments; |
614 final SourceInformation sourceInformation; | 636 final SourceInformation sourceInformation; |
615 | 637 |
616 CallingConvention callingConvention = CallingConvention.Normal; | 638 CallingConvention callingConvention = CallingConvention.Normal; |
617 | 639 |
618 Reference<Primitive> get dartReceiverReference { | 640 Reference<Primitive> get dartReceiverReference { |
619 return callingConvention == CallingConvention.Intercepted | 641 return callingConvention == CallingConvention.Intercepted |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 /// All optional arguments declared by [target] are passed in explicitly, and | 679 /// All optional arguments declared by [target] are passed in explicitly, and |
658 /// occur in the [arguments] list, in normalized order. | 680 /// occur in the [arguments] list, in normalized order. |
659 /// | 681 /// |
660 /// Last in the [arguments] list, after the mandatory and optional arguments, | 682 /// Last in the [arguments] list, after the mandatory and optional arguments, |
661 /// the internal representation of each type argument occurs, unless it could | 683 /// the internal representation of each type argument occurs, unless it could |
662 /// be determined at build-time that the constructed class has no need for its | 684 /// be determined at build-time that the constructed class has no need for its |
663 /// runtime type information. | 685 /// runtime type information. |
664 /// | 686 /// |
665 /// Note that [InvokeConstructor] does it itself allocate an object. | 687 /// Note that [InvokeConstructor] does it itself allocate an object. |
666 /// The invoked constructor will do that using [CreateInstance]. | 688 /// The invoked constructor will do that using [CreateInstance]. |
667 class InvokeConstructor extends UnsafePrimitive { | 689 class InvokeConstructor extends InvocationPrimitive { |
668 final DartType dartType; | 690 final DartType dartType; |
669 final ConstructorElement target; | 691 final ConstructorElement target; |
670 final List<Reference<Primitive>> arguments; | 692 final List<Reference<Primitive>> arguments; |
671 final Selector selector; | 693 final Selector selector; |
672 final SourceInformation sourceInformation; | 694 final SourceInformation sourceInformation; |
673 | 695 |
674 /// If non-null, this is an allocation site-specific type that is potentially | 696 /// If non-null, this is an allocation site-specific type that is potentially |
675 /// better than the inferred return type of [target]. | 697 /// better than the inferred return type of [target]. |
676 /// | 698 /// |
677 /// In particular, container type masks depend on the allocation site and | 699 /// In particular, container type masks depend on the allocation site and |
(...skipping 1003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1681 if (body != null) body.parent = this; | 1703 if (body != null) body.parent = this; |
1682 } | 1704 } |
1683 } | 1705 } |
1684 | 1706 |
1685 /// Common interface for [Primitive] and [MutableVariable]. | 1707 /// Common interface for [Primitive] and [MutableVariable]. |
1686 abstract class Variable<T extends Variable<T>> extends Definition<T> { | 1708 abstract class Variable<T extends Variable<T>> extends Definition<T> { |
1687 /// Type of value held in the variable. | 1709 /// Type of value held in the variable. |
1688 /// | 1710 /// |
1689 /// Is `null` until initialized by type propagation. | 1711 /// Is `null` until initialized by type propagation. |
1690 TypeMask type; | 1712 TypeMask type; |
| 1713 |
| 1714 /// The [VariableElement] or [ParameterElement] from which the variable |
| 1715 /// binding originated. |
| 1716 Entity hint; |
| 1717 |
| 1718 Variable(this.hint); |
| 1719 |
| 1720 /// Use the given element as a hint for naming this primitive. |
| 1721 /// |
| 1722 /// Has no effect if this primitive already has a non-null [element]. |
| 1723 void useElementAsHint(Entity hint) { |
| 1724 this.hint ??= hint; |
| 1725 } |
1691 } | 1726 } |
1692 | 1727 |
1693 /// Identifies a mutable variable. | 1728 /// Identifies a mutable variable. |
1694 class MutableVariable extends Variable<MutableVariable> { | 1729 class MutableVariable extends Variable<MutableVariable> { |
1695 Entity hint; | 1730 MutableVariable(Entity hint) : super(hint); |
1696 | |
1697 MutableVariable(this.hint); | |
1698 | 1731 |
1699 accept(Visitor v) => v.visitMutableVariable(this); | 1732 accept(Visitor v) => v.visitMutableVariable(this); |
1700 | 1733 |
1701 void setParentPointers() {} | 1734 void setParentPointers() {} |
1702 } | 1735 } |
1703 | 1736 |
1704 /// A function definition, consisting of parameters and a body. | 1737 /// A function definition, consisting of parameters and a body. |
1705 /// | 1738 /// |
1706 /// There is an explicit parameter for the `this` argument, and a return | 1739 /// There is an explicit parameter for the `this` argument, and a return |
1707 /// continuation to invoke when returning from the function. | 1740 /// continuation to invoke when returning from the function. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1867 | 1900 |
1868 // Concrete classes. | 1901 // Concrete classes. |
1869 T visitFunctionDefinition(FunctionDefinition node); | 1902 T visitFunctionDefinition(FunctionDefinition node); |
1870 | 1903 |
1871 // Expressions. | 1904 // Expressions. |
1872 T visitLetPrim(LetPrim node); | 1905 T visitLetPrim(LetPrim node); |
1873 T visitLetCont(LetCont node); | 1906 T visitLetCont(LetCont node); |
1874 T visitLetHandler(LetHandler node); | 1907 T visitLetHandler(LetHandler node); |
1875 T visitLetMutable(LetMutable node); | 1908 T visitLetMutable(LetMutable node); |
1876 T visitInvokeContinuation(InvokeContinuation node); | 1909 T visitInvokeContinuation(InvokeContinuation node); |
| 1910 T visitThrow(Throw node); |
| 1911 T visitRethrow(Rethrow node); |
| 1912 T visitBranch(Branch node); |
| 1913 T visitUnreachable(Unreachable node); |
| 1914 |
| 1915 // Definitions. |
1877 T visitInvokeStatic(InvokeStatic node); | 1916 T visitInvokeStatic(InvokeStatic node); |
1878 T visitInvokeMethod(InvokeMethod node); | 1917 T visitInvokeMethod(InvokeMethod node); |
1879 T visitInvokeMethodDirectly(InvokeMethodDirectly node); | 1918 T visitInvokeMethodDirectly(InvokeMethodDirectly node); |
1880 T visitInvokeConstructor(InvokeConstructor node); | 1919 T visitInvokeConstructor(InvokeConstructor node); |
1881 T visitThrow(Throw node); | |
1882 T visitRethrow(Rethrow node); | |
1883 T visitBranch(Branch node); | |
1884 T visitTypeCast(TypeCast node); | 1920 T visitTypeCast(TypeCast node); |
1885 T visitSetMutable(SetMutable node); | 1921 T visitSetMutable(SetMutable node); |
1886 T visitSetStatic(SetStatic node); | 1922 T visitSetStatic(SetStatic node); |
| 1923 T visitSetField(SetField node); |
1887 T visitGetLazyStatic(GetLazyStatic node); | 1924 T visitGetLazyStatic(GetLazyStatic node); |
1888 T visitSetField(SetField node); | |
1889 T visitUnreachable(Unreachable node); | |
1890 T visitAwait(Await node); | 1925 T visitAwait(Await node); |
1891 T visitYield(Yield node); | 1926 T visitYield(Yield node); |
1892 | |
1893 // Definitions. | |
1894 T visitLiteralList(LiteralList node); | 1927 T visitLiteralList(LiteralList node); |
1895 T visitLiteralMap(LiteralMap node); | 1928 T visitLiteralMap(LiteralMap node); |
1896 T visitConstant(Constant node); | 1929 T visitConstant(Constant node); |
1897 T visitGetMutable(GetMutable node); | 1930 T visitGetMutable(GetMutable node); |
1898 T visitParameter(Parameter node); | 1931 T visitParameter(Parameter node); |
1899 T visitContinuation(Continuation node); | 1932 T visitContinuation(Continuation node); |
1900 T visitMutableVariable(MutableVariable node); | 1933 T visitMutableVariable(MutableVariable node); |
1901 T visitGetStatic(GetStatic node); | 1934 T visitGetStatic(GetStatic node); |
1902 T visitInterceptor(Interceptor node); | 1935 T visitInterceptor(Interceptor node); |
1903 T visitCreateInstance(CreateInstance node); | 1936 T visitCreateInstance(CreateInstance node); |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2385 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2418 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
2386 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2419 class RemovalVisitor extends TrampolineRecursiveVisitor { |
2387 processReference(Reference reference) { | 2420 processReference(Reference reference) { |
2388 reference.unlink(); | 2421 reference.unlink(); |
2389 } | 2422 } |
2390 | 2423 |
2391 static void remove(Node node) { | 2424 static void remove(Node node) { |
2392 (new RemovalVisitor()).visit(node); | 2425 (new RemovalVisitor()).visit(node); |
2393 } | 2426 } |
2394 } | 2427 } |
| 2428 |
| 2429 /// A visitor to copy instances of [Definition] or its subclasses, except for |
| 2430 /// instances of [Continuation]. |
| 2431 /// |
| 2432 /// The visitor maintains a map from original definitions to their copies. |
| 2433 /// When the [copy] method is called for a non-Continuation definition, |
| 2434 /// a copy is created, added to the map and returned as the result. Copying a |
| 2435 /// definition assumes that the definitions of all references have already |
| 2436 /// been copied by the same visitor. |
| 2437 class DefinitionCopyingVisitor extends Visitor<Definition> { |
| 2438 Map<Definition, Definition> _copies = <Definition, Definition>{}; |
| 2439 |
| 2440 /// Put a copy into the map. |
| 2441 /// |
| 2442 /// This method should be used instead of directly adding copies to the map. |
| 2443 Definition putCopy(Definition original, Definition copy) { |
| 2444 if (copy is Variable) { |
| 2445 Variable originalVariable = original; |
| 2446 copy.type = originalVariable.type; |
| 2447 copy.hint = originalVariable.hint; |
| 2448 } |
| 2449 return _copies[original] = copy; |
| 2450 } |
| 2451 |
| 2452 /// Get the copy of a [Reference]'s definition from the map. |
| 2453 Definition getCopy(Reference reference) => _copies[reference.definition]; |
| 2454 |
| 2455 /// Map a list of [Reference]s to the list of their definition's copies. |
| 2456 List<Definition> getList(List<Reference> list) => list.map(getCopy).toList(); |
| 2457 |
| 2458 /// Copy a non-[Continuation] [Definition]. |
| 2459 Definition copy(Definition node) { |
| 2460 assert (node is! Continuation); |
| 2461 return putCopy(node, visit(node)); |
| 2462 } |
| 2463 |
| 2464 Definition visit(Node node) => node.accept(this); |
| 2465 |
| 2466 Definition visitFunctionDefinition(FunctionDefinition node) {} |
| 2467 Definition visitLetPrim(LetPrim node) {} |
| 2468 Definition visitLetCont(LetCont node) {} |
| 2469 Definition visitLetHandler(LetHandler node) {} |
| 2470 Definition visitLetMutable(LetMutable node) {} |
| 2471 Definition visitInvokeContinuation(InvokeContinuation node) {} |
| 2472 Definition visitThrow(Throw node) {} |
| 2473 Definition visitRethrow(Rethrow node) {} |
| 2474 Definition visitBranch(Branch node) {} |
| 2475 Definition visitUnreachable(Unreachable node) {} |
| 2476 Definition visitContinuation(Continuation node) {} |
| 2477 |
| 2478 Definition visitInvokeStatic(InvokeStatic node) { |
| 2479 return new InvokeStatic(node.target, node.selector, getList(node.arguments), |
| 2480 node.sourceInformation); |
| 2481 } |
| 2482 |
| 2483 Definition visitInvokeMethod(InvokeMethod node) { |
| 2484 return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask, |
| 2485 getList(node.arguments), |
| 2486 node.sourceInformation); |
| 2487 } |
| 2488 |
| 2489 Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) { |
| 2490 return new InvokeMethodDirectly(getCopy(node.receiver), node.target, |
| 2491 node.selector, |
| 2492 getList(node.arguments), |
| 2493 node.sourceInformation); |
| 2494 } |
| 2495 |
| 2496 Definition visitInvokeConstructor(InvokeConstructor node) { |
| 2497 return new InvokeConstructor(node.dartType, node.target, node.selector, |
| 2498 getList(node.arguments), |
| 2499 node.sourceInformation); |
| 2500 } |
| 2501 |
| 2502 Definition visitTypeCast(TypeCast node) { |
| 2503 return new TypeCast(getCopy(node.value), node.dartType, |
| 2504 getList(node.typeArguments)); |
| 2505 } |
| 2506 |
| 2507 Definition visitSetMutable(SetMutable node) { |
| 2508 return new SetMutable(getCopy(node.variable), getCopy(node.value)); |
| 2509 } |
| 2510 |
| 2511 Definition visitSetStatic(SetStatic node) { |
| 2512 return new SetStatic(node.element, getCopy(node.value), |
| 2513 node.sourceInformation); |
| 2514 } |
| 2515 |
| 2516 Definition visitSetField(SetField node) { |
| 2517 return new SetField(getCopy(node.object), node.field, getCopy(node.value)); |
| 2518 } |
| 2519 |
| 2520 Definition visitGetLazyStatic(GetLazyStatic node) { |
| 2521 return new GetLazyStatic(node.element, node.sourceInformation); |
| 2522 } |
| 2523 |
| 2524 Definition visitAwait(Await node) { |
| 2525 return new Await(getCopy(node.input)); |
| 2526 } |
| 2527 |
| 2528 Definition visitYield(Yield node) { |
| 2529 return new Yield(getCopy(node.input), node.hasStar); |
| 2530 } |
| 2531 |
| 2532 Definition visitLiteralList(LiteralList node) { |
| 2533 return new LiteralList(node.dartType, getList(node.values)); |
| 2534 } |
| 2535 |
| 2536 Definition visitLiteralMap(LiteralMap node) { |
| 2537 List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) { |
| 2538 return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value)); |
| 2539 }).toList(); |
| 2540 return new LiteralMap(node.dartType, entries); |
| 2541 } |
| 2542 |
| 2543 Definition visitConstant(Constant node) { |
| 2544 return new Constant(node.value, sourceInformation: node.sourceInformation); |
| 2545 } |
| 2546 |
| 2547 Definition visitGetMutable(GetMutable node) { |
| 2548 return new GetMutable(getCopy(node.variable)); |
| 2549 } |
| 2550 |
| 2551 Definition visitParameter(Parameter node) { |
| 2552 return new Parameter(node.hint); |
| 2553 } |
| 2554 |
| 2555 Definition visitMutableVariable(MutableVariable node) { |
| 2556 return new MutableVariable(node.hint); |
| 2557 } |
| 2558 |
| 2559 Definition visitGetStatic(GetStatic node) { |
| 2560 return new GetStatic(node.element, node.sourceInformation); |
| 2561 } |
| 2562 |
| 2563 Definition visitInterceptor(Interceptor node) { |
| 2564 return new Interceptor(getCopy(node.input), node.sourceInformation) |
| 2565 ..interceptedClasses.addAll(node.interceptedClasses); |
| 2566 } |
| 2567 |
| 2568 Definition visitCreateInstance(CreateInstance node) { |
| 2569 return new CreateInstance(node.classElement, getList(node.arguments), |
| 2570 getList(node.typeInformation), |
| 2571 node.sourceInformation); |
| 2572 } |
| 2573 |
| 2574 Definition visitGetField(GetField node) { |
| 2575 return new GetField(getCopy(node.object), node.field); |
| 2576 } |
| 2577 |
| 2578 Definition visitCreateBox(CreateBox node) { |
| 2579 return new CreateBox(); |
| 2580 } |
| 2581 |
| 2582 Definition visitReifyRuntimeType(ReifyRuntimeType node) { |
| 2583 return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation); |
| 2584 } |
| 2585 |
| 2586 Definition visitReadTypeVariable(ReadTypeVariable node) { |
| 2587 return new ReadTypeVariable(node.variable, getCopy(node.target), |
| 2588 node.sourceInformation); |
| 2589 } |
| 2590 |
| 2591 Definition visitTypeExpression(TypeExpression node) { |
| 2592 return new TypeExpression(node.dartType, getList(node.arguments)); |
| 2593 } |
| 2594 |
| 2595 Definition visitCreateInvocationMirror(CreateInvocationMirror node) { |
| 2596 return new CreateInvocationMirror(node.selector, getList(node.arguments)); |
| 2597 } |
| 2598 |
| 2599 Definition visitTypeTest(TypeTest node) { |
| 2600 return new TypeTest(getCopy(node.value), node.dartType, |
| 2601 getList(node.typeArguments)); |
| 2602 } |
| 2603 |
| 2604 Definition visitTypeTestViaFlag(TypeTestViaFlag node) { |
| 2605 return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType); |
| 2606 } |
| 2607 |
| 2608 Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) { |
| 2609 return new ApplyBuiltinOperator(node.operator, getList(node.arguments), |
| 2610 node.sourceInformation); |
| 2611 } |
| 2612 |
| 2613 Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
| 2614 return new ApplyBuiltinMethod(node.method, getCopy(node.receiver), |
| 2615 getList(node.arguments), |
| 2616 node.sourceInformation, |
| 2617 receiverIsNotNull: node.receiverIsNotNull); |
| 2618 } |
| 2619 |
| 2620 Definition visitGetLength(GetLength node) { |
| 2621 return new GetLength(getCopy(node.object)); |
| 2622 } |
| 2623 |
| 2624 Definition visitGetIndex(GetIndex node) { |
| 2625 return new GetIndex(getCopy(node.object), getCopy(node.index)); |
| 2626 } |
| 2627 |
| 2628 Definition visitSetIndex(SetIndex node) { |
| 2629 return new SetIndex(getCopy(node.object), getCopy(node.index), |
| 2630 getCopy(node.value)); |
| 2631 } |
| 2632 |
| 2633 Definition visitRefinement(Refinement node) { |
| 2634 return new Refinement(getCopy(node.value), node.refineType); |
| 2635 } |
| 2636 |
| 2637 Definition visitBoundsCheck(BoundsCheck node) { |
| 2638 if (node.hasNoChecks) { |
| 2639 return new BoundsCheck.noCheck(getCopy(node.object), |
| 2640 node.sourceInformation); |
| 2641 } else { |
| 2642 return new BoundsCheck(getCopy(node.object), getCopy(node.index), |
| 2643 getCopy(node.length), |
| 2644 node.checks, |
| 2645 node.sourceInformation); |
| 2646 } |
| 2647 } |
| 2648 |
| 2649 Definition visitNullCheck(NullCheck node) { |
| 2650 return new NullCheck(getCopy(node.value), node.sourceInformation); |
| 2651 } |
| 2652 |
| 2653 Definition visitForeignCode(ForeignCode node) { |
| 2654 return new ForeignCode(node.codeTemplate, node.type, |
| 2655 getList(node.arguments), |
| 2656 node.nativeBehavior, |
| 2657 dependency: node.dependency); |
| 2658 } |
| 2659 } |
| 2660 |
| 2661 /// A trampolining visitor to copy [FunctionDefinition]s. |
| 2662 class CopyingVisitor extends TrampolineRecursiveVisitor { |
| 2663 // The visitor maintains a map from original continuations to their copies. |
| 2664 Map<Continuation, Continuation> _copies = <Continuation, Continuation>{}; |
| 2665 |
| 2666 // The visitor uses an auxiliary visitor to copy definitions. |
| 2667 DefinitionCopyingVisitor _definitions = new DefinitionCopyingVisitor(); |
| 2668 |
| 2669 // While copying a block, the state of the visitor is a 'linked list' of |
| 2670 // the expressions in the block's body, with a pointer to the last element |
| 2671 // of the list. |
| 2672 Expression _first = null; |
| 2673 Expression _current = null; |
| 2674 |
| 2675 void plug(Expression body) { |
| 2676 if (_first == null) { |
| 2677 _first = body; |
| 2678 } else { |
| 2679 assert(_current != null); |
| 2680 InteriorExpression interior = _current; |
| 2681 interior.body = body; |
| 2682 } |
| 2683 _current = body; |
| 2684 } |
| 2685 |
| 2686 // Continuations are added to the visitor's stack to be visited after copying |
| 2687 // the current block is finished. The stack action saves the current block, |
| 2688 // copies the continuation's body, sets the body on the copy of the |
| 2689 // continuation, and restores the current block. |
| 2690 // |
| 2691 // Note that continuations are added to the copy map before the stack action |
| 2692 // to visit them is performed. |
| 2693 void push(Continuation cont) { |
| 2694 assert(!cont.isReturnContinuation); |
| 2695 _stack.add(() { |
| 2696 Expression savedFirst = _first; |
| 2697 _first = _current = null; |
| 2698 _processBlock(cont.body); |
| 2699 _copies[cont].body = _first; |
| 2700 _first = savedFirst; |
| 2701 _current = null; |
| 2702 }); |
| 2703 } |
| 2704 |
| 2705 FunctionDefinition copy(FunctionDefinition node) { |
| 2706 assert(_first == null && _current == null); |
| 2707 _first = _current = null; |
| 2708 // Definitions are copied where they are bound, before processing |
| 2709 // expressions in the scope of their binding. |
| 2710 Parameter thisParameter = node.thisParameter == null |
| 2711 ? null |
| 2712 : _definitions.copy(node.thisParameter); |
| 2713 List<Parameter> parameters = |
| 2714 node.parameters.map(_definitions.copy).toList(); |
| 2715 // Though the return continuation's parameter does not have any uses, |
| 2716 // we still make a proper copy to ensure that hints, type, etc. are |
| 2717 // copied. |
| 2718 Parameter returnParameter = |
| 2719 _definitions.copy(node.returnContinuation.parameters.first); |
| 2720 Continuation returnContinuation = _copies[node.returnContinuation] = |
| 2721 new Continuation([returnParameter]); |
| 2722 |
| 2723 visit(node.body); |
| 2724 FunctionDefinition copy = new FunctionDefinition(node.element, |
| 2725 thisParameter, |
| 2726 parameters, |
| 2727 returnContinuation, |
| 2728 _first); |
| 2729 _first = _current = null; |
| 2730 return copy; |
| 2731 } |
| 2732 |
| 2733 Node visit(Node node) => node.accept(this); |
| 2734 |
| 2735 Expression traverseLetCont(LetCont node) { |
| 2736 // Continuations are copied where they are bound, before processing |
| 2737 // expressions in the scope of their binding. |
| 2738 List<Continuation> continuations = node.continuations.map((Continuation c) { |
| 2739 push(c); |
| 2740 return _copies[c] = |
| 2741 new Continuation(c.parameters.map(_definitions.copy).toList()); |
| 2742 }).toList(); |
| 2743 plug(new LetCont.many(continuations, null)); |
| 2744 return node.body; |
| 2745 } |
| 2746 |
| 2747 Expression traverseLetHandler(LetHandler node) { |
| 2748 // Continuations are copied where they are bound, before processing |
| 2749 // expressions in the scope of their binding. |
| 2750 push(node.handler); |
| 2751 Continuation handler = _copies[node.handler] = |
| 2752 new Continuation(node.handler.parameters.map(_definitions.copy) |
| 2753 .toList()); |
| 2754 plug(new LetHandler(handler, null)); |
| 2755 return node.body; |
| 2756 } |
| 2757 |
| 2758 Expression traverseLetPrim(LetPrim node) { |
| 2759 plug(new LetPrim(_definitions.copy(node.primitive))); |
| 2760 return node.body; |
| 2761 } |
| 2762 |
| 2763 Expression traverseLetMutable(LetMutable node) { |
| 2764 plug(new LetMutable(_definitions.copy(node.variable), |
| 2765 _definitions.getCopy(node.value))); |
| 2766 return node.body; |
| 2767 } |
| 2768 |
| 2769 // Tail expressions do not have references, so we do not need to map them |
| 2770 // to their copies. |
| 2771 visitInvokeContinuation(InvokeContinuation node) { |
| 2772 plug(new InvokeContinuation(_copies[node.continuation.definition], |
| 2773 _definitions.getList(node.arguments), |
| 2774 isRecursive: node.isRecursive, |
| 2775 isEscapingTry: node.isEscapingTry, |
| 2776 sourceInformation: node.sourceInformation)); |
| 2777 } |
| 2778 |
| 2779 Node visitThrow(Throw node) { |
| 2780 plug(new Throw(_definitions.getCopy(node.value))); |
| 2781 } |
| 2782 |
| 2783 Node visitRethrow(Rethrow node) { |
| 2784 plug(new Rethrow()); |
| 2785 } |
| 2786 |
| 2787 Node visitBranch(Branch node) { |
| 2788 plug(new Branch.loose(_definitions.getCopy(node.condition), |
| 2789 _copies[node.trueContinuation.definition], |
| 2790 _copies[node.falseContinuation.definition]) |
| 2791 ..isStrictCheck = node.isStrictCheck); |
| 2792 } |
| 2793 |
| 2794 Node visitUnreachable(Unreachable node) { |
| 2795 plug(new Unreachable()); |
| 2796 } |
| 2797 } |
OLD | NEW |