OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 class BailoutInfo { | |
6 int instructionId; | |
7 int bailoutId; | |
8 BailoutInfo(this.instructionId, this.bailoutId); | |
9 } | |
10 | |
11 /** | |
12 * Keeps track of the execution environment for instructions. An | |
13 * execution environment contains the SSA instructions that are live. | |
14 */ | |
15 class Environment { | |
16 final Set<HInstruction> lives; | |
17 final Set<HBasicBlock> loopMarkers; | |
18 Environment() : lives = new Set<HInstruction>(), | |
19 loopMarkers = new Set<HBasicBlock>(); | |
20 Environment.from(Environment other) | |
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); | |
27 | |
28 void remove(HInstruction instruction) { | |
29 lives.remove(instruction); | |
30 } | |
31 | |
32 void add(HInstruction instruction) { | |
33 if (!instruction.isCodeMotionInvariant()) { | |
34 lives.add(instruction); | |
35 } else { | |
36 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | |
37 add(instruction.inputs[i]); | |
38 } | |
39 } | |
40 } | |
41 | |
42 void addLoopMarker(HBasicBlock block) { | |
43 loopMarkers.add(block); | |
44 } | |
45 | |
46 void removeLoopMarker(HBasicBlock block) { | |
47 loopMarkers.remove(block); | |
48 } | |
49 | |
50 void addAll(Environment other) { | |
51 lives.addAll(other.lives); | |
52 loopMarkers.addAll(other.loopMarkers); | |
53 } | |
54 | |
55 List<HInstruction> buildAndSetLast(HInstruction instruction) { | |
56 remove(instruction); | |
57 List<HInstruction> result = new List<HInstruction>.from(lives); | |
58 result.addLast(instruction); | |
59 add(instruction); | |
60 return result; | |
61 } | |
62 | |
63 bool isEmpty() => lives.isEmpty(); | |
64 bool contains(HInstruction instruction) => lives.contains(instruction); | |
65 bool containsLoopMarker(HBasicBlock block) => loopMarkers.contains(block); | |
66 void clear() => lives.clear(); | |
67 } | |
68 | |
69 /** | |
70 * Computes the environment for each SSA instruction: visits the graph | |
71 * in post-dominator order. Removes an instruction from the environment | |
72 * and adds its inputs to the environment at the instruction's | |
73 * definition. | |
74 * | |
75 * At the end of the computation, insert type guards in the graph. | |
76 */ | |
77 class SsaTypeGuardBuilder extends HBaseVisitor implements OptimizationPhase { | |
78 final Compiler compiler; | |
79 final WorkItem work; | |
80 final String name = 'SsaTypeGuardBuilder'; | |
81 Environment environment; | |
82 SubGraph subGraph; | |
83 | |
84 final Map<HInstruction, Environment> capturedEnvironments; | |
85 | |
86 SsaTypeGuardBuilder(Compiler this.compiler, WorkItem this.work) | |
87 : capturedEnvironments = new Map<HInstruction, Environment>(); | |
88 | |
89 | |
90 void visitGraph(HGraph graph) { | |
91 subGraph = new SubGraph(graph.entry, graph.exit); | |
92 environment = new Environment(); | |
93 visitBasicBlock(graph.entry); | |
94 if (!environment.isEmpty()) { | |
95 compiler.internalError('Bailout environment computation', | |
96 node: compiler.currentElement.parseNode(compiler)); | |
97 } | |
98 insertCapturedEnvironments(); | |
99 } | |
100 | |
101 void maybeCaptureEnvironment(HInstruction instruction) { | |
102 if (shouldCaptureEnvironment(instruction)) { | |
103 capturedEnvironments[instruction] = new Environment.from(environment); | |
104 } | |
105 } | |
106 | |
107 void visitSubGraph(SubGraph newSubGraph) { | |
108 SubGraph oldSubGraph = subGraph; | |
109 subGraph = newSubGraph; | |
110 visitBasicBlock(subGraph.start); | |
111 subGraph = oldSubGraph; | |
112 } | |
113 | |
114 void visitBasicBlock(HBasicBlock block) { | |
115 if (!subGraph.contains(block)) return; | |
116 block.last.accept(this); | |
117 | |
118 HInstruction instruction = block.last.previous; | |
119 while (instruction != null) { | |
120 HInstruction previous = instruction.previous; | |
121 instruction.accept(this); | |
122 instruction = previous; | |
123 } | |
124 | |
125 for (HPhi phi = block.phis.first; phi != null; phi = phi.next) { | |
126 phi.accept(this); | |
127 } | |
128 | |
129 if (block.isLoopHeader()) { | |
130 // If the block is a loop header, we need to change every uses | |
131 // of its loop marker to the current set of live instructions. | |
132 // For example with the following loop (read the example in | |
133 // reverse): | |
134 // | |
135 // while (true) { <-- (4) update the marker with the environment | |
136 // use(x); <-- (3) environment = {x} | |
137 // bailout; <-- (2) has the marker when computed | |
138 // } <-- (1) create a loop marker | |
139 // | |
140 // The bailout instruction first captures the marker, but it | |
141 // will be replaced by the live environment at the loop entry, | |
142 // in this case {x}. | |
143 environment.removeLoopMarker(block); | |
144 capturedEnvironments.forEach((instruction, env) { | |
145 if (env.containsLoopMarker(block)) { | |
146 env.removeLoopMarker(block); | |
147 env.addAll(environment); | |
148 } | |
149 }); | |
150 } | |
151 } | |
152 | |
153 void visitPhi(HPhi phi) { | |
154 maybeCaptureEnvironment(phi); | |
155 environment.remove(phi); | |
156 // If the block is a loop header, we insert the incoming values of | |
157 // the phis, and remove the loop values. | |
158 // If the block is not a loop header, the phi will be handled by | |
159 // the control flow instruction. | |
160 if (phi.block.isLoopHeader()) { | |
161 environment.add(phi.inputs[0]); | |
162 for (int i = 1, len = phi.inputs.length; i < len; i++) { | |
163 environment.remove(phi.inputs[i]); | |
164 } | |
165 } | |
166 } | |
167 | |
168 void visitInstruction(HInstruction instruction) { | |
169 maybeCaptureEnvironment(instruction); | |
170 environment.remove(instruction); | |
171 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | |
172 environment.add(instruction.inputs[i]); | |
173 } | |
174 } | |
175 | |
176 void visitIf(HIf instruction) { | |
177 HIfBlockInformation info = instruction.blockInformation; | |
178 HBasicBlock joinBlock = info.joinBlock; | |
179 | |
180 if (joinBlock != null) { | |
181 visitBasicBlock(joinBlock); | |
182 } | |
183 Environment thenEnvironment = new Environment.from(environment); | |
184 Environment elseEnvironment = environment; | |
185 | |
186 if (joinBlock != null) { | |
187 for (HPhi phi = joinBlock.phis.first; phi != null; phi = phi.next) { | |
188 if (joinBlock.predecessors[0] == instruction.block) { | |
189 // We're dealing with an 'if' without an else branch. | |
190 thenEnvironment.add(phi.inputs[1]); | |
191 elseEnvironment.add(phi.inputs[0]); | |
192 } else { | |
193 thenEnvironment.add(phi.inputs[0]); | |
194 elseEnvironment.add(phi.inputs[1]); | |
195 } | |
196 } | |
197 } | |
198 | |
199 if (instruction.hasElse) { | |
200 environment = elseEnvironment; | |
201 visitSubGraph(info.elseGraph); | |
202 elseEnvironment = environment; | |
203 } | |
204 | |
205 environment = thenEnvironment; | |
206 visitSubGraph(info.thenGraph); | |
207 environment.addAll(elseEnvironment); | |
208 } | |
209 | |
210 void visitGoto(HGoto goto) { | |
211 HBasicBlock block = goto.block; | |
212 if (block.successors[0].dominator != block) return; | |
213 visitBasicBlock(block.successors[0]); | |
214 } | |
215 | |
216 void visitBreak(HBreak breakInstruction) { | |
217 compiler.unimplemented("SsaEnvironmentBuilder.visitBreak"); | |
218 } | |
219 | |
220 void visitLoopBranch(HLoopBranch branch) { | |
221 HBasicBlock block = branch.block; | |
222 | |
223 // Visit the code after the loop. | |
224 visitBasicBlock(block.successors[1]); | |
225 | |
226 Environment joinEnvironment = environment; | |
227 | |
228 // When visiting the loop body, we don't require the live | |
229 // instructions after the loop body to be in the environment. They | |
230 // will be either recomputed in the loop header, or inserted | |
231 // with the loop marker. We still need to transfer existing loop | |
232 // markers from the current environment, because they must be live | |
233 // for this loop body. | |
234 environment = new Environment.forLoopBody(environment); | |
235 | |
236 // Put the loop phis in the environment. | |
237 HBasicBlock header = block.isLoopHeader() ? block : block.parentLoopHeader; | |
238 for (HPhi phi = header.phis.first; phi != null; phi = phi.next) { | |
239 for (int i = 1, len = phi.inputs.length; i < len; i++) { | |
240 environment.add(phi.inputs[i]); | |
241 } | |
242 } | |
243 | |
244 // Add the loop marker | |
245 environment.addLoopMarker(header); | |
246 | |
247 if (!branch.isDoWhile()) { | |
248 assert(block.successors[0] == block.dominatedBlocks[0]); | |
249 visitBasicBlock(block.successors[0]); | |
250 } | |
251 | |
252 // We merge the environment required by the code after the loop, | |
253 // and the code inside the loop. | |
254 environment.addAll(joinEnvironment); | |
255 } | |
256 | |
257 // Deal with all kinds of control flow instructions. In case we add | |
258 // a new one, we will hit an internal error. | |
259 void visitExit(HExit exit) {} | |
260 | |
261 void visitReturn(HReturn instruction) { | |
262 environment.clear(); | |
263 visitInstruction(instruction); | |
264 } | |
265 | |
266 void visitThrow(HThrow instruction) { | |
267 environment.clear(); | |
268 visitInstruction(instruction); | |
269 } | |
270 | |
271 void visitControlFlow(HControlFlow instruction) { | |
272 compiler.internalError('Control flow instructions already dealt with.', | |
273 instruction: instruction); | |
274 } | |
275 | |
276 bool shouldCaptureEnvironment(HInstruction instruction) { | |
277 return instruction.type.isKnown() && !instruction.hasExpectedType(); | |
278 } | |
279 | |
280 void insertCapturedEnvironments() { | |
281 work.guards = <HTypeGuard>[]; | |
282 int state = 1; | |
283 capturedEnvironments.forEach((HInstruction instruction, Environment env) { | |
284 List<HInstruction> inputs = env.buildAndSetLast(instruction); | |
285 HTypeGuard guard = new HTypeGuard(state++, inputs); | |
286 work.guards.add(guard); | |
287 instruction.block.rewrite(instruction, guard); | |
288 HInstruction insertionPoint = (instruction is HPhi) | |
289 ? instruction.block.first | |
290 : instruction.next; | |
291 insertionPoint.block.addBefore(insertionPoint, guard); | |
292 }); | |
293 } | |
294 } | |
295 | |
296 /** | |
297 * Propagates bailout information to blocks that need it. This visitor | |
298 * is run before codegen, to know which blocks have to deal with | |
299 * bailouts. | |
300 */ | |
301 class SsaBailoutPropagator extends HBaseVisitor { | |
302 final Compiler compiler; | |
303 final List<HBasicBlock> blocks; | |
304 | |
305 SsaBailoutPropagator(Compiler this.compiler) : blocks = <HBasicBlock>[]; | |
306 | |
307 void visitGraph(HGraph graph) { | |
308 blocks.addLast(graph.entry); | |
309 visitBasicBlock(graph.entry); | |
310 } | |
311 | |
312 void visitBasicBlock(HBasicBlock block) { | |
313 if (block.isLoopHeader()) blocks.addLast(block); | |
314 HInstruction instruction = block.first; | |
315 while (instruction != null) { | |
316 instruction.accept(this); | |
317 instruction = instruction.next; | |
318 } | |
319 } | |
320 | |
321 void enterBlock(HBasicBlock block) { | |
322 if (block == null) return; | |
323 blocks.addLast(block); | |
324 visitBasicBlock(block); | |
325 blocks.removeLast(); | |
326 } | |
327 | |
328 void visitIf(HIf instruction) { | |
329 enterBlock(instruction.thenBlock); | |
330 enterBlock(instruction.elseBlock); | |
331 enterBlock(instruction.joinBlock); | |
332 } | |
333 | |
334 void visitGoto(HGoto goto) { | |
335 HBasicBlock block = goto.block; | |
336 if (block.successors[0].dominator != block) return; | |
337 visitBasicBlock(block.successors[0]); | |
338 } | |
339 | |
340 void visitLoopBranch(HLoopBranch branch) { | |
341 HBasicBlock branchBlock = branch.block; | |
342 if (!branch.isDoWhile()) { | |
343 // Not a do while loop. We visit the body of the loop. | |
344 visitBasicBlock(branchBlock.dominatedBlocks[0]); | |
345 } | |
346 blocks.removeLast(); | |
347 visitBasicBlock(branchBlock.successors[1]); | |
348 } | |
349 | |
350 // Deal with all kinds of control flow instructions. In case we add | |
351 // a new one, we will hit an internal error. | |
352 void visitExit(HExit exit) {} | |
353 void visitReturn(HReturn instruction) {} | |
354 void visitThrow(HThrow instruction) {} | |
355 | |
356 void visitControlFlow(HControlFlow instruction) { | |
357 compiler.internalError('Control flow instructions already dealt with.', | |
358 instruction: instruction); | |
359 } | |
360 | |
361 visitTypeGuard(HTypeGuard guard) { | |
362 blocks.forEach((HBasicBlock block) { | |
363 block.guards.add(guard); | |
364 }); | |
365 } | |
366 } | |
OLD | NEW |