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

Side by Side Diff: frog/leg/ssa/bailout.dart

Issue 9668029: Fix a long-standing bug in the computation of the live environments for bailouts. When visiting a l… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « frog/leg/emitter.dart ('k') | frog/leg/ssa/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 class BailoutInfo { 5 class BailoutInfo {
6 int instructionId; 6 int instructionId;
7 int bailoutId; 7 int bailoutId;
8 BailoutInfo(this.instructionId, this.bailoutId); 8 BailoutInfo(this.instructionId, this.bailoutId);
9 } 9 }
10 10
11 /** 11 /**
12 * Keeps track of the execution environment for instructions. An 12 * Keeps track of the execution environment for instructions. An
13 * execution environment contains the SSA instructions that are live. 13 * execution environment contains the SSA instructions that are live.
14 */ 14 */
15 class Environment { 15 class Environment {
16 final Set<HInstruction> lives; 16 final Set<HInstruction> lives;
17 Environment() : lives = new Set<HInstruction>(); 17 final Set<HBasicBlock> loopMarkers;
18 Environment() : lives = new Set<HInstruction>(),
19 loopMarkers = new Set<HBasicBlock>();
18 Environment.from(Environment other) 20 Environment.from(Environment other)
19 : lives = new Set<HInstruction>.from(other.lives); 21 : lives = new Set<HInstruction>.from(other.lives),
22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers);
23
24 Environment.forLoopBody(Environment other)
25 : lives = new Set<HInstruction>(),
26 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers);
20 27
21 void remove(HInstruction instruction) { 28 void remove(HInstruction instruction) {
22 lives.remove(instruction); 29 lives.remove(instruction);
23 } 30 }
24 31
25 void add(HInstruction instruction) { 32 void add(HInstruction instruction) {
26 if (!instruction.generateAtUseSite()) { 33 if (!instruction.generateAtUseSite()) {
27 lives.add(instruction); 34 lives.add(instruction);
28 } else { 35 } else {
29 for (int i = 0, len = instruction.inputs.length; i < len; i++) { 36 for (int i = 0, len = instruction.inputs.length; i < len; i++) {
30 add(instruction.inputs[i]); 37 add(instruction.inputs[i]);
31 } 38 }
32 } 39 }
33 } 40 }
34 41
42 void addLoopMarker(HBasicBlock block) {
43 loopMarkers.add(block);
44 }
45
46 void removeLoopMarker(HBasicBlock block) {
47 loopMarkers.remove(block);
48 }
49
35 void addAll(Environment other) { 50 void addAll(Environment other) {
36 lives.addAll(other.lives); 51 lives.addAll(other.lives);
52 loopMarkers.addAll(other.loopMarkers);
37 } 53 }
38 54
39 List<HInstruction> buildAndSetLast(HInstruction instruction) { 55 List<HInstruction> buildAndSetLast(HInstruction instruction) {
40 remove(instruction); 56 remove(instruction);
41 List<HInstruction> result = new List<HInstruction>.from(lives); 57 List<HInstruction> result = new List<HInstruction>.from(lives);
42 result.addLast(instruction); 58 result.addLast(instruction);
43 add(instruction); 59 add(instruction);
44 return result; 60 return result;
45 } 61 }
46 62
47 bool isEmpty() => lives.isEmpty(); 63 bool isEmpty() => lives.isEmpty();
48 bool contains(HInstruction instruction) => lives.contains(instruction); 64 bool contains(HInstruction instruction) => lives.contains(instruction);
65 bool containsLoopMarker(HBasicBlock block) => loopMarkers.contains(block);
49 void clear() => lives.clear(); 66 void clear() => lives.clear();
50 } 67 }
51 68
52 /** 69 /**
53 * Computes the environment for each SSA instruction: visits the graph 70 * Computes the environment for each SSA instruction: visits the graph
54 * in post-dominator order. Removes an instruction from the environment 71 * in post-dominator order. Removes an instruction from the environment
55 * and adds its inputs to the environment at the instruction's 72 * and adds its inputs to the environment at the instruction's
56 * definition. 73 * definition.
57 */ 74 */
58 class SsaEnvironmentBuilder extends HBaseVisitor { 75 class SsaEnvironmentBuilder extends HBaseVisitor {
59 final Compiler compiler; 76 final Compiler compiler;
60 Environment environment; 77 Environment environment;
61 SubGraph subGraph; 78 SubGraph subGraph;
62 79
63 SsaEnvironmentBuilder(Compiler this.compiler); 80 final Map<HInstruction, Environment> capturedEnvironments;
81
82 SsaEnvironmentBuilder(Compiler this.compiler)
83 : capturedEnvironments = new Map<HInstruction, Environment>();
64 84
65 void visitGraph(HGraph graph) { 85 void visitGraph(HGraph graph) {
66 subGraph = new SubGraph(graph.entry, graph.exit); 86 subGraph = new SubGraph(graph.entry, graph.exit);
67 environment = new Environment(); 87 environment = new Environment();
68 visitBasicBlock(graph.entry); 88 visitBasicBlock(graph.entry);
69 if (!environment.isEmpty()) { 89 if (!environment.isEmpty()) {
70 compiler.internalError('Bailout environment computation', 90 compiler.internalError('Bailout environment computation',
71 node: compiler.currentElement.parseNode(compiler)); 91 node: compiler.currentElement.parseNode(compiler));
72 } 92 }
93 insertCapturedEnvironments();
94 }
95
96 abstract void insertCapturedEnvironments();
97 abstract bool shouldCaptureEnvironment(HInstruction instruction);
98
99 void maybeCaptureEnvironment(HInstruction instruction) {
100 if (shouldCaptureEnvironment(instruction)) {
101 capturedEnvironments[instruction] = new Environment.from(environment);
102 }
73 } 103 }
74 104
75 void visitSubGraph(SubGraph newSubGraph) { 105 void visitSubGraph(SubGraph newSubGraph) {
76 SubGraph oldSubGraph = subGraph; 106 SubGraph oldSubGraph = subGraph;
77 subGraph = newSubGraph; 107 subGraph = newSubGraph;
78 visitBasicBlock(subGraph.start); 108 visitBasicBlock(subGraph.start);
79 subGraph = oldSubGraph; 109 subGraph = oldSubGraph;
80 } 110 }
81 111
82 void visitBasicBlock(HBasicBlock block) { 112 void visitBasicBlock(HBasicBlock block) {
83 if (!subGraph.contains(block)) return; 113 if (!subGraph.contains(block)) return;
84 block.last.accept(this); 114 block.last.accept(this);
85 115
86 HInstruction instruction = block.last.previous; 116 HInstruction instruction = block.last.previous;
87 while (instruction != null) { 117 while (instruction != null) {
88 HInstruction previous = instruction.previous; 118 HInstruction previous = instruction.previous;
89 instruction.accept(this); 119 instruction.accept(this);
90 instruction = previous; 120 instruction = previous;
91 } 121 }
92 122
93 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { 123 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) {
94 phi.accept(this); 124 phi.accept(this);
95 } 125 }
126
127 if (block.isLoopHeader()) {
128 // If the block is a loop header, we need to change every uses
129 // of its loop marker to the current set of live instructions.
130 // For example with the following loop (read the example in
131 // reverse):
132 //
133 // while (true) { <-- (4) update the marker with the environment
134 // use(x); <-- (3) environment = {x}
135 // bailout; <-- (2) has the marker when computed
136 // } <-- (1) create a loop marker
137 //
138 // The bailout instruction first captures the marker, but it
139 // will be replaced by the live environment at the loop entry,
140 // in this case {x}.
141 environment.removeLoopMarker(block);
142 capturedEnvironments.forEach((instruction, env) {
143 if (env.containsLoopMarker(block)) {
144 env.removeLoopMarker(block);
145 env.addAll(environment);
146 }
147 });
148 }
96 } 149 }
97 150
98 void visitPhi(HPhi phi) { 151 void visitPhi(HPhi phi) {
152 maybeCaptureEnvironment(phi);
99 environment.remove(phi); 153 environment.remove(phi);
100 // If the block is a loop header, we insert the incoming values of 154 // If the block is a loop header, we insert the incoming values of
101 // the phis, and remove the loop values. 155 // the phis, and remove the loop values.
102 // If the block is not a loop header, the phi will be handled by 156 // If the block is not a loop header, the phi will be handled by
103 // the control flow instruction. 157 // the control flow instruction.
104 if (phi.block.isLoopHeader()) { 158 if (phi.block.isLoopHeader()) {
105 environment.add(phi.inputs[0]); 159 environment.add(phi.inputs[0]);
106 for (int i = 1, len = phi.inputs.length; i < len; i++) { 160 for (int i = 1, len = phi.inputs.length; i < len; i++) {
107 environment.remove(phi.inputs[i]); 161 environment.remove(phi.inputs[i]);
108 } 162 }
109 } 163 }
110 } 164 }
111 165
112 void visitInstruction(HInstruction instruction) { 166 void visitInstruction(HInstruction instruction) {
167 maybeCaptureEnvironment(instruction);
113 environment.remove(instruction); 168 environment.remove(instruction);
114 for (int i = 0, len = instruction.inputs.length; i < len; i++) { 169 for (int i = 0, len = instruction.inputs.length; i < len; i++) {
115 environment.add(instruction.inputs[i]); 170 environment.add(instruction.inputs[i]);
116 } 171 }
117 } 172 }
118 173
119 void visitIf(HIf instruction) { 174 void visitIf(HIf instruction) {
120 HIfBlockInformation info = instruction.blockInformation; 175 HIfBlockInformation info = instruction.blockInformation;
121 HBasicBlock joinBlock = info.joinBlock; 176 HBasicBlock joinBlock = info.joinBlock;
122 177
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
158 213
159 void visitBreak(HBreak breakInstruction) { 214 void visitBreak(HBreak breakInstruction) {
160 unimplemented(); 215 unimplemented();
161 } 216 }
162 217
163 void visitLoopBranch(HLoopBranch branch) { 218 void visitLoopBranch(HLoopBranch branch) {
164 HBasicBlock block = branch.block; 219 HBasicBlock block = branch.block;
165 220
166 // Visit the code after the loop. 221 // Visit the code after the loop.
167 visitBasicBlock(block.successors[1]); 222 visitBasicBlock(block.successors[1]);
168 // TODO(ngeoffray): Remove the instructions of the loop-exit from
169 // the environment.
170 223
224 Environment joinEnvironment = environment;
225
226 // When visiting the loop body, we don't require the live
227 // instructions after the loop body to be in the environment. They
228 // will be either recomputed in the loop header, or inserted
229 // with the loop marker. We still need to transfer existing loop
230 // markers from the current environment, because they must be live
231 // for this loop body.
232 environment = new Environment.forLoopBody(environment);
233
234 // Put the loop phis in the environment.
171 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; 235 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader;
172 // Put the loop phis in the environment.
173 for (HPhi phi = header.phis.first; phi != null; phi = phi.next) { 236 for (HPhi phi = header.phis.first; phi != null; phi = phi.next) {
174 for (int i = 1, len = phi.inputs.length; i < len; i++) { 237 for (int i = 1, len = phi.inputs.length; i < len; i++) {
175 environment.add(phi.inputs[i]); 238 environment.add(phi.inputs[i]);
176 } 239 }
177 } 240 }
178 241
242 // Add the loop marker
243 environment.addLoopMarker(header);
244
179 if (!branch.isDoWhile()) { 245 if (!branch.isDoWhile()) {
180 assert(block.successors[0] == block.dominatedBlocks[0]); 246 assert(block.successors[0] == block.dominatedBlocks[0]);
181 visitBasicBlock(block.successors[0]); 247 visitBasicBlock(block.successors[0]);
182 } 248 }
249
250 // We merge the environment required by the code after the loop,
251 // and the code inside the loop.
252 environment.addAll(joinEnvironment);
183 } 253 }
184 254
185 // Deal with all kinds of control flow instructions. In case we add 255 // Deal with all kinds of control flow instructions. In case we add
186 // a new one, we will hit an internal error. 256 // a new one, we will hit an internal error.
187 void visitExit(HExit exit) {} 257 void visitExit(HExit exit) {}
188 258
189 void visitReturn(HReturn instruction) { 259 void visitReturn(HReturn instruction) {
190 environment.clear(); 260 environment.clear();
191 visitInstruction(instruction); 261 visitInstruction(instruction);
192 } 262 }
(...skipping 12 matching lines...) Expand all
205 /** 275 /**
206 * Visits the graph and replaces guards with guards that capture the 276 * Visits the graph and replaces guards with guards that capture the
207 * environment. 277 * environment.
208 */ 278 */
209 class SsaTypeGuardBuilder extends SsaEnvironmentBuilder implements OptimizationP hase { 279 class SsaTypeGuardBuilder extends SsaEnvironmentBuilder implements OptimizationP hase {
210 280
211 final String name = 'SsaTypeGuardBuilder'; 281 final String name = 'SsaTypeGuardBuilder';
212 282
213 SsaTypeGuardBuilder(Compiler compiler) : super(compiler); 283 SsaTypeGuardBuilder(Compiler compiler) : super(compiler);
214 284
215 void tryInsertTypeGuard(HInstruction instruction, 285 bool shouldCaptureEnvironment(HInstruction instruction) {
216 HInstruction insertionPoint) { 286 return instruction.type.isKnown() && !instruction.hasExpectedType();
217 // If we found a type for the instruction, but the instruction 287 }
218 // does not know if it produces that type, add a type guard. 288
219 if (instruction.type.isKnown() && !instruction.hasExpectedType()) { 289 void insertCapturedEnvironments() {
220 // The type guard expects the guarded instruction to be at the 290 capturedEnvironments.forEach((HInstruction instruction, Environment env) {
221 // end of the inputs. 291 List<HInstruction> inputs = env.buildAndSetLast(instruction);
222 List<HInstruction> inputs = environment.buildAndSetLast(instruction);
223 HTypeGuard guard = 292 HTypeGuard guard =
224 new HTypeGuard(instruction.type, inputs, instruction.id); 293 new HTypeGuard(instruction.type, inputs, instruction.id);
225 // Remove the instruction's type, the guard is now holding that 294 // Remove the instruction's type, the guard is now holding that
226 // type. 295 // type.
227 instruction.type = HType.UNKNOWN; 296 instruction.type = HType.UNKNOWN;
228 instruction.block.rewrite(instruction, guard); 297 instruction.block.rewrite(instruction, guard);
298 HInstruction insertionPoint = (instruction is HPhi)
299 ? phi.block.first
300 : instruction.next;
229 insertionPoint.block.addBefore(insertionPoint, guard); 301 insertionPoint.block.addBefore(insertionPoint, guard);
230 } 302 });
231 }
232
233
234 void visitInstruction(HInstruction instruction) {
235 tryInsertTypeGuard(instruction, instruction.next);
236 super.visitInstruction(instruction);
237 }
238
239 void visitPhi(HPhi phi) {
240 tryInsertTypeGuard(phi, phi.block.first);
241 super.visitPhi(phi);
242 } 303 }
243 } 304 }
244 305
245 /* 306 /*
246 * Visits the graph and inserts [HBailoutTarget] instructions where 307 * Visits the graph and inserts [HBailoutTarget] instructions where
247 * the optimized version had [HTypeGuard] instructions. 308 * the optimized version had [HTypeGuard] instructions.
248 */ 309 */
249 class SsaBailoutBuilder extends SsaEnvironmentBuilder implements OptimizationPha se { 310 class SsaBailoutBuilder extends SsaEnvironmentBuilder implements OptimizationPha se {
250 final Map<int, BailoutInfo> bailouts; 311 final Map<int, BailoutInfo> bailouts;
251 final String name = 'SsaBailoutBuilder'; 312 final String name = 'SsaBailoutBuilder';
252 313
253 SsaBailoutBuilder(Compiler compiler, this.bailouts) : super(compiler); 314 SsaBailoutBuilder(Compiler compiler, this.bailouts) : super(compiler);
254 315
255 void checkBailout(HInstruction instruction, HInstruction insertionPoint) { 316 bool shouldCaptureEnvironment(HInstruction instruction) {
256 BailoutInfo info = bailouts[instruction.id]; 317 return bailouts[instruction.id] != null;
257 if (info != null) {
258 List<HInstruction> inputs = environment.buildAndSetLast(instruction);
259 HBailoutTarget bailout = new HBailoutTarget(info.bailoutId, inputs);
260 instruction.block.addBefore(insertionPoint, bailout);
261 }
262 } 318 }
263 319
264 void visitInstruction(HInstruction instruction) { 320 void insertCapturedEnvironments() {
265 checkBailout(instruction, instruction.next); 321 capturedEnvironments.forEach((HInstruction instruction, Environment env) {
266 super.visitInstruction(instruction); 322 BailoutInfo info = bailouts[instruction.id];
267 } 323 List<HInstruction> inputs = env.buildAndSetLast(instruction);
268 324 HBailoutTarget bailout = new HBailoutTarget(info.bailoutId, inputs);
269 void visitPhi(HPhi phi) { 325 HInstruction insertionPoint = (instruction is HPhi)
270 checkBailout(phi, phi.block.first); 326 ? phi.block.first
271 super.visitPhi(phi); 327 : instruction.next;
328 instruction.block.addBefore(insertionPoint, bailout);
329 });
272 } 330 }
273 } 331 }
274 332
275 /** 333 /**
276 * Propagates bailout information to blocks that need it. This visitor 334 * Propagates bailout information to blocks that need it. This visitor
277 * is run before codegen, to know which blocks have to deal with 335 * is run before codegen, to know which blocks have to deal with
278 * bailouts. 336 * bailouts.
279 */ 337 */
280 class SsaBailoutPropagator extends HBaseVisitor { 338 class SsaBailoutPropagator extends HBaseVisitor {
281 final Compiler compiler; 339 final Compiler compiler;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 compiler.internalError('Control flow instructions already dealt with.', 394 compiler.internalError('Control flow instructions already dealt with.',
337 instruction: instruction); 395 instruction: instruction);
338 } 396 }
339 397
340 visitBailoutTarget(HBailoutTarget target) { 398 visitBailoutTarget(HBailoutTarget target) {
341 blocks.forEach((HBasicBlock block) { 399 blocks.forEach((HBasicBlock block) {
342 block.bailouts.add(target); 400 block.bailouts.add(target);
343 }); 401 });
344 } 402 }
345 } 403 }
OLDNEW
« no previous file with comments | « frog/leg/emitter.dart ('k') | frog/leg/ssa/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698