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

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: 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
10 /// Eliminates [SetField] instructions when the value can instead be passed into
11 /// the field initializer of a [CreateInstance] instruction.
12 ///
13 /// This compensates for a somewhat common pattern where fields are initialized
14 /// in the constructor body instead of using intializers. For example:
15 ///
16 /// class Foo {
17 /// var x, y;
18 /// Foo(x, y) {
19 /// this.x = x;
20 /// this.y = y;
21 /// }
22 /// }
23 ///
24 /// ==> (IR for Foo constructor)
25 ///
26 /// foo = new D.Foo(null, null);
27 /// foo.x = 'a';
28 /// foo.y = 'b';
29 ///
30 /// ==> (after this pass)
31 ///
32 /// foo = new D.Foo('a', 'b');
33 //
34 // TODO(asgerf): Store forwarding and load elimination could most likely
35 // handle this more generally.
36 //
37 class UseFieldInitializers extends BlockVisitor implements Pass {
38 String get passName => 'Use field initializers';
39
40 final Set<CreateInstance> unescaped = new Set<CreateInstance>();
41
42 /// Continuation bindings separating the current traversal position from an
43 /// unescaped [CreateInstance]. When [CreateInstance] is sunk, these
44 /// continuations must sink as well to ensure the object remains in scope
45 /// inside the bound continuations.
46 final List<LetCont> letConts = <LetCont>[];
47
48 /// If non-null, the bindings in [letConts] should sink to immediately below
49 /// this node.
50 InteriorNode letContSinkTarget = null;
51 EscapeVisitor escapeVisitor;
52
53 void rewrite(FunctionDefinition node) {
54 escapeVisitor = new EscapeVisitor(this);
55 BlockVisitor.traverseInPreOrder(node, this);
56 }
57
58 void escape(Reference ref) {
59 Definition def = ref.definition;
60 if (def is CreateInstance) {
61 unescaped.remove(def);
62 }
63 }
64
65 void visitLetCont(LetCont node) {
66 if (unescaped.isNotEmpty) {
67 letConts.add(node);
68 }
69 }
70
71 void visitContinuation(Continuation node) {
72 endBasicBlock();
73 }
74 void visitLetHandler(LetHandler node) {
75 endBasicBlock();
76 }
77 void visitInvokeContinuation(InvokeContinuation node) {
78 endBasicBlock();
79 }
80 void visitBranch(Branch node) {
81 endBasicBlock();
82 }
83 void visitRethrow(Rethrow node) {
84 endBasicBlock();
85 }
86 void visitThrow(Throw node) {
87 endBasicBlock();
88 }
89 void visitUnreachable(Unreachable node) {
90 endBasicBlock();
91 }
92
93 void visitLetMutable(LetMutable node) {
94 escape(node.value);
95 }
96
97 void endBasicBlock() {
98 if (letContSinkTarget != null) {
99 for (LetCont letCont in letConts.reversed) {
100 letCont..remove()..insertBelow(letContSinkTarget);
101 }
102 }
103 unescaped.clear();
104 letConts.clear();
105 letContSinkTarget = null;
106 }
107
108 void visitLetPrim(LetPrim node) {
109 Primitive prim = node.primitive;
110 if (prim is CreateInstance) {
111 unescaped.add(prim);
112 prim.arguments.forEach(escape);
113 return;
114 }
115 if (unescaped.isEmpty) return;
116 if (prim is SetField) {
117 escape(prim.value);
118 Primitive object = prim.object.definition;
119 if (object is CreateInstance && unescaped.contains(object)) {
120 // Replace the field initializer with the new value. There are no uses
121 // of the object before this, so the old value cannot have been seen.
Siggi Cherem (dart-lang) 2016/02/05 18:46:39 I'm assuming it doesn't matter if the old value is
asgerf 2016/02/08 18:46:46 That's right.
122 int index = getFieldIndex(object.classElement, prim.field);
123 object.arguments[index].changeTo(prim.value.definition);
124 prim.destroy();
125 // The right-hand side might not be in scope at the CreateInstance.
126 // Sink the creation down to this point.
127 rebindCreateInstanceAt(object, node);
128 letContSinkTarget = node;
129 }
130 return;
131 }
132 if (prim is GetField) {
133 // When reading the field of a newly created object, just use the initial
134 // value and destroy the GetField. This can unblock the other optimization
135 // since we remove a use of the object.
136 Primitive object = prim.object.definition;
137 if (object is CreateInstance && unescaped.contains(object)) {
138 int index = getFieldIndex(object.classElement, prim.field);
139 prim.replaceUsesWith(object.arguments[index].definition);
140 prim.destroy();
141 node.remove();
142 }
143 return;
144 }
145 escapeVisitor.visit(node.primitive);
146 }
147
148 void rebindCreateInstanceAt(CreateInstance prim, LetPrim newBinding) {
149 removeBinding(prim);
150 newBinding.primitive = prim;
151 prim.parent = newBinding;
152 }
153
154 int getFieldIndex(ClassElement classElement, FieldElement field) {
155 // There is no stored map from a field to its index in a given class, so we
156 // have to iterate over all instance fields until we find it.
157 int current = -1, index = -1;
158 classElement.forEachInstanceField((host, currentField) {
159 ++current;
160 if (currentField == field) {
161 index = current;
162 }
163 }, includeSuperAndInjectedMembers: true);
164 return index;
165 }
166
167 void removeBinding(Primitive prim) {
168 LetPrim node = prim.parent;
169 node.remove();
170 }
171 }
172
173 class EscapeVisitor extends DeepRecursiveVisitor {
174 final UseFieldInitializers main;
175 EscapeVisitor(this.main);
176
177 processReference(Reference ref) {
178 main.escape(ref);
179 }
180 }
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