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

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

Issue 1444363002: dart2js cps: Global value numbering and loop-invariant code motion. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rebase 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart2js.cps_ir.share_interceptors; 5 library dart2js.cps_ir.optimize_interceptors;
6 6
7 import 'optimizers.dart'; 7 import 'optimizers.dart';
8 import 'cps_ir_nodes.dart'; 8 import 'cps_ir_nodes.dart';
9 import 'loop_hierarchy.dart'; 9 import 'loop_hierarchy.dart';
10 import 'cps_fragment.dart'; 10 import 'cps_fragment.dart';
11 import '../constants/values.dart'; 11 import '../constants/values.dart';
12 import '../elements/elements.dart'; 12 import '../elements/elements.dart';
13 import '../js_backend/backend_helpers.dart' show BackendHelpers; 13 import '../js_backend/backend_helpers.dart' show BackendHelpers;
14 import '../js_backend/js_backend.dart' show JavaScriptBackend; 14 import '../js_backend/js_backend.dart' show JavaScriptBackend;
15 import '../types/types.dart' show TypeMask; 15 import '../types/types.dart' show TypeMask;
16 import '../io/source_information.dart' show SourceInformation; 16 import '../io/source_information.dart' show SourceInformation;
17 17
18 /// Removes redundant `getInterceptor` calls. 18 /// Replaces `getInterceptor` calls with interceptor constants when possible,
19 /// 19 /// or with "almost constant" expressions like "x && CONST" when the input
20 /// The pass performs three optimizations for interceptors: 20 /// is either null or has a known interceptor.
21 ///- pull interceptors out of loops 21 //
22 ///- replace interceptors with constants 22 // TODO(asgerf): Compute intercepted classes in this pass.
23 ///- share interceptors when one is in scope of the other 23 class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
24 class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass { 24 String get passName => 'Optimize interceptors';
25 String get passName => 'Share interceptors';
26
27 /// The innermost loop containing a given primitive.
28 final Map<Primitive, Continuation> loopHeaderFor =
29 <Primitive, Continuation>{};
30
31 /// An interceptor currently in scope for a given primitive.
32 final Map<Primitive, Interceptor> interceptorFor = <Primitive, Interceptor>{};
33
34 /// Interceptors that have been hoisted out of a given loop.
35 final Map<Continuation, List<Interceptor>> loopHoistedInterceptors =
36 <Continuation, List<Interceptor>>{};
37 25
38 JavaScriptBackend backend; 26 JavaScriptBackend backend;
39 LoopHierarchy loopHierarchy; 27 LoopHierarchy loopHierarchy;
40 Continuation currentLoopHeader; 28 Continuation currentLoopHeader;
41 29
42 ShareInterceptors(this.backend); 30 OptimizeInterceptors(this.backend);
43 31
44 BackendHelpers get helpers => backend.helpers; 32 BackendHelpers get helpers => backend.helpers;
45 33
46 void rewrite(FunctionDefinition node) { 34 void rewrite(FunctionDefinition node) {
35 // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all
36 // we want is to hoist constants out of loops.
47 loopHierarchy = new LoopHierarchy(node); 37 loopHierarchy = new LoopHierarchy(node);
48 visit(node.body); 38 visit(node.body);
49 new ShareConstants().visit(node); 39 new ShareConstants().visit(node);
50 } 40 }
51 41
52 @override 42 @override
53 Expression traverseContinuation(Continuation cont) { 43 Expression traverseContinuation(Continuation cont) {
54 Continuation oldLoopHeader = currentLoopHeader; 44 Continuation oldLoopHeader = currentLoopHeader;
55 currentLoopHeader = loopHierarchy.getLoopHeader(cont); 45 currentLoopHeader = loopHierarchy.getLoopHeader(cont);
56 for (Parameter param in cont.parameters) {
57 loopHeaderFor[param] = currentLoopHeader;
58 }
59 if (cont.isRecursive) {
60 pushAction(() {
61 // After the loop body has been processed, all interceptors hoisted
62 // to this loop fall out of scope and should be removed from the
63 // environment.
64 List<Interceptor> hoisted = loopHoistedInterceptors[cont];
65 if (hoisted != null) {
66 for (Interceptor interceptor in hoisted) {
67 Primitive input = interceptor.input.definition;
68 assert(interceptorFor[input] == interceptor);
69 interceptorFor.remove(input);
70 constifyInterceptor(interceptor);
71 }
72 }
73 });
74 }
75 pushAction(() { 46 pushAction(() {
76 currentLoopHeader = oldLoopHeader; 47 currentLoopHeader = oldLoopHeader;
77 }); 48 });
78 return cont.body; 49 return cont.body;
79 } 50 }
80 51
81 /// If only one method table can be returned by the given interceptor, 52 /// If only one method table can be returned by the given interceptor,
82 /// returns a constant for that method table. 53 /// returns a constant for that method table.
83 InterceptorConstantValue getInterceptorConstant(Interceptor node) { 54 InterceptorConstantValue getInterceptorConstant(Interceptor node) {
84 if (node.interceptedClasses.length == 1 && 55 if (node.interceptedClasses.length == 1 &&
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 cps.invokeContinuation(cont, [constantPrim]); 137 cps.invokeContinuation(cont, [constantPrim]);
167 cps.context = cont; 138 cps.context = cont;
168 cps.insertAbove(let); 139 cps.insertAbove(let);
169 interceptor..replaceUsesWith(param)..destroy(); 140 interceptor..replaceUsesWith(param)..destroy();
170 let.remove(); 141 let.remove();
171 } 142 }
172 } 143 }
173 144
174 @override 145 @override
175 Expression traverseLetPrim(LetPrim node) { 146 Expression traverseLetPrim(LetPrim node) {
176 loopHeaderFor[node.primitive] = currentLoopHeader;
177 Expression next = node.body; 147 Expression next = node.body;
178 if (node.primitive is! Interceptor) { 148 if (node.primitive is Interceptor) {
179 return next; 149 constifyInterceptor(node.primitive);
180 } 150 }
181 Interceptor interceptor = node.primitive;
182 Primitive input = interceptor.input.definition;
183
184 // Try to reuse an existing interceptor for the same input.
185 Interceptor existing = interceptorFor[input];
186 if (existing != null) {
187 existing.interceptedClasses.addAll(interceptor.interceptedClasses);
188 existing.flags |= interceptor.flags;
189 interceptor..replaceUsesWith(existing)..destroy();
190 node.remove();
191 return next;
192 }
193
194 // Put this interceptor in the environment.
195 interceptorFor[input] = interceptor;
196
197 // Determine how far the interceptor can be lifted. The outermost loop
198 // that contains the input binding should also contain the interceptor
199 // binding.
200 Continuation referencedLoop =
201 lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
202 if (referencedLoop != currentLoopHeader) {
203 Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
204 LetCont loopBinding = hoistTarget.parent;
205 node.remove();
206 node.insertAbove(loopBinding);
207 // Remove the interceptor from the environment after processing the loop.
208 loopHoistedInterceptors
209 .putIfAbsent(hoistTarget, () => <Interceptor>[])
210 .add(interceptor);
211 } else {
212 // Remove the interceptor from the environment when it falls out of scope.
213 pushAction(() {
214 assert(interceptorFor[input] == interceptor);
215 interceptorFor.remove(input);
216
217 // Now that the final set of intercepted classes has been seen, try to
218 // replace it with a constant.
219 constifyInterceptor(interceptor);
220 });
221 }
222
223 return next; 151 return next;
224 } 152 }
225
226 /// Returns the the innermost loop that effectively encloses both
227 /// c1 and c2 (or `null` if there is no such loop).
228 Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
229 int d1 = getDepth(c1), d2 = getDepth(c2);
230 while (c1 != c2) {
231 if (d1 <= d2) {
232 c2 = loopHierarchy.getEnclosingLoop(c2);
233 d2 = getDepth(c2);
234 } else {
235 c1 = loopHierarchy.getEnclosingLoop(c1);
236 d1 = getDepth(c1);
237 }
238 }
239 return c1;
240 }
241
242 int getDepth(Continuation loop) {
243 if (loop == null) return -1;
244 return loopHierarchy.loopDepth[loop];
245 }
246 } 153 }
247 154
155 /// Shares interceptor constants when one is in scope of another.
156 ///
157 /// Interceptor optimization runs after GVN, hence this clean-up step is needed.
158 ///
159 /// TODO(asgerf): Handle in separate constant optimization pass? With some other
160 /// constant-related optimizations, like cloning small constants at use-site.
248 class ShareConstants extends TrampolineRecursiveVisitor { 161 class ShareConstants extends TrampolineRecursiveVisitor {
249 Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{}; 162 Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
250 163
251 Expression traverseLetPrim(LetPrim node) { 164 Expression traverseLetPrim(LetPrim node) {
252 Expression next = node.body; 165 Expression next = node.body;
253 if (node.primitive is Constant && shouldShareConstant(node.primitive)) { 166 if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
254 Constant prim = node.primitive; 167 Constant prim = node.primitive;
255 Constant existing = sharedConstantFor[prim.value]; 168 Constant existing = sharedConstantFor[prim.value];
256 if (existing != null) { 169 if (existing != null) {
257 existing.useElementAsHint(prim.hint); 170 existing.useElementAsHint(prim.hint);
258 prim..replaceUsesWith(existing)..destroy(); 171 prim..replaceUsesWith(existing)..destroy();
259 node.remove(); 172 node.remove();
260 return next; 173 return next;
261 } 174 }
262 sharedConstantFor[prim.value] = prim; 175 sharedConstantFor[prim.value] = prim;
263 pushAction(() { 176 pushAction(() {
264 assert(sharedConstantFor[prim.value] == prim); 177 assert(sharedConstantFor[prim.value] == prim);
265 sharedConstantFor.remove(prim.value); 178 sharedConstantFor.remove(prim.value);
266 }); 179 });
267 } 180 }
268 return next; 181 return next;
269 } 182 }
270 183
271 bool shouldShareConstant(Constant constant) { 184 bool shouldShareConstant(Constant constant) {
272 return constant.value.isInterceptor; 185 return constant.value.isInterceptor;
273 } 186 }
274 } 187 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart ('k') | pkg/compiler/lib/src/cps_ir/optimizers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698