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 |