Chromium Code Reviews| Index: lib/compiler/implementation/ssa/bailout.dart |
| =================================================================== |
| --- lib/compiler/implementation/ssa/bailout.dart (revision 8532) |
| +++ lib/compiler/implementation/ssa/bailout.dart (working copy) |
| @@ -26,7 +26,11 @@ |
| } |
| void add(HInstruction instruction) { |
| - if (!instruction.isCodeMotionInvariant()) { |
| + // 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.
|
| + // 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.
|
| + // always passed as the receiver). |
| + if (!instruction.isCodeMotionInvariant() |
|
floitsch
2012/06/12 15:01:17
Explain that this is, because we generate these at
|
| + || (instruction is HParameterValue && instruction is !HThis)) { |
| lives.add(instruction); |
| } else { |
| for (int i = 0, len = instruction.inputs.length; i < len; i++) { |
| @@ -199,13 +203,33 @@ |
| HType speculativeType = instruction.propagatedType; |
| if (shouldInsertTypeGuard(instruction)) { |
| List<HInstruction> inputs = <HInstruction>[instruction]; |
| - HTypeGuard guard = new HTypeGuard(speculativeType, stateId++, inputs); |
| + HInstruction insertionPoint; |
| + if (instruction is HPhi) { |
| + insertionPoint = instruction.block.first; |
| + } else if (instruction is HParameterValue) { |
| + // We insert the type guard at the end of the entry block |
| + // because if a parameter is live, it must be kept in the live |
| + // environment. Not doing so would mean we could visit a |
| + // parameter and remove it from the environment before |
| + // visiting a type guard. |
| + insertionPoint = instruction.block.last; |
| + } else { |
| + insertionPoint = instruction.next; |
| + } |
| + 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.
|
| + // If the previous instruction is also a type guard, then both |
| + // guards have the same environment, and can therefore share the |
| + // same state id. |
| + if (insertionPoint.previous is HTypeGuard) { |
| + HTypeGuard other = insertionPoint.previous; |
| + state = other.state; |
| + } else { |
| + state = stateId++; |
| + } |
| + HTypeGuard guard = new HTypeGuard(speculativeType, state, inputs); |
| guard.propagatedType = speculativeType; |
| work.guards.add(guard); |
| instruction.block.rewrite(instruction, guard); |
| - HInstruction insertionPoint = (instruction is HPhi) |
| - ? instruction.block.first |
| - : instruction.next; |
| insertionPoint.block.addBefore(insertionPoint, guard); |
| } |
| } |
| @@ -340,17 +364,39 @@ |
| final Compiler compiler; |
| final List<HBasicBlock> blocks; |
| final List<HLabeledBlockInformation> labeledBlockInformations; |
| + final Set<HInstruction> generateAtUseSite; |
| + final VariableNames variableNames; |
| SubGraph subGraph; |
| - SsaBailoutPropagator(Compiler this.compiler) |
| + /** |
| + * If set to true, the graph has either multiple bailouts in |
| + * different places, or a bailout inside an if or a loop. For such a |
| + * graph, the code generator will emit a generic switch. |
| + */ |
| + bool hasComplexTypeGuards = false; |
| + |
| + /** |
| + * The first type guard in the graph. |
| + */ |
| + HTypeGuard firstTypeGuard; |
| + |
| + /** |
| + * If set, it is the first block in the graph where we generate |
| + * code. Blocks before this one are dead code in the bailout |
| + * version. |
| + */ |
| + HBasicBlock startGeneratingAt; |
| + |
|
kasperl
2012/06/12 12:18:40
Remove one newline here.
ngeoffray
2012/06/12 12:28:18
Done.
|
| + |
| + SsaBailoutPropagator(this.compiler, |
| + this.generateAtUseSite, |
| + this.variableNames) |
| : blocks = <HBasicBlock>[], |
| labeledBlockInformations = <HLabeledBlockInformation>[]; |
| void visitGraph(HGraph graph) { |
| subGraph = new SubGraph(graph.entry, graph.exit); |
| - blocks.addLast(graph.entry); |
| visitBasicBlock(graph.entry); |
| - blocks.removeLast(); |
| if (!blocks.isEmpty()) { |
| compiler.internalError('Bailout propagation', |
| node: compiler.currentElement.parseNode(compiler)); |
| @@ -363,7 +409,8 @@ |
| if (block.isLoopHeader()) { |
| blocks.addLast(block); |
| - } else if (block.isLabeledBlock() && blocks.last() !== block) { |
| + } else if (block.isLabeledBlock() |
| + && (blocks.isEmpty() || blocks.last() !== block)) { |
| HLabeledBlockInformation info = block.blockFlow.body; |
| visitStatements(info.body); |
| return; |
| @@ -460,9 +507,45 @@ |
| } |
| } |
| + // If argument is a [HCheck] and it does not have a name, we try to |
| + // find the name of its checked input. Note that there must be a |
| + // name, otherwise the instruction would not be in the live |
| + // environment. |
| + HInstruction unwrap(argument) { |
| + while (argument is HCheck && !variableNames.hasName(argument)) { |
| + argument = argument.checkedInput; |
| + } |
| + assert(variableNames.hasName(argument)); |
| + return argument; |
| + } |
| + |
| visitTypeGuard(HTypeGuard guard) { |
| - blocks.forEach((HBasicBlock block) { |
| - block.guards.add(guard); |
| - }); |
| + // 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.
|
| + // guards that have the same state id. |
| + List<String> names = <String>[]; |
| + for (HInstruction input in guard.inputs) { |
| + HInstruction instruction = unwrap(input); |
| + names.add(variableNames.getName(instruction)); |
| + } |
| + names.sort((a, b) => a.compareTo(b)); |
| + guard.sortedVariableNames = names; |
| + |
| + if (firstTypeGuard === null || firstTypeGuard.state === guard.state) { |
| + firstTypeGuard = guard; |
| + if (!blocks.isEmpty()) { |
| + hasComplexTypeGuards = true; |
| + // We start generating at the first block that has control |
| + // flow. |
| + startGeneratingAt = blocks[0]; |
| + blocks.forEach((HBasicBlock block) { |
| + block.guards.add(guard); |
| + }); |
| + } |
| + } else { |
| + hasComplexTypeGuards = true; |
| + blocks.forEach((HBasicBlock block) { |
| + block.guards.add(guard); |
| + }); |
| + } |
| } |
| } |