| 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 |