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

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

Issue 1234753003: dart2js cps: Rewrite mutable variables to continuation parameters. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Adjust doc comment Created 5 years, 5 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) 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.mutable_ssa;
6
7 import 'cps_ir_nodes.dart';
8 import 'optimizers.dart';
9
10 /// Determines which mutable variables should be rewritten to phi assignments
11 /// in this pass.
12 ///
13 /// We do not rewrite variables that have an assignment inside a try block that
14 /// does not contain its declaration.
15 class MutableVariablePreanalysis extends RecursiveVisitor {
16 // Number of try blocks enclosing the current position.
17 int currentDepth = 0;
18
19 /// Number of try blocks enclosing the declaration of a given mutable
20 /// variable.
21 ///
22 /// All mutable variables seen will be present in the map after the analysis.
23 Map<MutableVariable, int> variableDepth = <MutableVariable, int>{};
24
25 /// Variables with an assignment inside a try block that does not contain
26 /// its declaration.
27 Set<MutableVariable> hasAssignmentInTry = new Set<MutableVariable>();
28
29 void visitLetHandler(LetHandler node) {
30 ++currentDepth;
31 visit(node.body);
32 --currentDepth;
33 visit(node.handler);
34 }
35
36 void processLetMutable(LetMutable node) {
37 variableDepth[node.variable] = currentDepth;
38 }
39
40 void processSetMutableVariable(SetMutableVariable node) {
41 MutableVariable variable = node.variable.definition;
42 if (currentDepth > variableDepth[variable]) {
43 hasAssignmentInTry.add(variable);
44 }
45 }
46
47 /// True if there are no mutable variables or they are all assigned inside
48 /// a try block. In this case, there is nothing to do and the pass should
49 /// be skipped.
50 bool get allMutablesAreAssignedInTryBlocks {
51 return hasAssignmentInTry.length == variableDepth.length;
52 }
53 }
54
55 /// Replaces mutable variables with continuation parameters, effectively
56 /// bringing them into SSA form.
57 ///
58 /// This pass is intended to clean up mutable variables that were introduced
59 /// by an optimization in the type propagation pass.
60 ///
61 /// This implementation potentially creates a lot of redundant and dead phi
62 /// parameters. These will be cleaned up by redundant phi elimination and
63 /// shrinking reductions.
64 ///
65 /// Discussion:
66 /// For methods with a lot of mutable variables, creating all the spurious
67 /// parameters might be too expensive. If this is the case, we should
68 /// improve this pass to avoid most spurious parameters in practice.
69 class MutableVariableEliminator implements Pass {
70 String get passName => 'Mutable variable elimination';
71
72 /// Mutable variables currently in scope, in order of declaration.
73 /// This list determines the order of the corresponding phi parameters.
74 final List<MutableVariable> mutableVariables = <MutableVariable>[];
75
76 /// Number of phi parameters added to the given continuation.
77 final Map<Continuation, int> continuationPhiCount = <Continuation, int>{};
78
79 /// Stack of yet unprocessed continuations interleaved with the
80 /// mutable variables currently in scope.
81 ///
82 /// Continuations are processed when taken off the stack and mutable
83 /// variables fall out of scope (i.e. removed from [mutableVariables]) when
84 /// taken off the stack.
85 final List<StackItem> stack = <StackItem>[];
86
87 MutableVariablePreanalysis analysis;
88
89 void rewrite(FunctionDefinition node) {
90 analysis = new MutableVariablePreanalysis()..visit(node);
91 if (analysis.allMutablesAreAssignedInTryBlocks) {
92 // Skip the pass if there is nothing to do.
93 return;
94 }
95 processBlock(node.body, <MutableVariable, Primitive>{});
96 while (stack.isNotEmpty) {
97 StackItem item = stack.removeLast();
98 if (item is ContinuationItem) {
99 processBlock(item.continuation.body, item.environment);
100 } else {
101 assert(item is VariableItem);
102 mutableVariables.removeLast();
103 }
104 }
105 }
106
107 bool shouldRewrite(MutableVariable variable) {
108 return !analysis.hasAssignmentInTry.contains(variable);
109 }
110
111 bool isJoinContinuation(Continuation cont) {
112 return !cont.hasExactlyOneUse ||
113 cont.firstRef.parent is InvokeContinuation;
114 }
115
116 void removeNode(InteriorNode node) {
117 InteriorNode parent = node.parent;
118 parent.body = node.body;
119 node.body.parent = parent;
120 }
121
122 /// If some useful source information is attached to exactly one of the
123 /// two definitions, the information is copied onto the other.
124 void merge(MutableVariable variable, Primitive value) {
karlklose 2015/07/14 08:39:44 Maybe call this 'mergeHints.'
asgerf 2015/07/14 09:00:22 Done.
125 if (variable.hint == null) {
126 variable.hint = value.hint;
127 } else if (value.hint == null) {
128 value.hint = variable.hint;
129 }
130 }
131
132 /// Processes a basic block, replacing mutable variable uses with direct
133 /// references to their values.
134 ///
135 /// [environment] is the current value of each mutable variable. The map
136 /// will be mutated during the processing.
137 ///
138 /// Continuations to be processed are put on the stack for later processing.
139 void processBlock(Expression node,
140 Map<MutableVariable, Primitive> environment) {
141 while (node is! TailExpression) {
karlklose 2015/07/14 08:39:44 Consider using a for-loop instead to make the trav
asgerf 2015/07/14 09:00:22 Nice idea! Done.
142 if (node is LetMutable && shouldRewrite(node.variable)) {
143 // Put the new mutable variable on the stack while processing the body.
karlklose 2015/07/14 08:39:44 Merge comment with comment below.
asgerf 2015/07/14 09:00:22 Done.
144 mutableVariables.add(node.variable);
145
146 // Pop it off again when done with the body.
147 stack.add(new VariableItem());
148
149 // Put the initial value into the environment.
150 Primitive value = node.value.definition;
151 environment[node.variable] = value;
152
153 // Preserve variable names.
154 merge(node.variable, value);
155
156 // Remove the mutable variable binding.
157 node.value.unlink();
158 removeNode(node);
159 } else if (node is SetMutableVariable &&
160 shouldRewrite(node.variable.definition)) {
161 // As above, update the environment, preserve variables and remove
162 // the mutable variable assignment.
163 MutableVariable variable = node.variable.definition;
164 environment[variable] = node.value.definition;
165 merge(variable, node.value.definition);
166 node.value.unlink();
167 removeNode(node);
168 } else if (node is LetPrim && node.primitive is GetMutableVariable) {
169 GetMutableVariable getter = node.primitive;
170 MutableVariable variable = getter.variable.definition;
171 if (shouldRewrite(variable)) {
172 // Replace with the reaching definition from the environment.
173 Primitive value = environment[variable];
174 value.substituteFor(getter);
175 merge(variable, value);
176 removeNode(node);
177 }
178 } else if (node is LetCont) {
179 // Create phi parameters for each join continuation bound here, and put
180 // them on the stack for later processing.
181 // Note that non-join continuations are handled at the use-site.
182 for (Continuation cont in node.continuations) {
183 if (!isJoinContinuation(cont)) continue;
184 // Create a phi parameter for every mutable variable in scope.
185 // At the same time, build the environment to use for processing
186 // the continuation (mapping mutables to phi parameters).
187 continuationPhiCount[cont] = mutableVariables.length;
188 Map<MutableVariable, Primitive> environment =
189 <MutableVariable, Primitive>{};
190 for (MutableVariable variable in mutableVariables) {
191 Parameter phi = new Parameter(variable.hint);
192 cont.parameters.add(phi);
193 phi.parent = cont;
194 environment[variable] = phi;
195 }
196 stack.add(new ContinuationItem(cont, environment));
197 }
198 } else if (node is LetHandler) {
199 // Process the catch block later and continue into the try block.
200 // We can use the same environment object for the try and catch blocks.
201 // The current environment bindings cannot change inside the try block
202 // because we exclude all variables assigned inside a try block.
203 // The environment might be extended with more bindings before we
204 // analyze the catch block, but that's ok.
205 stack.add(new ContinuationItem(node.handler, environment));
206 }
207
208 node = node.next;
209 }
210
211 // Analyze the terminal node.
212 if (node is InvokeContinuation) {
213 Continuation cont = node.continuation.definition;
214 if (cont.isReturnContinuation) return;
215 // This is a call to a join continuation. Add arguments for the phi
216 // parameters that were added to this continuation.
217 int phiCount = continuationPhiCount[cont];
218 for (int i = 0; i < phiCount; ++i) {
219 Primitive value = environment[mutableVariables[i]];
220 Reference<Primitive> arg = new Reference<Primitive>(value);
221 node.arguments.add(arg);
222 arg.parent = node;
223 }
224 } else if (node is Branch) {
225 // Enqueue both branches with the current environment.
226 // Clone the environments once so the processing of one branch does not
227 // mutate the environment needed to process the other branch.
228 stack.add(new ContinuationItem(
229 node.trueContinuation.definition,
230 new Map<MutableVariable, Primitive>.from(environment)));
231 stack.add(new ContinuationItem(
232 node.falseContinuation.definition,
233 environment));
234 } else {
235 assert(node is Throw || node is Unreachable);
236 }
237 }
238 }
239
240 abstract class StackItem {}
241
242 /// Represents a mutable variable that is in scope.
243 ///
244 /// The top-level mutable variable falls out of scope when this item is
245 /// taken off the stack.
246 class VariableItem extends StackItem {}
247
248 /// Represents a yet unprocessed continuation together with the
249 /// environment in which to process it.
250 class ContinuationItem extends StackItem {
251 final Continuation continuation;
252 final Map<MutableVariable, Primitive> environment;
253
254 ContinuationItem(this.continuation, this.environment);
255 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.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