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; | |
8 import '../constants/values.dart' as values; | 7 import '../constants/values.dart' as values; |
9 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
10 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
11 import '../io/source_information.dart' show SourceInformation; | 10 import '../io/source_information.dart' show SourceInformation; |
12 import '../types/types.dart' show TypeMask; | 11 import '../types/types.dart' show TypeMask; |
13 import '../universe/selector.dart' show Selector; | 12 import '../universe/selector.dart' show Selector; |
14 | 13 |
15 import 'builtin_operator.dart'; | 14 import 'builtin_operator.dart'; |
16 export 'builtin_operator.dart'; | 15 export 'builtin_operator.dart'; |
17 | 16 |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); | 196 EffectiveUseIterator get iterator => new EffectiveUseIterator(primitive); |
198 } | 197 } |
199 | 198 |
200 /// A named value. | 199 /// A named value. |
201 /// | 200 /// |
202 /// The identity of the [Primitive] object is the name of the value. | 201 /// The identity of the [Primitive] object is the name of the value. |
203 /// The subclass describes how to compute the value. | 202 /// The subclass describes how to compute the value. |
204 /// | 203 /// |
205 /// All primitives except [Parameter] must be bound by a [LetPrim]. | 204 /// All primitives except [Parameter] must be bound by a [LetPrim]. |
206 abstract class Primitive extends Variable<Primitive> { | 205 abstract class Primitive extends Variable<Primitive> { |
207 Primitive() : super(null); | 206 /// The [VariableElement] or [ParameterElement] from which the primitive |
| 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 } |
208 | 218 |
209 /// True if this primitive has a value that can be used by other expressions. | 219 /// True if this primitive has a value that can be used by other expressions. |
210 bool get hasValue; | 220 bool get hasValue; |
211 | 221 |
212 /// True if the primitive can be removed, assuming it has no uses | 222 /// True if the primitive can be removed, assuming it has no uses |
213 /// (this getter does not check if there are any uses). | 223 /// (this getter does not check if there are any uses). |
214 /// | 224 /// |
215 /// False must be returned for primitives that may throw, diverge, or have | 225 /// False must be returned for primitives that may throw, diverge, or have |
216 /// observable side-effects. | 226 /// observable side-effects. |
217 bool get isSafeForElimination; | 227 bool get isSafeForElimination; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 assert(this is! Parameter); | 288 assert(this is! Parameter); |
279 assert(newDefinition is! Parameter); | 289 assert(newDefinition is! Parameter); |
280 assert(newDefinition.parent == null); | 290 assert(newDefinition.parent == null); |
281 replaceUsesWith(newDefinition); | 291 replaceUsesWith(newDefinition); |
282 destroy(); | 292 destroy(); |
283 LetPrim let = parent; | 293 LetPrim let = parent; |
284 let.primitive = newDefinition; | 294 let.primitive = newDefinition; |
285 newDefinition.parent = let; | 295 newDefinition.parent = let; |
286 newDefinition.useElementAsHint(hint); | 296 newDefinition.useElementAsHint(hint); |
287 } | 297 } |
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 } | |
305 } | 298 } |
306 | 299 |
307 /// A primitive that is generally not safe for elimination, but may be marked | 300 /// A primitive that is generally not safe for elimination, but may be marked |
308 /// as safe by type propagation | 301 /// as safe by type propagation |
309 // | 302 // |
310 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this | 303 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this |
311 // class. | 304 // class. |
312 abstract class UnsafePrimitive extends Primitive { | 305 abstract class UnsafePrimitive extends Primitive { |
313 bool isSafeForElimination = false; | 306 bool isSafeForElimination = false; |
314 bool isSafeForReordering = false; | 307 bool isSafeForReordering = false; |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
464 | 457 |
465 accept(Visitor visitor) => visitor.visitLetMutable(this); | 458 accept(Visitor visitor) => visitor.visitLetMutable(this); |
466 | 459 |
467 void setParentPointers() { | 460 void setParentPointers() { |
468 variable.parent = this; | 461 variable.parent = this; |
469 value.parent = this; | 462 value.parent = this; |
470 if (body != null) body.parent = this; | 463 if (body != null) body.parent = this; |
471 } | 464 } |
472 } | 465 } |
473 | 466 |
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 | |
511 /// Invoke a static function. | 467 /// Invoke a static function. |
512 /// | 468 /// |
513 /// All optional arguments declared by [target] are passed in explicitly, and | 469 /// All optional arguments declared by [target] are passed in explicitly, and |
514 /// occur at the end of [arguments] list, in normalized order. | 470 /// occur at the end of [arguments] list, in normalized order. |
515 /// | 471 /// |
516 /// Discussion: | 472 /// Discussion: |
517 /// All information in the [selector] is technically redundant; it will likely | 473 /// All information in the [selector] is technically redundant; it will likely |
518 /// be removed. | 474 /// be removed. |
519 class InvokeStatic extends InvocationPrimitive { | 475 class InvokeStatic extends UnsafePrimitive { |
520 final FunctionElement target; | 476 final FunctionElement target; |
521 final Selector selector; | 477 final Selector selector; |
522 final List<Reference<Primitive>> arguments; | 478 final List<Reference<Primitive>> arguments; |
523 final SourceInformation sourceInformation; | 479 final SourceInformation sourceInformation; |
524 | 480 |
525 InvokeStatic(this.target, | 481 InvokeStatic(this.target, |
526 this.selector, | 482 this.selector, |
527 List<Primitive> args, | 483 List<Primitive> args, |
528 [this.sourceInformation]) | 484 [this.sourceInformation]) |
529 : arguments = _referenceList(args); | 485 : arguments = _referenceList(args); |
530 | 486 |
531 InvokeStatic.byReference(this.target, | 487 InvokeStatic.byReference(this.target, |
532 this.selector, | 488 this.selector, |
533 this.arguments, | 489 this.arguments, |
534 [this.sourceInformation]); | 490 [this.sourceInformation]); |
535 | 491 |
536 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 492 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
537 | 493 |
538 bool get hasValue => true; | 494 bool get hasValue => true; |
539 | 495 |
540 void setParentPointers() { | 496 void setParentPointers() { |
541 _setParentsOnList(arguments, this); | 497 _setParentsOnList(arguments, this); |
542 } | 498 } |
543 } | 499 } |
544 | 500 |
| 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 |
545 /// Invoke a method on an object. | 523 /// Invoke a method on an object. |
546 /// | 524 /// |
547 /// This includes getters, setters, operators, and index getter/setters. | 525 /// This includes getters, setters, operators, and index getter/setters. |
548 /// | 526 /// |
549 /// Tearing off a method is treated like a getter invocation (getters and | 527 /// Tearing off a method is treated like a getter invocation (getters and |
550 /// tear-offs cannot be distinguished at compile-time). | 528 /// tear-offs cannot be distinguished at compile-time). |
551 /// | 529 /// |
552 /// The [selector] records the names of named arguments. The value of named | 530 /// The [selector] records the names of named arguments. The value of named |
553 /// arguments occur at the end of the [arguments] list, in normalized order. | 531 /// arguments occur at the end of the [arguments] list, in normalized order. |
554 class InvokeMethod extends InvocationPrimitive { | 532 class InvokeMethod extends UnsafePrimitive { |
555 Reference<Primitive> receiver; | 533 Reference<Primitive> receiver; |
556 Selector selector; | 534 Selector selector; |
557 TypeMask mask; | 535 TypeMask mask; |
558 final List<Reference<Primitive>> arguments; | 536 final List<Reference<Primitive>> arguments; |
559 final SourceInformation sourceInformation; | 537 final SourceInformation sourceInformation; |
560 | 538 |
561 CallingConvention callingConvention = CallingConvention.Normal; | 539 CallingConvention callingConvention = CallingConvention.Normal; |
562 | 540 |
563 Reference<Primitive> get dartReceiverReference { | 541 Reference<Primitive> get dartReceiverReference { |
564 return callingConvention == CallingConvention.Intercepted | 542 return callingConvention == CallingConvention.Intercepted |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
621 /// If it is known that [target] does not use its receiver argument, then | 599 /// If it is known that [target] does not use its receiver argument, then |
622 /// [receiver] may refer to a null constant primitive. This happens for direct | 600 /// [receiver] may refer to a null constant primitive. This happens for direct |
623 /// invocations to intercepted methods, where the effective receiver is instead | 601 /// invocations to intercepted methods, where the effective receiver is instead |
624 /// passed as a formal parameter. | 602 /// passed as a formal parameter. |
625 /// | 603 /// |
626 /// TODO(sra): Review. A direct call to a method that is mixed into a native | 604 /// TODO(sra): Review. A direct call to a method that is mixed into a native |
627 /// class will still require an explicit argument. | 605 /// class will still require an explicit argument. |
628 /// | 606 /// |
629 /// All optional arguments declared by [target] are passed in explicitly, and | 607 /// All optional arguments declared by [target] are passed in explicitly, and |
630 /// occur at the end of [arguments] list, in normalized order. | 608 /// occur at the end of [arguments] list, in normalized order. |
631 class InvokeMethodDirectly extends InvocationPrimitive { | 609 class InvokeMethodDirectly extends UnsafePrimitive { |
632 Reference<Primitive> receiver; | 610 Reference<Primitive> receiver; |
633 final FunctionElement target; | 611 final FunctionElement target; |
634 final Selector selector; | 612 final Selector selector; |
635 final List<Reference<Primitive>> arguments; | 613 final List<Reference<Primitive>> arguments; |
636 final SourceInformation sourceInformation; | 614 final SourceInformation sourceInformation; |
637 | 615 |
638 CallingConvention callingConvention = CallingConvention.Normal; | 616 CallingConvention callingConvention = CallingConvention.Normal; |
639 | 617 |
640 Reference<Primitive> get dartReceiverReference { | 618 Reference<Primitive> get dartReceiverReference { |
641 return callingConvention == CallingConvention.Intercepted | 619 return callingConvention == CallingConvention.Intercepted |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
679 /// All optional arguments declared by [target] are passed in explicitly, and | 657 /// All optional arguments declared by [target] are passed in explicitly, and |
680 /// occur in the [arguments] list, in normalized order. | 658 /// occur in the [arguments] list, in normalized order. |
681 /// | 659 /// |
682 /// Last in the [arguments] list, after the mandatory and optional arguments, | 660 /// Last in the [arguments] list, after the mandatory and optional arguments, |
683 /// the internal representation of each type argument occurs, unless it could | 661 /// the internal representation of each type argument occurs, unless it could |
684 /// be determined at build-time that the constructed class has no need for its | 662 /// be determined at build-time that the constructed class has no need for its |
685 /// runtime type information. | 663 /// runtime type information. |
686 /// | 664 /// |
687 /// Note that [InvokeConstructor] does it itself allocate an object. | 665 /// Note that [InvokeConstructor] does it itself allocate an object. |
688 /// The invoked constructor will do that using [CreateInstance]. | 666 /// The invoked constructor will do that using [CreateInstance]. |
689 class InvokeConstructor extends InvocationPrimitive { | 667 class InvokeConstructor extends UnsafePrimitive { |
690 final DartType dartType; | 668 final DartType dartType; |
691 final ConstructorElement target; | 669 final ConstructorElement target; |
692 final List<Reference<Primitive>> arguments; | 670 final List<Reference<Primitive>> arguments; |
693 final Selector selector; | 671 final Selector selector; |
694 final SourceInformation sourceInformation; | 672 final SourceInformation sourceInformation; |
695 | 673 |
696 /// If non-null, this is an allocation site-specific type that is potentially | 674 /// If non-null, this is an allocation site-specific type that is potentially |
697 /// better than the inferred return type of [target]. | 675 /// better than the inferred return type of [target]. |
698 /// | 676 /// |
699 /// In particular, container type masks depend on the allocation site and | 677 /// In particular, container type masks depend on the allocation site and |
(...skipping 1003 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1703 if (body != null) body.parent = this; | 1681 if (body != null) body.parent = this; |
1704 } | 1682 } |
1705 } | 1683 } |
1706 | 1684 |
1707 /// Common interface for [Primitive] and [MutableVariable]. | 1685 /// Common interface for [Primitive] and [MutableVariable]. |
1708 abstract class Variable<T extends Variable<T>> extends Definition<T> { | 1686 abstract class Variable<T extends Variable<T>> extends Definition<T> { |
1709 /// Type of value held in the variable. | 1687 /// Type of value held in the variable. |
1710 /// | 1688 /// |
1711 /// Is `null` until initialized by type propagation. | 1689 /// Is `null` until initialized by type propagation. |
1712 TypeMask type; | 1690 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 } | |
1726 } | 1691 } |
1727 | 1692 |
1728 /// Identifies a mutable variable. | 1693 /// Identifies a mutable variable. |
1729 class MutableVariable extends Variable<MutableVariable> { | 1694 class MutableVariable extends Variable<MutableVariable> { |
1730 MutableVariable(Entity hint) : super(hint); | 1695 Entity hint; |
| 1696 |
| 1697 MutableVariable(this.hint); |
1731 | 1698 |
1732 accept(Visitor v) => v.visitMutableVariable(this); | 1699 accept(Visitor v) => v.visitMutableVariable(this); |
1733 | 1700 |
1734 void setParentPointers() {} | 1701 void setParentPointers() {} |
1735 } | 1702 } |
1736 | 1703 |
1737 /// A function definition, consisting of parameters and a body. | 1704 /// A function definition, consisting of parameters and a body. |
1738 /// | 1705 /// |
1739 /// There is an explicit parameter for the `this` argument, and a return | 1706 /// There is an explicit parameter for the `this` argument, and a return |
1740 /// continuation to invoke when returning from the function. | 1707 /// continuation to invoke when returning from the function. |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1900 | 1867 |
1901 // Concrete classes. | 1868 // Concrete classes. |
1902 T visitFunctionDefinition(FunctionDefinition node); | 1869 T visitFunctionDefinition(FunctionDefinition node); |
1903 | 1870 |
1904 // Expressions. | 1871 // Expressions. |
1905 T visitLetPrim(LetPrim node); | 1872 T visitLetPrim(LetPrim node); |
1906 T visitLetCont(LetCont node); | 1873 T visitLetCont(LetCont node); |
1907 T visitLetHandler(LetHandler node); | 1874 T visitLetHandler(LetHandler node); |
1908 T visitLetMutable(LetMutable node); | 1875 T visitLetMutable(LetMutable node); |
1909 T visitInvokeContinuation(InvokeContinuation node); | 1876 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. | |
1916 T visitInvokeStatic(InvokeStatic node); | 1877 T visitInvokeStatic(InvokeStatic node); |
1917 T visitInvokeMethod(InvokeMethod node); | 1878 T visitInvokeMethod(InvokeMethod node); |
1918 T visitInvokeMethodDirectly(InvokeMethodDirectly node); | 1879 T visitInvokeMethodDirectly(InvokeMethodDirectly node); |
1919 T visitInvokeConstructor(InvokeConstructor node); | 1880 T visitInvokeConstructor(InvokeConstructor node); |
| 1881 T visitThrow(Throw node); |
| 1882 T visitRethrow(Rethrow node); |
| 1883 T visitBranch(Branch node); |
1920 T visitTypeCast(TypeCast node); | 1884 T visitTypeCast(TypeCast node); |
1921 T visitSetMutable(SetMutable node); | 1885 T visitSetMutable(SetMutable node); |
1922 T visitSetStatic(SetStatic node); | 1886 T visitSetStatic(SetStatic node); |
| 1887 T visitGetLazyStatic(GetLazyStatic node); |
1923 T visitSetField(SetField node); | 1888 T visitSetField(SetField node); |
1924 T visitGetLazyStatic(GetLazyStatic node); | 1889 T visitUnreachable(Unreachable node); |
1925 T visitAwait(Await node); | 1890 T visitAwait(Await node); |
1926 T visitYield(Yield node); | 1891 T visitYield(Yield node); |
| 1892 |
| 1893 // Definitions. |
1927 T visitLiteralList(LiteralList node); | 1894 T visitLiteralList(LiteralList node); |
1928 T visitLiteralMap(LiteralMap node); | 1895 T visitLiteralMap(LiteralMap node); |
1929 T visitConstant(Constant node); | 1896 T visitConstant(Constant node); |
1930 T visitGetMutable(GetMutable node); | 1897 T visitGetMutable(GetMutable node); |
1931 T visitParameter(Parameter node); | 1898 T visitParameter(Parameter node); |
1932 T visitContinuation(Continuation node); | 1899 T visitContinuation(Continuation node); |
1933 T visitMutableVariable(MutableVariable node); | 1900 T visitMutableVariable(MutableVariable node); |
1934 T visitGetStatic(GetStatic node); | 1901 T visitGetStatic(GetStatic node); |
1935 T visitInterceptor(Interceptor node); | 1902 T visitInterceptor(Interceptor node); |
1936 T visitCreateInstance(CreateInstance node); | 1903 T visitCreateInstance(CreateInstance node); |
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2418 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2385 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
2419 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2386 class RemovalVisitor extends TrampolineRecursiveVisitor { |
2420 processReference(Reference reference) { | 2387 processReference(Reference reference) { |
2421 reference.unlink(); | 2388 reference.unlink(); |
2422 } | 2389 } |
2423 | 2390 |
2424 static void remove(Node node) { | 2391 static void remove(Node node) { |
2425 (new RemovalVisitor()).visit(node); | 2392 (new RemovalVisitor()).visit(node); |
2426 } | 2393 } |
2427 } | 2394 } |
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 |