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

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

Issue 1671073002: dart2js cps: Pull SetFields into field initializer arguments. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Disable tracing of LetCont Created 4 years, 10 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
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 'cps_ir_nodes.dart';
7 import 'optimizers.dart';
8 import '../elements/elements.dart';
9 import '../js_backend/js_backend.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 intializers. 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 void visitLetHandler(LetHandler node) {
78 endBasicBlock();
79 }
80 void visitInvokeContinuation(InvokeContinuation node) {
81 endBasicBlock();
82 }
83 void visitBranch(Branch node) {
84 endBasicBlock();
85 }
86 void visitRethrow(Rethrow node) {
87 endBasicBlock();
88 }
89 void visitThrow(Throw node) {
90 endBasicBlock();
91 }
92 void visitUnreachable(Unreachable node) {
93 endBasicBlock();
94 }
95
96 void visitLetMutable(LetMutable node) {
97 escape(node.value);
98 }
99
100 void visitLetCont(LetCont node) {
101 if (unescaped.isNotEmpty) {
102 // Ensure we do not lift a LetCont if there is a sink target set above
103 // the current node.
104 sinkLetConts();
105 letConts.add(node);
106 }
107 }
108
109 void sinkLetConts() {
110 if (letContSinkTarget != null) {
111 for (LetCont letCont in letConts.reversed) {
112 letCont..remove()..insertBelow(letContSinkTarget);
113 }
114 letContSinkTarget = null;
115 }
116 }
117
118 void endBasicBlock() {
119 sinkLetConts();
120 letConts.clear();
121 unescaped.clear();
122 }
123
124 void visitLetPrim(LetPrim node) {
125 Primitive prim = node.primitive;
126 if (prim is CreateInstance) {
127 unescaped.add(prim);
128 prim.arguments.forEach(escape);
129 return;
130 }
131 if (unescaped.isEmpty) return;
132 if (prim is SetField) {
133 escape(prim.value);
134 Primitive object = prim.object.definition;
135 if (object is CreateInstance && unescaped.contains(object)) {
136 int index = getFieldIndex(object.classElement, prim.field);
137 if (index == -1) {
138 // This field is not initialized at creation time, so we cannot pull
139 // set SetField into the CreateInstance instruction. We have to
140 // leave the instruction here, and this counts as a use of the object.
141 escape(prim.object);
142 } else {
143 // Replace the field initializer with the new value. There are no uses
144 // of the object before this, so the old value cannot have been seen.
145 object.arguments[index].changeTo(prim.value.definition);
146 prim.destroy();
147 // The right-hand side might not be in scope at the CreateInstance.
148 // Sink the creation down to this point.
149 rebindCreateInstanceAt(object, node);
150 letContSinkTarget = node;
151 }
152 }
153 return;
154 }
155 if (prim is GetField) {
156 // When reading the field of a newly created object, just use the initial
157 // value and destroy the GetField. This can unblock the other optimization
158 // since we remove a use of the object.
159 Primitive object = prim.object.definition;
160 if (object is CreateInstance && unescaped.contains(object)) {
161 int index = getFieldIndex(object.classElement, prim.field);
162 if (index == -1) {
163 escape(prim.object);
164 } else {
165 prim.replaceUsesWith(object.arguments[index].definition);
166 prim.destroy();
167 node.remove();
168 }
169 }
170 return;
171 }
172 escapeVisitor.visit(node.primitive);
173 }
174
175 void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
176 removeBinding(prim);
177 newBinding.primitive = prim;
178 prim.parent = newBinding;
179 }
180
181 /// Returns the index of [field] in the canonical initialization order in
182 /// [classElement], or -1 if the field is not initialized at creation time
183 /// for that class.
184 int getFieldIndex(ClassElement classElement, FieldElement field) {
185 // There is no stored map from a field to its index in a given class, so we
186 // have to iterate over all instance fields until we find it.
187 int current = -1, index = -1;
188 classElement.forEachInstanceField((host, currentField) {
189 if (!backend.isNativeOrExtendsNative(host)) {
190 ++current;
191 if (currentField == field) {
192 index = current;
193 }
194 }
195 }, includeSuperAndInjectedMembers: true);
196 return index;
197 }
198
199 void removeBinding(Primitive prim) {
200 LetPrim node = prim.parent;
201 node.remove();
202 }
203 }
204
205 class EscapeVisitor extends DeepRecursiveVisitor {
206 final UseFieldInitializers main;
207 EscapeVisitor(this.main);
208
209 processReference(Reference ref) {
210 main.escape(ref);
211 }
212 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/optimizers.dart ('k') | pkg/compiler/lib/src/js_backend/codegen/task.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698