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 // We don't need to an code motion invariant instructions in the |
|
kasperl
2012/06/12 12:18:40
need to an code?
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 30 // live set except for parameters that are not 'this' ('this' is | |
|
kasperl
2012/06/12 12:18:40
('this' is -> , which is
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 31 // always passed as the receiver). | |
| 32 if (!instruction.isCodeMotionInvariant() | |
|
floitsch
2012/06/12 15:01:17
Explain that this is, because we generate these at
| |
| 33 || (instruction is HParameterValue && instruction is !HThis)) { | |
| 30 lives.add(instruction); | 34 lives.add(instruction); |
| 31 } else { | 35 } else { |
| 32 for (int i = 0, len = instruction.inputs.length; i < len; i++) { | 36 for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| 33 add(instruction.inputs[i]); | 37 add(instruction.inputs[i]); |
| 34 } | 38 } |
| 35 } | 39 } |
| 36 } | 40 } |
| 37 | 41 |
| 38 void addLoopMarker(HBasicBlock block) { | 42 void addLoopMarker(HBasicBlock block) { |
| 39 loopMarkers.add(block); | 43 loopMarkers.add(block); |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 if (speculativeType == computedType) return false; | 196 if (speculativeType == computedType) return false; |
| 193 // If a bailout check is more expensive than doing the actual operation | 197 // If a bailout check is more expensive than doing the actual operation |
| 194 // don't do it either. | 198 // don't do it either. |
| 195 return typeGuardWouldBeValuable(instruction, speculativeType); | 199 return typeGuardWouldBeValuable(instruction, speculativeType); |
| 196 } | 200 } |
| 197 | 201 |
| 198 void visitInstruction(HInstruction instruction) { | 202 void visitInstruction(HInstruction instruction) { |
| 199 HType speculativeType = instruction.propagatedType; | 203 HType speculativeType = instruction.propagatedType; |
| 200 if (shouldInsertTypeGuard(instruction)) { | 204 if (shouldInsertTypeGuard(instruction)) { |
| 201 List<HInstruction> inputs = <HInstruction>[instruction]; | 205 List<HInstruction> inputs = <HInstruction>[instruction]; |
| 202 HTypeGuard guard = new HTypeGuard(speculativeType, stateId++, inputs); | 206 HInstruction insertionPoint; |
| 207 if (instruction is HPhi) { | |
| 208 insertionPoint = instruction.block.first; | |
| 209 } else if (instruction is HParameterValue) { | |
| 210 // We insert the type guard at the end of the entry block | |
| 211 // because if a parameter is live, it must be kept in the live | |
| 212 // environment. Not doing so would mean we could visit a | |
| 213 // parameter and remove it from the environment before | |
| 214 // visiting a type guard. | |
| 215 insertionPoint = instruction.block.last; | |
| 216 } else { | |
| 217 insertionPoint = instruction.next; | |
| 218 } | |
| 219 int state; | |
|
kasperl
2012/06/12 12:18:40
I would move 'int state' down below the comment.
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 220 // If the previous instruction is also a type guard, then both | |
| 221 // guards have the same environment, and can therefore share the | |
| 222 // same state id. | |
| 223 if (insertionPoint.previous is HTypeGuard) { | |
| 224 HTypeGuard other = insertionPoint.previous; | |
| 225 state = other.state; | |
| 226 } else { | |
| 227 state = stateId++; | |
| 228 } | |
| 229 HTypeGuard guard = new HTypeGuard(speculativeType, state, inputs); | |
| 203 guard.propagatedType = speculativeType; | 230 guard.propagatedType = speculativeType; |
| 204 work.guards.add(guard); | 231 work.guards.add(guard); |
| 205 instruction.block.rewrite(instruction, guard); | 232 instruction.block.rewrite(instruction, guard); |
| 206 HInstruction insertionPoint = (instruction is HPhi) | |
| 207 ? instruction.block.first | |
| 208 : instruction.next; | |
| 209 insertionPoint.block.addBefore(insertionPoint, guard); | 233 insertionPoint.block.addBefore(insertionPoint, guard); |
| 210 } | 234 } |
| 211 } | 235 } |
| 212 } | 236 } |
| 213 | 237 |
| 214 /** | 238 /** |
| 215 * Computes the environment for each SSA instruction: visits the graph | 239 * Computes the environment for each SSA instruction: visits the graph |
| 216 * in post-dominator order. Removes an instruction from the environment | 240 * in post-dominator order. Removes an instruction from the environment |
| 217 * and adds its inputs to the environment at the instruction's | 241 * and adds its inputs to the environment at the instruction's |
| 218 * definition. | 242 * definition. |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 333 | 357 |
| 334 /** | 358 /** |
| 335 * Propagates bailout information to blocks that need it. This visitor | 359 * Propagates bailout information to blocks that need it. This visitor |
| 336 * is run before codegen, to know which blocks have to deal with | 360 * is run before codegen, to know which blocks have to deal with |
| 337 * bailouts. | 361 * bailouts. |
| 338 */ | 362 */ |
| 339 class SsaBailoutPropagator extends HBaseVisitor { | 363 class SsaBailoutPropagator extends HBaseVisitor { |
| 340 final Compiler compiler; | 364 final Compiler compiler; |
| 341 final List<HBasicBlock> blocks; | 365 final List<HBasicBlock> blocks; |
| 342 final List<HLabeledBlockInformation> labeledBlockInformations; | 366 final List<HLabeledBlockInformation> labeledBlockInformations; |
| 367 final Set<HInstruction> generateAtUseSite; | |
| 368 final VariableNames variableNames; | |
| 343 SubGraph subGraph; | 369 SubGraph subGraph; |
| 344 | 370 |
| 345 SsaBailoutPropagator(Compiler this.compiler) | 371 /** |
| 372 * If set to true, the graph has either multiple bailouts in | |
| 373 * different places, or a bailout inside an if or a loop. For such a | |
| 374 * graph, the code generator will emit a generic switch. | |
| 375 */ | |
| 376 bool hasComplexTypeGuards = false; | |
| 377 | |
| 378 /** | |
| 379 * The first type guard in the graph. | |
| 380 */ | |
| 381 HTypeGuard firstTypeGuard; | |
| 382 | |
| 383 /** | |
| 384 * If set, it is the first block in the graph where we generate | |
| 385 * code. Blocks before this one are dead code in the bailout | |
| 386 * version. | |
| 387 */ | |
| 388 HBasicBlock startGeneratingAt; | |
| 389 | |
|
kasperl
2012/06/12 12:18:40
Remove one newline here.
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 390 | |
| 391 SsaBailoutPropagator(this.compiler, | |
| 392 this.generateAtUseSite, | |
| 393 this.variableNames) | |
| 346 : blocks = <HBasicBlock>[], | 394 : blocks = <HBasicBlock>[], |
| 347 labeledBlockInformations = <HLabeledBlockInformation>[]; | 395 labeledBlockInformations = <HLabeledBlockInformation>[]; |
| 348 | 396 |
| 349 void visitGraph(HGraph graph) { | 397 void visitGraph(HGraph graph) { |
| 350 subGraph = new SubGraph(graph.entry, graph.exit); | 398 subGraph = new SubGraph(graph.entry, graph.exit); |
| 351 blocks.addLast(graph.entry); | |
| 352 visitBasicBlock(graph.entry); | 399 visitBasicBlock(graph.entry); |
| 353 blocks.removeLast(); | |
| 354 if (!blocks.isEmpty()) { | 400 if (!blocks.isEmpty()) { |
| 355 compiler.internalError('Bailout propagation', | 401 compiler.internalError('Bailout propagation', |
| 356 node: compiler.currentElement.parseNode(compiler)); | 402 node: compiler.currentElement.parseNode(compiler)); |
| 357 } | 403 } |
| 358 } | 404 } |
| 359 | 405 |
| 360 void visitBasicBlock(HBasicBlock block) { | 406 void visitBasicBlock(HBasicBlock block) { |
| 361 // Abort traversal if we are leaving the currently active sub-graph. | 407 // Abort traversal if we are leaving the currently active sub-graph. |
| 362 if (!subGraph.contains(block)) return; | 408 if (!subGraph.contains(block)) return; |
| 363 | 409 |
| 364 if (block.isLoopHeader()) { | 410 if (block.isLoopHeader()) { |
| 365 blocks.addLast(block); | 411 blocks.addLast(block); |
| 366 } else if (block.isLabeledBlock() && blocks.last() !== block) { | 412 } else if (block.isLabeledBlock() |
| 413 && (blocks.isEmpty() || blocks.last() !== block)) { | |
| 367 HLabeledBlockInformation info = block.blockFlow.body; | 414 HLabeledBlockInformation info = block.blockFlow.body; |
| 368 visitStatements(info.body); | 415 visitStatements(info.body); |
| 369 return; | 416 return; |
| 370 } | 417 } |
| 371 | 418 |
| 372 HInstruction instruction = block.first; | 419 HInstruction instruction = block.first; |
| 373 while (instruction != null) { | 420 while (instruction != null) { |
| 374 instruction.accept(this); | 421 instruction.accept(this); |
| 375 instruction = instruction.next; | 422 instruction = instruction.next; |
| 376 } | 423 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 | 500 |
| 454 visitBasicBlock(branchBlock.successors[1]); | 501 visitBasicBlock(branchBlock.successors[1]); |
| 455 // With labeled breaks we can have more dominated blocks. | 502 // With labeled breaks we can have more dominated blocks. |
| 456 if (dominated.length >= 3) { | 503 if (dominated.length >= 3) { |
| 457 for (int i = 2; i < dominated.length; i++) { | 504 for (int i = 2; i < dominated.length; i++) { |
| 458 visitBasicBlock(dominated[i]); | 505 visitBasicBlock(dominated[i]); |
| 459 } | 506 } |
| 460 } | 507 } |
| 461 } | 508 } |
| 462 | 509 |
| 510 // If argument is a [HCheck] and it does not have a name, we try to | |
| 511 // find the name of its checked input. Note that there must be a | |
| 512 // name, otherwise the instruction would not be in the live | |
| 513 // environment. | |
| 514 HInstruction unwrap(argument) { | |
| 515 while (argument is HCheck && !variableNames.hasName(argument)) { | |
| 516 argument = argument.checkedInput; | |
| 517 } | |
| 518 assert(variableNames.hasName(argument)); | |
| 519 return argument; | |
| 520 } | |
| 521 | |
| 463 visitTypeGuard(HTypeGuard guard) { | 522 visitTypeGuard(HTypeGuard guard) { |
| 464 blocks.forEach((HBasicBlock block) { | 523 // Sort the names of all type guards, to be able to merge |
|
kasperl
2012/06/12 12:18:40
to be able to -> so we can
ngeoffray
2012/06/12 12:28:18
Done.
| |
| 465 block.guards.add(guard); | 524 // guards that have the same state id. |
| 466 }); | 525 List<String> names = <String>[]; |
| 526 for (HInstruction input in guard.inputs) { | |
| 527 HInstruction instruction = unwrap(input); | |
| 528 names.add(variableNames.getName(instruction)); | |
| 529 } | |
| 530 names.sort((a, b) => a.compareTo(b)); | |
| 531 guard.sortedVariableNames = names; | |
| 532 | |
| 533 if (firstTypeGuard === null || firstTypeGuard.state === guard.state) { | |
| 534 firstTypeGuard = guard; | |
| 535 if (!blocks.isEmpty()) { | |
| 536 hasComplexTypeGuards = true; | |
| 537 // We start generating at the first block that has control | |
| 538 // flow. | |
| 539 startGeneratingAt = blocks[0]; | |
| 540 blocks.forEach((HBasicBlock block) { | |
| 541 block.guards.add(guard); | |
| 542 }); | |
| 543 } | |
| 544 } else { | |
| 545 hasComplexTypeGuards = true; | |
| 546 blocks.forEach((HBasicBlock block) { | |
| 547 block.guards.add(guard); | |
| 548 }); | |
| 549 } | |
| 467 } | 550 } |
| 468 } | 551 } |
| OLD | NEW |