OLD | NEW |
1 library dart2js.cps_ir.backward_null_check_remover; | 1 library dart2js.cps_ir.backward_null_check_remover; |
2 | 2 |
3 import 'cps_ir_nodes.dart'; | 3 import 'cps_ir_nodes.dart'; |
4 import 'optimizers.dart'; | 4 import 'optimizers.dart'; |
5 import '../common/names.dart'; | 5 import '../common/names.dart'; |
6 import '../universe/selector.dart'; | 6 import '../universe/selector.dart'; |
7 import 'type_mask_system.dart'; | 7 import 'type_mask_system.dart'; |
8 import 'cps_fragment.dart'; | 8 import 'cps_fragment.dart'; |
9 | 9 |
10 /// Removes null checks that are follwed by another instruction that will | 10 /// Removes null checks that are follwed by another instruction that will |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 /// The [nullCheckedValue] at the entry point of a continuation. | 43 /// The [nullCheckedValue] at the entry point of a continuation. |
44 final Map<Continuation, Primitive> nullCheckedValueAt = | 44 final Map<Continuation, Primitive> nullCheckedValueAt = |
45 <Continuation, Primitive>{}; | 45 <Continuation, Primitive>{}; |
46 | 46 |
47 BackwardNullCheckRemover(this.typeSystem); | 47 BackwardNullCheckRemover(this.typeSystem); |
48 | 48 |
49 void rewrite(FunctionDefinition node) { | 49 void rewrite(FunctionDefinition node) { |
50 BlockVisitor.traverseInPostOrder(node, this); | 50 BlockVisitor.traverseInPostOrder(node, this); |
51 } | 51 } |
52 | 52 |
53 /// Returns a reference to an operand of [prim], where [prim] throws if null | 53 /// Returns an operand of [prim] that throws if null is passed into it. |
54 /// is passed into that operand. | 54 Primitive getNullCheckedOperand(Primitive prim) { |
55 Reference<Primitive> getNullCheckedOperand(Primitive prim) { | |
56 if (prim is ReceiverCheck) return prim.value; | 55 if (prim is ReceiverCheck) return prim.value; |
57 if (prim is GetLength) return prim.object; | 56 if (prim is GetLength) return prim.object; |
58 if (prim is GetField) return prim.object; | 57 if (prim is GetField) return prim.object; |
59 if (prim is GetIndex) return prim.object; | 58 if (prim is GetIndex) return prim.object; |
60 if (prim is SetField) return prim.object; | 59 if (prim is SetField) return prim.object; |
61 if (prim is SetIndex) return prim.object; | 60 if (prim is SetIndex) return prim.object; |
62 if (prim is InvokeMethod && !selectorsOnNull.contains(prim.selector)) { | 61 if (prim is InvokeMethod && !selectorsOnNull.contains(prim.selector)) { |
63 return prim.dartReceiverReference; | 62 return prim.dartReceiver; |
64 } | 63 } |
65 if (prim is ForeignCode) { | 64 if (prim is ForeignCode) { |
66 return prim.isNullGuardOnNullFirstArgument() ? prim.arguments[0] : null; | 65 return prim.isNullGuardOnNullFirstArgument() ? prim.argument(0) : null; |
67 } | 66 } |
68 return null; | 67 return null; |
69 } | 68 } |
70 | 69 |
71 /// It has been determined that the null check in [prim] made redundant by | 70 /// It has been determined that the null check in [prim] made redundant by |
72 /// [newNullCheck]. Eliminate [prim] if it is not needed any more. | 71 /// [newNullCheck]. Eliminate [prim] if it is not needed any more. |
73 void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) { | 72 void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) { |
74 if (prim is ReceiverCheck && prim.isNullCheck) { | 73 if (prim is ReceiverCheck && prim.isNullCheck) { |
75 Primitive value = prim.value.definition; | 74 Primitive value = prim.value; |
76 LetPrim let = prim.parent; | 75 LetPrim let = prim.parent; |
77 prim..replaceUsesWith(value)..destroy(); | 76 prim..replaceUsesWith(value)..destroy(); |
78 let.remove(); | 77 let.remove(); |
79 } else if (prim is GetLength || prim is GetField || prim is GetIndex) { | 78 } else if (prim is GetLength || prim is GetField || prim is GetIndex) { |
80 if (prim.hasNoRefinedUses) { | 79 if (prim.hasNoRefinedUses) { |
81 destroyRefinementsOfDeadPrimitive(prim); | 80 destroyRefinementsOfDeadPrimitive(prim); |
82 LetPrim let = prim.parent; | 81 LetPrim let = prim.parent; |
83 prim..destroy(); | 82 prim..destroy(); |
84 let.remove(); | 83 let.remove(); |
85 } | 84 } |
86 } | 85 } |
87 } | 86 } |
88 | 87 |
89 /// True if [prim] can be moved above a null check. This is safe if [prim] | 88 /// True if [prim] can be moved above a null check. This is safe if [prim] |
90 /// cannot throw or have side effects and does not carry any path-sensitive | 89 /// cannot throw or have side effects and does not carry any path-sensitive |
91 /// type information, such as [Refinement] nodes do. | 90 /// type information, such as [Refinement] nodes do. |
92 // | 91 // |
93 // TODO(asgerf): This prevents elimination of the .length created for a bounds | 92 // TODO(asgerf): This prevents elimination of the .length created for a bounds |
94 // check, because there is a refinement node below it. To handle this, we | 93 // check, because there is a refinement node below it. To handle this, we |
95 // would have to relocate the [Refinement] node below the new null check. | 94 // would have to relocate the [Refinement] node below the new null check. |
96 bool canMoveAboveNullCheck(Primitive prim) { | 95 bool canMoveAboveNullCheck(Primitive prim) { |
97 return prim.isSafeForReordering; | 96 return prim.isSafeForReordering; |
98 } | 97 } |
99 | 98 |
100 void visitLetPrim(LetPrim node) { | 99 void visitLetPrim(LetPrim node) { |
101 Primitive prim = node.primitive; | 100 Primitive prim = node.primitive; |
102 Primitive receiver = getNullCheckedOperand(prim)?.definition; | 101 Primitive receiver = getNullCheckedOperand(prim); |
103 if (receiver != null) { | 102 if (receiver != null) { |
104 if (nullCheckedValue != null && receiver.sameValue(nullCheckedValue)) { | 103 if (nullCheckedValue != null && receiver.sameValue(nullCheckedValue)) { |
105 tryEliminateRedundantNullCheck(prim, nullCheckedValue); | 104 tryEliminateRedundantNullCheck(prim, nullCheckedValue); |
106 } | 105 } |
107 nullCheckedValue = receiver; | 106 nullCheckedValue = receiver; |
108 } else if (!canMoveAboveNullCheck(prim)) { | 107 } else if (!canMoveAboveNullCheck(prim)) { |
109 nullCheckedValue = null; | 108 nullCheckedValue = null; |
110 } | 109 } |
111 } | 110 } |
112 | 111 |
113 void visitContinuation(Continuation cont) { | 112 void visitContinuation(Continuation cont) { |
114 if (nullCheckedValue != null) { | 113 if (nullCheckedValue != null) { |
115 nullCheckedValueAt[cont] = nullCheckedValue; | 114 nullCheckedValueAt[cont] = nullCheckedValue; |
116 nullCheckedValue = null; | 115 nullCheckedValue = null; |
117 } | 116 } |
118 } | 117 } |
119 | 118 |
120 void visitLetHandler(LetHandler node) { | 119 void visitLetHandler(LetHandler node) { |
121 nullCheckedValue = null; | 120 nullCheckedValue = null; |
122 } | 121 } |
123 | 122 |
124 visitInvokeContinuation(InvokeContinuation node) { | 123 visitInvokeContinuation(InvokeContinuation node) { |
125 if (!node.isRecursive) { | 124 if (!node.isRecursive) { |
126 nullCheckedValue = nullCheckedValueAt[node.continuation.definition]; | 125 nullCheckedValue = nullCheckedValueAt[node.continuation]; |
127 } | 126 } |
128 } | 127 } |
129 } | 128 } |
OLD | NEW |