Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(443)

Side by Side Diff: pkg/compiler/lib/src/cps_ir/backward_null_check_remover.dart

Issue 1538593003: dart2js cps: Backward redundant null check removal (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/compiler/lib/src/common/names.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_fragment.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 library dart2js.cps_ir.backward_null_check_remover;
2
3 import 'cps_ir_nodes.dart';
4 import 'optimizers.dart' show Pass;
5 import '../common/names.dart';
6 import '../universe/selector.dart';
7 import 'type_mask_system.dart';
8 import 'cps_fragment.dart';
9
10 /// Removes null checks that are follwed by another instruction that will
11 /// perform the same check.
12 ///
13 /// For example:
14 ///
15 /// x.toString; // NullCheck instruction
16 /// print(x.length);
17 ///
18 /// ==>
19 ///
20 /// print(x.length);
21 ///
22 /// `x.length` will throw when x is null, so the original [NullCheck] is not
23 /// needed. This changes the error message, but at least for now we are
24 /// willing to accept this.
25 ///
26 /// Note that code motion may not occur after this pass, since the [NullCheck]
27 /// nodes are not there to restrict it.
28 //
29 // TODO(asgerf): It would be nice with a clear specification of when we allow
30 // the wording of error message to change. E.g. "toString" is already pretty
31 // bad so changing that should be ok, but changing a field access is not as
32 // clear.
33 //
34 class BackwardNullCheckRemover extends TrampolineRecursiveVisitor
35 implements Pass {
36 String get passName => 'Backward null-check remover';
37
38 final TypeMaskSystem typeSystem;
39
40 /// When the analysis of an expression completes, [nullCheckValue] refers to
41 /// a value that is checked in the beginning of that expression.
42 Primitive nullCheckedValue;
43
44 BackwardNullCheckRemover(this.typeSystem);
45
46 void rewrite(FunctionDefinition node) {
47 visit(node);
48 }
49
50 /// Returns a reference to an operand of [prim], where [prim] throws if null
51 /// is passed into that operand.
52 Reference<Primitive> getNullCheckedOperand(Primitive prim) {
53 if (prim is NullCheck) return prim.value;
54 if (prim is GetLength) return prim.object;
55 if (prim is GetField) return prim.object;
56 if (prim is GetIndex) return prim.object;
57 if (prim is SetField) return prim.object;
58 if (prim is SetIndex) return prim.object;
59 if (prim is InvokeMethod && !nullSelectors.contains(prim.selector)) {
60 return prim.dartReceiverReference;
61 }
62 return null;
63 }
64
65 static final List<Selector> nullSelectors = <Selector>[
66 Selectors.equals, Selectors.hashCode_, Selectors.noSuchMethod_,
67 Selectors.runtimeType_];
68
69 /// It has been determined that the null check in [prim] made redundant by
70 /// [newNullCheck]. Eliminate [prim] if it is not needed any more.
71 void tryEliminateRedundantNullCheck(Primitive prim, Primitive newNullCheck) {
72 if (prim is NullCheck) {
73 Primitive value = prim.value.definition;
74 LetPrim let = prim.parent;
75 prim..replaceUsesWith(value)..destroy();
76 let.remove();
77 } else if (prim is GetLength || prim is GetField || prim is GetIndex) {
78 if (prim.hasNoEffectiveUses) {
79 destroyRefinementsOfDeadPrimitive(prim);
80 LetPrim let = prim.parent;
81 prim..destroy();
82 let.remove();
83 }
84 }
85 }
86
87 /// True if [prim] can be moved above a null check. This is safe if [prim]
88 /// cannot throw or have side effects and does not carry any path-sensitive
89 /// type information, such as [Refinement] nodes do.
90 //
91 // TODO(asgerf): This prevents elimination of the .length created for a bounds
92 // check, because there is a refinement node below it. To handle this, we
93 // would have to relocate the [Refinement] node below the new null check.
94 bool canMoveAboveNullCheck(Primitive prim) {
95 return prim.isSafeForReordering;
96 }
97
98 Expression traverseLetPrim(LetPrim node) {
99 Primitive prim = node.primitive;
100 Primitive receiver = getNullCheckedOperand(prim)?.definition;
101 if (receiver != null) {
102 pushAction(() {
103 Primitive successor = nullCheckedValue;
104 if (successor != null && receiver.sameValue(successor)) {
105 tryEliminateRedundantNullCheck(prim, successor);
106 }
107 nullCheckedValue = receiver;
108 });
109 } else if (!canMoveAboveNullCheck(prim)) {
110 pushAction(() {
111 nullCheckedValue = null;
112 });
113 }
114 return node.body;
115 }
116
117 Expression traverseContinuation(Continuation cont) {
118 pushAction(() {
119 nullCheckedValue = null;
120 });
121 return cont.body;
122 }
123
124 Expression traverseLetHandler(LetHandler node) {
125 push(node.handler);
126 pushAction(() {
127 nullCheckedValue = null;
128 });
129 return node.body;
130 }
131 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/common/names.dart ('k') | pkg/compiler/lib/src/cps_ir/cps_fragment.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698