| 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 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 } | 60 } |
| 61 | 61 |
| 62 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); | 62 bool isEmpty() => lives.isEmpty() && loopMarkers.isEmpty(); |
| 63 } | 63 } |
| 64 | 64 |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * 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 |
| 68 * we consider the guard to be of value. | 68 * we consider the guard to be of value. |
| 69 * | 69 * |
| 70 * Might modify the [:propagatedType:] fields of the instructions in an | 70 * Might modify the [types] in an inconsistent way. No further analysis should |
| 71 * inconsistent way. No further analysis should rely on them. | 71 * rely on them. |
| 72 */ | 72 */ |
| 73 class SsaTypeGuardInserter extends HGraphVisitor implements OptimizationPhase { | 73 class SsaTypeGuardInserter extends HGraphVisitor implements OptimizationPhase { |
| 74 final Compiler compiler; | 74 final Compiler compiler; |
| 75 final String name = 'SsaTypeGuardInserter'; | 75 final String name = 'SsaTypeGuardInserter'; |
| 76 final WorkItem work; | 76 final WorkItem work; |
| 77 final HTypeMap types; |
| 77 bool calledInLoop = false; | 78 bool calledInLoop = false; |
| 78 bool isRecursiveMethod = false; | 79 bool isRecursiveMethod = false; |
| 79 int stateId = 1; | 80 int stateId = 1; |
| 80 | 81 |
| 81 SsaTypeGuardInserter(this.compiler, this.work); | 82 SsaTypeGuardInserter(this.compiler, this.work, this.types); |
| 82 | 83 |
| 83 void visitGraph(HGraph graph) { | 84 void visitGraph(HGraph graph) { |
| 84 isRecursiveMethod = graph.isRecursiveMethod; | 85 isRecursiveMethod = graph.isRecursiveMethod; |
| 85 calledInLoop = graph.calledInLoop; | 86 calledInLoop = graph.calledInLoop; |
| 86 work.guards = <HTypeGuard>[]; | 87 work.guards = <HTypeGuard>[]; |
| 87 visitDominatorTree(graph); | 88 visitDominatorTree(graph); |
| 88 } | 89 } |
| 89 | 90 |
| 90 void visitBasicBlock(HBasicBlock block) { | 91 void visitBasicBlock(HBasicBlock block) { |
| 91 block.forEachPhi(visitInstruction); | 92 block.forEachPhi(visitInstruction); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 } | 147 } |
| 147 | 148 |
| 148 // To speed up computations on values loaded from arrays, we | 149 // To speed up computations on values loaded from arrays, we |
| 149 // insert type guards for builtin array indexing operations in | 150 // insert type guards for builtin array indexing operations in |
| 150 // nested loops. Since this can blow up code size quite | 151 // nested loops. Since this can blow up code size quite |
| 151 // significantly, we only do it if type guards have already been | 152 // significantly, we only do it if type guards have already been |
| 152 // inserted for this method. The code size price for an additional | 153 // inserted for this method. The code size price for an additional |
| 153 // type guard is much smaller than the first one that causes the | 154 // type guard is much smaller than the first one that causes the |
| 154 // generation of a bailout method. | 155 // generation of a bailout method. |
| 155 if (instruction is HIndex && | 156 if (instruction is HIndex && |
| 156 (instruction as HIndex).builtin && | 157 (instruction as HIndex).isBuiltin(types) && |
| 157 hasTypeGuards) { | 158 hasTypeGuards) { |
| 158 HBasicBlock loopHeader = instruction.block.enclosingLoopHeader; | 159 HBasicBlock loopHeader = instruction.block.enclosingLoopHeader; |
| 159 if (loopHeader != null && loopHeader.parentLoopHeader != null) { | 160 if (loopHeader != null && loopHeader.parentLoopHeader != null) { |
| 160 return true; | 161 return true; |
| 161 } | 162 } |
| 162 } | 163 } |
| 163 | 164 |
| 164 // Insert type guards if the method is likely to be called in a | 165 // Insert type guards if the method is likely to be called in a |
| 165 // loop. | 166 // loop. |
| 166 return calledInLoop; | 167 return calledInLoop; |
| 167 } | 168 } |
| 168 | 169 |
| 169 bool shouldInsertTypeGuard(HInstruction instruction) { | 170 bool shouldInsertTypeGuard(HInstruction instruction, |
| 170 HType speculativeType = instruction.propagatedType; | 171 HType speculativeType, |
| 171 HType computedType = instruction.computeTypeFromInputTypes(); | 172 HType computedType) { |
| 172 // Start by reverting the propagated type. If we add a type guard then the | |
| 173 // guard will expose the speculative type. If we don't add a type guard | |
| 174 // then this avoids subsequent instructions to use the the wrong type. | |
| 175 // | |
| 176 // Note that just setting the propagatedType of the instruction is not | |
| 177 // complete since the type could lead to a phi node which in turn could | |
| 178 // change the computedType. In this case we might miss some guards we | |
| 179 // would have liked to insert. Most of the time this should however be | |
| 180 // fine, due to dominator-order visiting. | |
| 181 instruction.propagatedType = computedType; | |
| 182 | |
| 183 if (!speculativeType.isUseful()) return false; | 173 if (!speculativeType.isUseful()) return false; |
| 184 // If the types agree we don't need to check. | 174 // If the types agree we don't need to check. |
| 185 if (speculativeType == computedType) return false; | 175 if (speculativeType == computedType) return false; |
| 186 // If a bailout check is more expensive than doing the actual operation | 176 // If a bailout check is more expensive than doing the actual operation |
| 187 // don't do it either. | 177 // don't do it either. |
| 188 return typeGuardWouldBeValuable(instruction, speculativeType); | 178 return typeGuardWouldBeValuable(instruction, speculativeType); |
| 189 } | 179 } |
| 190 | 180 |
| 191 void visitInstruction(HInstruction instruction) { | 181 void visitInstruction(HInstruction instruction) { |
| 192 HType speculativeType = instruction.propagatedType; | 182 HType speculativeType = types[instruction]; |
| 193 if (shouldInsertTypeGuard(instruction)) { | 183 HType computedType = instruction.computeTypeFromInputTypes(types); |
| 184 // Currently the type in [types] is the speculative type each instruction |
| 185 // would like to have. We start by recomputing the type non-speculatively. |
| 186 // If we add a type guard then the guard will expose the speculative type. |
| 187 // If we don't add a type guard then this avoids that subsequent |
| 188 // instructions use the wrong (speculative) type. |
| 189 // |
| 190 // Note that just setting the speculative type of the instruction is not |
| 191 // complete since the type could lead to a phi node which in turn could |
| 192 // change the speculative type. In this case we might miss some guards we |
| 193 // would have liked to insert. Most of the time this should however be |
| 194 // fine, due to dominator-order visiting. |
| 195 types[instruction] = computedType; |
| 196 |
| 197 if (shouldInsertTypeGuard(instruction, speculativeType, computedType)) { |
| 194 HInstruction insertionPoint; | 198 HInstruction insertionPoint; |
| 195 if (instruction is HPhi) { | 199 if (instruction is HPhi) { |
| 196 insertionPoint = instruction.block.first; | 200 insertionPoint = instruction.block.first; |
| 197 } else if (instruction is HParameterValue) { | 201 } else if (instruction is HParameterValue) { |
| 198 // We insert the type guard at the end of the entry block | 202 // We insert the type guard at the end of the entry block |
| 199 // because if a parameter is live, it must be kept in the live | 203 // because if a parameter is live, it must be kept in the live |
| 200 // environment. Not doing so would mean we could visit a | 204 // environment. Not doing so would mean we could visit a |
| 201 // parameter and remove it from the environment before | 205 // parameter and remove it from the environment before |
| 202 // visiting a type guard. | 206 // visiting a type guard. |
| 203 insertionPoint = instruction.block.last; | 207 insertionPoint = instruction.block.last; |
| 204 } else { | 208 } else { |
| 205 insertionPoint = instruction.next; | 209 insertionPoint = instruction.next; |
| 206 } | 210 } |
| 207 // If the previous instruction is also a type guard, then both | 211 // If the previous instruction is also a type guard, then both |
| 208 // guards have the same environment, and can therefore share the | 212 // guards have the same environment, and can therefore share the |
| 209 // same state id. | 213 // same state id. |
| 210 HBailoutTarget target; | 214 HBailoutTarget target; |
| 211 int state; | 215 int state; |
| 212 if (insertionPoint.previous is HTypeGuard) { | 216 if (insertionPoint.previous is HTypeGuard) { |
| 213 HTypeGuard other = insertionPoint.previous; | 217 HTypeGuard other = insertionPoint.previous; |
| 214 target = other.bailoutTarget; | 218 target = other.bailoutTarget; |
| 215 } else { | 219 } else { |
| 216 state = stateId++; | 220 state = stateId++; |
| 217 target = new HBailoutTarget(state); | 221 target = new HBailoutTarget(state); |
| 218 insertionPoint.block.addBefore(insertionPoint, target); | 222 insertionPoint.block.addBefore(insertionPoint, target); |
| 219 } | 223 } |
| 220 HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target); | 224 HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target); |
| 221 guard.propagatedType = speculativeType; | 225 types[guard] = speculativeType; |
| 222 work.guards.add(guard); | 226 work.guards.add(guard); |
| 223 instruction.block.rewrite(instruction, guard); | 227 instruction.block.rewrite(instruction, guard); |
| 224 insertionPoint.block.addBefore(insertionPoint, guard); | 228 insertionPoint.block.addBefore(insertionPoint, guard); |
| 225 } | 229 } |
| 226 } | 230 } |
| 227 } | 231 } |
| 228 | 232 |
| 229 /** | 233 /** |
| 230 * Computes the environment for each SSA instruction: visits the graph | 234 * Computes the environment for each SSA instruction: visits the graph |
| 231 * in post-dominator order. Removes an instruction from the environment | 235 * in post-dominator order. Removes an instruction from the environment |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 523 hasComplexBailoutTargets = true; | 527 hasComplexBailoutTargets = true; |
| 524 } | 528 } |
| 525 } else { | 529 } else { |
| 526 hasComplexBailoutTargets = true; | 530 hasComplexBailoutTargets = true; |
| 527 blocks.forEach((HBasicBlock block) { | 531 blocks.forEach((HBasicBlock block) { |
| 528 block.bailoutTargets.add(target); | 532 block.bailoutTargets.add(target); |
| 529 }); | 533 }); |
| 530 } | 534 } |
| 531 } | 535 } |
| 532 } | 536 } |
| OLD | NEW |