| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |