| 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 '../constants/values.dart' as values; | 7 import '../constants/values.dart' as values; |
| 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; | 8 import '../dart_types.dart' show DartType, InterfaceType, TypeVariableType; |
| 9 import '../elements/elements.dart'; | 9 import '../elements/elements.dart'; |
| 10 import '../io/source_information.dart' show SourceInformation; | 10 import '../io/source_information.dart' show SourceInformation; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 116 assert(parent == null); | 116 assert(parent == null); |
| 117 assert(body == null); | 117 assert(body == null); |
| 118 Expression child = newParent.body; | 118 Expression child = newParent.body; |
| 119 newParent.body = this; | 119 newParent.body = this; |
| 120 this.body = child; | 120 this.body = child; |
| 121 child.parent = this; | 121 child.parent = this; |
| 122 this.parent = newParent; | 122 this.parent = newParent; |
| 123 } | 123 } |
| 124 } | 124 } |
| 125 | 125 |
| 126 /// An expression that passes a continuation to a call. | |
| 127 abstract class CallExpression extends Expression { | |
| 128 Reference<Continuation> get continuation; | |
| 129 Expression get next => continuation.definition.body; | |
| 130 } | |
| 131 | |
| 132 /// An expression without a continuation or a subexpression body. | 126 /// An expression without a continuation or a subexpression body. |
| 133 /// | 127 /// |
| 134 /// These break straight-line control flow and can be thought of as ending a | 128 /// These break straight-line control flow and can be thought of as ending a |
| 135 /// basic block. | 129 /// basic block. |
| 136 abstract class TailExpression extends Expression { | 130 abstract class TailExpression extends Expression { |
| 137 Expression get next => null; | 131 Expression get next => null; |
| 138 } | 132 } |
| 139 | 133 |
| 140 /// The base class of things that variables can refer to: primitives, | 134 /// The base class of things that variables can refer to: primitives, |
| 141 /// continuations, function and continuation parameters, etc. | 135 /// continuations, function and continuation parameters, etc. |
| 142 abstract class Definition<T extends Definition<T>> extends Node { | 136 abstract class Definition<T extends Definition<T>> extends Node { |
| 143 // The head of a linked-list of occurrences, in no particular order. | 137 // The head of a linked-list of occurrences, in no particular order. |
| 144 Reference<T> firstRef; | 138 Reference<T> firstRef; |
| 145 | 139 |
| 146 bool get hasAtMostOneUse => firstRef == null || firstRef.next == null; | 140 bool get hasAtMostOneUse => firstRef == null || firstRef.next == null; |
| 147 bool get hasExactlyOneUse => firstRef != null && firstRef.next == null; | 141 bool get hasExactlyOneUse => firstRef != null && firstRef.next == null; |
| 148 bool get hasNoUses => firstRef == null; | 142 bool get hasNoUses => firstRef == null; |
| 149 bool get hasAtLeastOneUse => firstRef != null; | 143 bool get hasAtLeastOneUse => firstRef != null; |
| 150 bool get hasMultipleUses => !hasAtMostOneUse; | 144 bool get hasMultipleUses => !hasAtMostOneUse; |
| 151 | 145 |
| 152 void substituteFor(Definition<T> other) { | 146 void replaceUsesWith(Definition<T> newDefinition) { |
| 153 if (other == this) return; | 147 if (newDefinition == this) return; |
| 154 if (other.hasNoUses) return; | 148 if (hasNoUses) return; |
| 155 Reference<T> previous, current = other.firstRef; | 149 Reference<T> previous, current = firstRef; |
| 156 do { | 150 do { |
| 157 current.definition = this; | 151 current.definition = newDefinition; |
| 158 previous = current; | 152 previous = current; |
| 159 current = current.next; | 153 current = current.next; |
| 160 } while (current != null); | 154 } while (current != null); |
| 161 previous.next = firstRef; | 155 previous.next = newDefinition.firstRef; |
| 162 if (firstRef != null) firstRef.previous = previous; | 156 if (newDefinition.firstRef != null) { |
| 163 firstRef = other.firstRef; | 157 newDefinition.firstRef.previous = previous; |
| 164 other.firstRef = null; | 158 } |
| 159 newDefinition.firstRef = firstRef; |
| 160 firstRef = null; |
| 165 } | 161 } |
| 166 } | 162 } |
| 167 | 163 |
| 168 class EffectiveUseIterator extends Iterator<Reference<Primitive>> { | 164 class EffectiveUseIterator extends Iterator<Reference<Primitive>> { |
| 169 Reference<Primitive> current; | 165 Reference<Primitive> current; |
| 170 Reference<Primitive> next; | 166 Reference<Primitive> next; |
| 171 final List<Refinement> stack = <Refinement>[]; | 167 final List<Refinement> stack = <Refinement>[]; |
| 172 | 168 |
| 173 EffectiveUseIterator(Primitive prim) : next = prim.firstRef; | 169 EffectiveUseIterator(Primitive prim) : next = prim.firstRef; |
| 174 | 170 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 | 257 |
| 262 bool get hasNoEffectiveUses { | 258 bool get hasNoEffectiveUses { |
| 263 return effectiveUses.isEmpty; | 259 return effectiveUses.isEmpty; |
| 264 } | 260 } |
| 265 | 261 |
| 266 /// Unlinks all references contained in this node. | 262 /// Unlinks all references contained in this node. |
| 267 void destroy() { | 263 void destroy() { |
| 268 assert(hasNoUses); | 264 assert(hasNoUses); |
| 269 RemovalVisitor.remove(this); | 265 RemovalVisitor.remove(this); |
| 270 } | 266 } |
| 267 |
| 268 /// Replaces this definition, both at the binding site and at all uses sites. |
| 269 /// |
| 270 /// This can be thought of as changing the definition of a `let` while |
| 271 /// preserving the variable name: |
| 272 /// |
| 273 /// let x = OLD in BODY |
| 274 /// ==> |
| 275 /// let x = NEW in BODY |
| 276 /// |
| 277 void replaceWith(Primitive newDefinition) { |
| 278 assert(this is! Parameter); |
| 279 assert(newDefinition is! Parameter); |
| 280 assert(newDefinition.parent == null); |
| 281 replaceUsesWith(newDefinition); |
| 282 destroy(); |
| 283 LetPrim let = parent; |
| 284 let.primitive = newDefinition; |
| 285 newDefinition.parent = let; |
| 286 newDefinition.useElementAsHint(hint); |
| 287 } |
| 288 } |
| 289 |
| 290 /// A primitive that is generally not safe for elimination, but may be marked |
| 291 /// as safe by type propagation |
| 292 // |
| 293 // TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this |
| 294 // class. |
| 295 abstract class UnsafePrimitive extends Primitive { |
| 296 bool isSafeForElimination = false; |
| 297 bool isSafeForReordering = false; |
| 271 } | 298 } |
| 272 | 299 |
| 273 /// Operands to invocations and primitives are always variables. They point to | 300 /// Operands to invocations and primitives are always variables. They point to |
| 274 /// their definition and are doubly-linked into a list of occurrences. | 301 /// their definition and are doubly-linked into a list of occurrences. |
| 275 class Reference<T extends Definition<T>> { | 302 class Reference<T extends Definition<T>> { |
| 276 T definition; | 303 T definition; |
| 277 Reference<T> previous; | 304 Reference<T> previous; |
| 278 Reference<T> next; | 305 Reference<T> next; |
| 279 | 306 |
| 280 /// A pointer to the parent node. Is null until set by optimization passes. | 307 /// A pointer to the parent node. Is null until set by optimization passes. |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 } | 455 } |
| 429 | 456 |
| 430 /// Invoke a static function. | 457 /// Invoke a static function. |
| 431 /// | 458 /// |
| 432 /// All optional arguments declared by [target] are passed in explicitly, and | 459 /// All optional arguments declared by [target] are passed in explicitly, and |
| 433 /// occur at the end of [arguments] list, in normalized order. | 460 /// occur at the end of [arguments] list, in normalized order. |
| 434 /// | 461 /// |
| 435 /// Discussion: | 462 /// Discussion: |
| 436 /// All information in the [selector] is technically redundant; it will likely | 463 /// All information in the [selector] is technically redundant; it will likely |
| 437 /// be removed. | 464 /// be removed. |
| 438 class InvokeStatic extends CallExpression { | 465 class InvokeStatic extends UnsafePrimitive { |
| 439 final FunctionElement target; | 466 final FunctionElement target; |
| 440 final Selector selector; | 467 final Selector selector; |
| 441 final List<Reference<Primitive>> arguments; | 468 final List<Reference<Primitive>> arguments; |
| 442 final Reference<Continuation> continuation; | |
| 443 final SourceInformation sourceInformation; | 469 final SourceInformation sourceInformation; |
| 444 | 470 |
| 445 InvokeStatic(this.target, | 471 InvokeStatic(this.target, |
| 446 this.selector, | 472 this.selector, |
| 447 List<Primitive> args, | 473 List<Primitive> args, |
| 448 Continuation cont, | |
| 449 [this.sourceInformation]) | 474 [this.sourceInformation]) |
| 450 : arguments = _referenceList(args), | 475 : arguments = _referenceList(args); |
| 451 continuation = new Reference<Continuation>(cont); | |
| 452 | 476 |
| 453 InvokeStatic.byReference(this.target, | 477 InvokeStatic.byReference(this.target, |
| 454 this.selector, | 478 this.selector, |
| 455 this.arguments, | 479 this.arguments, |
| 456 this.continuation, | |
| 457 [this.sourceInformation]); | 480 [this.sourceInformation]); |
| 458 | 481 |
| 459 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 482 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
| 460 | 483 |
| 461 void setParentPointers() { | 484 void setParentPointers() { |
| 462 _setParentsOnList(arguments, this); | 485 _setParentsOnList(arguments, this); |
| 463 continuation.parent = this; | |
| 464 } | 486 } |
| 465 } | 487 } |
| 466 | 488 |
| 489 enum CallingConvention { |
| 490 /// JS receiver is the Dart receiver, there are no extra arguments. |
| 491 /// |
| 492 /// For example: `foo.bar$1(x)` |
| 493 Normal, |
| 494 |
| 495 /// JS receiver is an interceptor, the first argument is the Dart receiver. |
| 496 /// |
| 497 /// For example: `getInterceptor(foo).bar$1(foo, x)` |
| 498 Intercepted, |
| 499 |
| 500 /// JS receiver is the Dart receiver, the first argument is a dummy value. |
| 501 /// |
| 502 /// For example: `foo.bar$1(0, x)` |
| 503 DummyIntercepted, |
| 504 } |
| 505 |
| 467 /// Invoke a method on an object. | 506 /// Invoke a method on an object. |
| 468 /// | 507 /// |
| 469 /// This includes getters, setters, operators, and index getter/setters. | 508 /// This includes getters, setters, operators, and index getter/setters. |
| 470 /// | 509 /// |
| 471 /// Tearing off a method is treated like a getter invocation (getters and | 510 /// Tearing off a method is treated like a getter invocation (getters and |
| 472 /// tear-offs cannot be distinguished at compile-time). | 511 /// tear-offs cannot be distinguished at compile-time). |
| 473 /// | 512 /// |
| 474 /// The [selector] records the names of named arguments. The value of named | 513 /// The [selector] records the names of named arguments. The value of named |
| 475 /// arguments occur at the end of the [arguments] list, in normalized order. | 514 /// arguments occur at the end of the [arguments] list, in normalized order. |
| 476 class InvokeMethod extends CallExpression { | 515 class InvokeMethod extends UnsafePrimitive { |
| 477 Reference<Primitive> receiver; | 516 Reference<Primitive> receiver; |
| 478 Selector selector; | 517 Selector selector; |
| 479 TypeMask mask; | 518 TypeMask mask; |
| 480 final List<Reference<Primitive>> arguments; | 519 final List<Reference<Primitive>> arguments; |
| 481 final Reference<Continuation> continuation; | |
| 482 final SourceInformation sourceInformation; | 520 final SourceInformation sourceInformation; |
| 483 | 521 |
| 484 /// If true, the [receiver] is intercepted and the actual receiver is in | 522 CallingConvention callingConvention = CallingConvention.Normal; |
| 485 /// the first argument. Otherwise, the [receiver] is the actual receiver. | 523 |
| 486 /// | 524 Reference<Primitive> get dartReceiverReference { |
| 487 /// This flag is always false for non-intercepted selectors, but it may also | 525 return callingConvention == CallingConvention.Intercepted |
| 488 /// be false for intercepted selectors after dummy receiver optimization | 526 ? arguments[0] |
| 489 /// (in this case the first argument is a dummy value). | 527 : receiver; |
| 490 /// | 528 } |
| 491 /// It is always false before the unsugaring pass, where interceptors have | 529 |
| 492 /// not yet been introduced. | 530 Primitive get dartReceiver => dartReceiverReference.definition; |
| 493 bool receiverIsIntercepted = false; | 531 |
| 532 Reference<Primitive> dartArgumentReference(int n) { |
| 533 return callingConvention == CallingConvention.Normal |
| 534 ? arguments[n] |
| 535 : arguments[n + 1]; |
| 536 } |
| 537 |
| 538 Primitive dartArgument(int n) => dartArgumentReference(n).definition; |
| 494 | 539 |
| 495 /// If true, it is known that the receiver cannot be `null`. | 540 /// If true, it is known that the receiver cannot be `null`. |
| 496 bool receiverIsNotNull = false; | 541 bool receiverIsNotNull = false; |
| 497 | 542 |
| 498 InvokeMethod(Primitive receiver, | 543 InvokeMethod(Primitive receiver, |
| 499 this.selector, | 544 this.selector, |
| 500 this.mask, | 545 this.mask, |
| 501 List<Primitive> arguments, | 546 List<Primitive> arguments, |
| 502 Continuation continuation, | |
| 503 [this.sourceInformation]) | 547 [this.sourceInformation]) |
| 504 : this.receiver = new Reference<Primitive>(receiver), | 548 : this.receiver = new Reference<Primitive>(receiver), |
| 505 this.arguments = _referenceList(arguments), | 549 this.arguments = _referenceList(arguments); |
| 506 this.continuation = new Reference<Continuation>(continuation); | |
| 507 | 550 |
| 508 InvokeMethod.byReference(this.receiver, | 551 InvokeMethod.byReference(this.receiver, |
| 509 this.selector, | 552 this.selector, |
| 510 this.mask, | 553 this.mask, |
| 511 this.arguments, | 554 this.arguments, |
| 512 this.continuation, | |
| 513 this.sourceInformation); | 555 this.sourceInformation); |
| 514 | 556 |
| 515 accept(Visitor visitor) => visitor.visitInvokeMethod(this); | 557 accept(Visitor visitor) => visitor.visitInvokeMethod(this); |
| 516 | 558 |
| 517 void setParentPointers() { | 559 void setParentPointers() { |
| 518 receiver.parent = this; | 560 receiver.parent = this; |
| 519 _setParentsOnList(arguments, this); | 561 _setParentsOnList(arguments, this); |
| 520 continuation.parent = this; | |
| 521 } | 562 } |
| 522 } | 563 } |
| 523 | 564 |
| 524 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. | 565 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. |
| 525 /// | 566 /// |
| 526 /// That is, if [receiver] is an instance of a class that overrides [target] | 567 /// That is, if [receiver] is an instance of a class that overrides [target] |
| 527 /// with a different implementation, the overriding implementation is bypassed | 568 /// with a different implementation, the overriding implementation is bypassed |
| 528 /// and [target]'s implementation is invoked. | 569 /// and [target]'s implementation is invoked. |
| 529 /// | 570 /// |
| 530 /// As with [InvokeMethod], this can be used to invoke a method, operator, | 571 /// As with [InvokeMethod], this can be used to invoke a method, operator, |
| 531 /// getter, setter, or index getter/setter. | 572 /// getter, setter, or index getter/setter. |
| 532 /// | 573 /// |
| 533 /// If it is known that [target] does not use its receiver argument, then | 574 /// If it is known that [target] does not use its receiver argument, then |
| 534 /// [receiver] may refer to a null constant primitive. This happens for direct | 575 /// [receiver] may refer to a null constant primitive. This happens for direct |
| 535 /// invocations to intercepted methods, where the effective receiver is instead | 576 /// invocations to intercepted methods, where the effective receiver is instead |
| 536 /// passed as a formal parameter. | 577 /// passed as a formal parameter. |
| 537 /// | 578 /// |
| 538 /// TODO(sra): Review. A direct call to a method that is mixed into a native | 579 /// TODO(sra): Review. A direct call to a method that is mixed into a native |
| 539 /// class will still require an explicit argument. | 580 /// class will still require an explicit argument. |
| 540 /// | 581 /// |
| 541 /// All optional arguments declared by [target] are passed in explicitly, and | 582 /// All optional arguments declared by [target] are passed in explicitly, and |
| 542 /// occur at the end of [arguments] list, in normalized order. | 583 /// occur at the end of [arguments] list, in normalized order. |
| 543 class InvokeMethodDirectly extends CallExpression { | 584 class InvokeMethodDirectly extends UnsafePrimitive { |
| 544 Reference<Primitive> receiver; | 585 Reference<Primitive> receiver; |
| 545 final FunctionElement target; | 586 final FunctionElement target; |
| 546 final Selector selector; | 587 final Selector selector; |
| 547 final List<Reference<Primitive>> arguments; | 588 final List<Reference<Primitive>> arguments; |
| 548 final Reference<Continuation> continuation; | |
| 549 final SourceInformation sourceInformation; | 589 final SourceInformation sourceInformation; |
| 550 | 590 |
| 591 CallingConvention callingConvention = CallingConvention.Normal; |
| 592 |
| 593 Reference<Primitive> get dartReceiverReference { |
| 594 return callingConvention == CallingConvention.Intercepted |
| 595 ? arguments[0] |
| 596 : receiver; |
| 597 } |
| 598 |
| 599 Primitive get dartReceiver => dartReceiverReference.definition; |
| 600 |
| 601 Reference<Primitive> dartArgumentReference(int n) { |
| 602 return callingConvention == CallingConvention.Normal |
| 603 ? arguments[n] |
| 604 : arguments[n + 1]; |
| 605 } |
| 606 |
| 607 Primitive dartArgument(int n) => dartArgumentReference(n).definition; |
| 608 |
| 551 InvokeMethodDirectly(Primitive receiver, | 609 InvokeMethodDirectly(Primitive receiver, |
| 552 this.target, | 610 this.target, |
| 553 this.selector, | 611 this.selector, |
| 554 List<Primitive> arguments, | 612 List<Primitive> arguments, |
| 555 Continuation continuation, | |
| 556 this.sourceInformation) | 613 this.sourceInformation) |
| 557 : this.receiver = new Reference<Primitive>(receiver), | 614 : this.receiver = new Reference<Primitive>(receiver), |
| 558 this.arguments = _referenceList(arguments), | 615 this.arguments = _referenceList(arguments); |
| 559 this.continuation = new Reference<Continuation>(continuation); | |
| 560 | 616 |
| 561 accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this); | 617 accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this); |
| 562 | 618 |
| 563 void setParentPointers() { | 619 void setParentPointers() { |
| 564 receiver.parent = this; | 620 receiver.parent = this; |
| 565 _setParentsOnList(arguments, this); | 621 _setParentsOnList(arguments, this); |
| 566 continuation.parent = this; | |
| 567 } | 622 } |
| 568 } | 623 } |
| 569 | 624 |
| 570 /// Non-const call to a constructor. | 625 /// Non-const call to a constructor. |
| 571 /// | 626 /// |
| 572 /// The [target] may be a generative constructor (forwarding or normal) | 627 /// The [target] may be a generative constructor (forwarding or normal) |
| 573 /// or a non-redirecting factory. | 628 /// or a non-redirecting factory. |
| 574 /// | 629 /// |
| 575 /// All optional arguments declared by [target] are passed in explicitly, and | 630 /// All optional arguments declared by [target] are passed in explicitly, and |
| 576 /// occur in the [arguments] list, in normalized order. | 631 /// occur in the [arguments] list, in normalized order. |
| 577 /// | 632 /// |
| 578 /// Last in the [arguments] list, after the mandatory and optional arguments, | 633 /// Last in the [arguments] list, after the mandatory and optional arguments, |
| 579 /// the internal representation of each type argument occurs, unless it could | 634 /// the internal representation of each type argument occurs, unless it could |
| 580 /// be determined at build-time that the constructed class has no need for its | 635 /// be determined at build-time that the constructed class has no need for its |
| 581 /// runtime type information. | 636 /// runtime type information. |
| 582 /// | 637 /// |
| 583 /// Note that [InvokeConstructor] does it itself allocate an object. | 638 /// Note that [InvokeConstructor] does it itself allocate an object. |
| 584 /// The invoked constructor will do that using [CreateInstance]. | 639 /// The invoked constructor will do that using [CreateInstance]. |
| 585 class InvokeConstructor extends CallExpression { | 640 class InvokeConstructor extends UnsafePrimitive { |
| 586 final DartType dartType; | 641 final DartType dartType; |
| 587 final ConstructorElement target; | 642 final ConstructorElement target; |
| 588 final List<Reference<Primitive>> arguments; | 643 final List<Reference<Primitive>> arguments; |
| 589 final Reference<Continuation> continuation; | |
| 590 final Selector selector; | 644 final Selector selector; |
| 591 final SourceInformation sourceInformation; | 645 final SourceInformation sourceInformation; |
| 592 | 646 |
| 593 /// If non-null, this is an allocation site-specific type that is potentially | 647 /// If non-null, this is an allocation site-specific type that is potentially |
| 594 /// better than the inferred return type of [target]. | 648 /// better than the inferred return type of [target]. |
| 595 /// | 649 /// |
| 596 /// In particular, container type masks depend on the allocation site and | 650 /// In particular, container type masks depend on the allocation site and |
| 597 /// can therefore not be inferred solely based on the call target. | 651 /// can therefore not be inferred solely based on the call target. |
| 598 TypeMask allocationSiteType; | 652 TypeMask allocationSiteType; |
| 599 | 653 |
| 600 InvokeConstructor(this.dartType, | 654 InvokeConstructor(this.dartType, |
| 601 this.target, | 655 this.target, |
| 602 this.selector, | 656 this.selector, |
| 603 List<Primitive> args, | 657 List<Primitive> args, |
| 604 Continuation cont, | |
| 605 this.sourceInformation, | 658 this.sourceInformation, |
| 606 {this.allocationSiteType}) | 659 {this.allocationSiteType}) |
| 607 : arguments = _referenceList(args), | 660 : arguments = _referenceList(args); |
| 608 continuation = new Reference<Continuation>(cont); | |
| 609 | 661 |
| 610 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); | 662 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
| 611 | 663 |
| 612 void setParentPointers() { | 664 void setParentPointers() { |
| 613 _setParentsOnList(arguments, this); | 665 _setParentsOnList(arguments, this); |
| 614 continuation.parent = this; | |
| 615 } | 666 } |
| 616 } | 667 } |
| 617 | 668 |
| 618 /// An alias for [value] in a context where the value is known to satisfy | 669 /// An alias for [value] in a context where the value is known to satisfy |
| 619 /// [type]. | 670 /// [type]. |
| 620 /// | 671 /// |
| 621 /// Refinement nodes are inserted before the type propagator pass and removed | 672 /// Refinement nodes are inserted before the type propagator pass and removed |
| 622 /// afterwards, so as not to complicate passes that don't reason about types, | 673 /// afterwards, so as not to complicate passes that don't reason about types, |
| 623 /// but need to reason about value references being identical (i.e. referring | 674 /// but need to reason about value references being identical (i.e. referring |
| 624 /// to the same primitive). | 675 /// to the same primitive). |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 /// An "as" type cast. | 763 /// An "as" type cast. |
| 713 /// | 764 /// |
| 714 /// If [value] is `null` or is an instance of [type], [continuation] is invoked | 765 /// If [value] is `null` or is an instance of [type], [continuation] is invoked |
| 715 /// with [value] as argument. Otherwise, a [CastError] is thrown. | 766 /// with [value] as argument. Otherwise, a [CastError] is thrown. |
| 716 /// | 767 /// |
| 717 /// Discussion: | 768 /// Discussion: |
| 718 /// The parameter to [continuation] is redundant since it will always equal | 769 /// The parameter to [continuation] is redundant since it will always equal |
| 719 /// [value], which is typically in scope in the continuation. However, it might | 770 /// [value], which is typically in scope in the continuation. However, it might |
| 720 /// simplify type propagation, since a better type can be computed for the | 771 /// simplify type propagation, since a better type can be computed for the |
| 721 /// continuation parameter without needing flow-sensitive analysis. | 772 /// continuation parameter without needing flow-sensitive analysis. |
| 722 class TypeCast extends CallExpression { | 773 class TypeCast extends UnsafePrimitive { |
| 723 Reference<Primitive> value; | 774 Reference<Primitive> value; |
| 724 final DartType dartType; | 775 final DartType dartType; |
| 725 | 776 |
| 726 /// See the corresponding field on [TypeTest]. | 777 /// See the corresponding field on [TypeTest]. |
| 727 final List<Reference<Primitive>> typeArguments; | 778 final List<Reference<Primitive>> typeArguments; |
| 728 final Reference<Continuation> continuation; | |
| 729 | 779 |
| 730 TypeCast(Primitive value, | 780 TypeCast(Primitive value, |
| 731 this.dartType, | 781 this.dartType, |
| 732 List<Primitive> typeArguments, | 782 List<Primitive> typeArguments) |
| 733 Continuation cont) | |
| 734 : this.value = new Reference<Primitive>(value), | 783 : this.value = new Reference<Primitive>(value), |
| 735 this.typeArguments = _referenceList(typeArguments), | 784 this.typeArguments = _referenceList(typeArguments); |
| 736 this.continuation = new Reference<Continuation>(cont); | |
| 737 | 785 |
| 738 accept(Visitor visitor) => visitor.visitTypeCast(this); | 786 accept(Visitor visitor) => visitor.visitTypeCast(this); |
| 739 | 787 |
| 740 void setParentPointers() { | 788 void setParentPointers() { |
| 741 value.parent = this; | 789 value.parent = this; |
| 790 _setParentsOnList(typeArguments, this); |
| 742 } | 791 } |
| 743 } | 792 } |
| 744 | 793 |
| 745 /// Apply a built-in operator. | 794 /// Apply a built-in operator. |
| 746 /// | 795 /// |
| 747 /// It must be known that the arguments have the proper types. | 796 /// It must be known that the arguments have the proper types. |
| 748 class ApplyBuiltinOperator extends Primitive { | 797 class ApplyBuiltinOperator extends Primitive { |
| 749 BuiltinOperator operator; | 798 BuiltinOperator operator; |
| 750 List<Reference<Primitive>> arguments; | 799 List<Reference<Primitive>> arguments; |
| 751 final SourceInformation sourceInformation; | 800 final SourceInformation sourceInformation; |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 | 1168 |
| 1120 void setParentPointers() { | 1169 void setParentPointers() { |
| 1121 value.parent = this; | 1170 value.parent = this; |
| 1122 } | 1171 } |
| 1123 } | 1172 } |
| 1124 | 1173 |
| 1125 /// Reads the value of a lazily initialized static field. | 1174 /// Reads the value of a lazily initialized static field. |
| 1126 /// | 1175 /// |
| 1127 /// If the field has not yet been initialized, its initializer is evaluated | 1176 /// If the field has not yet been initialized, its initializer is evaluated |
| 1128 /// and assigned to the field. | 1177 /// and assigned to the field. |
| 1129 /// | 1178 class GetLazyStatic extends UnsafePrimitive { |
| 1130 /// [continuation] is then invoked with the value of the field as argument. | |
| 1131 class GetLazyStatic extends CallExpression { | |
| 1132 final FieldElement element; | 1179 final FieldElement element; |
| 1133 final Reference<Continuation> continuation; | |
| 1134 final SourceInformation sourceInformation; | 1180 final SourceInformation sourceInformation; |
| 1135 | 1181 |
| 1136 GetLazyStatic(this.element, | 1182 GetLazyStatic(this.element, [this.sourceInformation]); |
| 1137 Continuation continuation, | |
| 1138 [this.sourceInformation]) | |
| 1139 : continuation = new Reference<Continuation>(continuation); | |
| 1140 | 1183 |
| 1141 accept(Visitor visitor) => visitor.visitGetLazyStatic(this); | 1184 accept(Visitor visitor) => visitor.visitGetLazyStatic(this); |
| 1142 | 1185 |
| 1143 void setParentPointers() { | 1186 void setParentPointers() { |
| 1144 continuation.parent = this; | |
| 1145 } | 1187 } |
| 1146 } | 1188 } |
| 1147 | 1189 |
| 1148 /// Creates an object for holding boxed variables captured by a closure. | 1190 /// Creates an object for holding boxed variables captured by a closure. |
| 1149 class CreateBox extends Primitive { | 1191 class CreateBox extends Primitive { |
| 1150 accept(Visitor visitor) => visitor.visitCreateBox(this); | 1192 accept(Visitor visitor) => visitor.visitCreateBox(this); |
| 1151 | 1193 |
| 1152 bool get isSafeForElimination => true; | 1194 bool get isSafeForElimination => true; |
| 1153 bool get isSafeForReordering => true; | 1195 bool get isSafeForReordering => true; |
| 1154 | 1196 |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this); | 1338 accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this); |
| 1297 | 1339 |
| 1298 bool get isSafeForElimination => true; | 1340 bool get isSafeForElimination => true; |
| 1299 bool get isSafeForReordering => true; | 1341 bool get isSafeForReordering => true; |
| 1300 | 1342 |
| 1301 void setParentPointers() { | 1343 void setParentPointers() { |
| 1302 _setParentsOnList(arguments, this); | 1344 _setParentsOnList(arguments, this); |
| 1303 } | 1345 } |
| 1304 } | 1346 } |
| 1305 | 1347 |
| 1306 class ForeignCode extends CallExpression { | 1348 class ForeignCode extends UnsafePrimitive { |
| 1307 final js.Template codeTemplate; | 1349 final js.Template codeTemplate; |
| 1308 final TypeMask type; | 1350 final TypeMask type; |
| 1309 final List<Reference<Primitive>> arguments; | 1351 final List<Reference<Primitive>> arguments; |
| 1310 final native.NativeBehavior nativeBehavior; | 1352 final native.NativeBehavior nativeBehavior; |
| 1311 final FunctionElement dependency; | 1353 final FunctionElement dependency; |
| 1312 final Reference<Continuation> continuation; | |
| 1313 | 1354 |
| 1314 ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments, | 1355 ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments, |
| 1315 this.nativeBehavior, Continuation continuation, {this.dependency}) | 1356 this.nativeBehavior, {this.dependency}) |
| 1316 : this.arguments = _referenceList(arguments), | 1357 : this.arguments = _referenceList(arguments); |
| 1317 this.continuation = new Reference<Continuation>(continuation); | |
| 1318 | 1358 |
| 1319 accept(Visitor visitor) => visitor.visitForeignCode(this); | 1359 accept(Visitor visitor) => visitor.visitForeignCode(this); |
| 1320 | 1360 |
| 1321 void setParentPointers() { | 1361 void setParentPointers() { |
| 1322 _setParentsOnList(arguments, this); | 1362 _setParentsOnList(arguments, this); |
| 1323 continuation.parent = this; | |
| 1324 } | 1363 } |
| 1325 } | 1364 } |
| 1326 | 1365 |
| 1327 class Constant extends Primitive { | 1366 class Constant extends Primitive { |
| 1328 final values.ConstantValue value; | 1367 final values.ConstantValue value; |
| 1329 final SourceInformation sourceInformation; | 1368 final SourceInformation sourceInformation; |
| 1330 | 1369 |
| 1331 Constant(this.value, {this.sourceInformation}) { | 1370 Constant(this.value, {this.sourceInformation}) { |
| 1332 assert(value != null); | 1371 assert(value != null); |
| 1333 } | 1372 } |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1569 } | 1608 } |
| 1570 | 1609 |
| 1571 bool get isSafeForElimination => true; | 1610 bool get isSafeForElimination => true; |
| 1572 bool get isSafeForReordering => true; | 1611 bool get isSafeForReordering => true; |
| 1573 | 1612 |
| 1574 void setParentPointers() { | 1613 void setParentPointers() { |
| 1575 _setParentsOnList(arguments, this); | 1614 _setParentsOnList(arguments, this); |
| 1576 } | 1615 } |
| 1577 } | 1616 } |
| 1578 | 1617 |
| 1579 class Await extends CallExpression { | 1618 class Await extends UnsafePrimitive { |
| 1580 final Reference<Primitive> input; | 1619 final Reference<Primitive> input; |
| 1581 final Reference<Continuation> continuation; | |
| 1582 | 1620 |
| 1583 Await(Primitive input, Continuation continuation) | 1621 Await(Primitive input) |
| 1584 : this.input = new Reference<Primitive>(input), | 1622 : this.input = new Reference<Primitive>(input); |
| 1585 this.continuation = new Reference<Continuation>(continuation); | |
| 1586 | 1623 |
| 1587 @override | 1624 @override |
| 1588 accept(Visitor visitor) { | 1625 accept(Visitor visitor) { |
| 1589 return visitor.visitAwait(this); | 1626 return visitor.visitAwait(this); |
| 1590 } | 1627 } |
| 1591 | 1628 |
| 1592 void setParentPointers() { | 1629 void setParentPointers() { |
| 1593 input.parent = this; | 1630 input.parent = this; |
| 1594 continuation.parent = this; | |
| 1595 } | 1631 } |
| 1596 } | 1632 } |
| 1597 | 1633 |
| 1598 class Yield extends CallExpression { | 1634 class Yield extends UnsafePrimitive { |
| 1599 final Reference<Primitive> input; | 1635 final Reference<Primitive> input; |
| 1600 final Reference<Continuation> continuation; | |
| 1601 final bool hasStar; | 1636 final bool hasStar; |
| 1602 | 1637 |
| 1603 Yield(Primitive input, this.hasStar, Continuation continuation) | 1638 Yield(Primitive input, this.hasStar) |
| 1604 : this.input = new Reference<Primitive>(input), | 1639 : this.input = new Reference<Primitive>(input); |
| 1605 this.continuation = new Reference<Continuation>(continuation); | |
| 1606 | 1640 |
| 1607 @override | 1641 @override |
| 1608 accept(Visitor visitor) { | 1642 accept(Visitor visitor) { |
| 1609 return visitor.visitYield(this); | 1643 return visitor.visitYield(this); |
| 1610 } | 1644 } |
| 1611 | 1645 |
| 1612 void setParentPointers() { | 1646 void setParentPointers() { |
| 1613 input.parent = this; | 1647 input.parent = this; |
| 1614 continuation.parent = this; | |
| 1615 } | 1648 } |
| 1616 } | 1649 } |
| 1617 | 1650 |
| 1618 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { | 1651 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { |
| 1619 return definitions.map((e) => new Reference<Primitive>(e)).toList(); | 1652 return definitions.map((e) => new Reference<Primitive>(e)).toList(); |
| 1620 } | 1653 } |
| 1621 | 1654 |
| 1622 void _setParentsOnNodes(List<Node> nodes, Node parent) { | 1655 void _setParentsOnNodes(List<Node> nodes, Node parent) { |
| 1623 for (Node node in nodes) { | 1656 for (Node node in nodes) { |
| 1624 node.parent = parent; | 1657 node.parent = parent; |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1753 visitLetMutable(LetMutable node) { | 1786 visitLetMutable(LetMutable node) { |
| 1754 processLetMutable(node); | 1787 processLetMutable(node); |
| 1755 visit(node.variable); | 1788 visit(node.variable); |
| 1756 processReference(node.value); | 1789 processReference(node.value); |
| 1757 visit(node.body); | 1790 visit(node.body); |
| 1758 } | 1791 } |
| 1759 | 1792 |
| 1760 processInvokeStatic(InvokeStatic node) {} | 1793 processInvokeStatic(InvokeStatic node) {} |
| 1761 visitInvokeStatic(InvokeStatic node) { | 1794 visitInvokeStatic(InvokeStatic node) { |
| 1762 processInvokeStatic(node); | 1795 processInvokeStatic(node); |
| 1763 processReference(node.continuation); | |
| 1764 node.arguments.forEach(processReference); | 1796 node.arguments.forEach(processReference); |
| 1765 } | 1797 } |
| 1766 | 1798 |
| 1767 processInvokeContinuation(InvokeContinuation node) {} | 1799 processInvokeContinuation(InvokeContinuation node) {} |
| 1768 visitInvokeContinuation(InvokeContinuation node) { | 1800 visitInvokeContinuation(InvokeContinuation node) { |
| 1769 processInvokeContinuation(node); | 1801 processInvokeContinuation(node); |
| 1770 processReference(node.continuation); | 1802 processReference(node.continuation); |
| 1771 node.arguments.forEach(processReference); | 1803 node.arguments.forEach(processReference); |
| 1772 } | 1804 } |
| 1773 | 1805 |
| 1774 processInvokeMethod(InvokeMethod node) {} | 1806 processInvokeMethod(InvokeMethod node) {} |
| 1775 visitInvokeMethod(InvokeMethod node) { | 1807 visitInvokeMethod(InvokeMethod node) { |
| 1776 processInvokeMethod(node); | 1808 processInvokeMethod(node); |
| 1777 processReference(node.receiver); | 1809 processReference(node.receiver); |
| 1778 processReference(node.continuation); | |
| 1779 node.arguments.forEach(processReference); | 1810 node.arguments.forEach(processReference); |
| 1780 } | 1811 } |
| 1781 | 1812 |
| 1782 processInvokeMethodDirectly(InvokeMethodDirectly node) {} | 1813 processInvokeMethodDirectly(InvokeMethodDirectly node) {} |
| 1783 visitInvokeMethodDirectly(InvokeMethodDirectly node) { | 1814 visitInvokeMethodDirectly(InvokeMethodDirectly node) { |
| 1784 processInvokeMethodDirectly(node); | 1815 processInvokeMethodDirectly(node); |
| 1785 processReference(node.receiver); | 1816 processReference(node.receiver); |
| 1786 processReference(node.continuation); | |
| 1787 node.arguments.forEach(processReference); | 1817 node.arguments.forEach(processReference); |
| 1788 } | 1818 } |
| 1789 | 1819 |
| 1790 processInvokeConstructor(InvokeConstructor node) {} | 1820 processInvokeConstructor(InvokeConstructor node) {} |
| 1791 visitInvokeConstructor(InvokeConstructor node) { | 1821 visitInvokeConstructor(InvokeConstructor node) { |
| 1792 processInvokeConstructor(node); | 1822 processInvokeConstructor(node); |
| 1793 processReference(node.continuation); | |
| 1794 node.arguments.forEach(processReference); | 1823 node.arguments.forEach(processReference); |
| 1795 } | 1824 } |
| 1796 | 1825 |
| 1797 processThrow(Throw node) {} | 1826 processThrow(Throw node) {} |
| 1798 visitThrow(Throw node) { | 1827 visitThrow(Throw node) { |
| 1799 processThrow(node); | 1828 processThrow(node); |
| 1800 processReference(node.value); | 1829 processReference(node.value); |
| 1801 } | 1830 } |
| 1802 | 1831 |
| 1803 processRethrow(Rethrow node) {} | 1832 processRethrow(Rethrow node) {} |
| 1804 visitRethrow(Rethrow node) { | 1833 visitRethrow(Rethrow node) { |
| 1805 processRethrow(node); | 1834 processRethrow(node); |
| 1806 } | 1835 } |
| 1807 | 1836 |
| 1808 processBranch(Branch node) {} | 1837 processBranch(Branch node) {} |
| 1809 visitBranch(Branch node) { | 1838 visitBranch(Branch node) { |
| 1810 processBranch(node); | 1839 processBranch(node); |
| 1811 processReference(node.trueContinuation); | 1840 processReference(node.trueContinuation); |
| 1812 processReference(node.falseContinuation); | 1841 processReference(node.falseContinuation); |
| 1813 processReference(node.condition); | 1842 processReference(node.condition); |
| 1814 } | 1843 } |
| 1815 | 1844 |
| 1816 processTypeCast(TypeCast node) {} | 1845 processTypeCast(TypeCast node) {} |
| 1817 visitTypeCast(TypeCast node) { | 1846 visitTypeCast(TypeCast node) { |
| 1818 processTypeCast(node); | 1847 processTypeCast(node); |
| 1819 processReference(node.continuation); | |
| 1820 processReference(node.value); | 1848 processReference(node.value); |
| 1821 node.typeArguments.forEach(processReference); | 1849 node.typeArguments.forEach(processReference); |
| 1822 } | 1850 } |
| 1823 | 1851 |
| 1824 processTypeTest(TypeTest node) {} | 1852 processTypeTest(TypeTest node) {} |
| 1825 visitTypeTest(TypeTest node) { | 1853 visitTypeTest(TypeTest node) { |
| 1826 processTypeTest(node); | 1854 processTypeTest(node); |
| 1827 processReference(node.value); | 1855 processReference(node.value); |
| 1828 if (node.interceptor != null) processReference(node.interceptor); | 1856 if (node.interceptor != null) processReference(node.interceptor); |
| 1829 node.typeArguments.forEach(processReference); | 1857 node.typeArguments.forEach(processReference); |
| 1830 } | 1858 } |
| 1831 | 1859 |
| 1832 processTypeTestViaFlag(TypeTestViaFlag node) {} | 1860 processTypeTestViaFlag(TypeTestViaFlag node) {} |
| 1833 visitTypeTestViaFlag(TypeTestViaFlag node) { | 1861 visitTypeTestViaFlag(TypeTestViaFlag node) { |
| 1834 processTypeTestViaFlag(node); | 1862 processTypeTestViaFlag(node); |
| 1835 processReference(node.interceptor); | 1863 processReference(node.interceptor); |
| 1836 } | 1864 } |
| 1837 | 1865 |
| 1838 processSetMutable(SetMutable node) {} | 1866 processSetMutable(SetMutable node) {} |
| 1839 visitSetMutable(SetMutable node) { | 1867 visitSetMutable(SetMutable node) { |
| 1840 processSetMutable(node); | 1868 processSetMutable(node); |
| 1841 processReference(node.variable); | 1869 processReference(node.variable); |
| 1842 processReference(node.value); | 1870 processReference(node.value); |
| 1843 } | 1871 } |
| 1844 | 1872 |
| 1845 processGetLazyStatic(GetLazyStatic node) {} | 1873 processGetLazyStatic(GetLazyStatic node) {} |
| 1846 visitGetLazyStatic(GetLazyStatic node) { | 1874 visitGetLazyStatic(GetLazyStatic node) { |
| 1847 processGetLazyStatic(node); | 1875 processGetLazyStatic(node); |
| 1848 processReference(node.continuation); | |
| 1849 } | 1876 } |
| 1850 | 1877 |
| 1851 processLiteralList(LiteralList node) {} | 1878 processLiteralList(LiteralList node) {} |
| 1852 visitLiteralList(LiteralList node) { | 1879 visitLiteralList(LiteralList node) { |
| 1853 processLiteralList(node); | 1880 processLiteralList(node); |
| 1854 node.values.forEach(processReference); | 1881 node.values.forEach(processReference); |
| 1855 } | 1882 } |
| 1856 | 1883 |
| 1857 processLiteralMap(LiteralMap node) {} | 1884 processLiteralMap(LiteralMap node) {} |
| 1858 visitLiteralMap(LiteralMap node) { | 1885 visitLiteralMap(LiteralMap node) { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1965 processApplyBuiltinMethod(ApplyBuiltinMethod node) {} | 1992 processApplyBuiltinMethod(ApplyBuiltinMethod node) {} |
| 1966 visitApplyBuiltinMethod(ApplyBuiltinMethod node) { | 1993 visitApplyBuiltinMethod(ApplyBuiltinMethod node) { |
| 1967 processApplyBuiltinMethod(node); | 1994 processApplyBuiltinMethod(node); |
| 1968 processReference(node.receiver); | 1995 processReference(node.receiver); |
| 1969 node.arguments.forEach(processReference); | 1996 node.arguments.forEach(processReference); |
| 1970 } | 1997 } |
| 1971 | 1998 |
| 1972 processForeignCode(ForeignCode node) {} | 1999 processForeignCode(ForeignCode node) {} |
| 1973 visitForeignCode(ForeignCode node) { | 2000 visitForeignCode(ForeignCode node) { |
| 1974 processForeignCode(node); | 2001 processForeignCode(node); |
| 1975 if (node.continuation != null) { | |
| 1976 processReference(node.continuation); | |
| 1977 } | |
| 1978 node.arguments.forEach(processReference); | 2002 node.arguments.forEach(processReference); |
| 1979 } | 2003 } |
| 1980 | 2004 |
| 1981 processUnreachable(Unreachable node) {} | 2005 processUnreachable(Unreachable node) {} |
| 1982 visitUnreachable(Unreachable node) { | 2006 visitUnreachable(Unreachable node) { |
| 1983 processUnreachable(node); | 2007 processUnreachable(node); |
| 1984 } | 2008 } |
| 1985 | 2009 |
| 1986 processAwait(Await node) {} | 2010 processAwait(Await node) {} |
| 1987 visitAwait(Await node) { | 2011 visitAwait(Await node) { |
| 1988 processAwait(node); | 2012 processAwait(node); |
| 1989 processReference(node.input); | 2013 processReference(node.input); |
| 1990 processReference(node.continuation); | |
| 1991 } | 2014 } |
| 1992 | 2015 |
| 1993 processYield(Yield node) {} | 2016 processYield(Yield node) {} |
| 1994 visitYield(Yield node) { | 2017 visitYield(Yield node) { |
| 1995 processYield(node); | 2018 processYield(node); |
| 1996 processReference(node.input); | 2019 processReference(node.input); |
| 1997 processReference(node.continuation); | |
| 1998 } | 2020 } |
| 1999 | 2021 |
| 2000 processGetLength(GetLength node) {} | 2022 processGetLength(GetLength node) {} |
| 2001 visitGetLength(GetLength node) { | 2023 visitGetLength(GetLength node) { |
| 2002 processGetLength(node); | 2024 processGetLength(node); |
| 2003 processReference(node.object); | 2025 processReference(node.object); |
| 2004 } | 2026 } |
| 2005 | 2027 |
| 2006 processGetIndex(GetIndex node) {} | 2028 processGetIndex(GetIndex node) {} |
| 2007 visitGetIndex(GetIndex node) { | 2029 visitGetIndex(GetIndex node) { |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2149 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2171 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
| 2150 class RemovalVisitor extends TrampolineRecursiveVisitor { | 2172 class RemovalVisitor extends TrampolineRecursiveVisitor { |
| 2151 processReference(Reference reference) { | 2173 processReference(Reference reference) { |
| 2152 reference.unlink(); | 2174 reference.unlink(); |
| 2153 } | 2175 } |
| 2154 | 2176 |
| 2155 static void remove(Node node) { | 2177 static void remove(Node node) { |
| 2156 (new RemovalVisitor()).visit(node); | 2178 (new RemovalVisitor()).visit(node); |
| 2157 } | 2179 } |
| 2158 } | 2180 } |
| OLD | NEW |