Chromium Code Reviews| 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 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 288 assert(this is! Parameter); | 289 assert(this is! Parameter); |
| 289 assert(newDefinition is! Parameter); | 290 assert(newDefinition is! Parameter); |
| 290 assert(newDefinition.parent == null); | 291 assert(newDefinition.parent == null); |
| 291 replaceUsesWith(newDefinition); | 292 replaceUsesWith(newDefinition); |
| 292 destroy(); | 293 destroy(); |
| 293 LetPrim let = parent; | 294 LetPrim let = parent; |
| 294 let.primitive = newDefinition; | 295 let.primitive = newDefinition; |
| 295 newDefinition.parent = let; | 296 newDefinition.parent = let; |
| 296 newDefinition.useElementAsHint(hint); | 297 newDefinition.useElementAsHint(hint); |
| 297 } | 298 } |
| 299 | |
| 300 /// Replaces this definition with a CPS fragment (a term with a hole in it), | |
| 301 /// given the value to replace the uses of the definition with. | |
| 302 /// | |
| 303 /// This can be thought of as substituting: | |
| 304 /// | |
| 305 /// let x = OLD in BODY | |
| 306 /// ==> | |
| 307 /// FRAGMENT[BODY{newPrimitive/x}] | |
| 308 void replaceWithFragment(CpsFragment fragment, Primitive newPrimitive) { | |
| 309 assert(this is! Parameter); | |
| 310 replaceUsesWith(newPrimitive); | |
| 311 destroy(); | |
| 312 LetPrim let = parent; | |
| 313 fragment.insertBelow(let); | |
| 314 let.remove(); | |
| 315 } | |
| 298 } | 316 } |
| 299 | 317 |
| 300 /// A primitive that is generally not safe for elimination, but may be marked | 318 /// A primitive that is generally not safe for elimination, but may be marked |
| 301 /// as safe by type propagation | 319 /// as safe by type propagation |
| 302 // | 320 // |
| 303 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this | 321 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this |
| 304 // class. | 322 // class. |
| 305 abstract class UnsafePrimitive extends Primitive { | 323 abstract class UnsafePrimitive extends Primitive { |
| 306 bool isSafeForElimination = false; | 324 bool isSafeForElimination = false; |
| 307 bool isSafeForReordering = false; | 325 bool isSafeForReordering = false; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 457 | 475 |
| 458 accept(Visitor visitor) => visitor.visitLetMutable(this); | 476 accept(Visitor visitor) => visitor.visitLetMutable(this); |
| 459 | 477 |
| 460 void setParentPointers() { | 478 void setParentPointers() { |
| 461 variable.parent = this; | 479 variable.parent = this; |
| 462 value.parent = this; | 480 value.parent = this; |
| 463 if (body != null) body.parent = this; | 481 if (body != null) body.parent = this; |
| 464 } | 482 } |
| 465 } | 483 } |
| 466 | 484 |
| 485 /// Base class of function invocations. | |
| 486 /// | |
| 487 /// This class defines the common interface of function invocations. | |
| 488 abstract class InvocationPrimitive extends UnsafePrimitive { | |
| 489 Reference<Primitive> get receiver => null; | |
| 490 List<Reference<Primitive>> get arguments; | |
| 491 SourceInformation get sourceInformation; | |
| 492 } | |
| 493 | |
| 467 /// Invoke a static function. | 494 /// Invoke a static function. |
| 468 /// | 495 /// |
| 469 /// All optional arguments declared by [target] are passed in explicitly, and | 496 /// All optional arguments declared by [target] are passed in explicitly, and |
| 470 /// occur at the end of [arguments] list, in normalized order. | 497 /// occur at the end of [arguments] list, in normalized order. |
| 471 /// | 498 /// |
| 472 /// Discussion: | 499 /// Discussion: |
| 473 /// All information in the [selector] is technically redundant; it will likely | 500 /// All information in the [selector] is technically redundant; it will likely |
| 474 /// be removed. | 501 /// be removed. |
| 475 class InvokeStatic extends UnsafePrimitive { | 502 class InvokeStatic extends InvocationPrimitive { |
| 476 final FunctionElement target; | 503 final FunctionElement target; |
| 477 final Selector selector; | 504 final Selector selector; |
| 478 final List<Reference<Primitive>> arguments; | 505 final List<Reference<Primitive>> arguments; |
| 479 final SourceInformation sourceInformation; | 506 final SourceInformation sourceInformation; |
| 480 | 507 |
| 481 InvokeStatic(this.target, | 508 InvokeStatic(this.target, |
| 482 this.selector, | 509 this.selector, |
| 483 List<Primitive> args, | 510 List<Primitive> args, |
| 484 [this.sourceInformation]) | 511 [this.sourceInformation]) |
| 485 : arguments = _referenceList(args); | 512 : arguments = _referenceList(args); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 | 549 |
| 523 /// Invoke a method on an object. | 550 /// Invoke a method on an object. |
| 524 /// | 551 /// |
| 525 /// This includes getters, setters, operators, and index getter/setters. | 552 /// This includes getters, setters, operators, and index getter/setters. |
| 526 /// | 553 /// |
| 527 /// Tearing off a method is treated like a getter invocation (getters and | 554 /// Tearing off a method is treated like a getter invocation (getters and |
| 528 /// tear-offs cannot be distinguished at compile-time). | 555 /// tear-offs cannot be distinguished at compile-time). |
| 529 /// | 556 /// |
| 530 /// The [selector] records the names of named arguments. The value of named | 557 /// 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. | 558 /// arguments occur at the end of the [arguments] list, in normalized order. |
| 532 class InvokeMethod extends UnsafePrimitive { | 559 class InvokeMethod extends InvocationPrimitive { |
| 533 Reference<Primitive> receiver; | 560 Reference<Primitive> receiver; |
| 534 Selector selector; | 561 Selector selector; |
| 535 TypeMask mask; | 562 TypeMask mask; |
| 536 final List<Reference<Primitive>> arguments; | 563 final List<Reference<Primitive>> arguments; |
| 537 final SourceInformation sourceInformation; | 564 final SourceInformation sourceInformation; |
| 538 | 565 |
| 539 CallingConvention callingConvention = CallingConvention.Normal; | 566 CallingConvention callingConvention = CallingConvention.Normal; |
| 540 | 567 |
| 541 Reference<Primitive> get dartReceiverReference { | 568 Reference<Primitive> get dartReceiverReference { |
| 542 return callingConvention == CallingConvention.Intercepted | 569 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 | 626 /// 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 | 627 /// [receiver] may refer to a null constant primitive. This happens for direct |
| 601 /// invocations to intercepted methods, where the effective receiver is instead | 628 /// invocations to intercepted methods, where the effective receiver is instead |
| 602 /// passed as a formal parameter. | 629 /// passed as a formal parameter. |
| 603 /// | 630 /// |
| 604 /// TODO(sra): Review. A direct call to a method that is mixed into a native | 631 /// TODO(sra): Review. A direct call to a method that is mixed into a native |
| 605 /// class will still require an explicit argument. | 632 /// class will still require an explicit argument. |
| 606 /// | 633 /// |
| 607 /// All optional arguments declared by [target] are passed in explicitly, and | 634 /// All optional arguments declared by [target] are passed in explicitly, and |
| 608 /// occur at the end of [arguments] list, in normalized order. | 635 /// occur at the end of [arguments] list, in normalized order. |
| 609 class InvokeMethodDirectly extends UnsafePrimitive { | 636 class InvokeMethodDirectly extends InvocationPrimitive { |
| 610 Reference<Primitive> receiver; | 637 Reference<Primitive> receiver; |
| 611 final FunctionElement target; | 638 final FunctionElement target; |
| 612 final Selector selector; | 639 final Selector selector; |
| 613 final List<Reference<Primitive>> arguments; | 640 final List<Reference<Primitive>> arguments; |
| 614 final SourceInformation sourceInformation; | 641 final SourceInformation sourceInformation; |
| 615 | 642 |
| 616 CallingConvention callingConvention = CallingConvention.Normal; | 643 CallingConvention callingConvention = CallingConvention.Normal; |
| 617 | 644 |
| 618 Reference<Primitive> get dartReceiverReference { | 645 Reference<Primitive> get dartReceiverReference { |
| 619 return callingConvention == CallingConvention.Intercepted | 646 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 | 684 /// All optional arguments declared by [target] are passed in explicitly, and |
| 658 /// occur in the [arguments] list, in normalized order. | 685 /// occur in the [arguments] list, in normalized order. |
| 659 /// | 686 /// |
| 660 /// Last in the [arguments] list, after the mandatory and optional arguments, | 687 /// Last in the [arguments] list, after the mandatory and optional arguments, |
| 661 /// the internal representation of each type argument occurs, unless it could | 688 /// 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 | 689 /// be determined at build-time that the constructed class has no need for its |
| 663 /// runtime type information. | 690 /// runtime type information. |
| 664 /// | 691 /// |
| 665 /// Note that [InvokeConstructor] does it itself allocate an object. | 692 /// Note that [InvokeConstructor] does it itself allocate an object. |
| 666 /// The invoked constructor will do that using [CreateInstance]. | 693 /// The invoked constructor will do that using [CreateInstance]. |
| 667 class InvokeConstructor extends UnsafePrimitive { | 694 class InvokeConstructor extends InvocationPrimitive { |
| 668 final DartType dartType; | 695 final DartType dartType; |
| 669 final ConstructorElement target; | 696 final ConstructorElement target; |
| 670 final List<Reference<Primitive>> arguments; | 697 final List<Reference<Primitive>> arguments; |
| 671 final Selector selector; | 698 final Selector selector; |
| 672 final SourceInformation sourceInformation; | 699 final SourceInformation sourceInformation; |
| 673 | 700 |
| 674 /// If non-null, this is an allocation site-specific type that is potentially | 701 /// If non-null, this is an allocation site-specific type that is potentially |
| 675 /// better than the inferred return type of [target]. | 702 /// better than the inferred return type of [target]. |
| 676 /// | 703 /// |
| 677 /// In particular, container type masks depend on the allocation site and | 704 /// In particular, container type masks depend on the allocation site and |
| (...skipping 1189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1867 | 1894 |
| 1868 // Concrete classes. | 1895 // Concrete classes. |
| 1869 T visitFunctionDefinition(FunctionDefinition node); | 1896 T visitFunctionDefinition(FunctionDefinition node); |
| 1870 | 1897 |
| 1871 // Expressions. | 1898 // Expressions. |
| 1872 T visitLetPrim(LetPrim node); | 1899 T visitLetPrim(LetPrim node); |
| 1873 T visitLetCont(LetCont node); | 1900 T visitLetCont(LetCont node); |
| 1874 T visitLetHandler(LetHandler node); | 1901 T visitLetHandler(LetHandler node); |
| 1875 T visitLetMutable(LetMutable node); | 1902 T visitLetMutable(LetMutable node); |
| 1876 T visitInvokeContinuation(InvokeContinuation node); | 1903 T visitInvokeContinuation(InvokeContinuation node); |
| 1904 T visitThrow(Throw node); | |
| 1905 T visitRethrow(Rethrow node); | |
| 1906 T visitBranch(Branch node); | |
| 1907 T visitUnreachable(Unreachable node); | |
| 1908 | |
| 1909 // Definitions. | |
| 1877 T visitInvokeStatic(InvokeStatic node); | 1910 T visitInvokeStatic(InvokeStatic node); |
| 1878 T visitInvokeMethod(InvokeMethod node); | 1911 T visitInvokeMethod(InvokeMethod node); |
| 1879 T visitInvokeMethodDirectly(InvokeMethodDirectly node); | 1912 T visitInvokeMethodDirectly(InvokeMethodDirectly node); |
| 1880 T visitInvokeConstructor(InvokeConstructor node); | 1913 T visitInvokeConstructor(InvokeConstructor node); |
| 1881 T visitThrow(Throw node); | |
| 1882 T visitRethrow(Rethrow node); | |
| 1883 T visitBranch(Branch node); | |
| 1884 T visitTypeCast(TypeCast node); | 1914 T visitTypeCast(TypeCast node); |
| 1885 T visitSetMutable(SetMutable node); | 1915 T visitSetMutable(SetMutable node); |
| 1886 T visitSetStatic(SetStatic node); | 1916 T visitSetStatic(SetStatic node); |
| 1917 T visitSetField(SetField node); | |
| 1887 T visitGetLazyStatic(GetLazyStatic node); | 1918 T visitGetLazyStatic(GetLazyStatic node); |
| 1888 T visitSetField(SetField node); | |
| 1889 T visitUnreachable(Unreachable node); | |
| 1890 T visitAwait(Await node); | 1919 T visitAwait(Await node); |
| 1891 T visitYield(Yield node); | 1920 T visitYield(Yield node); |
| 1892 | |
| 1893 // Definitions. | |
| 1894 T visitLiteralList(LiteralList node); | 1921 T visitLiteralList(LiteralList node); |
| 1895 T visitLiteralMap(LiteralMap node); | 1922 T visitLiteralMap(LiteralMap node); |
| 1896 T visitConstant(Constant node); | 1923 T visitConstant(Constant node); |
| 1897 T visitGetMutable(GetMutable node); | 1924 T visitGetMutable(GetMutable node); |
| 1898 T visitParameter(Parameter node); | 1925 T visitParameter(Parameter node); |
| 1899 T visitContinuation(Continuation node); | 1926 T visitContinuation(Continuation node); |
| 1900 T visitMutableVariable(MutableVariable node); | 1927 T visitMutableVariable(MutableVariable node); |
| 1901 T visitGetStatic(GetStatic node); | 1928 T visitGetStatic(GetStatic node); |
| 1902 T visitInterceptor(Interceptor node); | 1929 T visitInterceptor(Interceptor node); |
| 1903 T visitCreateInstance(CreateInstance node); | 1930 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. | 2412 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
| 2386 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2413 class RemovalVisitor extends TrampolineRecursiveVisitor { |
| 2387 processReference(Reference reference) { | 2414 processReference(Reference reference) { |
| 2388 reference.unlink(); | 2415 reference.unlink(); |
| 2389 } | 2416 } |
| 2390 | 2417 |
| 2391 static void remove(Node node) { | 2418 static void remove(Node node) { |
| 2392 (new RemovalVisitor()).visit(node); | 2419 (new RemovalVisitor()).visit(node); |
| 2393 } | 2420 } |
| 2394 } | 2421 } |
| 2422 | |
| 2423 /// A visitor to copy instances of [Definition] or its subclasses, except for | |
| 2424 /// instances of [Continuation]. | |
| 2425 /// | |
| 2426 /// The visitor maintains a map from original definitions to their copies. | |
| 2427 /// When the [copy] method is called for a non-Continuation definition, | |
| 2428 /// a copy is created, added to the map and returned as the result. Copying a | |
| 2429 /// definition assumes that the definitions of all references have already | |
| 2430 /// been copied by the same visitor. | |
| 2431 class DefinitionCopyingVisitor extends Visitor<Definition> { | |
| 2432 Map<Definition, Definition> _copies = <Definition, Definition>{}; | |
| 2433 | |
| 2434 /// Put a copy into the map. | |
| 2435 /// | |
| 2436 /// This method should be used instead of directly adding copies to the map. | |
| 2437 Definition putCopy(Definition original, Definition copy) { | |
| 2438 if (copy is Variable) { | |
| 2439 copy.type = (original as Variable).type; | |
|
sra1
2015/12/18 02:16:26
We usually use a typed local rather than 'as'.
Kevin Millikin (Google)
2015/12/21 12:28:02
I know, but it looks horrible. We shouldn't have
| |
| 2440 if (copy is Primitive) { | |
|
asgerf
2015/12/17 15:40:34
MutableVariable also has a hint, so we could just
Kevin Millikin (Google)
2015/12/21 12:28:02
Done.
| |
| 2441 copy.hint = (original as Primitive).hint; | |
| 2442 } | |
| 2443 } | |
| 2444 return _copies[original] = copy; | |
| 2445 } | |
| 2446 | |
| 2447 /// Get the copy of a [Reference]'s definition from the map. | |
| 2448 Definition getCopy(Reference reference) => _copies[reference.definition]; | |
| 2449 | |
| 2450 /// Map a list of [Reference]s to the list of their definition's copies. | |
| 2451 List<Definition> getList(List<Reference> list) => list.map(getCopy).toList(); | |
| 2452 | |
| 2453 /// Copy a non-[Continuation] [Definition]. | |
| 2454 Definition copy(Definition node) { | |
| 2455 assert (node is! Continuation); | |
| 2456 return putCopy(node, visit(node)); | |
| 2457 } | |
| 2458 | |
| 2459 Definition visit(Node node) => node.accept(this); | |
| 2460 | |
| 2461 Definition visitFunctionDefinition(FunctionDefinition node) {} | |
| 2462 Definition visitLetPrim(LetPrim node) {} | |
| 2463 Definition visitLetCont(LetCont node) {} | |
| 2464 Definition visitLetHandler(LetHandler node) {} | |
| 2465 Definition visitLetMutable(LetMutable node) {} | |
| 2466 Definition visitInvokeContinuation(InvokeContinuation node) {} | |
| 2467 Definition visitThrow(Throw node) {} | |
| 2468 Definition visitRethrow(Rethrow node) {} | |
| 2469 Definition visitBranch(Branch node) {} | |
| 2470 Definition visitUnreachable(Unreachable node) {} | |
| 2471 Definition visitContinuation(Continuation node) {} | |
| 2472 | |
| 2473 Definition visitInvokeStatic(InvokeStatic node) { | |
| 2474 return new InvokeStatic(node.target, node.selector, getList(node.arguments), | |
| 2475 node.sourceInformation); | |
| 2476 } | |
| 2477 | |
| 2478 Definition visitInvokeMethod(InvokeMethod node) { | |
| 2479 return new InvokeMethod(getCopy(node.receiver), node.selector, node.mask, | |
| 2480 getList(node.arguments), | |
| 2481 node.sourceInformation); | |
| 2482 } | |
| 2483 | |
| 2484 Definition visitInvokeMethodDirectly(InvokeMethodDirectly node) { | |
| 2485 return new InvokeMethodDirectly(getCopy(node.receiver), node.target, | |
| 2486 node.selector, | |
| 2487 getList(node.arguments), | |
| 2488 node.sourceInformation); | |
| 2489 } | |
| 2490 | |
| 2491 Definition visitInvokeConstructor(InvokeConstructor node) { | |
| 2492 return new InvokeConstructor(node.dartType, node.target, node.selector, | |
| 2493 getList(node.arguments), | |
| 2494 node.sourceInformation); | |
| 2495 } | |
| 2496 | |
| 2497 Definition visitTypeCast(TypeCast node) { | |
| 2498 return new TypeCast(getCopy(node.value), node.dartType, | |
| 2499 getList(node.typeArguments)); | |
| 2500 } | |
| 2501 | |
| 2502 Definition visitSetMutable(SetMutable node) { | |
| 2503 return new SetMutable(getCopy(node.variable), getCopy(node.value)); | |
| 2504 } | |
| 2505 | |
| 2506 Definition visitSetStatic(SetStatic node) { | |
| 2507 return new SetStatic(node.element, getCopy(node.value), | |
| 2508 node.sourceInformation); | |
| 2509 } | |
| 2510 | |
| 2511 Definition visitSetField(SetField node) { | |
| 2512 return new SetField(getCopy(node.object), node.field, getCopy(node.value)); | |
| 2513 } | |
| 2514 | |
| 2515 Definition visitGetLazyStatic(GetLazyStatic node) { | |
| 2516 return new GetLazyStatic(node.element, node.sourceInformation); | |
| 2517 } | |
| 2518 | |
| 2519 Definition visitAwait(Await node) { | |
| 2520 return new Await(getCopy(node.input)); | |
| 2521 } | |
| 2522 | |
| 2523 Definition visitYield(Yield node) { | |
| 2524 return new Yield(getCopy(node.input), node.hasStar); | |
| 2525 } | |
| 2526 | |
| 2527 Definition visitLiteralList(LiteralList node) { | |
| 2528 return new LiteralList(node.dartType, getList(node.values)); | |
| 2529 } | |
| 2530 | |
| 2531 Definition visitLiteralMap(LiteralMap node) { | |
| 2532 List<LiteralMapEntry> entries = node.entries.map((LiteralMapEntry entry) { | |
| 2533 return new LiteralMapEntry(getCopy(entry.key), getCopy(entry.value)); | |
| 2534 }).toList(); | |
| 2535 return new LiteralMap(node.dartType, entries); | |
| 2536 } | |
| 2537 | |
| 2538 Definition visitConstant(Constant node) { | |
| 2539 return new Constant(node.value, sourceInformation: node.sourceInformation); | |
| 2540 } | |
| 2541 | |
| 2542 Definition visitGetMutable(GetMutable node) { | |
| 2543 return new GetMutable(getCopy(node.variable)); | |
| 2544 } | |
| 2545 | |
| 2546 Definition visitParameter(Parameter node) { | |
| 2547 return new Parameter(node.hint); | |
| 2548 } | |
| 2549 | |
| 2550 Definition visitMutableVariable(MutableVariable node) { | |
| 2551 return new MutableVariable(node.hint); | |
| 2552 } | |
| 2553 | |
| 2554 Definition visitGetStatic(GetStatic node) { | |
| 2555 return new GetStatic(node.element, node.sourceInformation); | |
| 2556 } | |
| 2557 | |
| 2558 Definition visitInterceptor(Interceptor node) { | |
| 2559 return new Interceptor(getCopy(node.input), node.sourceInformation) | |
| 2560 ..interceptedClasses.addAll(node.interceptedClasses); | |
| 2561 } | |
| 2562 | |
| 2563 Definition visitCreateInstance(CreateInstance node) { | |
| 2564 return new CreateInstance(node.classElement, getList(node.arguments), | |
| 2565 getList(node.typeInformation), | |
| 2566 node.sourceInformation); | |
| 2567 } | |
| 2568 | |
| 2569 Definition visitGetField(GetField node) { | |
| 2570 return new GetField(getCopy(node.object), node.field); | |
| 2571 } | |
| 2572 | |
| 2573 Definition visitCreateBox(CreateBox node) { | |
| 2574 return new CreateBox(); | |
| 2575 } | |
| 2576 | |
| 2577 Definition visitReifyRuntimeType(ReifyRuntimeType node) { | |
| 2578 return new ReifyRuntimeType(getCopy(node.value), node.sourceInformation); | |
| 2579 } | |
| 2580 | |
| 2581 Definition visitReadTypeVariable(ReadTypeVariable node) { | |
| 2582 return new ReadTypeVariable(node.variable, getCopy(node.target), | |
| 2583 node.sourceInformation); | |
| 2584 } | |
| 2585 | |
| 2586 Definition visitTypeExpression(TypeExpression node) { | |
| 2587 return new TypeExpression(node.dartType, getList(node.arguments)); | |
| 2588 } | |
| 2589 | |
| 2590 Definition visitCreateInvocationMirror(CreateInvocationMirror node) { | |
| 2591 return new CreateInvocationMirror(node.selector, getList(node.arguments)); | |
| 2592 } | |
| 2593 | |
| 2594 Definition visitTypeTest(TypeTest node) { | |
| 2595 return new TypeTest(getCopy(node.value), node.dartType, | |
| 2596 getList(node.typeArguments)); | |
| 2597 } | |
| 2598 | |
| 2599 Definition visitTypeTestViaFlag(TypeTestViaFlag node) { | |
| 2600 return new TypeTestViaFlag(getCopy(node.interceptor), node.dartType); | |
| 2601 } | |
| 2602 | |
| 2603 Definition visitApplyBuiltinOperator(ApplyBuiltinOperator node) { | |
| 2604 return new ApplyBuiltinOperator(node.operator, getList(node.arguments), | |
| 2605 node.sourceInformation); | |
| 2606 } | |
| 2607 | |
| 2608 Definition visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | |
| 2609 return new ApplyBuiltinMethod(node.method, getCopy(node.receiver), | |
| 2610 getList(node.arguments), | |
| 2611 node.sourceInformation, | |
| 2612 receiverIsNotNull: node.receiverIsNotNull); | |
| 2613 } | |
| 2614 | |
| 2615 Definition visitGetLength(GetLength node) { | |
| 2616 return new GetLength(getCopy(node.object)); | |
| 2617 } | |
| 2618 | |
| 2619 Definition visitGetIndex(GetIndex node) { | |
| 2620 return new GetIndex(getCopy(node.object), getCopy(node.index)); | |
| 2621 } | |
| 2622 | |
| 2623 Definition visitSetIndex(SetIndex node) { | |
| 2624 return new SetIndex(getCopy(node.object), getCopy(node.index), | |
| 2625 getCopy(node.value)); | |
| 2626 } | |
| 2627 | |
| 2628 Definition visitRefinement(Refinement node) { | |
| 2629 return new Refinement(getCopy(node.value), node.refineType); | |
| 2630 } | |
| 2631 | |
| 2632 Definition visitBoundsCheck(BoundsCheck node) { | |
| 2633 if (node.hasNoChecks) { | |
| 2634 return new BoundsCheck.noCheck(getCopy(node.object), | |
| 2635 node.sourceInformation); | |
| 2636 } else { | |
| 2637 return new BoundsCheck(getCopy(node.object), getCopy(node.index), | |
| 2638 getCopy(node.length), | |
| 2639 node.checks, | |
| 2640 node.sourceInformation); | |
| 2641 } | |
| 2642 } | |
| 2643 | |
| 2644 Definition visitNullCheck(NullCheck node) { | |
| 2645 return new NullCheck(getCopy(node.value), node.sourceInformation); | |
| 2646 } | |
| 2647 | |
| 2648 Definition visitForeignCode(ForeignCode node) { | |
| 2649 return new ForeignCode(node.codeTemplate, node.type, | |
| 2650 getList(node.arguments), | |
| 2651 node.nativeBehavior, | |
| 2652 dependency: node.dependency); | |
| 2653 } | |
| 2654 } | |
| 2655 | |
| 2656 /// A trampolining visitor to copy [FunctionDefinition]s. | |
| 2657 class CopyingVisitor extends TrampolineRecursiveVisitor { | |
| 2658 // The visitor maintains a map from original continuations to their copies. | |
| 2659 Map<Continuation, Continuation> _copies = <Continuation, Continuation>{}; | |
| 2660 | |
| 2661 // The visitor uses an auxiliary visitor to copy definitions. | |
| 2662 DefinitionCopyingVisitor _definitions = new DefinitionCopyingVisitor(); | |
| 2663 | |
| 2664 // While copying a block, the state of the visitor is a 'linked list' of | |
| 2665 // the expressions in the block's body, with a pointer to the last element | |
| 2666 // of the list. | |
| 2667 Expression _first = null; | |
| 2668 Expression _current = null; | |
| 2669 | |
| 2670 void plug(Expression body) { | |
| 2671 if (_first == null) { | |
| 2672 _first = body; | |
| 2673 } else { | |
| 2674 assert(_current != null); | |
| 2675 (_current as InteriorExpression).body = body; | |
| 2676 } | |
| 2677 _current = body; | |
| 2678 } | |
| 2679 | |
| 2680 // Continuations are added to the visitor's stack to be visited after copying | |
| 2681 // the current block is finished. The stack action saves the current block, | |
| 2682 // copies the continuation's body, sets the body on the copy of the | |
| 2683 // continuation, and restores the current block. | |
| 2684 // | |
| 2685 // Note that continuations are added to the copy map before the stack action | |
| 2686 // to visit them is performed. | |
| 2687 void push(Continuation cont) { | |
| 2688 assert(!cont.isReturnContinuation); | |
| 2689 _stack.add(() { | |
| 2690 Expression savedFirst = _first; | |
| 2691 Expression savedPrevious = _current; | |
|
asgerf
2015/12/17 15:40:34
Do we need to cache _current?
Kevin Millikin (Google)
2015/12/21 12:28:02
Nope. And that nicely dodges the issue of whether
| |
| 2692 _first = _current = null; | |
| 2693 _processBlock(cont.body); | |
| 2694 _copies[cont].body = _first; | |
| 2695 _first = savedFirst; | |
| 2696 _current = savedPrevious; | |
| 2697 }); | |
| 2698 } | |
| 2699 | |
| 2700 FunctionDefinition copy(FunctionDefinition node) { | |
| 2701 assert(_first == null && _current == null); | |
| 2702 _first = _current = null; | |
| 2703 // Definitions are copied where they are bound, before processing | |
| 2704 // expressions in the scope of their binding. | |
| 2705 Parameter thisParameter = node.thisParameter == null | |
| 2706 ? null | |
| 2707 : _definitions.copy(node.thisParameter); | |
| 2708 List<Parameter> parameters = | |
| 2709 node.parameters.map(_definitions.copy).toList(); | |
| 2710 // Though the return continuation's parameter does not have any uses, | |
| 2711 // we still make a proper copy to ensure that hints, type, etc. are | |
| 2712 // copied. | |
| 2713 Parameter returnParameter = | |
| 2714 _definitions.copy(node.returnContinuation.parameters.first); | |
| 2715 Continuation returnContinuation = _copies[node.returnContinuation] = | |
| 2716 new Continuation([returnParameter]); | |
| 2717 | |
| 2718 visit(node.body); | |
| 2719 FunctionDefinition copy = new FunctionDefinition(node.element, | |
| 2720 thisParameter, | |
| 2721 parameters, | |
| 2722 returnContinuation, | |
| 2723 _first); | |
| 2724 _first = _current = null; | |
| 2725 return copy; | |
| 2726 } | |
| 2727 | |
| 2728 Node visit(Node node) => node.accept(this); | |
| 2729 | |
| 2730 Expression traverseLetCont(LetCont node) { | |
| 2731 // Continuations are copied where they are bound, before processing | |
| 2732 // expressions in the scope of their binding. | |
| 2733 List<Continuation> continuations = node.continuations.map((Continuation c) { | |
| 2734 push(c); | |
| 2735 return _copies[c] = | |
| 2736 new Continuation(c.parameters.map(_definitions.copy).toList()); | |
| 2737 }).toList(); | |
| 2738 plug(new LetCont.many(continuations, null)); | |
| 2739 return node.body; | |
| 2740 } | |
| 2741 | |
| 2742 Expression traverseLetHandler(LetHandler node) { | |
| 2743 // Continuations are copied where they are bound, before processing | |
| 2744 // expressions in the scope of their binding. | |
| 2745 push(node.handler); | |
| 2746 Continuation handler = _copies[node.handler] = | |
| 2747 new Continuation(node.handler.parameters.map(_definitions.copy) | |
| 2748 .toList()); | |
| 2749 plug(new LetHandler(handler, null)); | |
| 2750 return node.body; | |
| 2751 } | |
| 2752 | |
| 2753 Expression traverseLetPrim(LetPrim node) { | |
| 2754 plug(new LetPrim(_definitions.copy(node.primitive))); | |
| 2755 return node.body; | |
| 2756 } | |
| 2757 | |
| 2758 Expression traverseLetMutable(LetMutable node) { | |
| 2759 plug(new LetMutable(_definitions.copy(node.variable), | |
| 2760 _definitions.getCopy(node.value))); | |
| 2761 return node.body; | |
| 2762 } | |
| 2763 | |
| 2764 // Tail expressions do not have references, so we do not need to map them | |
| 2765 // to their copies. | |
| 2766 visitInvokeContinuation(InvokeContinuation node) { | |
| 2767 plug(new InvokeContinuation(_copies[node.continuation.definition], | |
| 2768 _definitions.getList(node.arguments), | |
| 2769 isRecursive: node.isRecursive, | |
| 2770 isEscapingTry: node.isEscapingTry, | |
| 2771 sourceInformation: node.sourceInformation)); | |
| 2772 } | |
| 2773 | |
| 2774 Node visitThrow(Throw node) { | |
| 2775 plug(new Throw(_definitions.getCopy(node.value))); | |
| 2776 } | |
| 2777 | |
| 2778 Node visitRethrow(Rethrow node) { | |
| 2779 plug(new Rethrow()); | |
| 2780 } | |
| 2781 | |
| 2782 Node visitBranch(Branch node) { | |
| 2783 plug(new Branch.loose(_definitions.getCopy(node.condition), | |
| 2784 _copies[node.trueContinuation.definition], | |
| 2785 _copies[node.falseContinuation.definition]) | |
| 2786 ..isStrictCheck = node.isStrictCheck); | |
| 2787 } | |
| 2788 | |
| 2789 Node visitUnreachable(Unreachable node) { | |
| 2790 plug(new Unreachable()); | |
| 2791 } | |
| 2792 } | |
| OLD | NEW |