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

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

Issue 1364703004: dart2js cps: LICM, GVN, and constify for interceptors in one pass. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 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
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.share_interceptors;
6 6
7 import 'optimizers.dart';
7 import 'cps_ir_nodes.dart'; 8 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart'; 9 import 'loop_hierarchy.dart';
9 import 'type_mask_system.dart';
10 import '../elements/elements.dart';
11 import '../constants/values.dart'; 10 import '../constants/values.dart';
12 11
13 /// Merges calls to `getInterceptor` when one call is in scope of the other. 12 /// Removes redundant `getInterceptor` calls.
14 ///
15 /// Also replaces `getInterceptor` calls with an interceptor constant when
16 /// the result is known statically, and there is no interceptor already in
17 /// scope.
18 /// 13 ///
19 /// Should run after [LoopInvariantCodeMotion] so interceptors lifted out from 14 /// The pass performs three optimizations for interceptors:
20 /// loops can be merged. 15 ///- pull interceptors out of loops
16 ///- replace interceptors with constants
17 ///- share interceptors when one is in scope of the other
21 class ShareInterceptors extends RecursiveVisitor implements Pass { 18 class ShareInterceptors extends RecursiveVisitor implements Pass {
22 String get passName => 'Share interceptors'; 19 String get passName => 'Share interceptors';
23 20
21 /// The innermost loop containing a given primitive.
22 final Map<Primitive, Continuation> loopHeaderFor =
23 <Primitive, Continuation>{};
24
25 /// An interceptor currently in scope for a given primitive.
24 final Map<Primitive, Primitive> interceptorFor = 26 final Map<Primitive, Primitive> interceptorFor =
25 <Primitive, Primitive>{}; 27 <Primitive, Primitive>{};
26 28
29 /// A primitive currently in scope holding a given interceptor constant.
27 final Map<ConstantValue, Primitive> sharedConstantFor = 30 final Map<ConstantValue, Primitive> sharedConstantFor =
28 <ConstantValue, Primitive>{}; 31 <ConstantValue, Primitive>{};
29 32
33 /// Interceptors to be hoisted out of the given loop.
34 final Map<Continuation, List<Primitive>> loopHoistedInterceptors =
35 <Continuation, List<Primitive>>{};
36
37 LoopHierarchy loopHierarchy;
38 Continuation currentLoopHeader;
39
30 void rewrite(FunctionDefinition node) { 40 void rewrite(FunctionDefinition node) {
41 loopHierarchy = new LoopHierarchy(node);
31 visit(node.body); 42 visit(node.body);
32 } 43 }
33 44
34 @override 45 @override
46 Expression traverseContinuation(Continuation cont) {
47 Continuation oldLoopHeader = currentLoopHeader;
48 pushAction(() {
49 currentLoopHeader = oldLoopHeader;
50 });
51 currentLoopHeader = loopHierarchy.getLoopHeader(cont);
52 for (Parameter param in cont.parameters) {
53 loopHeaderFor[param] = currentLoopHeader;
54 }
55 if (cont.isRecursive) {
56 pushAction(() {
57 // After the loop body has been processed, all interceptors hoisted
58 // to this loop fall out of scope and should be removed from the
59 // environment.
60 List<Primitive> hoisted = loopHoistedInterceptors[cont];
61 if (hoisted != null) {
62 for (Primitive interceptor in hoisted) {
63 if (interceptor is Interceptor) {
64 Primitive input = interceptor.input.definition;
65 assert(interceptorFor[input] == interceptor);
66 interceptorFor.remove(input);
67 } else if (interceptor is Constant) {
68 assert(sharedConstantFor[interceptor.value] == interceptor);
69 sharedConstantFor.remove(interceptor.value);
70 } else {
71 throw "Unexpected interceptor: $interceptor";
72 }
73 }
74 }
75 });
76 }
77 return cont.body;
78 }
79
80 @override
35 Expression traverseLetPrim(LetPrim node) { 81 Expression traverseLetPrim(LetPrim node) {
36 if (node.primitive is Interceptor) { 82 loopHeaderFor[node.primitive] = currentLoopHeader;
37 Interceptor interceptor = node.primitive; 83 Expression next = node.body;
38 Primitive input = interceptor.input.definition; 84 if (node.primitive is! Interceptor) {
39 Primitive existing = interceptorFor[input]; 85 return next;
86 }
87 Interceptor interceptor = node.primitive;
88 Primitive input = interceptor.input.definition;
89
90 // Try to reuse an existing interceptor for the same input.
91 Primitive existing = interceptorFor[input];
92 if (existing != null) {
93 if (existing is Interceptor) {
94 existing.interceptedClasses.addAll(interceptor.interceptedClasses);
95 }
96 existing.substituteFor(interceptor);
97 InteriorNode parent = node.parent;
98 parent.body = node.body;
99 node.body.parent = parent;
100 interceptor.input.unlink();
sra1 2015/09/25 18:26:17 Perhaps we should add a more general dead node rem
asgerf 2015/09/28 10:50:14 I was reluctant to do this, but I admit it does ma
101 return next;
102 }
103
104 // There is no interceptor obtained from this particular input, but
105 // there might one obtained from another input that is known to
106 // have the same result, so try to reuse that.
107 InterceptorConstantValue constant = interceptor.constantValue;
108 if (constant != null) {
109 existing = sharedConstantFor[constant];
40 if (existing != null) { 110 if (existing != null) {
41 if (existing is Interceptor) {
42 existing.interceptedClasses.addAll(interceptor.interceptedClasses);
43 }
44 existing.substituteFor(interceptor); 111 existing.substituteFor(interceptor);
45 } else if (interceptor.constantValue != null) { 112 InteriorNode parent = node.parent;
46 InterceptorConstantValue value = interceptor.constantValue; 113 parent.body = node.body;
47 // There is no interceptor obtained from this particular input, but 114 node.body.parent = parent;
48 // there might one obtained from another input that is known to 115 interceptor.input.unlink();
sra1 2015/09/25 18:26:17 These five lines are the same as above. If we don'
asgerf 2015/09/28 10:50:14 (see above)
49 // have the same result, so try to reuse that. 116 return next;
50 Primitive shared = sharedConstantFor[value]; 117 }
51 if (shared != null) { 118
52 shared.substituteFor(interceptor); 119 // The interceptor could not be shared. Replace it with a constant.
53 } else { 120 Constant constantPrim = new Constant(constant);
54 Constant constant = new Constant(value); 121 node.primitive = constantPrim;
55 constant.hint = interceptor.hint; 122 constantPrim.hint = interceptor.hint;
56 node.primitive = constant; 123 constantPrim.type = interceptor.type;
57 constant.parent = node; 124 constantPrim.substituteFor(interceptor);
58 interceptor.input.unlink(); 125 interceptor.input.unlink();
59 constant.substituteFor(interceptor); 126 sharedConstantFor[constant] = constantPrim;
60 interceptorFor[input] = constant; 127 } else {
61 sharedConstantFor[value] = constant; 128 interceptorFor[input] = interceptor;
62 pushAction(() { 129 }
63 interceptorFor.remove(input); 130
64 sharedConstantFor.remove(value); 131 // Determine the outermost loop where the input to the interceptor call
65 132 // is available. Constant interceptors take no input and can thus be
66 if (constant.hasExactlyOneUse) { 133 // hoisted all way to the top-level.
67 // As a heuristic, always sink single-use interceptor constants 134 Continuation referencedLoop = constant != null
68 // to their use, even if it is inside a loop. 135 ? null
69 Expression use = getEnclosingExpression(constant.firstRef.parent); 136 : lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
70 InteriorNode parent = node.parent; 137 if (referencedLoop != currentLoopHeader) {
71 parent.body = node.body; 138 // [referencedLoop] contains the binding for [input], so we cannot hoist
72 node.body.parent = parent; 139 // the interceptor outside that loop. Find the loop nested one level
73 140 // inside referencedLoop, and hoist the interceptor just outside that one.
74 InteriorNode useParent = use.parent; 141 Continuation loop = currentLoopHeader;
75 useParent.body = node; 142 Continuation enclosing = loopHierarchy.getEnclosingLoop(loop);
76 node.body = use; 143 while (enclosing != referencedLoop) {
77 use.parent = node; 144 assert(loop != null);
78 node.parent = useParent; 145 loop = enclosing;
79 } 146 enclosing = loopHierarchy.getEnclosingLoop(loop);
80 }); 147 }
81 } 148 assert(loop != null);
149
150 // Remove LetPrim from its current position.
151 InteriorNode parent = node.parent;
152 parent.body = node.body;
153 node.body.parent = parent;
154
155 // Insert the LetPrim immediately before the loop.
156 LetCont loopBinding = loop.parent;
157 InteriorNode newParent = loopBinding.parent;
158 newParent.body = node;
159 node.body = loopBinding;
160 loopBinding.parent = node;
161 node.parent = newParent;
162
163 // A different loop now contains the interceptor.
164 loopHeaderFor[node.primitive] = enclosing;
165
166 // Register the interceptor as hoisted to that loop, so it will be
167 // removed from the environment when it falls out of scope.
168 loopHoistedInterceptors
169 .putIfAbsent(loop, () => <Primitive>[])
170 .add(node.primitive);
171 } else if (constant != null) {
172 // The LetPrim was not hoisted. Remove the bound interceptor from the
173 // environment when leaving the LetPrim body.
174 pushAction(() {
175 assert(sharedConstantFor[constant] == node.primitive);
176 sharedConstantFor.remove(constant);
177 });
178 } else {
179 pushAction(() {
180 assert(interceptorFor[input] == node.primitive);
181 interceptorFor.remove(input);
182 });
183 }
184 return next;
185 }
186
187 /// Returns the the innermost loop that effectively encloses both
188 /// c1 and c2 (or `null` if there is no such loop).
189 Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
190 int d1 = getDepth(c1), d2 = getDepth(c2);
191 while (c1 != c2) {
192 if (d1 <= d2) {
193 c2 = loopHierarchy.getEnclosingLoop(c2);
194 d2 = getDepth(c2);
82 } else { 195 } else {
83 interceptorFor[input] = interceptor; 196 c1 = loopHierarchy.getEnclosingLoop(c1);
84 pushAction(() { 197 d1 = getDepth(c1);
85 interceptorFor.remove(input); 198 }
86 }); 199 }
87 } 200 return c1;
88 } 201 }
89 return node.body; 202
90 } 203 int getDepth(Continuation loop) {
91 204 if (loop == null) return -1;
92 Expression getEnclosingExpression(Node node) { 205 return loopHierarchy.loopDepth[loop];
93 while (node is! Expression) {
94 node = node.parent;
95 }
96 return node;
97 } 206 }
98 } 207 }
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