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

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

Issue 2246623002: Delete CPS IR (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 4 months 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/cps_ir/update_refinements.dart ('k') | pkg/compiler/lib/src/dart2js.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 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4 library dart2js.cps_ir.use_field_initializers;
5
6 import '../elements/elements.dart';
7 import '../js_backend/js_backend.dart';
8 import 'cps_ir_nodes.dart';
9 import 'optimizers.dart';
10
11 /// Eliminates [SetField] instructions when the value can instead be passed into
12 /// the field initializer of a [CreateInstance] instruction.
13 ///
14 /// This compensates for a somewhat common pattern where fields are initialized
15 /// in the constructor body instead of using initializers. For example:
16 ///
17 /// class Foo {
18 /// var x, y;
19 /// Foo(x, y) {
20 /// this.x = x;
21 /// this.y = y;
22 /// }
23 /// }
24 ///
25 /// ==> (IR for Foo constructor)
26 ///
27 /// foo = new D.Foo(null, null);
28 /// foo.x = 'a';
29 /// foo.y = 'b';
30 ///
31 /// ==> (after this pass)
32 ///
33 /// foo = new D.Foo('a', 'b');
34 //
35 // TODO(asgerf): Store forwarding and load elimination could most likely
36 // handle this more generally.
37 //
38 class UseFieldInitializers extends BlockVisitor implements Pass {
39 String get passName => 'Use field initializers';
40
41 final JavaScriptBackend backend;
42
43 final Set<CreateInstance> unescaped = new Set<CreateInstance>();
44
45 /// Continuation bindings separating the current traversal position from an
46 /// unescaped [CreateInstance]. When [CreateInstance] is sunk, these
47 /// continuations must sink as well to ensure the object remains in scope
48 /// inside the bound continuations.
49 final List<LetCont> letConts = <LetCont>[];
50
51 /// If non-null, the bindings in [letConts] should sink to immediately below
52 /// this node.
53 InteriorNode letContSinkTarget = null;
54 EscapeVisitor escapeVisitor;
55
56 UseFieldInitializers(this.backend);
57
58 void rewrite(FunctionDefinition node) {
59 escapeVisitor = new EscapeVisitor(this);
60 BlockVisitor.traverseInPreOrder(node, this);
61 }
62
63 void escape(Reference ref) {
64 Definition def = ref.definition;
65 if (def is CreateInstance) {
66 unescaped.remove(def);
67 if (unescaped.isEmpty) {
68 sinkLetConts();
69 letConts.clear();
70 }
71 }
72 }
73
74 void visitContinuation(Continuation node) {
75 endBasicBlock();
76 }
77
78 void visitLetHandler(LetHandler node) {
79 endBasicBlock();
80 }
81
82 void visitInvokeContinuation(InvokeContinuation node) {
83 endBasicBlock();
84 }
85
86 void visitBranch(Branch node) {
87 endBasicBlock();
88 }
89
90 void visitRethrow(Rethrow node) {
91 endBasicBlock();
92 }
93
94 void visitThrow(Throw node) {
95 endBasicBlock();
96 }
97
98 void visitUnreachable(Unreachable node) {
99 endBasicBlock();
100 }
101
102 void visitLetMutable(LetMutable node) {
103 escape(node.valueRef);
104 }
105
106 void visitLetCont(LetCont node) {
107 if (unescaped.isNotEmpty) {
108 // Ensure we do not lift a LetCont if there is a sink target set above
109 // the current node.
110 sinkLetConts();
111 letConts.add(node);
112 }
113 }
114
115 void sinkLetConts() {
116 if (letContSinkTarget != null) {
117 for (LetCont letCont in letConts.reversed) {
118 letCont
119 ..remove()
120 ..insertBelow(letContSinkTarget);
121 }
122 letContSinkTarget = null;
123 }
124 }
125
126 void endBasicBlock() {
127 sinkLetConts();
128 letConts.clear();
129 unescaped.clear();
130 }
131
132 void visitLetPrim(LetPrim node) {
133 Primitive prim = node.primitive;
134 if (prim is CreateInstance) {
135 unescaped.add(prim);
136 prim.argumentRefs.forEach(escape);
137 return;
138 }
139 if (unescaped.isEmpty) return;
140 if (prim is SetField) {
141 escape(prim.valueRef);
142 Primitive object = prim.object;
143 if (object is CreateInstance && unescaped.contains(object)) {
144 int index = getFieldIndex(object.classElement, prim.field);
145 if (index == -1) {
146 // This field is not initialized at creation time, so we cannot pull
147 // set SetField into the CreateInstance instruction. We have to
148 // leave the instruction here, and this counts as a use of the object.
149 escape(prim.objectRef);
150 } else {
151 // Replace the field initializer with the new value. There are no uses
152 // of the object before this, so the old value cannot have been seen.
153 object.argumentRefs[index].changeTo(prim.value);
154 prim.destroy();
155 // The right-hand side might not be in scope at the CreateInstance.
156 // Sink the creation down to this point.
157 rebindCreateInstanceAt(object, node);
158 letContSinkTarget = node;
159 }
160 }
161 return;
162 }
163 if (prim is GetField) {
164 // When reading the field of a newly created object, just use the initial
165 // value and destroy the GetField. This can unblock the other optimization
166 // since we remove a use of the object.
167 Primitive object = prim.object;
168 if (object is CreateInstance && unescaped.contains(object)) {
169 int index = getFieldIndex(object.classElement, prim.field);
170 if (index == -1) {
171 escape(prim.objectRef);
172 } else {
173 prim.replaceUsesWith(object.argument(index));
174 prim.destroy();
175 node.remove();
176 }
177 }
178 return;
179 }
180 escapeVisitor.visit(node.primitive);
181 }
182
183 void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
184 removeBinding(prim);
185 newBinding.primitive = prim;
186 prim.parent = newBinding;
187 }
188
189 /// Returns the index of [field] in the canonical initialization order in
190 /// [classElement], or -1 if the field is not initialized at creation time
191 /// for that class.
192 int getFieldIndex(ClassElement classElement, FieldElement field) {
193 // There is no stored map from a field to its index in a given class, so we
194 // have to iterate over all instance fields until we find it.
195 int current = -1, index = -1;
196 classElement.forEachInstanceField((host, currentField) {
197 if (!backend.isNativeOrExtendsNative(host)) {
198 ++current;
199 if (currentField == field) {
200 index = current;
201 }
202 }
203 }, includeSuperAndInjectedMembers: true);
204 return index;
205 }
206
207 void removeBinding(Primitive prim) {
208 LetPrim node = prim.parent;
209 node.remove();
210 }
211 }
212
213 class EscapeVisitor extends DeepRecursiveVisitor {
214 final UseFieldInitializers main;
215 EscapeVisitor(this.main);
216
217 processReference(Reference ref) {
218 main.escape(ref);
219 }
220 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/update_refinements.dart ('k') | pkg/compiler/lib/src/dart2js.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698