OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 | 4 |
5 import 'optimizers.dart'; | 5 import 'optimizers.dart'; |
6 | 6 |
7 import '../constants/constant_system.dart'; | 7 import '../constants/constant_system.dart'; |
8 import '../resolution/operators.dart'; | 8 import '../resolution/operators.dart'; |
9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
10 import '../dart_types.dart' as types; | 10 import '../dart_types.dart' as types; |
(...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
592 parent.body = replacement; | 592 parent.body = replacement; |
593 replacement.parent = parent; | 593 replacement.parent = parent; |
594 node.parent = null; | 594 node.parent = null; |
595 if (unlink) { | 595 if (unlink) { |
596 RemovalVisitor.remove(node); | 596 RemovalVisitor.remove(node); |
597 } | 597 } |
598 reanalyze(replacement); | 598 reanalyze(replacement); |
599 } | 599 } |
600 | 600 |
601 /// Inserts [insertedCode] before [node]. | 601 /// Inserts [insertedCode] before [node]. |
602 /// | 602 /// |
603 /// [node] will end up in the hole of [insertedCode], and [insertedCode] | 603 /// [node] will end up in the hole of [insertedCode], and [insertedCode] |
604 /// will become rooted where [node] was. | 604 /// will become rooted where [node] was. |
605 void insertBefore(Expression node, CpsFragment insertedCode) { | 605 void insertBefore(Expression node, CpsFragment insertedCode) { |
606 if (insertedCode.isEmpty) return; // Nothing to do. | 606 if (insertedCode.isEmpty) return; // Nothing to do. |
607 assert(insertedCode.isOpen); | 607 assert(insertedCode.isOpen); |
608 InteriorNode parent = node.parent; | 608 InteriorNode parent = node.parent; |
609 InteriorNode context = insertedCode.context; | 609 InteriorNode context = insertedCode.context; |
610 | 610 |
611 parent.body = insertedCode.root; | 611 parent.body = insertedCode.root; |
612 insertedCode.root.parent = parent; | 612 insertedCode.root.parent = parent; |
613 | 613 |
614 // We want to recompute the types for [insertedCode] without | 614 // We want to recompute the types for [insertedCode] without |
615 // traversing the entire subtree of [node]. Temporarily close the | 615 // traversing the entire subtree of [node]. Temporarily close the |
616 // term with a dummy node while recomputing types. | 616 // term with a dummy node while recomputing types. |
617 context.body = new Unreachable(); | 617 context.body = new Unreachable(); |
618 new ParentVisitor().visit(insertedCode.root); | 618 new ParentVisitor().visit(insertedCode.root); |
619 reanalyze(insertedCode.root); | 619 reanalyze(insertedCode.root); |
620 | 620 |
621 context.body = node; | 621 context.body = node; |
622 node.parent = context; | 622 node.parent = context; |
623 } | 623 } |
624 | 624 |
625 /// Make a constant primitive for [constant] and set its entry in [values]. | 625 /// Make a constant primitive for [constant] and set its entry in [values]. |
626 Constant makeConstantPrimitive(ConstantValue constant) { | 626 Constant makeConstantPrimitive(ConstantValue constant) { |
627 Constant primitive = new Constant(constant); | 627 Constant primitive = new Constant(constant); |
(...skipping 18 matching lines...) Expand all Loading... |
646 return letPrim; | 646 return letPrim; |
647 } | 647 } |
648 | 648 |
649 /// Side-effect free expressions with constant results are be replaced by: | 649 /// Side-effect free expressions with constant results are be replaced by: |
650 /// | 650 /// |
651 /// (LetPrim p = constant (InvokeContinuation k p)). | 651 /// (LetPrim p = constant (InvokeContinuation k p)). |
652 /// | 652 /// |
653 /// The new expression will be visited. | 653 /// The new expression will be visited. |
654 /// | 654 /// |
655 /// Returns true if the node was replaced. | 655 /// Returns true if the node was replaced. |
656 bool constifyExpression(Invoke node) { | 656 bool constifyExpression(CallExpression node) { |
657 Continuation continuation = node.continuation.definition; | 657 Continuation continuation = node.continuation.definition; |
658 ConstantValue constant = replacements[node]; | 658 ConstantValue constant = replacements[node]; |
659 if (constant == null) return false; | 659 if (constant == null) return false; |
660 Constant primitive = makeConstantPrimitive(constant); | 660 Constant primitive = makeConstantPrimitive(constant); |
661 LetPrim letPrim = makeLetPrimInvoke(primitive, continuation); | 661 LetPrim letPrim = makeLetPrimInvoke(primitive, continuation); |
662 replaceSubtree(node, letPrim); | 662 replaceSubtree(node, letPrim); |
663 visitLetPrim(letPrim); | 663 visitLetPrim(letPrim); |
664 return true; | 664 return true; |
665 } | 665 } |
666 | 666 |
(...skipping 18 matching lines...) Expand all Loading... |
685 visitInvokeContinuation(invoke); | 685 visitInvokeContinuation(invoke); |
686 return; | 686 return; |
687 } | 687 } |
688 if (boolifiedValue == AbstractBool.False) { | 688 if (boolifiedValue == AbstractBool.False) { |
689 InvokeContinuation invoke = new InvokeContinuation(falseCont, []); | 689 InvokeContinuation invoke = new InvokeContinuation(falseCont, []); |
690 replaceSubtree(node, invoke); | 690 replaceSubtree(node, invoke); |
691 visitInvokeContinuation(invoke); | 691 visitInvokeContinuation(invoke); |
692 return; | 692 return; |
693 } | 693 } |
694 | 694 |
695 if (condition is ApplyBuiltinOperator && | 695 if (condition is ApplyBuiltinOperator && |
696 condition.operator == BuiltinOperator.LooseEq) { | 696 condition.operator == BuiltinOperator.LooseEq) { |
697 Primitive leftArg = condition.arguments[0].definition; | 697 Primitive leftArg = condition.arguments[0].definition; |
698 Primitive rightArg = condition.arguments[1].definition; | 698 Primitive rightArg = condition.arguments[1].definition; |
699 AbstractValue left = getValue(leftArg); | 699 AbstractValue left = getValue(leftArg); |
700 AbstractValue right = getValue(rightArg); | 700 AbstractValue right = getValue(rightArg); |
701 if (right.isNullConstant && | 701 if (right.isNullConstant && |
702 lattice.isDefinitelyNotNumStringBool(left)) { | 702 lattice.isDefinitelyNotNumStringBool(left)) { |
703 // Rewrite: | 703 // Rewrite: |
704 // if (x == null) S1 else S2 | 704 // if (x == null) S1 else S2 |
705 // => | 705 // => |
706 // if (x) S2 else S1 (note the swapped branches) | 706 // if (x) S2 else S1 (note the swapped branches) |
707 Branch branch = new Branch(new IsTrue(leftArg), falseCont, trueCont); | 707 Branch branch = new Branch(new IsTrue(leftArg), falseCont, trueCont); |
708 replaceSubtree(node, branch); | 708 replaceSubtree(node, branch); |
709 return; | 709 return; |
710 } else if (left.isNullConstant && | 710 } else if (left.isNullConstant && |
711 lattice.isDefinitelyNotNumStringBool(right)) { | 711 lattice.isDefinitelyNotNumStringBool(right)) { |
712 Branch branch = new Branch(new IsTrue(rightArg), falseCont, trueCont); | 712 Branch branch = new Branch(new IsTrue(rightArg), falseCont, trueCont); |
713 replaceSubtree(node, branch); | 713 replaceSubtree(node, branch); |
714 return; | 714 return; |
715 } | 715 } |
716 } | 716 } |
717 } | 717 } |
718 | 718 |
719 /// Replaces [node] with a more specialized instruction, if possible. | 719 /// Replaces [node] with a more specialized instruction, if possible. |
720 /// | 720 /// |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
836 target, | 836 target, |
837 getDartArgument(node, 0)); | 837 getDartArgument(node, 0)); |
838 set.body = new InvokeContinuation(cont, <Primitive>[]); | 838 set.body = new InvokeContinuation(cont, <Primitive>[]); |
839 replaceSubtree(node, set); | 839 replaceSubtree(node, set); |
840 visitSetField(set); | 840 visitSetField(set); |
841 return true; | 841 return true; |
842 } | 842 } |
843 } | 843 } |
844 | 844 |
845 /// Create a check that throws if [index] is not a valid index on [list]. | 845 /// Create a check that throws if [index] is not a valid index on [list]. |
846 /// | 846 /// |
847 /// This function assumes that [index] is an integer. | 847 /// This function assumes that [index] is an integer. |
848 /// | 848 /// |
849 /// Returns a CPS fragment whose context is the branch where no error | 849 /// Returns a CPS fragment whose context is the branch where no error |
850 /// was thrown. | 850 /// was thrown. |
851 CpsFragment makeBoundsCheck(Primitive list, | 851 CpsFragment makeBoundsCheck(Primitive list, |
852 Primitive index, | 852 Primitive index, |
853 SourceInformation sourceInfo) { | 853 SourceInformation sourceInfo) { |
854 CpsFragment cps = new CpsFragment(sourceInfo); | 854 CpsFragment cps = new CpsFragment(sourceInfo); |
855 Continuation fail = cps.letCont(); | 855 Continuation fail = cps.letCont(); |
856 Primitive isTooSmall = cps.applyBuiltin( | 856 Primitive isTooSmall = cps.applyBuiltin( |
(...skipping 30 matching lines...) Expand all Loading... |
887 | 887 |
888 /// Counts number of index accesses on [list] and determines based on | 888 /// Counts number of index accesses on [list] and determines based on |
889 /// that number if we should try to inline them. | 889 /// that number if we should try to inline them. |
890 /// | 890 /// |
891 /// This is a short-term solution to avoid inserting a lot of bounds checks, | 891 /// This is a short-term solution to avoid inserting a lot of bounds checks, |
892 /// since there is currently no optimization for eliminating them. | 892 /// since there is currently no optimization for eliminating them. |
893 bool hasTooManyIndexAccesses(Primitive list) { | 893 bool hasTooManyIndexAccesses(Primitive list) { |
894 int count = 0; | 894 int count = 0; |
895 for (Reference ref = list.firstRef; ref != null; ref = ref.next) { | 895 for (Reference ref = list.firstRef; ref != null; ref = ref.next) { |
896 Node use = ref.parent; | 896 Node use = ref.parent; |
897 if (use is InvokeMethod && | 897 if (use is InvokeMethod && |
898 (use.selector.isIndex || use.selector.isIndexSet) && | 898 (use.selector.isIndex || use.selector.isIndexSet) && |
899 getDartReceiver(use) == list) { | 899 getDartReceiver(use) == list) { |
900 ++count; | 900 ++count; |
901 } else if (use is GetIndex && use.object.definition == list) { | 901 } else if (use is GetIndex && use.object.definition == list) { |
902 ++count; | 902 ++count; |
903 } else if (use is SetIndex && use.object.definition == list) { | 903 } else if (use is SetIndex && use.object.definition == list) { |
904 ++count; | 904 ++count; |
905 } | 905 } |
906 if (count > 2) return true; | 906 if (count > 2) return true; |
907 } | 907 } |
908 return false; | 908 return false; |
909 } | 909 } |
910 | 910 |
911 /// Tries to replace [node] with one or more direct array access operations. | 911 /// Tries to replace [node] with one or more direct array access operations. |
912 /// | 912 /// |
913 /// Returns `true` if the node was replaced. | 913 /// Returns `true` if the node was replaced. |
914 bool specializeArrayAccess(InvokeMethod node) { | 914 bool specializeArrayAccess(InvokeMethod node) { |
915 Primitive list = getDartReceiver(node); | 915 Primitive list = getDartReceiver(node); |
916 AbstractValue listValue = getValue(list); | 916 AbstractValue listValue = getValue(list); |
917 // Ensure that the object is a native list or null. | 917 // Ensure that the object is a native list or null. |
918 if (!lattice.isDefinitelyNativeList(listValue, allowNull: true)) { | 918 if (!lattice.isDefinitelyNativeList(listValue, allowNull: true)) { |
919 return false; | 919 return false; |
920 } | 920 } |
921 bool isFixedLength = | 921 bool isFixedLength = |
922 lattice.isDefinitelyFixedNativeList(listValue, allowNull: true); | 922 lattice.isDefinitelyFixedNativeList(listValue, allowNull: true); |
923 bool isMutable = | 923 bool isMutable = |
924 lattice.isDefinitelyMutableNativeList(listValue, allowNull: true); | 924 lattice.isDefinitelyMutableNativeList(listValue, allowNull: true); |
925 SourceInformation sourceInfo = node.sourceInformation; | 925 SourceInformation sourceInfo = node.sourceInformation; |
926 Continuation cont = node.continuation.definition; | 926 Continuation cont = node.continuation.definition; |
927 switch (node.selector.name) { | 927 switch (node.selector.name) { |
928 case 'length': | 928 case 'length': |
929 if (!node.selector.isGetter) return false; | 929 if (!node.selector.isGetter) return false; |
930 CpsFragment cps = new CpsFragment(sourceInfo); | 930 CpsFragment cps = new CpsFragment(sourceInfo); |
931 cps.invokeContinuation(cont, [cps.letPrim(new GetLength(list))]); | 931 cps.invokeContinuation(cont, [cps.letPrim(new GetLength(list))]); |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1034 } | 1034 } |
1035 } | 1035 } |
1036 | 1036 |
1037 // Rewrite the iterator variable to 'current' and 'index' variables. | 1037 // Rewrite the iterator variable to 'current' and 'index' variables. |
1038 Primitive originalLength = new GetLength(list); | 1038 Primitive originalLength = new GetLength(list); |
1039 originalLength.hint = new OriginalLengthEntity(); | 1039 originalLength.hint = new OriginalLengthEntity(); |
1040 MutableVariable index = new MutableVariable(new LoopIndexEntity()); | 1040 MutableVariable index = new MutableVariable(new LoopIndexEntity()); |
1041 MutableVariable current = new MutableVariable(new LoopItemEntity()); | 1041 MutableVariable current = new MutableVariable(new LoopItemEntity()); |
1042 | 1042 |
1043 // Rewrite all uses of the iterator. | 1043 // Rewrite all uses of the iterator. |
1044 while (iterator.firstRef != null) { | 1044 while (iterator.firstRef != null) { |
1045 InvokeMethod use = iterator.firstRef.parent; | 1045 InvokeMethod use = iterator.firstRef.parent; |
1046 Continuation useCont = use.continuation.definition; | 1046 Continuation useCont = use.continuation.definition; |
1047 if (use.selector == currentSelector) { | 1047 if (use.selector == currentSelector) { |
1048 // Rewrite iterator.current to a use of the 'current' variable. | 1048 // Rewrite iterator.current to a use of the 'current' variable. |
1049 Parameter result = useCont.parameters.single; | 1049 Parameter result = useCont.parameters.single; |
1050 if (result.hint != null) { | 1050 if (result.hint != null) { |
1051 // If 'current' was originally moved into a named variable, use | 1051 // If 'current' was originally moved into a named variable, use |
1052 // that variable name for the mutable variable. | 1052 // that variable name for the mutable variable. |
1053 current.hint = result.hint; | 1053 current.hint = result.hint; |
1054 } | 1054 } |
1055 LetPrim let = | 1055 LetPrim let = |
1056 makeLetPrimInvoke(new GetMutableVariable(current), useCont); | 1056 makeLetPrimInvoke(new GetMutableVariable(current), useCont); |
1057 replaceSubtree(use, let); | 1057 replaceSubtree(use, let); |
1058 } else { | 1058 } else { |
1059 assert (use.selector == moveNextSelector); | 1059 assert (use.selector == moveNextSelector); |
1060 // Rewrite iterator.moveNext() to: | 1060 // Rewrite iterator.moveNext() to: |
1061 // | 1061 // |
1062 // if (index < list.length) { | 1062 // if (index < list.length) { |
1063 // current = null; | 1063 // current = null; |
1064 // continuation(false); | 1064 // continuation(false); |
1065 // } else { | 1065 // } else { |
1066 // current = list[index]; | 1066 // current = list[index]; |
1067 // index = index + 1; | 1067 // index = index + 1; |
1068 // continuation(true); | 1068 // continuation(true); |
1069 // } | 1069 // } |
1070 // | 1070 // |
1071 // (The above does not show concurrent modification checks) | 1071 // (The above does not show concurrent modification checks) |
1072 | 1072 |
1073 // [cps] contains the code we insert instead of moveNext(). | 1073 // [cps] contains the code we insert instead of moveNext(). |
1074 CpsFragment cps = new CpsFragment(node.sourceInformation); | 1074 CpsFragment cps = new CpsFragment(node.sourceInformation); |
1075 | 1075 |
1076 // We must check for concurrent modification when calling moveNext. | 1076 // We must check for concurrent modification when calling moveNext. |
1077 // When moveNext is used as a loop condition, the check prevents | 1077 // When moveNext is used as a loop condition, the check prevents |
1078 // `index < list.length` from becoming the loop condition, and we | 1078 // `index < list.length` from becoming the loop condition, and we |
1079 // get code like this: | 1079 // get code like this: |
1080 // | 1080 // |
1081 // while (true) { | 1081 // while (true) { |
1082 // if (originalLength !== list.length) throw; | 1082 // if (originalLength !== list.length) throw; |
1083 // if (index < list.length) { | 1083 // if (index < list.length) { |
1084 // ... | 1084 // ... |
1085 // } else { | 1085 // } else { |
1086 // ... | 1086 // ... |
1087 // break; | 1087 // break; |
1088 // } | 1088 // } |
1089 // } | 1089 // } |
1090 // | 1090 // |
1091 // For loops, we therefore check for concurrent modification before | 1091 // For loops, we therefore check for concurrent modification before |
1092 // invoking the recursive continuation, so the loop becomes: | 1092 // invoking the recursive continuation, so the loop becomes: |
1093 // | 1093 // |
1094 // if (originalLength !== list.length) throw; | 1094 // if (originalLength !== list.length) throw; |
1095 // while (index < list.length) { | 1095 // while (index < list.length) { |
1096 // ... | 1096 // ... |
1097 // if (originalLength !== list.length) throw; | 1097 // if (originalLength !== list.length) throw; |
1098 // } | 1098 // } |
1099 // | 1099 // |
1100 // The check before the loop can often be eliminated because it | 1100 // The check before the loop can often be eliminated because it |
1101 // follows immediately after the 'iterator' call. | 1101 // follows immediately after the 'iterator' call. |
1102 InteriorNode parent = getEffectiveParent(use); | 1102 InteriorNode parent = getEffectiveParent(use); |
1103 if (!isFixedLength) { | 1103 if (!isFixedLength) { |
1104 if (parent is Continuation && parent.isRecursive) { | 1104 if (parent is Continuation && parent.isRecursive) { |
1105 // Check for concurrent modification before every invocation | 1105 // Check for concurrent modification before every invocation |
1106 // of the continuation. | 1106 // of the continuation. |
1107 // TODO(asgerf): Do this in a continuation so multiple | 1107 // TODO(asgerf): Do this in a continuation so multiple |
1108 // continues can share the same code. | 1108 // continues can share the same code. |
1109 for (Reference ref = parent.firstRef; | 1109 for (Reference ref = parent.firstRef; |
1110 ref != null; | 1110 ref != null; |
1111 ref = ref.next) { | 1111 ref = ref.next) { |
1112 Expression invocationCaller = ref.parent; | 1112 Expression invocationCaller = ref.parent; |
1113 if (getEffectiveParent(invocationCaller) == iteratorCont) { | 1113 if (getEffectiveParent(invocationCaller) == iteratorCont) { |
1114 // No need to check for concurrent modification immediately | 1114 // No need to check for concurrent modification immediately |
1115 // after the call to 'iterator'. | 1115 // after the call to 'iterator'. |
1116 continue; | 1116 continue; |
1117 } | 1117 } |
1118 CpsFragment check = makeConcurrentModificationCheck( | 1118 CpsFragment check = makeConcurrentModificationCheck( |
1119 list, originalLength, sourceInfo); | 1119 list, originalLength, sourceInfo); |
1120 insertBefore(invocationCaller, check); | 1120 insertBefore(invocationCaller, check); |
1121 } | 1121 } |
1122 } else { | 1122 } else { |
1123 cps.append(makeConcurrentModificationCheck( | 1123 cps.append(makeConcurrentModificationCheck( |
1124 list, originalLength, sourceInfo)); | 1124 list, originalLength, sourceInfo)); |
1125 } | 1125 } |
1126 } | 1126 } |
1127 | 1127 |
1128 // Check if there are more elements. | 1128 // Check if there are more elements. |
1129 Primitive hasMore = cps.applyBuiltin( | 1129 Primitive hasMore = cps.applyBuiltin( |
1130 BuiltinOperator.NumLt, | 1130 BuiltinOperator.NumLt, |
1131 [cps.getMutable(index), cps.letPrim(new GetLength(list))]); | 1131 [cps.getMutable(index), cps.letPrim(new GetLength(list))]); |
1132 | 1132 |
1133 // Return false if there are no more. | 1133 // Return false if there are no more. |
1134 CpsFragment falseBranch = cps.ifFalse(hasMore); | 1134 CpsFragment falseBranch = cps.ifFalse(hasMore); |
1135 falseBranch | 1135 falseBranch |
1136 ..setMutable(current, falseBranch.makeNull()) | 1136 ..setMutable(current, falseBranch.makeNull()) |
1137 ..invokeContinuation(useCont, [falseBranch.makeFalse()]); | 1137 ..invokeContinuation(useCont, [falseBranch.makeFalse()]); |
1138 | 1138 |
1139 // Return true if there are more element. | 1139 // Return true if there are more element. |
1140 cps.setMutable(current, | 1140 cps.setMutable(current, |
1141 cps.letPrim(new GetIndex(list, cps.getMutable(index)))); | 1141 cps.letPrim(new GetIndex(list, cps.getMutable(index)))); |
1142 cps.setMutable(index, cps.applyBuiltin( | 1142 cps.setMutable(index, cps.applyBuiltin( |
1143 BuiltinOperator.NumAdd, | 1143 BuiltinOperator.NumAdd, |
1144 [cps.getMutable(index), cps.makeOne()])); | 1144 [cps.getMutable(index), cps.makeOne()])); |
1145 cps.invokeContinuation(useCont, [cps.makeTrue()]); | 1145 cps.invokeContinuation(useCont, [cps.makeTrue()]); |
1146 | 1146 |
1147 // Replace the moveNext() call. It will be visited later. | 1147 // Replace the moveNext() call. It will be visited later. |
1148 replaceSubtree(use, cps.result); | 1148 replaceSubtree(use, cps.result); |
1149 } | 1149 } |
1150 } | 1150 } |
(...skipping 19 matching lines...) Expand all Loading... |
1170 | 1170 |
1171 // TODO(asgerf): Rewrite 'add', 'removeLast', ... | 1171 // TODO(asgerf): Rewrite 'add', 'removeLast', ... |
1172 | 1172 |
1173 default: | 1173 default: |
1174 return false; | 1174 return false; |
1175 } | 1175 } |
1176 } | 1176 } |
1177 | 1177 |
1178 /// If [prim] is the parameter to a call continuation, returns the | 1178 /// If [prim] is the parameter to a call continuation, returns the |
1179 /// corresponding call. | 1179 /// corresponding call. |
1180 Invoke getInvocationWithResult(Primitive prim) { | 1180 CallExpression getCallWithResult(Primitive prim) { |
1181 if (prim is Parameter && prim.parent is Continuation) { | 1181 if (prim is Parameter && prim.parent is Continuation) { |
1182 Continuation cont = prim.parent; | 1182 Continuation cont = prim.parent; |
1183 if (cont.hasExactlyOneUse) { | 1183 if (cont.hasExactlyOneUse) { |
1184 Node use = cont.firstRef.parent; | 1184 Node use = cont.firstRef.parent; |
1185 if (use is Invoke) { | 1185 if (use is CallExpression) { |
1186 return use; | 1186 return use; |
1187 } | 1187 } |
1188 } | 1188 } |
1189 } | 1189 } |
1190 return null; | 1190 return null; |
1191 } | 1191 } |
1192 | 1192 |
1193 /// Returns the first parent of [node] that is not a pure expression. | 1193 /// Returns the first parent of [node] that is not a pure expression. |
1194 InteriorNode getEffectiveParent(Expression node) { | 1194 InteriorNode getEffectiveParent(Expression node) { |
1195 while (true) { | 1195 while (true) { |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 target, | 1236 target, |
1237 new Selector.fromElement(target), | 1237 new Selector.fromElement(target), |
1238 node.arguments, | 1238 node.arguments, |
1239 node.continuation, | 1239 node.continuation, |
1240 node.sourceInformation); | 1240 node.sourceInformation); |
1241 node.receiver.unlink(); | 1241 node.receiver.unlink(); |
1242 replaceSubtree(node, invoke, unlink: false); | 1242 replaceSubtree(node, invoke, unlink: false); |
1243 visitInvokeStatic(invoke); | 1243 visitInvokeStatic(invoke); |
1244 return true; | 1244 return true; |
1245 } | 1245 } |
1246 Invoke tearOffInvoke = getInvocationWithResult(tearOff); | 1246 CallExpression tearOffInvoke = getCallWithResult(tearOff); |
1247 if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) { | 1247 if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) { |
1248 Selector getter = tearOffInvoke.selector; | 1248 Selector getter = tearOffInvoke.selector; |
1249 | 1249 |
1250 // TODO(asgerf): Support torn-off intercepted methods. | 1250 // TODO(asgerf): Support torn-off intercepted methods. |
1251 if (isInterceptedSelector(getter)) return false; | 1251 if (isInterceptedSelector(getter)) return false; |
1252 | 1252 |
1253 Continuation getterCont = tearOffInvoke.continuation.definition; | 1253 Continuation getterCont = tearOffInvoke.continuation.definition; |
1254 | 1254 |
1255 // TODO(asgerf): Support torn-off intercepted methods. | 1255 // TODO(asgerf): Support torn-off intercepted methods. |
1256 if (isInterceptedSelector(getter)) return false; | 1256 if (isInterceptedSelector(getter)) return false; |
(...skipping 1027 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2284 Map<Definition, AbstractValue> values; | 2284 Map<Definition, AbstractValue> values; |
2285 | 2285 |
2286 ResetAnalysisInfo(this.reachableNodes, this.values); | 2286 ResetAnalysisInfo(this.reachableNodes, this.values); |
2287 | 2287 |
2288 visit(Node node) { | 2288 visit(Node node) { |
2289 reachableNodes.remove(node); | 2289 reachableNodes.remove(node); |
2290 if (node is Definition) values.remove(node); | 2290 if (node is Definition) values.remove(node); |
2291 node.accept(this); | 2291 node.accept(this); |
2292 } | 2292 } |
2293 } | 2293 } |
OLD | NEW |