OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, 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 | |
5 import 'optimizers.dart'; | |
6 | |
7 import 'dart:collection' show Queue; | |
8 | |
9 import '../closure.dart' show | |
10 ClosureClassElement, Identifiers; | |
11 import '../common/names.dart' show | |
12 Selectors, Identifiers; | |
13 import '../compiler.dart' as dart2js show | |
14 Compiler; | |
15 import '../constants/constant_system.dart'; | |
16 import '../constants/values.dart'; | |
17 import '../dart_types.dart' as types; | |
18 import '../diagnostics/invariant.dart' as dart2js show | |
19 InternalErrorFunction; | |
20 import '../elements/elements.dart'; | |
21 import '../io/source_information.dart' show SourceInformation; | |
22 import '../resolution/access_semantics.dart'; | |
23 import '../resolution/operators.dart'; | |
24 import '../resolution/send_structure.dart'; | |
25 import '../tree/tree.dart' as ast; | |
26 import '../types/types.dart'; | |
27 import '../types/constants.dart' show computeTypeMask; | |
28 import '../universe/universe.dart'; | |
29 import '../world.dart' show World; | |
30 import 'cps_fragment.dart'; | |
31 import 'cps_ir_nodes.dart'; | |
32 import 'cps_ir_nodes_sexpr.dart' show SExpressionStringifier; | |
33 | |
34 /** | |
35 * Replaces aggregates with a set of local values. Performs inlining of | |
36 * single-use closures to generate more replacable aggregates. | |
37 */ | |
38 class ScalarReplacer extends Pass { | |
39 String get passName => 'Scalar replacement'; | |
40 | |
41 final dart2js.InternalErrorFunction _internalError; | |
42 | |
43 ScalarReplacer(dart2js.Compiler compiler) | |
44 : _internalError = compiler.internalError; | |
45 | |
46 @override | |
47 void rewrite(FunctionDefinition root) { | |
48 // Set all parent pointers. | |
49 new ParentVisitor().visit(root); | |
50 ScalarReplacementVisitor analyzer = | |
51 new ScalarReplacementVisitor(_internalError); | |
52 analyzer.analyze(root); | |
53 analyzer.process(); | |
54 } | |
55 } | |
56 | |
57 /** | |
58 * Do scalar replacement of aggregates on instances. Since scalar replacement | |
59 * can create new candidiates, iterate until all scalar replacements are done. | |
60 */ | |
61 class ScalarReplacementVisitor extends RecursiveVisitor { | |
62 | |
63 final dart2js.InternalErrorFunction internalError; | |
64 ScalarReplacementRemovalVisitor removalVisitor; | |
65 | |
66 Primitive _current = null; | |
67 Set<Primitive> _allocations = new Set<Primitive>(); | |
68 Queue<Primitive> _queue = new Queue<Primitive>(); | |
69 | |
70 ScalarReplacementVisitor(this.internalError) { | |
71 removalVisitor = new ScalarReplacementRemovalVisitor(this); | |
72 } | |
73 | |
74 void analyze(FunctionDefinition root) { | |
75 visit(root); | |
76 } | |
77 | |
78 void process() { | |
79 while (_queue.isNotEmpty) { | |
80 Primitive allocation = _queue.removeFirst(); | |
81 _allocations.remove(allocation); | |
82 _current = allocation; | |
83 tryScalarReplacement(allocation); | |
84 } | |
85 } | |
86 | |
87 void tryScalarReplacement(Primitive allocation) { | |
88 | |
89 // We can do scalar replacement of an aggregate if all uses of an allocation | |
90 // are reads or writes. | |
91 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
92 Node use = ref.parent; | |
93 if (use is GetField) continue; | |
94 if (use is SetField && use.object == ref) continue; | |
95 return; | |
96 } | |
97 | |
98 Set<FieldElement> reads = new Set<FieldElement>(); | |
99 Set<FieldElement> writes = new Set<FieldElement>(); | |
100 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
101 Node use = ref.parent; | |
102 if (use is GetField) { | |
103 reads.add(use.field); | |
104 } else { | |
105 writes.add(use.field); | |
106 } | |
107 } | |
108 | |
109 // Find the initial values of the fields. A CreateBox has no initial | |
110 // values. CreateInstance has initial values in the order of the fields. | |
111 Map<FieldElement, Primitive> fieldInitialValues = | |
112 <FieldElement, Primitive>{}; | |
113 if (allocation is CreateInstance) { | |
114 int i = 0; | |
115 allocation.classElement.forEachInstanceField( | |
116 (ClassElement enclosingClass, FieldElement field) { | |
117 Primitive argument = allocation.arguments[i++].definition; | |
118 fieldInitialValues[field] = argument; | |
119 }); | |
120 } | |
121 | |
122 // Create [MutableVariable]s for each written field. Initialize the | |
123 // MutableVariable with the value from the allocator, or initialize with a | |
124 // `null` constant if there is not initial value. | |
125 Map<FieldElement, MutableVariable> cells = <FieldElement, MutableVariable>{} ; | |
asgerf
2015/08/31 09:57:30
long line :(
sra1
2015/09/02 01:12:57
Done.
| |
126 InteriorNode insertionPoint = allocation.parent; // LetPrim | |
127 for (FieldElement field in writes) { | |
128 MutableVariable variable = new MutableVariable(field); | |
129 cells[field] = variable; | |
130 Primitive initialValue = fieldInitialValues[field]; | |
131 if (initialValue == null) { | |
132 assert(allocation is CreateBox); | |
133 initialValue = new Constant(new NullConstantValue()); | |
134 LetPrim let = new LetPrim(initialValue); | |
135 let.primitive.parent = let; | |
136 insertionPoint = insertAtBody(insertionPoint, let); | |
137 } | |
138 LetMutable let = new LetMutable(variable, initialValue); | |
139 let.value.parent = let; | |
140 insertionPoint = insertAtBody(insertionPoint, let); | |
141 } | |
142 | |
143 // Replace references with MutableVariable operations or references to the | |
144 // field's value. | |
145 for (Reference ref = allocation.firstRef; ref != null; ref = ref.next) { | |
146 Node use = ref.parent; | |
147 if (use is GetField) { | |
148 GetField getField = use; | |
149 MutableVariable variable = cells[getField.field]; | |
150 if (variable != null) { | |
151 GetMutable getter = new GetMutable(variable); | |
152 getter.variable.parent = getter; | |
153 getter.substituteFor(getField); | |
154 getField.parent.primitive = getter; // Replace primitive of LetPrim. | |
155 deletePrimitive(getField); | |
156 } else { | |
157 Primitive value = fieldInitialValues[getField.field]; | |
158 value.substituteFor(getField); | |
159 deleteLetPrimOf(getField); | |
160 } | |
161 } else if (use is SetField && use.object == ref) { | |
162 SetField setField = use; | |
163 MutableVariable variable = cells[setField.field]; | |
164 Primitive value = setField.value.definition; | |
165 SetMutable setter = new SetMutable(variable, value); | |
166 setter.variable.parent = setter; | |
167 setter.value.parent = setter; | |
168 setter.substituteFor(setField); | |
169 setField.parent.primitive = setter; // Replace primitive of LetPrim. | |
170 deletePrimitive(setField); | |
171 } else { | |
172 throw 'unexpected use: $use'; | |
173 } | |
174 } | |
175 | |
176 // Delete [allocation] since that might 'free' another scalar replacement | |
177 // candidate by deleting the last non-field-access. | |
178 deleteLetPrimOf(allocation); | |
179 } | |
180 | |
181 InteriorNode insertAtBody(InteriorNode insertionPoint, InteriorNode let) { | |
182 let.parent = insertionPoint; | |
183 let.body = insertionPoint.body; | |
184 let.body.parent = let; | |
185 insertionPoint.body = let; | |
186 return let; | |
187 } | |
188 | |
189 void deleteLetPrimOf(Primitive primitive) { | |
190 assert(primitive.hasNoUses); | |
191 LetPrim letPrim = primitive.parent; | |
192 Node child = letPrim.body; | |
193 InteriorNode parent = letPrim.parent; | |
194 child.parent = parent; | |
195 parent.body = child; | |
196 | |
197 deletePrimitive(primitive); | |
198 } | |
199 | |
200 void deletePrimitive(Primitive primitive) { | |
201 assert(primitive.hasNoUses); | |
202 removalVisitor.visit(primitive); | |
203 } | |
204 | |
205 void reconsider(Definition node) { | |
206 if (node is CreateInstance || node is CreateBox) { | |
207 if (node == _current) return; | |
208 print('reconsider $node'); | |
asgerf
2015/08/31 09:57:30
Stray print call
sra1
2015/09/02 01:12:57
Done.
| |
209 enqueue(node); | |
210 } | |
211 } | |
212 | |
213 void enqueue(Primitive node) { | |
214 assert(node is CreateInstance || node is CreateBox); | |
215 if (_allocations.contains(node)) return; | |
216 _allocations.add(node); | |
217 _queue.add(node); | |
218 } | |
219 | |
220 // -------------------------- Visitor overrides ------------------------------ | |
221 void visit(Node node) { node.accept(this); } | |
asgerf
2015/08/31 09:57:30
The visit method is not necessary when extending R
sra1
2015/09/02 01:12:57
Done.
| |
222 | |
223 void visitCreateInstance(CreateInstance node) { | |
224 enqueue(node); | |
225 } | |
226 | |
227 void visitCreateBox(CreateBox node) { | |
228 enqueue(node); | |
229 } | |
230 } | |
231 | |
232 | |
233 /// Visit a just-deleted subterm and unlink all [Reference]s in it. Reconsider | |
234 /// allocations for sclara replacement. | |
asgerf
2015/08/31 09:57:30
sclara -> scalar
sra1
2015/09/02 01:12:57
Done.
| |
235 class ScalarReplacementRemovalVisitor extends RecursiveVisitor { | |
236 ScalarReplacementVisitor process; | |
237 | |
238 ScalarReplacementRemovalVisitor(this.process); | |
239 | |
240 processReference(Reference reference) { | |
241 process.reconsider(reference.definition); | |
242 reference.unlink(); | |
243 } | |
244 } | |
OLD | NEW |