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 library dart2js.cps_ir.share_final_fields; | |
6 | |
7 import 'optimizers.dart'; | |
8 import 'cps_ir_nodes.dart'; | |
9 import 'loop_hierarchy.dart'; | |
10 import 'cps_fragment.dart'; | |
11 import '../constants/values.dart'; | |
12 import '../elements/elements.dart'; | |
13 import '../js_backend/backend_helpers.dart' show BackendHelpers; | |
14 import '../js_backend/js_backend.dart' show JavaScriptBackend; | |
15 import '../types/types.dart' show TypeMask; | |
16 import '../io/source_information.dart' show SourceInformation; | |
17 | |
18 /// Removes redundant GetField operations. | |
19 /// | |
20 /// The pass performs these optimizations for field loads. | |
21 ///- share GetFields of final fields when one is in scope of the other. | |
22 ///- pull GetField operations out of loops. | |
23 class ShareFinalFields extends TrampolineRecursiveVisitor implements Pass { | |
24 String get passName => 'Share final fields'; | |
25 | |
26 /// The innermost loop containing a given primitive. | |
27 final Map<Primitive, Continuation> loopHeaderFor = | |
28 <Primitive, Continuation>{}; | |
29 | |
30 /// An interceptor currently in scope for a given primitive. | |
31 final Map<Primitive, Interceptor> interceptorFor = <Primitive, Interceptor>{}; | |
asgerf
2015/10/30 09:57:46
Unused field
| |
32 | |
33 // field -> receiver -> GetField | |
34 Map<FieldElement, Map<Primitive, Primitive>> fieldValues = | |
35 <FieldElement, Map<Primitive, Primitive>>{}; | |
36 | |
37 /// Interceptors that have been hoisted out of a given loop. | |
38 final Map<Continuation, List<GetField>> loopHoistedGetters = | |
39 <Continuation, List<GetField>>{}; | |
40 | |
41 JavaScriptBackend backend; | |
42 LoopHierarchy loopHierarchy; | |
43 Continuation currentLoopHeader; | |
44 | |
45 ShareFinalFields(this.backend); | |
46 | |
47 BackendHelpers get helpers => backend.helpers; | |
48 | |
49 void rewrite(FunctionDefinition node) { | |
50 loopHierarchy = new LoopHierarchy(node); | |
51 visit(node.body); | |
52 } | |
53 | |
54 @override | |
55 Expression traverseContinuation(Continuation cont) { | |
56 Continuation oldLoopHeader = currentLoopHeader; | |
57 currentLoopHeader = loopHierarchy.getLoopHeader(cont); | |
58 for (Parameter parameter in cont.parameters) { | |
59 loopHeaderFor[parameter] = currentLoopHeader; | |
60 } | |
61 if (cont.isRecursive) { | |
62 pushAction(() { | |
63 // After the loop body has been processed, all values hoisted to this | |
64 // loop fall out of scope and should be removed from the environment. | |
65 List<GetField> hoisted = loopHoistedGetters[cont]; | |
66 if (hoisted != null) { | |
67 for (GetField primitive in hoisted) { | |
68 Primitive refinedReceiver = primitive.object.definition; | |
69 Primitive receiver = refinedReceiver.effectiveDefinition; | |
70 var map = fieldValues[primitive.field]; | |
71 assert(map[receiver] == primitive); | |
72 map.remove(receiver); | |
73 } | |
74 } | |
75 }); | |
76 } | |
77 pushAction(() { | |
78 currentLoopHeader = oldLoopHeader; | |
79 }); | |
80 return cont.body; | |
81 } | |
82 | |
83 Continuation getCurrentOuterLoop({Continuation scope}) { | |
84 Continuation inner = null, outer = currentLoopHeader; | |
85 while (outer != scope) { | |
86 inner = outer; | |
87 outer = loopHierarchy.getEnclosingLoop(outer); | |
88 } | |
89 return inner; | |
90 } | |
91 | |
92 @override | |
93 Expression traverseLetPrim(LetPrim node) { | |
94 loopHeaderFor[node.primitive] = currentLoopHeader; | |
95 Expression next = node.body; | |
96 if (node.primitive is! GetField) { | |
97 return next; | |
98 } | |
99 GetField primitive = node.primitive; | |
100 FieldElement field = primitive.field; | |
101 | |
102 if (!shouldShareField(field)) { | |
103 return next; | |
104 } | |
105 | |
106 Primitive refinedReceiver = primitive.object.definition; | |
107 Primitive receiver = refinedReceiver.effectiveDefinition; | |
108 | |
109 // Try to reuse an existing load for the same input. | |
110 var map = fieldValues.putIfAbsent(field, () => <Primitive,Primitive>{}); | |
111 Primitive existing = map[receiver]; | |
112 if (existing != null) { | |
113 existing.substituteFor(primitive); | |
114 primitive.destroy(); | |
115 node.remove(); | |
116 return next; | |
117 } | |
118 | |
119 map[receiver] = primitive; | |
120 | |
121 if (primitive.objectIsNotNull) { | |
122 // Determine how far the GetField can be lifted. The outermost loop that | |
123 // contains the input binding should also contain the load. | |
124 // Don't move above a refinement guard since that might be unsafe. | |
125 // TODO(sra): We can move above a refinement guard provided the input is | |
126 // still safe (non-null). | |
127 Continuation referencedLoop = | |
128 lowestCommonAncestor(loopHeaderFor[refinedReceiver], | |
129 currentLoopHeader); | |
130 if (referencedLoop != currentLoopHeader) { | |
131 Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop); | |
132 LetCont loopBinding = hoistTarget.parent; | |
133 node.remove(); | |
134 node.insertAbove(loopBinding); | |
135 // Remove the hoisted operations from the environment after processing | |
136 // the loop. | |
137 loopHoistedGetters | |
138 .putIfAbsent(hoistTarget, () => <GetField>[]) | |
139 .add(primitive); | |
140 return next; | |
141 } | |
142 } | |
143 | |
144 pushAction(() { | |
145 var map = fieldValues[field]; | |
146 assert(map[receiver] == primitive); | |
147 map.remove(receiver); | |
148 }); | |
149 return next; | |
150 } | |
151 | |
152 bool shouldShareField(FieldElement field) { | |
153 return backend.compiler.world.fieldNeverChanges(field); | |
154 } | |
155 | |
156 | |
157 /// Returns the the innermost loop that effectively encloses both | |
158 /// c1 and c2 (or `null` if there is no such loop). | |
159 Continuation lowestCommonAncestor(Continuation c1, Continuation c2) { | |
160 int d1 = getDepth(c1), d2 = getDepth(c2); | |
161 while (c1 != c2) { | |
162 if (d1 <= d2) { | |
163 c2 = loopHierarchy.getEnclosingLoop(c2); | |
164 d2 = getDepth(c2); | |
165 } else { | |
166 c1 = loopHierarchy.getEnclosingLoop(c1); | |
167 d1 = getDepth(c1); | |
168 } | |
169 } | |
170 return c1; | |
171 } | |
172 | |
173 int getDepth(Continuation loop) { | |
174 if (loop == null) return -1; | |
175 return loopHierarchy.loopDepth[loop]; | |
176 } | |
177 } | |
OLD | NEW |