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 10 matching lines...) Expand all Loading... | |
21 import '../native/native.dart' as native show NativeBehavior; | 21 import '../native/native.dart' as native show NativeBehavior; |
22 | 22 |
23 abstract class Node { | 23 abstract class Node { |
24 /// A pointer to the parent node. Is null until set by optimization passes. | 24 /// A pointer to the parent node. Is null until set by optimization passes. |
25 Node parent; | 25 Node parent; |
26 | 26 |
27 /// Workaround for a slow Object.hashCode in the VM. | 27 /// Workaround for a slow Object.hashCode in the VM. |
28 static int _usedHashCodes = 0; | 28 static int _usedHashCodes = 0; |
29 final int hashCode = ++_usedHashCodes; | 29 final int hashCode = ++_usedHashCodes; |
30 | 30 |
31 Node() { | |
32 setParentPointers(); | |
33 } | |
34 | |
31 accept(Visitor visitor); | 35 accept(Visitor visitor); |
36 | |
37 /// Updates the [parent] of the immediate children to refer to this node. | |
38 /// | |
39 /// All constructors call this method to initialize parent pointers. | |
40 void setParentPointers(); | |
32 } | 41 } |
33 | 42 |
34 /// Expressions can be evaluated, and may diverge, throw, and/or have | 43 /// Expressions can be evaluated, and may diverge, throw, and/or have |
35 /// side-effects. | 44 /// side-effects. |
36 /// | 45 /// |
37 /// Evaluation continues by stepping into a sub-expression, invoking a | 46 /// Evaluation continues by stepping into a sub-expression, invoking a |
38 /// continuation, or throwing an exception. | 47 /// continuation, or throwing an exception. |
39 /// | 48 /// |
40 /// Expressions do not a return value. Expressions that produce values should | 49 /// Expressions do not a return value. Expressions that produce values should |
41 /// invoke a [Continuation] with the result as argument. Alternatively, values | 50 /// invoke a [Continuation] with the result as argument. Alternatively, values |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
305 /// The bound value is in scope in the body. | 314 /// The bound value is in scope in the body. |
306 /// | 315 /// |
307 /// During one-pass construction a LetPrim with an empty body is used to | 316 /// During one-pass construction a LetPrim with an empty body is used to |
308 /// represent the one-hole context `let val x = V in []`. | 317 /// represent the one-hole context `let val x = V in []`. |
309 class LetPrim extends InteriorExpression { | 318 class LetPrim extends InteriorExpression { |
310 Primitive primitive; | 319 Primitive primitive; |
311 Expression body; | 320 Expression body; |
312 | 321 |
313 LetPrim(this.primitive, [this.body = null]); | 322 LetPrim(this.primitive, [this.body = null]); |
314 | 323 |
315 Expression plug(Expression expr) { | 324 Expression plug(Expression expr) { |
Kevin Millikin (Google)
2015/10/05 12:04:37
It seems better to also set the parent pointer her
asgerf
2015/10/12 13:18:31
There are too many explicit setter calls in the bu
| |
316 assert(body == null); | 325 assert(body == null); |
317 return body = expr; | 326 return body = expr; |
318 } | 327 } |
319 | 328 |
320 accept(Visitor visitor) => visitor.visitLetPrim(this); | 329 accept(Visitor visitor) => visitor.visitLetPrim(this); |
330 | |
331 void setParentPointers() { | |
332 primitive.parent = this; | |
333 if (body != null) body.parent = this; | |
334 } | |
321 } | 335 } |
322 | 336 |
323 | |
324 /// Binding continuations. | 337 /// Binding continuations. |
325 /// | 338 /// |
326 /// let cont k0(v0 ...) = E0 | 339 /// let cont k0(v0 ...) = E0 |
327 /// k1(v1 ...) = E1 | 340 /// k1(v1 ...) = E1 |
328 /// ... | 341 /// ... |
329 /// in E | 342 /// in E |
330 /// | 343 /// |
331 /// The bound continuations are in scope in the body and the continuation | 344 /// The bound continuations are in scope in the body and the continuation |
332 /// parameters are in scope in the respective continuation bodies. | 345 /// parameters are in scope in the respective continuation bodies. |
333 /// | 346 /// |
(...skipping 13 matching lines...) Expand all Loading... | |
347 LetCont.many(this.continuations, this.body); | 360 LetCont.many(this.continuations, this.body); |
348 | 361 |
349 Expression plug(Expression expr) { | 362 Expression plug(Expression expr) { |
350 assert(continuations != null && | 363 assert(continuations != null && |
351 continuations.isNotEmpty && | 364 continuations.isNotEmpty && |
352 continuations.first.body == null); | 365 continuations.first.body == null); |
353 return continuations.first.body = expr; | 366 return continuations.first.body = expr; |
354 } | 367 } |
355 | 368 |
356 accept(Visitor visitor) => visitor.visitLetCont(this); | 369 accept(Visitor visitor) => visitor.visitLetCont(this); |
370 | |
371 void setParentPointers() { | |
372 _setParentsOnNodes(continuations, this); | |
373 if (body != null) body.parent = this; | |
374 } | |
357 } | 375 } |
358 | 376 |
359 // Binding an exception handler. | 377 // Binding an exception handler. |
360 // | 378 // |
361 // let handler h(v0, v1) = E0 in E1 | 379 // let handler h(v0, v1) = E0 in E1 |
362 // | 380 // |
363 // The handler is a two-argument (exception, stack trace) continuation which | 381 // The handler is a two-argument (exception, stack trace) continuation which |
364 // is implicitly the error continuation of all the code in its body E1. | 382 // is implicitly the error continuation of all the code in its body E1. |
365 // [LetHandler] differs from a [LetCont] binding in that it (1) has the | 383 // [LetHandler] differs from a [LetCont] binding in that it (1) has the |
366 // runtime semantics of pushing/popping a handler from the dynamic exception | 384 // runtime semantics of pushing/popping a handler from the dynamic exception |
367 // handler stack and (2) it does not have any explicit invocations. | 385 // handler stack and (2) it does not have any explicit invocations. |
368 class LetHandler extends InteriorExpression { | 386 class LetHandler extends InteriorExpression { |
369 Continuation handler; | 387 Continuation handler; |
370 Expression body; | 388 Expression body; |
371 | 389 |
372 LetHandler(this.handler, this.body); | 390 LetHandler(this.handler, this.body); |
373 | 391 |
374 accept(Visitor visitor) => visitor.visitLetHandler(this); | 392 accept(Visitor visitor) => visitor.visitLetHandler(this); |
393 | |
394 void setParentPointers() { | |
395 handler.parent = this; | |
396 if (body != null) body.parent = this; | |
397 } | |
375 } | 398 } |
376 | 399 |
377 /// Binding mutable variables. | 400 /// Binding mutable variables. |
378 /// | 401 /// |
379 /// let mutable v = P in E | 402 /// let mutable v = P in E |
380 /// | 403 /// |
381 /// [MutableVariable]s can be seen as ref cells that are not first-class | 404 /// [MutableVariable]s can be seen as ref cells that are not first-class |
382 /// values. They are therefore not [Primitive]s and not bound by [LetPrim] | 405 /// values. They are therefore not [Primitive]s and not bound by [LetPrim] |
383 /// to prevent unrestricted use of references to them. During one-pass | 406 /// to prevent unrestricted use of references to them. During one-pass |
384 /// construction, a [LetMutable] with an empty body is use to represent the | 407 /// construction, a [LetMutable] with an empty body is use to represent the |
385 /// one-hole context 'let mutable v = P in []'. | 408 /// one-hole context 'let mutable v = P in []'. |
386 class LetMutable extends InteriorExpression { | 409 class LetMutable extends InteriorExpression { |
387 final MutableVariable variable; | 410 final MutableVariable variable; |
388 final Reference<Primitive> value; | 411 final Reference<Primitive> value; |
389 Expression body; | 412 Expression body; |
390 | 413 |
391 LetMutable(this.variable, Primitive value) | 414 LetMutable(this.variable, Primitive value) |
392 : this.value = new Reference<Primitive>(value); | 415 : this.value = new Reference<Primitive>(value); |
393 | 416 |
394 Expression plug(Expression expr) { | 417 Expression plug(Expression expr) { |
395 return body = expr; | 418 return body = expr; |
396 } | 419 } |
397 | 420 |
398 accept(Visitor visitor) => visitor.visitLetMutable(this); | 421 accept(Visitor visitor) => visitor.visitLetMutable(this); |
422 | |
423 void setParentPointers() { | |
424 variable.parent = this; | |
425 value.parent = this; | |
426 if (body != null) body.parent = this; | |
427 } | |
399 } | 428 } |
400 | 429 |
401 /// Invoke a static function. | 430 /// Invoke a static function. |
402 /// | 431 /// |
403 /// All optional arguments declared by [target] are passed in explicitly, and | 432 /// All optional arguments declared by [target] are passed in explicitly, and |
404 /// occur at the end of [arguments] list, in normalized order. | 433 /// occur at the end of [arguments] list, in normalized order. |
405 /// | 434 /// |
406 /// Discussion: | 435 /// Discussion: |
407 /// All information in the [selector] is technically redundant; it will likely | 436 /// All information in the [selector] is technically redundant; it will likely |
408 /// be removed. | 437 /// be removed. |
(...skipping 12 matching lines...) Expand all Loading... | |
421 : arguments = _referenceList(args), | 450 : arguments = _referenceList(args), |
422 continuation = new Reference<Continuation>(cont); | 451 continuation = new Reference<Continuation>(cont); |
423 | 452 |
424 InvokeStatic.byReference(this.target, | 453 InvokeStatic.byReference(this.target, |
425 this.selector, | 454 this.selector, |
426 this.arguments, | 455 this.arguments, |
427 this.continuation, | 456 this.continuation, |
428 [this.sourceInformation]); | 457 [this.sourceInformation]); |
429 | 458 |
430 accept(Visitor visitor) => visitor.visitInvokeStatic(this); | 459 accept(Visitor visitor) => visitor.visitInvokeStatic(this); |
460 | |
461 void setParentPointers() { | |
462 _setParentsOnList(arguments, this); | |
463 continuation.parent = this; | |
464 } | |
431 } | 465 } |
432 | 466 |
433 /// Invoke a method on an object. | 467 /// Invoke a method on an object. |
434 /// | 468 /// |
435 /// This includes getters, setters, operators, and index getter/setters. | 469 /// This includes getters, setters, operators, and index getter/setters. |
436 /// | 470 /// |
437 /// Tearing off a method is treated like a getter invocation (getters and | 471 /// Tearing off a method is treated like a getter invocation (getters and |
438 /// tear-offs cannot be distinguished at compile-time). | 472 /// tear-offs cannot be distinguished at compile-time). |
439 /// | 473 /// |
440 /// The [selector] records the names of named arguments. The value of named | 474 /// The [selector] records the names of named arguments. The value of named |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
472 this.continuation = new Reference<Continuation>(continuation); | 506 this.continuation = new Reference<Continuation>(continuation); |
473 | 507 |
474 InvokeMethod.byReference(this.receiver, | 508 InvokeMethod.byReference(this.receiver, |
475 this.selector, | 509 this.selector, |
476 this.mask, | 510 this.mask, |
477 this.arguments, | 511 this.arguments, |
478 this.continuation, | 512 this.continuation, |
479 this.sourceInformation); | 513 this.sourceInformation); |
480 | 514 |
481 accept(Visitor visitor) => visitor.visitInvokeMethod(this); | 515 accept(Visitor visitor) => visitor.visitInvokeMethod(this); |
516 | |
517 void setParentPointers() { | |
518 receiver.parent = this; | |
519 _setParentsOnList(arguments, this); | |
520 continuation.parent = this; | |
521 } | |
482 } | 522 } |
483 | 523 |
484 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. | 524 /// Invoke [target] on [receiver], bypassing dispatch and override semantics. |
485 /// | 525 /// |
486 /// That is, if [receiver] is an instance of a class that overrides [target] | 526 /// That is, if [receiver] is an instance of a class that overrides [target] |
487 /// with a different implementation, the overriding implementation is bypassed | 527 /// with a different implementation, the overriding implementation is bypassed |
488 /// and [target]'s implementation is invoked. | 528 /// and [target]'s implementation is invoked. |
489 /// | 529 /// |
490 /// As with [InvokeMethod], this can be used to invoke a method, operator, | 530 /// As with [InvokeMethod], this can be used to invoke a method, operator, |
491 /// getter, setter, or index getter/setter. | 531 /// getter, setter, or index getter/setter. |
(...skipping 20 matching lines...) Expand all Loading... | |
512 this.target, | 552 this.target, |
513 this.selector, | 553 this.selector, |
514 List<Primitive> arguments, | 554 List<Primitive> arguments, |
515 Continuation continuation, | 555 Continuation continuation, |
516 this.sourceInformation) | 556 this.sourceInformation) |
517 : this.receiver = new Reference<Primitive>(receiver), | 557 : this.receiver = new Reference<Primitive>(receiver), |
518 this.arguments = _referenceList(arguments), | 558 this.arguments = _referenceList(arguments), |
519 this.continuation = new Reference<Continuation>(continuation); | 559 this.continuation = new Reference<Continuation>(continuation); |
520 | 560 |
521 accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this); | 561 accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this); |
562 | |
563 void setParentPointers() { | |
564 receiver.parent = this; | |
565 _setParentsOnList(arguments, this); | |
566 continuation.parent = this; | |
567 } | |
522 } | 568 } |
523 | 569 |
524 /// Non-const call to a constructor. | 570 /// Non-const call to a constructor. |
525 /// | 571 /// |
526 /// The [target] may be a generative constructor (forwarding or normal) | 572 /// The [target] may be a generative constructor (forwarding or normal) |
527 /// or a non-redirecting factory. | 573 /// or a non-redirecting factory. |
528 /// | 574 /// |
529 /// All optional arguments declared by [target] are passed in explicitly, and | 575 /// All optional arguments declared by [target] are passed in explicitly, and |
530 /// occur in the [arguments] list, in normalized order. | 576 /// occur in the [arguments] list, in normalized order. |
531 /// | 577 /// |
(...skipping 15 matching lines...) Expand all Loading... | |
547 InvokeConstructor(this.dartType, | 593 InvokeConstructor(this.dartType, |
548 this.target, | 594 this.target, |
549 this.selector, | 595 this.selector, |
550 List<Primitive> args, | 596 List<Primitive> args, |
551 Continuation cont, | 597 Continuation cont, |
552 this.sourceInformation) | 598 this.sourceInformation) |
553 : arguments = _referenceList(args), | 599 : arguments = _referenceList(args), |
554 continuation = new Reference<Continuation>(cont); | 600 continuation = new Reference<Continuation>(cont); |
555 | 601 |
556 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); | 602 accept(Visitor visitor) => visitor.visitInvokeConstructor(this); |
603 | |
604 void setParentPointers() { | |
605 _setParentsOnList(arguments, this); | |
606 continuation.parent = this; | |
607 } | |
557 } | 608 } |
558 | 609 |
559 /// An alias for [value] in a context where the value is known to satisfy | 610 /// An alias for [value] in a context where the value is known to satisfy |
560 /// [type]. | 611 /// [type]. |
561 /// | 612 /// |
562 /// Refinement nodes are inserted before the type propagator pass and removed | 613 /// Refinement nodes are inserted before the type propagator pass and removed |
563 /// afterwards, so as not to complicate passes that don't reason about types, | 614 /// afterwards, so as not to complicate passes that don't reason about types, |
564 /// but need to reason about value references being identical (i.e. referring | 615 /// but need to reason about value references being identical (i.e. referring |
565 /// to the same primitive). | 616 /// to the same primitive). |
566 class Refinement extends Primitive { | 617 class Refinement extends Primitive { |
567 Reference<Primitive> value; | 618 Reference<Primitive> value; |
568 final TypeMask refineType; | 619 final TypeMask refineType; |
569 | 620 |
570 Refinement(Primitive value, this.refineType) | 621 Refinement(Primitive value, this.refineType) |
571 : value = new Reference<Primitive>(value); | 622 : value = new Reference<Primitive>(value); |
572 | 623 |
573 bool get isSafeForElimination => true; | 624 bool get isSafeForElimination => true; |
574 bool get isSafeForReordering => false; | 625 bool get isSafeForReordering => false; |
575 | 626 |
576 accept(Visitor visitor) => visitor.visitRefinement(this); | 627 accept(Visitor visitor) => visitor.visitRefinement(this); |
577 | 628 |
578 Primitive get effectiveDefinition => value.definition.effectiveDefinition; | 629 Primitive get effectiveDefinition => value.definition.effectiveDefinition; |
630 | |
631 void setParentPointers() { | |
632 value.parent = this; | |
633 } | |
579 } | 634 } |
580 | 635 |
581 /// An "is" type test. | 636 /// An "is" type test. |
582 /// | 637 /// |
583 /// Returns `true` if [value] is an instance of [type]. | 638 /// Returns `true` if [value] is an instance of [type]. |
584 /// | 639 /// |
585 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might | 640 /// [type] must not be the [Object], `dynamic` or [Null] types (though it might |
586 /// be a type variable containing one of these types). This design is chosen | 641 /// be a type variable containing one of these types). This design is chosen |
587 /// to simplify code generation for type tests. | 642 /// to simplify code generation for type tests. |
588 class TypeTest extends Primitive { | 643 class TypeTest extends Primitive { |
(...skipping 16 matching lines...) Expand all Loading... | |
605 TypeTest(Primitive value, | 660 TypeTest(Primitive value, |
606 this.dartType, | 661 this.dartType, |
607 List<Primitive> typeArguments) | 662 List<Primitive> typeArguments) |
608 : this.value = new Reference<Primitive>(value), | 663 : this.value = new Reference<Primitive>(value), |
609 this.typeArguments = _referenceList(typeArguments); | 664 this.typeArguments = _referenceList(typeArguments); |
610 | 665 |
611 accept(Visitor visitor) => visitor.visitTypeTest(this); | 666 accept(Visitor visitor) => visitor.visitTypeTest(this); |
612 | 667 |
613 bool get isSafeForElimination => true; | 668 bool get isSafeForElimination => true; |
614 bool get isSafeForReordering => true; | 669 bool get isSafeForReordering => true; |
670 | |
671 void setParentPointers() { | |
672 value.parent = this; | |
673 _setParentsOnList(typeArguments, this); | |
674 } | |
615 } | 675 } |
616 | 676 |
617 /// An "as" type cast. | 677 /// An "as" type cast. |
618 /// | 678 /// |
619 /// If [value] is `null` or is an instance of [type], [continuation] is invoked | 679 /// If [value] is `null` or is an instance of [type], [continuation] is invoked |
620 /// with [value] as argument. Otherwise, a [CastError] is thrown. | 680 /// with [value] as argument. Otherwise, a [CastError] is thrown. |
621 /// | 681 /// |
622 /// Discussion: | 682 /// Discussion: |
623 /// The parameter to [continuation] is redundant since it will always equal | 683 /// The parameter to [continuation] is redundant since it will always equal |
624 /// [value], which is typically in scope in the continuation. However, it might | 684 /// [value], which is typically in scope in the continuation. However, it might |
625 /// simplify type propagation, since a better type can be computed for the | 685 /// simplify type propagation, since a better type can be computed for the |
626 /// continuation parameter without needing flow-sensitive analysis. | 686 /// continuation parameter without needing flow-sensitive analysis. |
627 class TypeCast extends CallExpression { | 687 class TypeCast extends CallExpression { |
628 Reference<Primitive> value; | 688 Reference<Primitive> value; |
629 final DartType dartType; | 689 final DartType dartType; |
630 | 690 |
631 /// See the corresponding field on [TypeTest]. | 691 /// See the corresponding field on [TypeTest]. |
632 final List<Reference<Primitive>> typeArguments; | 692 final List<Reference<Primitive>> typeArguments; |
633 final Reference<Continuation> continuation; | 693 final Reference<Continuation> continuation; |
634 | 694 |
635 TypeCast(Primitive value, | 695 TypeCast(Primitive value, |
636 this.dartType, | 696 this.dartType, |
637 List<Primitive> typeArguments, | 697 List<Primitive> typeArguments, |
638 Continuation cont) | 698 Continuation cont) |
639 : this.value = new Reference<Primitive>(value), | 699 : this.value = new Reference<Primitive>(value), |
640 this.typeArguments = _referenceList(typeArguments), | 700 this.typeArguments = _referenceList(typeArguments), |
641 this.continuation = new Reference<Continuation>(cont); | 701 this.continuation = new Reference<Continuation>(cont); |
642 | 702 |
643 accept(Visitor visitor) => visitor.visitTypeCast(this); | 703 accept(Visitor visitor) => visitor.visitTypeCast(this); |
704 | |
705 void setParentPointers() { | |
706 value.parent = this; | |
707 } | |
644 } | 708 } |
645 | 709 |
646 /// Apply a built-in operator. | 710 /// Apply a built-in operator. |
647 /// | 711 /// |
648 /// It must be known that the arguments have the proper types. | 712 /// It must be known that the arguments have the proper types. |
649 class ApplyBuiltinOperator extends Primitive { | 713 class ApplyBuiltinOperator extends Primitive { |
650 BuiltinOperator operator; | 714 BuiltinOperator operator; |
651 List<Reference<Primitive>> arguments; | 715 List<Reference<Primitive>> arguments; |
652 final SourceInformation sourceInformation; | 716 final SourceInformation sourceInformation; |
653 | 717 |
654 ApplyBuiltinOperator(this.operator, | 718 ApplyBuiltinOperator(this.operator, |
655 List<Primitive> arguments, | 719 List<Primitive> arguments, |
656 this.sourceInformation) | 720 this.sourceInformation) |
657 : this.arguments = _referenceList(arguments); | 721 : this.arguments = _referenceList(arguments); |
658 | 722 |
659 accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this); | 723 accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this); |
660 | 724 |
661 bool get isSafeForElimination => true; | 725 bool get isSafeForElimination => true; |
662 bool get isSafeForReordering => true; | 726 bool get isSafeForReordering => true; |
727 | |
728 void setParentPointers() { | |
729 _setParentsOnList(arguments, this); | |
730 } | |
663 } | 731 } |
664 | 732 |
665 /// Apply a built-in method. | 733 /// Apply a built-in method. |
666 /// | 734 /// |
667 /// It must be known that the arguments have the proper types. | 735 /// It must be known that the arguments have the proper types. |
668 class ApplyBuiltinMethod extends Primitive { | 736 class ApplyBuiltinMethod extends Primitive { |
669 BuiltinMethod method; | 737 BuiltinMethod method; |
670 Reference<Primitive> receiver; | 738 Reference<Primitive> receiver; |
671 List<Reference<Primitive>> arguments; | 739 List<Reference<Primitive>> arguments; |
672 final SourceInformation sourceInformation; | 740 final SourceInformation sourceInformation; |
673 | 741 |
674 bool receiverIsNotNull; | 742 bool receiverIsNotNull; |
675 | 743 |
676 ApplyBuiltinMethod(this.method, | 744 ApplyBuiltinMethod(this.method, |
677 Primitive receiver, | 745 Primitive receiver, |
678 List<Primitive> arguments, | 746 List<Primitive> arguments, |
679 this.sourceInformation, | 747 this.sourceInformation, |
680 {this.receiverIsNotNull: false}) | 748 {this.receiverIsNotNull: false}) |
681 : this.receiver = new Reference<Primitive>(receiver), | 749 : this.receiver = new Reference<Primitive>(receiver), |
682 this.arguments = _referenceList(arguments); | 750 this.arguments = _referenceList(arguments); |
683 | 751 |
684 accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this); | 752 accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this); |
685 | 753 |
686 bool get isSafeForElimination => false; | 754 bool get isSafeForElimination => false; |
687 bool get isSafeForReordering => false; | 755 bool get isSafeForReordering => false; |
756 | |
757 void setParentPointers() { | |
758 receiver.parent = this; | |
759 _setParentsOnList(arguments, this); | |
760 } | |
688 } | 761 } |
689 | 762 |
690 /// Throw a value. | 763 /// Throw a value. |
691 /// | 764 /// |
692 /// Throw is an expression, i.e., it always occurs in tail position with | 765 /// Throw is an expression, i.e., it always occurs in tail position with |
693 /// respect to a body or expression. | 766 /// respect to a body or expression. |
694 class Throw extends TailExpression { | 767 class Throw extends TailExpression { |
695 Reference<Primitive> value; | 768 Reference<Primitive> value; |
696 | 769 |
697 Throw(Primitive value) : value = new Reference<Primitive>(value); | 770 Throw(Primitive value) : value = new Reference<Primitive>(value); |
698 | 771 |
699 accept(Visitor visitor) => visitor.visitThrow(this); | 772 accept(Visitor visitor) => visitor.visitThrow(this); |
773 | |
774 void setParentPointers() { | |
775 value.parent = this; | |
776 } | |
700 } | 777 } |
701 | 778 |
702 /// Rethrow | 779 /// Rethrow |
703 /// | 780 /// |
704 /// Rethrow can only occur inside a continuation bound by [LetHandler]. It | 781 /// Rethrow can only occur inside a continuation bound by [LetHandler]. It |
705 /// implicitly throws the exception parameter of the enclosing handler with | 782 /// implicitly throws the exception parameter of the enclosing handler with |
706 /// the same stack trace as the enclosing handler. | 783 /// the same stack trace as the enclosing handler. |
707 class Rethrow extends TailExpression { | 784 class Rethrow extends TailExpression { |
708 accept(Visitor visitor) => visitor.visitRethrow(this); | 785 accept(Visitor visitor) => visitor.visitRethrow(this); |
786 void setParentPointers() {} | |
709 } | 787 } |
710 | 788 |
711 /// An expression that is known to be unreachable. | 789 /// An expression that is known to be unreachable. |
712 /// | 790 /// |
713 /// This can be placed as the body of a call continuation, when the caller is | 791 /// This can be placed as the body of a call continuation, when the caller is |
714 /// known never to invoke it, e.g. because the calling expression always throws. | 792 /// known never to invoke it, e.g. because the calling expression always throws. |
715 class Unreachable extends TailExpression { | 793 class Unreachable extends TailExpression { |
716 accept(Visitor visitor) => visitor.visitUnreachable(this); | 794 accept(Visitor visitor) => visitor.visitUnreachable(this); |
795 void setParentPointers() {} | |
717 } | 796 } |
718 | 797 |
719 /// Gets the value from a [MutableVariable]. | 798 /// Gets the value from a [MutableVariable]. |
720 /// | 799 /// |
721 /// [MutableVariable]s can be seen as ref cells that are not first-class | 800 /// [MutableVariable]s can be seen as ref cells that are not first-class |
722 /// values. A [LetPrim] with a [GetMutable] can then be seen as: | 801 /// values. A [LetPrim] with a [GetMutable] can then be seen as: |
723 /// | 802 /// |
724 /// let prim p = ![variable] in [body] | 803 /// let prim p = ![variable] in [body] |
725 /// | 804 /// |
726 class GetMutable extends Primitive { | 805 class GetMutable extends Primitive { |
727 final Reference<MutableVariable> variable; | 806 final Reference<MutableVariable> variable; |
728 | 807 |
729 GetMutable(MutableVariable variable) | 808 GetMutable(MutableVariable variable) |
730 : this.variable = new Reference<MutableVariable>(variable); | 809 : this.variable = new Reference<MutableVariable>(variable); |
731 | 810 |
732 accept(Visitor visitor) => visitor.visitGetMutable(this); | 811 accept(Visitor visitor) => visitor.visitGetMutable(this); |
733 | 812 |
734 bool get isSafeForElimination => true; | 813 bool get isSafeForElimination => true; |
735 bool get isSafeForReordering => false; | 814 bool get isSafeForReordering => false; |
815 | |
816 void setParentPointers() { | |
817 variable.parent = this; | |
818 } | |
736 } | 819 } |
737 | 820 |
738 /// Assign a [MutableVariable]. | 821 /// Assign a [MutableVariable]. |
739 /// | 822 /// |
740 /// [MutableVariable]s can be seen as ref cells that are not first-class | 823 /// [MutableVariable]s can be seen as ref cells that are not first-class |
741 /// values. This can be seen as a dereferencing assignment: | 824 /// values. This can be seen as a dereferencing assignment: |
742 /// | 825 /// |
743 /// { [variable] := [value]; [body] } | 826 /// { [variable] := [value]; [body] } |
744 class SetMutable extends Primitive { | 827 class SetMutable extends Primitive { |
745 final Reference<MutableVariable> variable; | 828 final Reference<MutableVariable> variable; |
746 final Reference<Primitive> value; | 829 final Reference<Primitive> value; |
747 | 830 |
748 SetMutable(MutableVariable variable, Primitive value) | 831 SetMutable(MutableVariable variable, Primitive value) |
749 : this.variable = new Reference<MutableVariable>(variable), | 832 : this.variable = new Reference<MutableVariable>(variable), |
750 this.value = new Reference<Primitive>(value); | 833 this.value = new Reference<Primitive>(value); |
751 | 834 |
752 accept(Visitor visitor) => visitor.visitSetMutable(this); | 835 accept(Visitor visitor) => visitor.visitSetMutable(this); |
753 | 836 |
754 bool get isSafeForElimination => false; | 837 bool get isSafeForElimination => false; |
755 bool get isSafeForReordering => false; | 838 bool get isSafeForReordering => false; |
839 | |
840 void setParentPointers() { | |
841 variable.parent = this; | |
842 value.parent = this; | |
843 } | |
756 } | 844 } |
757 | 845 |
758 /// Invoke a continuation in tail position. | 846 /// Invoke a continuation in tail position. |
759 class InvokeContinuation extends TailExpression { | 847 class InvokeContinuation extends TailExpression { |
760 Reference<Continuation> continuation; | 848 Reference<Continuation> continuation; |
761 List<Reference<Primitive>> arguments; | 849 List<Reference<Primitive>> arguments; |
762 SourceInformation sourceInformation; | 850 SourceInformation sourceInformation; |
763 | 851 |
764 // An invocation of a continuation is recursive if it occurs in the body of | 852 // An invocation of a continuation is recursive if it occurs in the body of |
765 // the continuation itself. | 853 // the continuation itself. |
(...skipping 18 matching lines...) Expand all Loading... | |
784 /// | 872 /// |
785 /// Used as a placeholder for a jump whose target is not yet created | 873 /// Used as a placeholder for a jump whose target is not yet created |
786 /// (e.g., in the translation of break and continue). | 874 /// (e.g., in the translation of break and continue). |
787 InvokeContinuation.uninitialized({this.isRecursive: false, | 875 InvokeContinuation.uninitialized({this.isRecursive: false, |
788 this.isEscapingTry: false}) | 876 this.isEscapingTry: false}) |
789 : continuation = null, | 877 : continuation = null, |
790 arguments = null, | 878 arguments = null, |
791 sourceInformation = null; | 879 sourceInformation = null; |
792 | 880 |
793 accept(Visitor visitor) => visitor.visitInvokeContinuation(this); | 881 accept(Visitor visitor) => visitor.visitInvokeContinuation(this); |
882 | |
883 void setParentPointers() { | |
884 if (continuation != null) continuation.parent = this; | |
885 if (arguments != null) _setParentsOnList(arguments, this); | |
886 } | |
794 } | 887 } |
795 | 888 |
796 /// Choose between a pair of continuations based on a condition value. | 889 /// Choose between a pair of continuations based on a condition value. |
797 /// | 890 /// |
798 /// The two continuations must not declare any parameters. | 891 /// The two continuations must not declare any parameters. |
799 class Branch extends TailExpression { | 892 class Branch extends TailExpression { |
800 final Reference<Primitive> condition; | 893 final Reference<Primitive> condition; |
801 final Reference<Continuation> trueContinuation; | 894 final Reference<Continuation> trueContinuation; |
802 final Reference<Continuation> falseContinuation; | 895 final Reference<Continuation> falseContinuation; |
803 | 896 |
(...skipping 14 matching lines...) Expand all Loading... | |
818 | 911 |
819 Branch.loose(Primitive condition, | 912 Branch.loose(Primitive condition, |
820 Continuation trueCont, | 913 Continuation trueCont, |
821 Continuation falseCont) | 914 Continuation falseCont) |
822 : this.condition = new Reference<Primitive>(condition), | 915 : this.condition = new Reference<Primitive>(condition), |
823 trueContinuation = new Reference<Continuation>(trueCont), | 916 trueContinuation = new Reference<Continuation>(trueCont), |
824 falseContinuation = new Reference<Continuation>(falseCont), | 917 falseContinuation = new Reference<Continuation>(falseCont), |
825 this.isStrictCheck = false; | 918 this.isStrictCheck = false; |
826 | 919 |
827 accept(Visitor visitor) => visitor.visitBranch(this); | 920 accept(Visitor visitor) => visitor.visitBranch(this); |
921 | |
922 void setParentPointers() { | |
923 condition.parent = this; | |
924 trueContinuation.parent = this; | |
925 falseContinuation.parent = this; | |
926 } | |
828 } | 927 } |
829 | 928 |
830 /// Directly assigns to a field on a given object. | 929 /// Directly assigns to a field on a given object. |
831 class SetField extends Primitive { | 930 class SetField extends Primitive { |
832 final Reference<Primitive> object; | 931 final Reference<Primitive> object; |
833 FieldElement field; | 932 FieldElement field; |
834 final Reference<Primitive> value; | 933 final Reference<Primitive> value; |
835 | 934 |
836 SetField(Primitive object, this.field, Primitive value) | 935 SetField(Primitive object, this.field, Primitive value) |
837 : this.object = new Reference<Primitive>(object), | 936 : this.object = new Reference<Primitive>(object), |
838 this.value = new Reference<Primitive>(value); | 937 this.value = new Reference<Primitive>(value); |
839 | 938 |
840 accept(Visitor visitor) => visitor.visitSetField(this); | 939 accept(Visitor visitor) => visitor.visitSetField(this); |
841 | 940 |
842 bool get isSafeForElimination => false; | 941 bool get isSafeForElimination => false; |
843 bool get isSafeForReordering => false; | 942 bool get isSafeForReordering => false; |
943 | |
944 void setParentPointers() { | |
945 object.parent = this; | |
946 value.parent = this; | |
947 } | |
844 } | 948 } |
845 | 949 |
846 /// Directly reads from a field on a given object. | 950 /// Directly reads from a field on a given object. |
847 /// | 951 /// |
848 /// The [object] must either be `null` or an object that has [field]. | 952 /// The [object] must either be `null` or an object that has [field]. |
849 class GetField extends Primitive { | 953 class GetField extends Primitive { |
850 final Reference<Primitive> object; | 954 final Reference<Primitive> object; |
851 FieldElement field; | 955 FieldElement field; |
852 | 956 |
853 /// True if the object is known not to be null. | 957 /// True if the object is known not to be null. |
854 // TODO(asgerf): This is a placeholder until we agree on how to track | 958 // TODO(asgerf): This is a placeholder until we agree on how to track |
855 // side effects. | 959 // side effects. |
856 bool objectIsNotNull = false; | 960 bool objectIsNotNull = false; |
857 | 961 |
858 GetField(Primitive object, this.field) | 962 GetField(Primitive object, this.field) |
859 : this.object = new Reference<Primitive>(object); | 963 : this.object = new Reference<Primitive>(object); |
860 | 964 |
861 accept(Visitor visitor) => visitor.visitGetField(this); | 965 accept(Visitor visitor) => visitor.visitGetField(this); |
862 | 966 |
863 bool get isSafeForElimination => objectIsNotNull; | 967 bool get isSafeForElimination => objectIsNotNull; |
864 bool get isSafeForReordering => false; | 968 bool get isSafeForReordering => false; |
865 | 969 |
866 toString() => 'GetField($field)'; | 970 toString() => 'GetField($field)'; |
971 | |
972 void setParentPointers() { | |
973 object.parent = this; | |
974 } | |
867 } | 975 } |
868 | 976 |
869 /// Get the length of a string or native list. | 977 /// Get the length of a string or native list. |
870 class GetLength extends Primitive { | 978 class GetLength extends Primitive { |
871 final Reference<Primitive> object; | 979 final Reference<Primitive> object; |
872 | 980 |
873 /// True if the object is known not to be null. | 981 /// True if the object is known not to be null. |
874 bool objectIsNotNull = false; | 982 bool objectIsNotNull = false; |
875 | 983 |
876 GetLength(Primitive object) : this.object = new Reference<Primitive>(object); | 984 GetLength(Primitive object) : this.object = new Reference<Primitive>(object); |
877 | 985 |
878 bool get isSafeForElimination => objectIsNotNull; | 986 bool get isSafeForElimination => objectIsNotNull; |
879 bool get isSafeForReordering => false; | 987 bool get isSafeForReordering => false; |
880 | 988 |
881 accept(Visitor v) => v.visitGetLength(this); | 989 accept(Visitor v) => v.visitGetLength(this); |
990 | |
991 void setParentPointers() { | |
992 object.parent = this; | |
993 } | |
882 } | 994 } |
883 | 995 |
884 /// Read an entry from a string or native list. | 996 /// Read an entry from a string or native list. |
885 /// | 997 /// |
886 /// [object] must be null or a native list or a string, and [index] must be | 998 /// [object] must be null or a native list or a string, and [index] must be |
887 /// an integer. | 999 /// an integer. |
888 class GetIndex extends Primitive { | 1000 class GetIndex extends Primitive { |
889 final Reference<Primitive> object; | 1001 final Reference<Primitive> object; |
890 final Reference<Primitive> index; | 1002 final Reference<Primitive> index; |
891 | 1003 |
892 /// True if the object is known not to be null. | 1004 /// True if the object is known not to be null. |
893 bool objectIsNotNull = false; | 1005 bool objectIsNotNull = false; |
894 | 1006 |
895 GetIndex(Primitive object, Primitive index) | 1007 GetIndex(Primitive object, Primitive index) |
896 : this.object = new Reference<Primitive>(object), | 1008 : this.object = new Reference<Primitive>(object), |
897 this.index = new Reference<Primitive>(index); | 1009 this.index = new Reference<Primitive>(index); |
898 | 1010 |
899 bool get isSafeForElimination => objectIsNotNull; | 1011 bool get isSafeForElimination => objectIsNotNull; |
900 bool get isSafeForReordering => false; | 1012 bool get isSafeForReordering => false; |
901 | 1013 |
902 accept(Visitor v) => v.visitGetIndex(this); | 1014 accept(Visitor v) => v.visitGetIndex(this); |
1015 | |
1016 void setParentPointers() { | |
1017 object.parent = this; | |
1018 index.parent = this; | |
1019 } | |
903 } | 1020 } |
904 | 1021 |
905 /// Set an entry on a native list. | 1022 /// Set an entry on a native list. |
906 /// | 1023 /// |
907 /// [object] must be null or a native list, and [index] must be an integer. | 1024 /// [object] must be null or a native list, and [index] must be an integer. |
908 /// | 1025 /// |
909 /// The primitive itself has no value and may not be referenced. | 1026 /// The primitive itself has no value and may not be referenced. |
910 class SetIndex extends Primitive { | 1027 class SetIndex extends Primitive { |
911 final Reference<Primitive> object; | 1028 final Reference<Primitive> object; |
912 final Reference<Primitive> index; | 1029 final Reference<Primitive> index; |
913 final Reference<Primitive> value; | 1030 final Reference<Primitive> value; |
914 | 1031 |
915 SetIndex(Primitive object, Primitive index, Primitive value) | 1032 SetIndex(Primitive object, Primitive index, Primitive value) |
916 : this.object = new Reference<Primitive>(object), | 1033 : this.object = new Reference<Primitive>(object), |
917 this.index = new Reference<Primitive>(index), | 1034 this.index = new Reference<Primitive>(index), |
918 this.value = new Reference<Primitive>(value); | 1035 this.value = new Reference<Primitive>(value); |
919 | 1036 |
920 bool get isSafeForElimination => false; | 1037 bool get isSafeForElimination => false; |
921 bool get isSafeForReordering => false; | 1038 bool get isSafeForReordering => false; |
922 | 1039 |
923 accept(Visitor v) => v.visitSetIndex(this); | 1040 accept(Visitor v) => v.visitSetIndex(this); |
1041 | |
1042 void setParentPointers() { | |
1043 object.parent = this; | |
1044 index.parent = this; | |
1045 value.parent = this; | |
1046 } | |
924 } | 1047 } |
925 | 1048 |
926 /// Reads the value of a static field or tears off a static method. | 1049 /// Reads the value of a static field or tears off a static method. |
927 /// | 1050 /// |
928 /// Note that lazily initialized fields should be read using GetLazyStatic. | 1051 /// Note that lazily initialized fields should be read using GetLazyStatic. |
929 class GetStatic extends Primitive { | 1052 class GetStatic extends Primitive { |
930 /// Can be [FieldElement] or [FunctionElement]. | 1053 /// Can be [FieldElement] or [FunctionElement]. |
931 final Element element; | 1054 final Element element; |
932 final SourceInformation sourceInformation; | 1055 final SourceInformation sourceInformation; |
933 | 1056 |
934 GetStatic(this.element, [this.sourceInformation]); | 1057 GetStatic(this.element, [this.sourceInformation]); |
935 | 1058 |
936 accept(Visitor visitor) => visitor.visitGetStatic(this); | 1059 accept(Visitor visitor) => visitor.visitGetStatic(this); |
937 | 1060 |
938 bool get isSafeForElimination { | 1061 bool get isSafeForElimination { |
939 return true; | 1062 return true; |
940 } | 1063 } |
941 bool get isSafeForReordering { | 1064 bool get isSafeForReordering { |
942 return element is FunctionElement || element.isFinal; | 1065 return element is FunctionElement || element.isFinal; |
943 } | 1066 } |
1067 | |
1068 void setParentPointers() {} | |
944 } | 1069 } |
945 | 1070 |
946 /// Sets the value of a static field. | 1071 /// Sets the value of a static field. |
947 class SetStatic extends Primitive { | 1072 class SetStatic extends Primitive { |
948 final FieldElement element; | 1073 final FieldElement element; |
949 final Reference<Primitive> value; | 1074 final Reference<Primitive> value; |
950 final SourceInformation sourceInformation; | 1075 final SourceInformation sourceInformation; |
951 | 1076 |
952 SetStatic(this.element, Primitive value, [this.sourceInformation]) | 1077 SetStatic(this.element, Primitive value, [this.sourceInformation]) |
953 : this.value = new Reference<Primitive>(value); | 1078 : this.value = new Reference<Primitive>(value); |
954 | 1079 |
955 accept(Visitor visitor) => visitor.visitSetStatic(this); | 1080 accept(Visitor visitor) => visitor.visitSetStatic(this); |
956 | 1081 |
957 bool get isSafeForElimination => false; | 1082 bool get isSafeForElimination => false; |
958 bool get isSafeForReordering => false; | 1083 bool get isSafeForReordering => false; |
1084 | |
1085 void setParentPointers() { | |
1086 value.parent = this; | |
1087 } | |
959 } | 1088 } |
960 | 1089 |
961 /// Reads the value of a lazily initialized static field. | 1090 /// Reads the value of a lazily initialized static field. |
962 /// | 1091 /// |
963 /// If the field has not yet been initialized, its initializer is evaluated | 1092 /// If the field has not yet been initialized, its initializer is evaluated |
964 /// and assigned to the field. | 1093 /// and assigned to the field. |
965 /// | 1094 /// |
966 /// [continuation] is then invoked with the value of the field as argument. | 1095 /// [continuation] is then invoked with the value of the field as argument. |
967 class GetLazyStatic extends CallExpression { | 1096 class GetLazyStatic extends CallExpression { |
968 final FieldElement element; | 1097 final FieldElement element; |
969 final Reference<Continuation> continuation; | 1098 final Reference<Continuation> continuation; |
970 final SourceInformation sourceInformation; | 1099 final SourceInformation sourceInformation; |
971 | 1100 |
972 GetLazyStatic(this.element, | 1101 GetLazyStatic(this.element, |
973 Continuation continuation, | 1102 Continuation continuation, |
974 [this.sourceInformation]) | 1103 [this.sourceInformation]) |
975 : continuation = new Reference<Continuation>(continuation); | 1104 : continuation = new Reference<Continuation>(continuation); |
976 | 1105 |
977 accept(Visitor visitor) => visitor.visitGetLazyStatic(this); | 1106 accept(Visitor visitor) => visitor.visitGetLazyStatic(this); |
1107 | |
1108 void setParentPointers() { | |
1109 continuation.parent = this; | |
1110 } | |
978 } | 1111 } |
979 | 1112 |
980 /// Creates an object for holding boxed variables captured by a closure. | 1113 /// Creates an object for holding boxed variables captured by a closure. |
981 class CreateBox extends Primitive { | 1114 class CreateBox extends Primitive { |
982 accept(Visitor visitor) => visitor.visitCreateBox(this); | 1115 accept(Visitor visitor) => visitor.visitCreateBox(this); |
983 | 1116 |
984 bool get isSafeForElimination => true; | 1117 bool get isSafeForElimination => true; |
985 bool get isSafeForReordering => true; | 1118 bool get isSafeForReordering => true; |
1119 | |
1120 void setParentPointers() {} | |
986 } | 1121 } |
987 | 1122 |
988 /// Creates an instance of a class and initializes its fields and runtime type | 1123 /// Creates an instance of a class and initializes its fields and runtime type |
989 /// information. | 1124 /// information. |
990 class CreateInstance extends Primitive { | 1125 class CreateInstance extends Primitive { |
991 final ClassElement classElement; | 1126 final ClassElement classElement; |
992 | 1127 |
993 /// Initial values for the fields on the class. | 1128 /// Initial values for the fields on the class. |
994 /// The order corresponds to the order of fields on the class. | 1129 /// The order corresponds to the order of fields on the class. |
995 final List<Reference<Primitive>> arguments; | 1130 final List<Reference<Primitive>> arguments; |
(...skipping 12 matching lines...) Expand all Loading... | |
1008 this.sourceInformation) | 1143 this.sourceInformation) |
1009 : this.arguments = _referenceList(arguments), | 1144 : this.arguments = _referenceList(arguments), |
1010 this.typeInformation = _referenceList(typeInformation); | 1145 this.typeInformation = _referenceList(typeInformation); |
1011 | 1146 |
1012 accept(Visitor visitor) => visitor.visitCreateInstance(this); | 1147 accept(Visitor visitor) => visitor.visitCreateInstance(this); |
1013 | 1148 |
1014 bool get isSafeForElimination => true; | 1149 bool get isSafeForElimination => true; |
1015 bool get isSafeForReordering => true; | 1150 bool get isSafeForReordering => true; |
1016 | 1151 |
1017 toString() => 'CreateInstance($classElement)'; | 1152 toString() => 'CreateInstance($classElement)'; |
1153 | |
1154 void setParentPointers() { | |
1155 _setParentsOnList(arguments, this); | |
1156 if (typeInformation != null) _setParentsOnList(typeInformation, this); | |
1157 } | |
1018 } | 1158 } |
1019 | 1159 |
1020 class Interceptor extends Primitive { | 1160 class Interceptor extends Primitive { |
1021 final Reference<Primitive> input; | 1161 final Reference<Primitive> input; |
1022 final Set<ClassElement> interceptedClasses = new Set<ClassElement>(); | 1162 final Set<ClassElement> interceptedClasses = new Set<ClassElement>(); |
1023 final SourceInformation sourceInformation; | 1163 final SourceInformation sourceInformation; |
1024 | 1164 |
1025 /// If non-null, all uses of this the interceptor call are guaranteed to | 1165 /// If non-null, all uses of this the interceptor call are guaranteed to |
1026 /// see this value. | 1166 /// see this value. |
1027 /// | 1167 /// |
1028 /// The interceptor call is not immediately replaced by the constant, because | 1168 /// The interceptor call is not immediately replaced by the constant, because |
1029 /// that might prevent the interceptor from being shared. | 1169 /// that might prevent the interceptor from being shared. |
1030 /// | 1170 /// |
1031 /// The precise input type is not known when sharing interceptors, because | 1171 /// The precise input type is not known when sharing interceptors, because |
1032 /// refinement nodes have been removed by then. So this field carries the | 1172 /// refinement nodes have been removed by then. So this field carries the |
1033 /// known constant until we know if it should be shared or replaced by | 1173 /// known constant until we know if it should be shared or replaced by |
1034 /// the constant. | 1174 /// the constant. |
1035 values.InterceptorConstantValue constantValue; | 1175 values.InterceptorConstantValue constantValue; |
1036 | 1176 |
1037 Interceptor(Primitive input, this.sourceInformation) | 1177 Interceptor(Primitive input, this.sourceInformation) |
1038 : this.input = new Reference<Primitive>(input); | 1178 : this.input = new Reference<Primitive>(input); |
1039 | 1179 |
1040 accept(Visitor visitor) => visitor.visitInterceptor(this); | 1180 accept(Visitor visitor) => visitor.visitInterceptor(this); |
1041 | 1181 |
1042 bool get isSafeForElimination => true; | 1182 bool get isSafeForElimination => true; |
1043 bool get isSafeForReordering => true; | 1183 bool get isSafeForReordering => true; |
1184 | |
1185 void setParentPointers() { | |
1186 input.parent = this; | |
1187 } | |
1044 } | 1188 } |
1045 | 1189 |
1046 /// Create an instance of [Invocation] for use in a call to `noSuchMethod`. | 1190 /// Create an instance of [Invocation] for use in a call to `noSuchMethod`. |
1047 class CreateInvocationMirror extends Primitive { | 1191 class CreateInvocationMirror extends Primitive { |
1048 final Selector selector; | 1192 final Selector selector; |
1049 final List<Reference<Primitive>> arguments; | 1193 final List<Reference<Primitive>> arguments; |
1050 | 1194 |
1051 CreateInvocationMirror(this.selector, List<Primitive> arguments) | 1195 CreateInvocationMirror(this.selector, List<Primitive> arguments) |
1052 : this.arguments = _referenceList(arguments); | 1196 : this.arguments = _referenceList(arguments); |
1053 | 1197 |
1054 accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this); | 1198 accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this); |
1055 | 1199 |
1056 bool get isSafeForElimination => true; | 1200 bool get isSafeForElimination => true; |
1057 bool get isSafeForReordering => true; | 1201 bool get isSafeForReordering => true; |
1202 | |
1203 void setParentPointers() { | |
1204 _setParentsOnList(arguments, this); | |
1205 } | |
1058 } | 1206 } |
1059 | 1207 |
1060 class ForeignCode extends CallExpression { | 1208 class ForeignCode extends CallExpression { |
1061 final js.Template codeTemplate; | 1209 final js.Template codeTemplate; |
1062 final TypeMask type; | 1210 final TypeMask type; |
1063 final List<Reference<Primitive>> arguments; | 1211 final List<Reference<Primitive>> arguments; |
1064 final native.NativeBehavior nativeBehavior; | 1212 final native.NativeBehavior nativeBehavior; |
1065 final FunctionElement dependency; | 1213 final FunctionElement dependency; |
1066 final Reference<Continuation> continuation; | 1214 final Reference<Continuation> continuation; |
1067 | 1215 |
1068 ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments, | 1216 ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments, |
1069 this.nativeBehavior, Continuation continuation, {this.dependency}) | 1217 this.nativeBehavior, Continuation continuation, {this.dependency}) |
1070 : this.arguments = _referenceList(arguments), | 1218 : this.arguments = _referenceList(arguments), |
1071 this.continuation = new Reference<Continuation>(continuation); | 1219 this.continuation = new Reference<Continuation>(continuation); |
1072 | 1220 |
1073 accept(Visitor visitor) => visitor.visitForeignCode(this); | 1221 accept(Visitor visitor) => visitor.visitForeignCode(this); |
1222 | |
1223 void setParentPointers() { | |
1224 _setParentsOnList(arguments, this); | |
1225 continuation.parent = this; | |
1226 } | |
1074 } | 1227 } |
1075 | 1228 |
1076 class Constant extends Primitive { | 1229 class Constant extends Primitive { |
1077 final values.ConstantValue value; | 1230 final values.ConstantValue value; |
1078 final SourceInformation sourceInformation; | 1231 final SourceInformation sourceInformation; |
1079 | 1232 |
1080 Constant(this.value, {this.sourceInformation}) { | 1233 Constant(this.value, {this.sourceInformation}) { |
1081 assert(value != null); | 1234 assert(value != null); |
1082 } | 1235 } |
1083 | 1236 |
1084 accept(Visitor visitor) => visitor.visitConstant(this); | 1237 accept(Visitor visitor) => visitor.visitConstant(this); |
1085 | 1238 |
1086 bool get isSafeForElimination => true; | 1239 bool get isSafeForElimination => true; |
1087 bool get isSafeForReordering => true; | 1240 bool get isSafeForReordering => true; |
1241 | |
1242 void setParentPointers() {} | |
1088 } | 1243 } |
1089 | 1244 |
1090 class LiteralList extends Primitive { | 1245 class LiteralList extends Primitive { |
1091 /// The List type being created; this is not the type argument. | 1246 /// The List type being created; this is not the type argument. |
1092 final InterfaceType dartType; | 1247 final InterfaceType dartType; |
1093 final List<Reference<Primitive>> values; | 1248 final List<Reference<Primitive>> values; |
1094 | 1249 |
1095 LiteralList(this.dartType, List<Primitive> values) | 1250 LiteralList(this.dartType, List<Primitive> values) |
1096 : this.values = _referenceList(values); | 1251 : this.values = _referenceList(values); |
1097 | 1252 |
1098 accept(Visitor visitor) => visitor.visitLiteralList(this); | 1253 accept(Visitor visitor) => visitor.visitLiteralList(this); |
1099 | 1254 |
1100 bool get isSafeForElimination => true; | 1255 bool get isSafeForElimination => true; |
1101 bool get isSafeForReordering => true; | 1256 bool get isSafeForReordering => true; |
1257 | |
1258 void setParentPointers() { | |
1259 _setParentsOnList(values, this); | |
1260 } | |
1102 } | 1261 } |
1103 | 1262 |
1104 class LiteralMapEntry { | 1263 class LiteralMapEntry { |
1105 final Reference<Primitive> key; | 1264 final Reference<Primitive> key; |
1106 final Reference<Primitive> value; | 1265 final Reference<Primitive> value; |
1107 | 1266 |
1108 LiteralMapEntry(Primitive key, Primitive value) | 1267 LiteralMapEntry(Primitive key, Primitive value) |
1109 : this.key = new Reference<Primitive>(key), | 1268 : this.key = new Reference<Primitive>(key), |
1110 this.value = new Reference<Primitive>(value); | 1269 this.value = new Reference<Primitive>(value); |
1111 } | 1270 } |
1112 | 1271 |
1113 class LiteralMap extends Primitive { | 1272 class LiteralMap extends Primitive { |
1114 final InterfaceType dartType; | 1273 final InterfaceType dartType; |
1115 final List<LiteralMapEntry> entries; | 1274 final List<LiteralMapEntry> entries; |
1116 | 1275 |
1117 LiteralMap(this.dartType, this.entries); | 1276 LiteralMap(this.dartType, this.entries); |
1118 | 1277 |
1119 accept(Visitor visitor) => visitor.visitLiteralMap(this); | 1278 accept(Visitor visitor) => visitor.visitLiteralMap(this); |
1120 | 1279 |
1121 bool get isSafeForElimination => true; | 1280 bool get isSafeForElimination => true; |
1122 bool get isSafeForReordering => true; | 1281 bool get isSafeForReordering => true; |
1282 | |
1283 void setParentPointers() { | |
1284 for (LiteralMapEntry entry in entries) { | |
1285 entry.key.parent = this; | |
1286 entry.value.parent = this; | |
1287 } | |
1288 } | |
1123 } | 1289 } |
1124 | 1290 |
1125 /// Currently unused. | 1291 /// Currently unused. |
1126 /// | 1292 /// |
1127 /// Nested functions (from Dart code) are translated to classes by closure | 1293 /// Nested functions (from Dart code) are translated to classes by closure |
1128 /// conversion, hence they are instantiated with [CreateInstance]. | 1294 /// conversion, hence they are instantiated with [CreateInstance]. |
1129 /// | 1295 /// |
1130 /// We keep this around for now because it might come in handy when we | 1296 /// We keep this around for now because it might come in handy when we |
1131 /// handle async/await in the CPS IR. | 1297 /// handle async/await in the CPS IR. |
1132 /// | 1298 /// |
1133 /// Instantiates a nested function. [MutableVariable]s are in scope in the | 1299 /// Instantiates a nested function. [MutableVariable]s are in scope in the |
1134 /// inner function, but primitives are not shared across function boundaries. | 1300 /// inner function, but primitives are not shared across function boundaries. |
1135 class CreateFunction extends Primitive { | 1301 class CreateFunction extends Primitive { |
1136 final FunctionDefinition definition; | 1302 final FunctionDefinition definition; |
1137 | 1303 |
1138 CreateFunction(this.definition); | 1304 CreateFunction(this.definition); |
1139 | 1305 |
1140 accept(Visitor visitor) => visitor.visitCreateFunction(this); | 1306 accept(Visitor visitor) => visitor.visitCreateFunction(this); |
1141 | 1307 |
1142 bool get isSafeForElimination => true; | 1308 bool get isSafeForElimination => true; |
1143 bool get isSafeForReordering => true; | 1309 bool get isSafeForReordering => true; |
1310 | |
1311 void setParentPointers() {} | |
1144 } | 1312 } |
1145 | 1313 |
1146 class Parameter extends Primitive { | 1314 class Parameter extends Primitive { |
1147 Parameter(Entity hint) { | 1315 Parameter(Entity hint) { |
1148 super.hint = hint; | 1316 super.hint = hint; |
1149 } | 1317 } |
1150 | 1318 |
1151 // In addition to a parent pointer to the containing Continuation or | |
1152 // FunctionDefinition, parameters have an index into the list of parameters | |
1153 // bound by the parent. This gives constant-time access to the continuation | |
1154 // from the parent. | |
1155 int parentIndex; | |
1156 | |
1157 accept(Visitor visitor) => visitor.visitParameter(this); | 1319 accept(Visitor visitor) => visitor.visitParameter(this); |
1158 | 1320 |
1159 String toString() => 'Parameter(${hint == null ? null : hint.name})'; | 1321 String toString() => 'Parameter(${hint == null ? null : hint.name})'; |
1160 | 1322 |
1161 bool get isSafeForElimination => true; | 1323 bool get isSafeForElimination => true; |
1162 bool get isSafeForReordering => true; | 1324 bool get isSafeForReordering => true; |
1325 | |
1326 void setParentPointers() {} | |
1163 } | 1327 } |
1164 | 1328 |
1165 /// Continuations are normally bound by 'let cont'. A continuation with one | 1329 /// Continuations are normally bound by 'let cont'. A continuation with one |
1166 /// parameter and no body is used to represent a function's return continuation. | 1330 /// parameter and no body is used to represent a function's return continuation. |
1167 /// The return continuation is bound by the function, not by 'let cont'. | 1331 /// The return continuation is bound by the function, not by 'let cont'. |
1168 class Continuation extends Definition<Continuation> implements InteriorNode { | 1332 class Continuation extends Definition<Continuation> implements InteriorNode { |
1169 final List<Parameter> parameters; | 1333 final List<Parameter> parameters; |
1170 Expression body = null; | 1334 Expression body = null; |
1171 | 1335 |
1172 // In addition to a parent pointer to the containing LetCont, continuations | |
1173 // have an index into the list of continuations bound by the LetCont. This | |
1174 // gives constant-time access to the continuation from the parent. | |
1175 int parent_index; | |
1176 | |
1177 // A continuation is recursive if it has any recursive invocations. | 1336 // A continuation is recursive if it has any recursive invocations. |
1178 bool isRecursive; | 1337 bool isRecursive; |
1179 | 1338 |
1180 bool get isReturnContinuation => body == null; | 1339 bool get isReturnContinuation => body == null; |
1181 | 1340 |
1182 Continuation(this.parameters, {this.isRecursive: false}); | 1341 Continuation(this.parameters, {this.isRecursive: false}); |
1183 | 1342 |
1184 Continuation.retrn() | 1343 Continuation.retrn() |
1185 : parameters = <Parameter>[new Parameter(null)], | 1344 : parameters = <Parameter>[new Parameter(null)], |
1186 isRecursive = false; | 1345 isRecursive = false; |
1187 | 1346 |
1188 accept(Visitor visitor) => visitor.visitContinuation(this); | 1347 accept(Visitor visitor) => visitor.visitContinuation(this); |
1348 | |
1349 void setParentPointers() { | |
1350 _setParentsOnNodes(parameters, this); | |
1351 if (body != null) body.parent = this; | |
1352 } | |
1189 } | 1353 } |
1190 | 1354 |
1191 /// Common interface for [Primitive] and [MutableVariable]. | 1355 /// Common interface for [Primitive] and [MutableVariable]. |
1192 abstract class Variable<T extends Variable<T>> extends Definition<T> { | 1356 abstract class Variable<T extends Variable<T>> extends Definition<T> { |
1193 /// Type of value held in the variable. | 1357 /// Type of value held in the variable. |
1194 /// | 1358 /// |
1195 /// Is `null` until initialized by type propagation. | 1359 /// Is `null` until initialized by type propagation. |
1196 TypeMask type; | 1360 TypeMask type; |
1197 } | 1361 } |
1198 | 1362 |
1199 /// Identifies a mutable variable. | 1363 /// Identifies a mutable variable. |
1200 class MutableVariable extends Variable<MutableVariable> { | 1364 class MutableVariable extends Variable<MutableVariable> { |
1201 Entity hint; | 1365 Entity hint; |
1202 | 1366 |
1203 MutableVariable(this.hint); | 1367 MutableVariable(this.hint); |
1204 | 1368 |
1205 accept(Visitor v) => v.visitMutableVariable(this); | 1369 accept(Visitor v) => v.visitMutableVariable(this); |
1370 | |
1371 void setParentPointers() {} | |
1206 } | 1372 } |
1207 | 1373 |
1208 /// A function definition, consisting of parameters and a body. | 1374 /// A function definition, consisting of parameters and a body. |
1209 /// | 1375 /// |
1210 /// There is an explicit parameter for the `this` argument, and a return | 1376 /// There is an explicit parameter for the `this` argument, and a return |
1211 /// continuation to invoke when returning from the function. | 1377 /// continuation to invoke when returning from the function. |
1212 class FunctionDefinition extends InteriorNode { | 1378 class FunctionDefinition extends InteriorNode { |
1213 final ExecutableElement element; | 1379 final ExecutableElement element; |
1214 final Parameter thisParameter; | 1380 final Parameter thisParameter; |
1215 final List<Parameter> parameters; | 1381 final List<Parameter> parameters; |
1216 final Continuation returnContinuation; | 1382 final Continuation returnContinuation; |
1217 Expression body; | 1383 Expression body; |
1218 | 1384 |
1219 FunctionDefinition(this.element, | 1385 FunctionDefinition(this.element, |
1220 this.thisParameter, | 1386 this.thisParameter, |
1221 this.parameters, | 1387 this.parameters, |
1222 this.returnContinuation, | 1388 this.returnContinuation, |
1223 this.body); | 1389 this.body); |
1224 | 1390 |
1225 accept(Visitor visitor) => visitor.visitFunctionDefinition(this); | 1391 accept(Visitor visitor) => visitor.visitFunctionDefinition(this); |
1392 | |
1393 void setParentPointers() { | |
1394 if (thisParameter != null) thisParameter.parent = this; | |
1395 _setParentsOnNodes(parameters, this); | |
1396 returnContinuation.parent = this; | |
1397 if (body != null) body.parent = this; | |
1398 } | |
1226 } | 1399 } |
1227 | 1400 |
1228 /// Converts the internal representation of a type to a Dart object of type | 1401 /// Converts the internal representation of a type to a Dart object of type |
1229 /// [Type]. | 1402 /// [Type]. |
1230 class ReifyRuntimeType extends Primitive { | 1403 class ReifyRuntimeType extends Primitive { |
1231 /// Reference to the internal representation of a type (as produced, for | 1404 /// Reference to the internal representation of a type (as produced, for |
1232 /// example, by [ReadTypeVariable]). | 1405 /// example, by [ReadTypeVariable]). |
1233 final Reference<Primitive> value; | 1406 final Reference<Primitive> value; |
1234 | 1407 |
1235 final SourceInformation sourceInformation; | 1408 final SourceInformation sourceInformation; |
1236 | 1409 |
1237 ReifyRuntimeType(Primitive value, this.sourceInformation) | 1410 ReifyRuntimeType(Primitive value, this.sourceInformation) |
1238 : this.value = new Reference<Primitive>(value); | 1411 : this.value = new Reference<Primitive>(value); |
1239 | 1412 |
1240 @override | 1413 @override |
1241 accept(Visitor visitor) => visitor.visitReifyRuntimeType(this); | 1414 accept(Visitor visitor) => visitor.visitReifyRuntimeType(this); |
1242 | 1415 |
1243 bool get isSafeForElimination => true; | 1416 bool get isSafeForElimination => true; |
1244 bool get isSafeForReordering => true; | 1417 bool get isSafeForReordering => true; |
1418 | |
1419 void setParentPointers() { | |
1420 value.parent = this; | |
1421 } | |
1245 } | 1422 } |
1246 | 1423 |
1247 /// Read the value the type variable [variable] from the target object. | 1424 /// Read the value the type variable [variable] from the target object. |
1248 /// | 1425 /// |
1249 /// The resulting value is an internal representation (and not neccessarily a | 1426 /// The resulting value is an internal representation (and not neccessarily a |
1250 /// Dart object), and must be reified by [ReifyRuntimeType], if it should be | 1427 /// Dart object), and must be reified by [ReifyRuntimeType], if it should be |
1251 /// used as a Dart value. | 1428 /// used as a Dart value. |
1252 class ReadTypeVariable extends Primitive { | 1429 class ReadTypeVariable extends Primitive { |
1253 final TypeVariableType variable; | 1430 final TypeVariableType variable; |
1254 final Reference<Primitive> target; | 1431 final Reference<Primitive> target; |
1255 final SourceInformation sourceInformation; | 1432 final SourceInformation sourceInformation; |
1256 | 1433 |
1257 ReadTypeVariable(this.variable, Primitive target, this.sourceInformation) | 1434 ReadTypeVariable(this.variable, Primitive target, this.sourceInformation) |
1258 : this.target = new Reference<Primitive>(target); | 1435 : this.target = new Reference<Primitive>(target); |
1259 | 1436 |
1260 @override | 1437 @override |
1261 accept(Visitor visitor) => visitor.visitReadTypeVariable(this); | 1438 accept(Visitor visitor) => visitor.visitReadTypeVariable(this); |
1262 | 1439 |
1263 bool get isSafeForElimination => true; | 1440 bool get isSafeForElimination => true; |
1264 bool get isSafeForReordering => true; | 1441 bool get isSafeForReordering => true; |
1442 | |
1443 void setParentPointers() { | |
1444 target.parent = this; | |
1445 } | |
1265 } | 1446 } |
1266 | 1447 |
1267 /// Representation of a closed type (that is, a type without type variables). | 1448 /// Representation of a closed type (that is, a type without type variables). |
1268 /// | 1449 /// |
1269 /// The resulting value is constructed from [dartType] by replacing the type | 1450 /// The resulting value is constructed from [dartType] by replacing the type |
1270 /// variables with consecutive values from [arguments], in the order generated | 1451 /// variables with consecutive values from [arguments], in the order generated |
1271 /// by [DartType.forEachTypeVariable]. The type variables in [dartType] are | 1452 /// by [DartType.forEachTypeVariable]. The type variables in [dartType] are |
1272 /// treated as 'holes' in the term, which means that it must be ensured at | 1453 /// treated as 'holes' in the term, which means that it must be ensured at |
1273 /// construction, that duplicate occurences of a type variable in [dartType] | 1454 /// construction, that duplicate occurences of a type variable in [dartType] |
1274 /// are assigned the same value. | 1455 /// are assigned the same value. |
1275 class TypeExpression extends Primitive { | 1456 class TypeExpression extends Primitive { |
1276 final DartType dartType; | 1457 final DartType dartType; |
1277 final List<Reference<Primitive>> arguments; | 1458 final List<Reference<Primitive>> arguments; |
1278 | 1459 |
1279 TypeExpression(this.dartType, | 1460 TypeExpression(this.dartType, |
1280 [List<Primitive> arguments = const <Primitive>[]]) | 1461 [List<Primitive> arguments = const <Primitive>[]]) |
1281 : this.arguments = _referenceList(arguments); | 1462 : this.arguments = _referenceList(arguments); |
1282 | 1463 |
1283 @override | 1464 @override |
1284 accept(Visitor visitor) { | 1465 accept(Visitor visitor) { |
1285 return visitor.visitTypeExpression(this); | 1466 return visitor.visitTypeExpression(this); |
1286 } | 1467 } |
1287 | 1468 |
1288 bool get isSafeForElimination => true; | 1469 bool get isSafeForElimination => true; |
1289 bool get isSafeForReordering => true; | 1470 bool get isSafeForReordering => true; |
1471 | |
1472 void setParentPointers() { | |
1473 _setParentsOnList(arguments, this); | |
1474 } | |
1290 } | 1475 } |
1291 | 1476 |
1292 class Await extends CallExpression { | 1477 class Await extends CallExpression { |
1293 final Reference<Primitive> input; | 1478 final Reference<Primitive> input; |
1294 final Reference<Continuation> continuation; | 1479 final Reference<Continuation> continuation; |
1295 | 1480 |
1296 Await(Primitive input, Continuation continuation) | 1481 Await(Primitive input, Continuation continuation) |
1297 : this.input = new Reference<Primitive>(input), | 1482 : this.input = new Reference<Primitive>(input), |
1298 this.continuation = new Reference<Continuation>(continuation); | 1483 this.continuation = new Reference<Continuation>(continuation); |
1299 | 1484 |
1300 @override | 1485 @override |
1301 accept(Visitor visitor) { | 1486 accept(Visitor visitor) { |
1302 return visitor.visitAwait(this); | 1487 return visitor.visitAwait(this); |
1303 } | 1488 } |
1489 | |
1490 void setParentPointers() { | |
1491 input.parent = this; | |
1492 continuation.parent = this; | |
1493 } | |
1304 } | 1494 } |
1305 | 1495 |
1306 class Yield extends CallExpression { | 1496 class Yield extends CallExpression { |
1307 final Reference<Primitive> input; | 1497 final Reference<Primitive> input; |
1308 final Reference<Continuation> continuation; | 1498 final Reference<Continuation> continuation; |
1309 final bool hasStar; | 1499 final bool hasStar; |
1310 | 1500 |
1311 Yield(Primitive input, this.hasStar, Continuation continuation) | 1501 Yield(Primitive input, this.hasStar, Continuation continuation) |
1312 : this.input = new Reference<Primitive>(input), | 1502 : this.input = new Reference<Primitive>(input), |
1313 this.continuation = new Reference<Continuation>(continuation); | 1503 this.continuation = new Reference<Continuation>(continuation); |
1314 | 1504 |
1315 @override | 1505 @override |
1316 accept(Visitor visitor) { | 1506 accept(Visitor visitor) { |
1317 return visitor.visitYield(this); | 1507 return visitor.visitYield(this); |
1318 } | 1508 } |
1509 | |
1510 void setParentPointers() { | |
1511 input.parent = this; | |
1512 continuation.parent = this; | |
1513 } | |
1319 } | 1514 } |
1320 | 1515 |
1321 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { | 1516 List<Reference<Primitive>> _referenceList(Iterable<Primitive> definitions) { |
1322 return definitions.map((e) => new Reference<Primitive>(e)).toList(); | 1517 return definitions.map((e) => new Reference<Primitive>(e)).toList(); |
1323 } | 1518 } |
1324 | 1519 |
1520 void _setParentsOnNodes(List<Node> nodes, Node parent) { | |
1521 for (Node node in nodes) { | |
1522 node.parent = parent; | |
1523 } | |
1524 } | |
1525 | |
1526 void _setParentsOnList(List<Reference> nodes, Node parent) { | |
1527 for (Reference node in nodes) { | |
1528 node.parent = parent; | |
1529 } | |
1530 } | |
1531 | |
1325 abstract class Visitor<T> { | 1532 abstract class Visitor<T> { |
1326 const Visitor(); | 1533 const Visitor(); |
1327 | 1534 |
1328 T visit(Node node); | 1535 T visit(Node node); |
1329 | 1536 |
1330 // Concrete classes. | 1537 // Concrete classes. |
1331 T visitFunctionDefinition(FunctionDefinition node); | 1538 T visitFunctionDefinition(FunctionDefinition node); |
1332 | 1539 |
1333 // Expressions. | 1540 // Expressions. |
1334 T visitLetPrim(LetPrim node); | 1541 T visitLetPrim(LetPrim node); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1375 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); | 1582 T visitApplyBuiltinMethod(ApplyBuiltinMethod node); |
1376 T visitGetLength(GetLength node); | 1583 T visitGetLength(GetLength node); |
1377 T visitGetIndex(GetIndex node); | 1584 T visitGetIndex(GetIndex node); |
1378 T visitSetIndex(SetIndex node); | 1585 T visitSetIndex(SetIndex node); |
1379 T visitRefinement(Refinement node); | 1586 T visitRefinement(Refinement node); |
1380 | 1587 |
1381 // Support for literal foreign code. | 1588 // Support for literal foreign code. |
1382 T visitForeignCode(ForeignCode node); | 1589 T visitForeignCode(ForeignCode node); |
1383 } | 1590 } |
1384 | 1591 |
1385 /// Visits all non-recursive children of a CPS term, i.e. anything | 1592 /// Recursively visits all children of a CPS term. |
1386 /// not of type [Expression] or [Continuation]. | 1593 /// |
1594 /// The user of the class is responsible for avoiding stack overflows from | |
1595 /// deep recursion, e.g. by overriding methods to cut off recursion at certain | |
1596 /// points. | |
1597 /// | |
1598 /// All recursive invocations occur through the [visit] method, which the | |
1599 /// subclass may override as a generic way to control the visitor without | |
1600 /// overriding all visitor methods. | |
1387 /// | 1601 /// |
1388 /// The `process*` methods are called in pre-order for every node visited. | 1602 /// The `process*` methods are called in pre-order for every node visited. |
1389 /// These can be overridden without disrupting the visitor traversal. | 1603 /// These can be overridden without disrupting the visitor traversal. |
1390 class LeafVisitor implements Visitor { | 1604 class DeepRecursiveVisitor implements Visitor { |
1391 const LeafVisitor(); | 1605 const DeepRecursiveVisitor(); |
1392 | 1606 |
1393 visit(Node node) => node.accept(this); | 1607 visit(Node node) => node.accept(this); |
1394 | 1608 |
1395 processReference(Reference ref) {} | 1609 processReference(Reference ref) {} |
1396 | 1610 |
1397 processFunctionDefinition(FunctionDefinition node) {} | 1611 processFunctionDefinition(FunctionDefinition node) {} |
1398 visitFunctionDefinition(FunctionDefinition node) { | 1612 visitFunctionDefinition(FunctionDefinition node) { |
1399 processFunctionDefinition(node); | 1613 processFunctionDefinition(node); |
1400 if (node.thisParameter != null) visit(node.thisParameter); | 1614 if (node.thisParameter != null) visit(node.thisParameter); |
1401 node.parameters.forEach(visit); | 1615 node.parameters.forEach(visit); |
1402 visit(node.returnContinuation); | 1616 visit(node.returnContinuation); |
1617 visit(node.body); | |
1618 } | |
1619 | |
1620 processContinuation(Continuation node) {} | |
1621 visitContinuation(Continuation node) { | |
1622 processContinuation(node); | |
1623 node.parameters.forEach(visit); | |
1624 if (node.body != null) visit(node.body); | |
1403 } | 1625 } |
1404 | 1626 |
1405 // Expressions. | 1627 // Expressions. |
1406 | |
1407 processLetPrim(LetPrim node) {} | 1628 processLetPrim(LetPrim node) {} |
1408 visitLetPrim(LetPrim node) { | 1629 visitLetPrim(LetPrim node) { |
1409 processLetPrim(node); | 1630 processLetPrim(node); |
1410 visit(node.primitive); | 1631 visit(node.primitive); |
1632 visit(node.body); | |
1411 } | 1633 } |
1412 | 1634 |
1413 processLetCont(LetCont node) {} | 1635 processLetCont(LetCont node) {} |
1414 visitLetCont(LetCont node) { | 1636 visitLetCont(LetCont node) { |
1415 processLetCont(node); | 1637 processLetCont(node); |
1416 node.continuations.forEach(visit); | 1638 node.continuations.forEach(visit); |
1639 visit(node.body); | |
1417 } | 1640 } |
1418 | 1641 |
1419 processLetHandler(LetHandler node) {} | 1642 processLetHandler(LetHandler node) {} |
1420 visitLetHandler(LetHandler node) { | 1643 visitLetHandler(LetHandler node) { |
1421 processLetHandler(node); | 1644 processLetHandler(node); |
1645 visit(node.handler); | |
1646 visit(node.body); | |
1422 } | 1647 } |
1423 | 1648 |
1424 processLetMutable(LetMutable node) {} | 1649 processLetMutable(LetMutable node) {} |
1425 visitLetMutable(LetMutable node) { | 1650 visitLetMutable(LetMutable node) { |
1426 processLetMutable(node); | 1651 processLetMutable(node); |
1427 visit(node.variable); | 1652 visit(node.variable); |
1428 processReference(node.value); | 1653 processReference(node.value); |
1654 visit(node.body); | |
1429 } | 1655 } |
1430 | 1656 |
1431 processInvokeStatic(InvokeStatic node) {} | 1657 processInvokeStatic(InvokeStatic node) {} |
1432 visitInvokeStatic(InvokeStatic node) { | 1658 visitInvokeStatic(InvokeStatic node) { |
1433 processInvokeStatic(node); | 1659 processInvokeStatic(node); |
1434 processReference(node.continuation); | 1660 processReference(node.continuation); |
1435 node.arguments.forEach(processReference); | 1661 node.arguments.forEach(processReference); |
1436 } | 1662 } |
1437 | 1663 |
1438 processInvokeContinuation(InvokeContinuation node) {} | 1664 processInvokeContinuation(InvokeContinuation node) {} |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1547 visitGetMutable(GetMutable node) { | 1773 visitGetMutable(GetMutable node) { |
1548 processGetMutable(node); | 1774 processGetMutable(node); |
1549 processReference(node.variable); | 1775 processReference(node.variable); |
1550 } | 1776 } |
1551 | 1777 |
1552 processParameter(Parameter node) {} | 1778 processParameter(Parameter node) {} |
1553 visitParameter(Parameter node) { | 1779 visitParameter(Parameter node) { |
1554 processParameter(node); | 1780 processParameter(node); |
1555 } | 1781 } |
1556 | 1782 |
1557 processContinuation(Continuation node) {} | |
1558 visitContinuation(Continuation node) { | |
1559 processContinuation(node); | |
1560 node.parameters.forEach(visitParameter); | |
1561 } | |
1562 | |
1563 processInterceptor(Interceptor node) {} | 1783 processInterceptor(Interceptor node) {} |
1564 visitInterceptor(Interceptor node) { | 1784 visitInterceptor(Interceptor node) { |
1565 processInterceptor(node); | 1785 processInterceptor(node); |
1566 processReference(node.input); | 1786 processReference(node.input); |
1567 } | 1787 } |
1568 | 1788 |
1569 processCreateInstance(CreateInstance node) {} | 1789 processCreateInstance(CreateInstance node) {} |
1570 visitCreateInstance(CreateInstance node) { | 1790 visitCreateInstance(CreateInstance node) { |
1571 processCreateInstance(node); | 1791 processCreateInstance(node); |
1572 node.arguments.forEach(processReference); | 1792 node.arguments.forEach(processReference); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1713 /// The `traverse*` methods return the expression to visit next, and may | 1933 /// The `traverse*` methods return the expression to visit next, and may |
1714 /// push other subterms onto the stack using [push] or [pushAction] to visit | 1934 /// push other subterms onto the stack using [push] or [pushAction] to visit |
1715 /// them later. Actions pushed onto the stack will be executed after the body | 1935 /// them later. Actions pushed onto the stack will be executed after the body |
1716 /// has been processed (and the stack actions it pushed have been executed). | 1936 /// has been processed (and the stack actions it pushed have been executed). |
1717 /// | 1937 /// |
1718 /// By default, the `traverse` methods visit all non-recursive subterms, | 1938 /// By default, the `traverse` methods visit all non-recursive subterms, |
1719 /// push all bound continuations on the stack, and return the body of the term. | 1939 /// push all bound continuations on the stack, and return the body of the term. |
1720 /// | 1940 /// |
1721 /// Subclasses should not override the `visit` methods for the nodes that have | 1941 /// Subclasses should not override the `visit` methods for the nodes that have |
1722 /// a `traverse` method. | 1942 /// a `traverse` method. |
1723 class RecursiveVisitor extends LeafVisitor { | 1943 class TrampolineRecursiveVisitor extends DeepRecursiveVisitor { |
1724 List<StackAction> _stack = <StackAction>[]; | 1944 List<StackAction> _stack = <StackAction>[]; |
1725 | 1945 |
1726 void pushAction(StackAction callback) { | 1946 void pushAction(StackAction callback) { |
1727 _stack.add(callback); | 1947 _stack.add(callback); |
1728 } | 1948 } |
1729 | 1949 |
1730 void push(Continuation cont) { | 1950 void push(Continuation cont) { |
1731 _stack.add(() { | 1951 _stack.add(() { |
1732 if (cont.isReturnContinuation) { | 1952 if (cont.isReturnContinuation) { |
1733 traverseContinuation(cont); | 1953 traverseContinuation(cont); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1808 node = traverseLetPrim(node); | 2028 node = traverseLetPrim(node); |
1809 } else { | 2029 } else { |
1810 node = traverseLetMutable(node); | 2030 node = traverseLetMutable(node); |
1811 } | 2031 } |
1812 } | 2032 } |
1813 visit(node); | 2033 visit(node); |
1814 } | 2034 } |
1815 } | 2035 } |
1816 | 2036 |
1817 /// Visit a just-deleted subterm and unlink all [Reference]s in it. | 2037 /// Visit a just-deleted subterm and unlink all [Reference]s in it. |
1818 class RemovalVisitor extends RecursiveVisitor { | 2038 class RemovalVisitor extends TrampolineRecursiveVisitor { |
1819 processReference(Reference reference) { | 2039 processReference(Reference reference) { |
1820 reference.unlink(); | 2040 reference.unlink(); |
1821 } | 2041 } |
1822 | 2042 |
1823 static void remove(Node node) { | 2043 static void remove(Node node) { |
1824 (new RemovalVisitor()).visit(node); | 2044 (new RemovalVisitor()).visit(node); |
1825 } | 2045 } |
1826 } | 2046 } |
OLD | NEW |