Chromium Code Reviews| 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 final Set<HBasicBlock> loopMarkers; | 17 final Set<HBasicBlock> loopMarkers; |
| 18 Environment() : lives = new Set<HInstruction>(), | 18 Environment() : lives = new Set<HInstruction>(), |
| 19 loopMarkers = new Set<HBasicBlock>(); | 19 loopMarkers = new Set<HBasicBlock>(); |
| 20 Environment.from(Environment other) | 20 Environment.from(Environment other) |
| 21 : lives = new Set<HInstruction>.from(other.lives), | 21 : lives = new Set<HInstruction>.from(other.lives), |
| 22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers); | 22 loopMarkers = new Set<HBasicBlock>.from(other.loopMarkers); |
| 23 | 23 |
| 24 void remove(HInstruction instruction) { | 24 void remove(HInstruction instruction) { |
| 25 lives.remove(instruction); | 25 lives.remove(instruction); |
| 26 } | 26 } |
| 27 | 27 |
| 28 void add(HInstruction instruction) { | 28 void add(HInstruction instruction) { |
| 29 if (!instruction.isCodeMotionInvariant()) { | 29 // If the instruction is a type guard, we add its checked input |
| 30 // instead. This allows sharing the same environment between | |
| 31 // different type guards. | |
| 32 // | |
| 33 // Also, we don't need to add code motion invariant instructions | |
| 34 // in the live set (because we generate them at use-site), except | |
| 35 // for parameters that are not 'this', which is always passed as | |
| 36 // the receiver. | |
| 37 if (instruction is HTypeGuard) { | |
| 38 add(instruction.checkedInput); | |
| 39 } else if (!instruction.isCodeMotionInvariant() | |
| 40 || (instruction is HParameterValue && instruction is !HThis)) { | |
| 30 lives.add(instruction); | 41 lives.add(instruction); |
| 31 } else { | 42 } else { |
| 32 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 43 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 33 add(instruction.inputs[i]); | 44 add(instruction.inputs[i]); |
| 34 } | 45 } |
| 35 } | 46 } |
| 36 } | 47 } |
| 37 | 48 |
| 38 void addLoopMarker(HBasicBlock block) { | 49 void addLoopMarker(HBasicBlock block) { |
| 39 loopMarkers.add(block); | 50 loopMarkers.add(block); |
| 40 } | 51 } |
| 41 | 52 |
| 42 void removeLoopMarker(HBasicBlock block) { | 53 void removeLoopMarker(HBasicBlock block) { |
| 43 loopMarkers.remove(block); | 54 loopMarkers.remove(block); |
| 44 } | 55 } |
| 45 | 56 |
| 46 void addAll(Environment other) { | 57 void addAll(Environment other) { |
| 47 lives.addAll(other.lives); | 58 lives.addAll(other.lives); |
| 48 loopMarkers.addAll(other.loopMarkers); | 59 loopMarkers.addAll(other.loopMarkers); |
| 49 } | 60 } |
| 50 | 61 |
| 51 /** | |
| 52 * Stores all live variables in the guard. The guarded instruction will be the | |
| 53 * last input in the guard's input list. | |
| 54 */ | |
| 55 void storeInGuard(HTypeGuard guard) { | |
| 56 HInstruction guarded = guard.guarded; | |
| 57 List<HInstruction> inputs = guard.inputs; | |
| 58 assert(inputs.length == 1); | |
| 59 inputs.clear(); | |
| 60 // Remove the guarded from the environment, so that we are sure it is last | |
| 61 // when we add it again. | |
| 62 remove(guarded); | |
| 63 inputs.addAll(lives); | |
| 64 inputs.addLast(guarded); | |
| 65 add(guarded); | |
| 66 for (int i = 0; i < inputs.length - 1; i++) { | |
| 67 HInstruction input = inputs[i]; | |
| 68 input.usedBy.add(guard); | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); | 62 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); |
| 73 } | 63 } |
| 74 | 64 |
| 75 | 65 |
| 76 /** | 66 /** |
| 77 * Visits the graph in dominator order and inserts TypeGuards in places where | 67 * Visits the graph in dominator order and inserts TypeGuards in places where |
| 78 * we consider the guard to be of value. | 68 * we consider the guard to be of value. |
| 79 * | 69 * |
| 80 * Might modify the [:propagatedType:] fields of the instructions in an | 70 * Might modify the [:propagatedType:] fields of the instructions in an |
| 81 * inconsistent way. No further analysis should rely on them. | 71 * inconsistent way. No further analysis should rely on them. |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 if (speculativeType == computedType) return false; | 167 if (speculativeType == computedType) return false; |
| 178 // If a bailout check is more expensive than doing the actual operation | 168 // If a bailout check is more expensive than doing the actual operation |
| 179 // don't do it either. | 169 // don't do it either. |
| 180 return typeGuardWouldBeValuable(instruction, speculativeType); | 170 return typeGuardWouldBeValuable(instruction, speculativeType); |
| 181 } | 171 } |
| 182 | 172 |
| 183 void visitInstruction(HInstruction instruction) { | 173 void visitInstruction(HInstruction instruction) { |
| 184 HType speculativeType = instruction.propagatedType; | 174 HType speculativeType = instruction.propagatedType; |
| 185 if (shouldInsertTypeGuard(instruction)) { | 175 if (shouldInsertTypeGuard(instruction)) { |
| 186 List<HInstruction> inputs = <HInstruction>[instruction]; | 176 List<HInstruction> inputs = <HInstruction>[instruction]; |
| 187 HTypeGuard guard = new HTypeGuard(speculativeType, stateId++, inputs); | 177 HInstruction insertionPoint; |
| 178 if (instruction is HPhi) { | |
| 179 insertionPoint = instruction.block.first; | |
| 180 } else if (instruction is HParameterValue) { | |
| 181 // We insert the type guard at the end of the entry block | |
| 182 // because if a parameter is live, it must be kept in the live | |
| 183 // environment. Not doing so would mean we could visit a | |
| 184 // parameter and remove it from the environment before | |
| 185 // visiting a type guard. | |
| 186 insertionPoint = instruction.block.last; | |
| 187 } else { | |
| 188 insertionPoint = instruction.next; | |
| 189 } | |
| 190 // If the previous instruction is also a type guard, then both | |
| 191 // guards have the same environment, and can therefore share the | |
| 192 // same state id. | |
| 193 int state; | |
| 194 if (insertionPoint.previous is HTypeGuard) { | |
| 195 HTypeGuard other = insertionPoint.previous; | |
| 196 state = other.state; | |
| 197 } else { | |
| 198 state = stateId++; | |
| 199 } | |
| 200 HTypeGuard guard = new HTypeGuard(speculativeType, state, inputs); | |
| 188 guard.propagatedType = speculativeType; | 201 guard.propagatedType = speculativeType; |
| 189 work.guards.add(guard); | 202 work.guards.add(guard); |
| 190 instruction.block.rewrite(instruction, guard); | 203 instruction.block.rewrite(instruction, guard); |
| 191 HInstruction insertionPoint = (instruction is HPhi) | |
| 192 ? instruction.block.first | |
| 193 : instruction.next; | |
| 194 insertionPoint.block.addBefore(insertionPoint, guard); | 204 insertionPoint.block.addBefore(insertionPoint, guard); |
| 195 } | 205 } |
| 196 } | 206 } |
| 197 } | 207 } |
| 198 | 208 |
| 199 /** | 209 /** |
| 200 * Computes the environment for each SSA instruction: visits the graph | 210 * Computes the environment for each SSA instruction: visits the graph |
| 201 * in post-dominator order. Removes an instruction from the environment | 211 * in post-dominator order. Removes an instruction from the environment |
| 202 * and adds its inputs to the environment at the instruction's | 212 * and adds its inputs to the environment at the instruction's |
| 203 * definition. | 213 * definition. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 } | 313 } |
| 304 | 314 |
| 305 void visitInstruction(HInstruction instruction) { | 315 void visitInstruction(HInstruction instruction) { |
| 306 environment.remove(instruction); | 316 environment.remove(instruction); |
| 307 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 317 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 308 environment.add(instruction.inputs[i]); | 318 environment.add(instruction.inputs[i]); |
| 309 } | 319 } |
| 310 } | 320 } |
| 311 | 321 |
| 312 void insertCapturedEnvironments() { | 322 void insertCapturedEnvironments() { |
| 323 Map<int, HTypeGuard> seenGuardStates = new Map<int, HTypeGuard>(); | |
| 313 capturedEnvironments.forEach((HTypeGuard guard, Environment env) { | 324 capturedEnvironments.forEach((HTypeGuard guard, Environment env) { |
| 314 env.storeInGuard(guard); | 325 storeInGuard(guard, env.lives, seenGuardStates); |
| 315 }); | 326 }); |
| 316 } | 327 } |
| 328 | |
| 329 /** | |
| 330 * Stores all live variables in the guard. | |
| 331 */ | |
| 332 void storeInGuard(HTypeGuard guard, | |
| 333 Set<HInstruction> lives, | |
| 334 Map<int, HTypeGuard> seenGuardStates) { | |
| 335 HInstruction guarded = guard.guarded; | |
| 336 List<HInstruction> inputs = guard.inputs; | |
| 337 assert(inputs.length == 1); | |
| 338 inputs.clear(); | |
| 339 HTypeGuard other = seenGuardStates[guard.state]; | |
| 340 if (other !== null) { | |
| 341 // The guards are sharing the same state. Also share the same | |
| 342 // environment, in the same order. | |
| 343 inputs.addAll(other.inputs); | |
| 344 assert(inputs.length == lives.length); | |
| 345 } else { | |
| 346 seenGuardStates[guard.state] = guard; | |
| 347 inputs.addAll(lives); | |
| 348 } | |
| 349 | |
| 350 for (int i = 0; i < inputs.length; i++) { | |
| 351 HInstruction input = inputs[i]; | |
| 352 if (input == guarded) { | |
| 353 guard.checkedInputIndex = i; | |
| 354 // No need to update [input.usedBy], the guard is already | |
| 355 // there. | |
| 356 } else { | |
| 357 input.usedBy.add(guard); | |
| 358 } | |
| 359 } | |
| 360 } | |
| 317 } | 361 } |
| 318 | 362 |
| 319 /** | 363 /** |
| 320 * Propagates bailout information to blocks that need it. This visitor | 364 * Propagates bailout information to blocks that need it. This visitor |
| 321 * is run before codegen, to know which blocks have to deal with | 365 * is run before codegen, to know which blocks have to deal with |
| 322 * bailouts. | 366 * bailouts. |
| 323 */ | 367 */ |
| 324 class SsaBailoutPropagator extends HBaseVisitor { | 368 class SsaBailoutPropagator extends HBaseVisitor { |
| 325 final Compiler compiler; | 369 final Compiler compiler; |
| 326 final List<HBasicBlock> blocks; | 370 final List<HBasicBlock> blocks; |
| 327 final List<HLabeledBlockInformation> labeledBlockInformations; | 371 final List<HLabeledBlockInformation> labeledBlockInformations; |
| 372 final Set<HInstruction> generateAtUseSite; | |
| 328 SubGraph subGraph; | 373 SubGraph subGraph; |
| 329 | 374 |
| 330 SsaBailoutPropagator(Compiler this.compiler) | 375 /** |
| 376 * If set to true, the graph has either multiple bailouts in | |
| 377 * different places, or a bailout inside an if or a loop. For such a | |
| 378 * graph, the code generator will emit a generic switch. | |
| 379 */ | |
| 380 bool hasComplexTypeGuards = false; | |
| 381 | |
| 382 /** | |
| 383 * The first type guard in the graph. | |
| 384 */ | |
| 385 HTypeGuard firstTypeGuard; | |
| 386 | |
| 387 /** | |
| 388 * If set, it is the first block in the graph where we generate | |
| 389 * code. Blocks before this one are dead code in the bailout | |
| 390 * version. | |
| 391 */ | |
| 392 | |
| 393 SsaBailoutPropagator(this.compiler, | |
|
kasperl
2012/06/13 07:37:05
Arguments fit on one line.
ngeoffray
2012/06/13 07:41:38
Done.
| |
| 394 this.generateAtUseSite) | |
| 331 : blocks = <HBasicBlock>[], | 395 : blocks = <HBasicBlock>[], |
| 332 labeledBlockInformations = <HLabeledBlockInformation>[]; | 396 labeledBlockInformations = <HLabeledBlockInformation>[]; |
| 333 | 397 |
| 334 void visitGraph(HGraph graph) { | 398 void visitGraph(HGraph graph) { |
| 335 subGraph = new SubGraph(graph.entry, graph.exit); | 399 subGraph = new SubGraph(graph.entry, graph.exit); |
| 336 blocks.addLast(graph.entry); | |
| 337 visitBasicBlock(graph.entry); | 400 visitBasicBlock(graph.entry); |
| 338 blocks.removeLast(); | |
| 339 if (!blocks.isEmpty()) { | 401 if (!blocks.isEmpty()) { |
| 340 compiler.internalError('Bailout propagation', | 402 compiler.internalError('Bailout propagation', |
| 341 node: compiler.currentElement.parseNode(compiler)); | 403 node: compiler.currentElement.parseNode(compiler)); |
| 342 } | 404 } |
| 343 } | 405 } |
| 344 | 406 |
| 345 void visitBasicBlock(HBasicBlock block) { | 407 void visitBasicBlock(HBasicBlock block) { |
| 346 // Abort traversal if we are leaving the currently active sub-graph. | 408 // Abort traversal if we are leaving the currently active sub-graph. |
| 347 if (!subGraph.contains(block)) return; | 409 if (!subGraph.contains(block)) return; |
| 348 | 410 |
| 349 if (block.isLoopHeader()) { | 411 if (block.isLoopHeader()) { |
| 350 blocks.addLast(block); | 412 blocks.addLast(block); |
| 351 } else if (block.isLabeledBlock() && blocks.last() !== block) { | 413 } else if (block.isLabeledBlock() |
| 414 && (blocks.isEmpty() || blocks.last() !== block)) { | |
| 352 HLabeledBlockInformation info = block.blockFlow.body; | 415 HLabeledBlockInformation info = block.blockFlow.body; |
| 353 visitStatements(info.body); | 416 visitStatements(info.body); |
| 354 return; | 417 return; |
| 355 } | 418 } |
| 356 | 419 |
| 357 HInstruction instruction = block.first; | 420 HInstruction instruction = block.first; |
| 358 while (instruction != null) { | 421 while (instruction != null) { |
| 359 instruction.accept(this); | 422 instruction.accept(this); |
| 360 instruction = instruction.next; | 423 instruction = instruction.next; |
| 361 } | 424 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 visitBasicBlock(branchBlock.successors[1]); | 502 visitBasicBlock(branchBlock.successors[1]); |
| 440 // With labeled breaks we can have more dominated blocks. | 503 // With labeled breaks we can have more dominated blocks. |
| 441 if (dominated.length >= 3) { | 504 if (dominated.length >= 3) { |
| 442 for (int i = 2; i < dominated.length; i++) { | 505 for (int i = 2; i < dominated.length; i++) { |
| 443 visitBasicBlock(dominated[i]); | 506 visitBasicBlock(dominated[i]); |
| 444 } | 507 } |
| 445 } | 508 } |
| 446 } | 509 } |
| 447 | 510 |
| 448 visitTypeGuard(HTypeGuard guard) { | 511 visitTypeGuard(HTypeGuard guard) { |
| 449 blocks.forEach((HBasicBlock block) { | 512 if (blocks.isEmpty()) { |
| 450 block.guards.add(guard); | 513 if (firstTypeGuard === null || firstTypeGuard.state === guard.state) { |
| 451 }); | 514 firstTypeGuard = guard; |
| 515 } else { | |
| 516 hasComplexTypeGuards = true; | |
| 517 } | |
| 518 } else { | |
| 519 hasComplexTypeGuards = true; | |
| 520 blocks.forEach((HBasicBlock block) { | |
| 521 block.guards.add(guard); | |
| 522 }); | |
| 523 } | |
| 452 } | 524 } |
| 453 } | 525 } |
| OLD | NEW |