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 part of ssa; | 5 part of ssa; |
| 6 | 6 |
| 7 class BailoutInfo { | 7 class BailoutInfo { |
| 8 int instructionId; | 8 int instructionId; |
| 9 int bailoutId; | 9 int bailoutId; |
| 10 BailoutInfo(this.instructionId, this.bailoutId); | 10 BailoutInfo(this.instructionId, this.bailoutId); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 60 * Visits the graph in dominator order and inserts TypeGuards in places where | 60 * Visits the graph in dominator order and inserts TypeGuards in places where |
| 61 * we consider the guard to be of value. This phase also does type | 61 * we consider the guard to be of value. This phase also does type |
| 62 * propagation to help find valuable type guards. | 62 * propagation to help find valuable type guards. |
| 63 */ | 63 */ |
| 64 class SsaTypeGuardInserter extends SsaNonSpeculativeTypePropagator | 64 class SsaTypeGuardInserter extends SsaNonSpeculativeTypePropagator |
| 65 implements OptimizationPhase { | 65 implements OptimizationPhase { |
| 66 final String name = 'SsaTypeGuardInserter'; | 66 final String name = 'SsaTypeGuardInserter'; |
| 67 final CodegenWorkItem work; | 67 final CodegenWorkItem work; |
| 68 bool calledInLoop = false; | 68 bool calledInLoop = false; |
| 69 bool isRecursiveMethod = false; | 69 bool isRecursiveMethod = false; |
| 70 bool hasInsertedChecks = false; | |
| 70 int stateId = 1; | 71 int stateId = 1; |
| 71 Map<HInstruction, HType> savedTypes = new Map<HInstruction, HType>(); | 72 Map<HInstruction, HType> savedTypes = new Map<HInstruction, HType>(); |
| 72 | 73 |
| 73 SsaTypeGuardInserter(compiler, this.work) : super(compiler); | 74 SsaTypeGuardInserter(compiler, this.work) : super(compiler); |
| 74 | 75 |
| 75 void visitGraph(HGraph graph) { | 76 void visitGraph(HGraph graph) { |
| 76 // Run the speculative type propagator. This does in-place | 77 // Run the speculative type propagator. This does in-place |
| 77 // update of the type of the instructions, and saves the | 78 // update of the type of the instructions, and saves the |
| 78 // previous types in the [savedTypes] map. | 79 // previous types in the [savedTypes] map. |
| 79 SsaTypePropagator propagator = | 80 SsaTypePropagator propagator = |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 183 && typeGuardWouldBeValuable(user, speculativeType)) { | 184 && typeGuardWouldBeValuable(user, speculativeType)) { |
| 184 return true; | 185 return true; |
| 185 } | 186 } |
| 186 } | 187 } |
| 187 | 188 |
| 188 // Insert type guards if the method is likely to be called in a | 189 // Insert type guards if the method is likely to be called in a |
| 189 // loop. | 190 // loop. |
| 190 return calledInLoop; | 191 return calledInLoop; |
| 191 } | 192 } |
| 192 | 193 |
| 194 // Returns whether an invocation of [selector] on [receiver] will throw a | |
| 195 // [ArgumentError] if the argument is not of the right type. | |
| 196 bool willThrowArgumentError(Selector selector, HInstruction receiver) { | |
| 197 if (receiver != null && (receiver.isInteger() || receiver.isString())) { | |
| 198 return selector.isOperator() && selector.name != const SourceString('=='); | |
| 199 } | |
| 200 return false; | |
| 201 } | |
| 202 | |
| 203 // Returns whether an invocation of [selector] will throw a | |
| 204 // [NoSuchMethodError] if the receiver is not of the type | |
| 205 // [speculativeType]. | |
| 206 bool willThrowNoSuchMethodErrorIfNot(Selector selector, | |
| 207 HType speculativeType) { | |
| 208 return compiler.world.hasSingleMatch(selector) | |
| 209 // In some cases, we want the receiver to be an integer, | |
| 210 // but that does not mean we will get a NoSuchMethodError | |
| 211 // if it's not: the receiver could be a double. | |
| 212 && !speculativeType.isInteger() | |
| 213 // We speculate on the [operator==] instruction, but we know it | |
| 214 // will never throw a [NoSuchMethodError]. | |
| 215 && selector.name != const SourceString('=='); | |
| 216 } | |
| 217 | |
| 193 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) { | 218 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) { |
| 194 if (!speculativeType.isUseful()) return false; | 219 if (!speculativeType.isUseful()) return false; |
| 195 // If the types agree we don't need to check. | 220 // If the types agree we don't need to check. |
| 196 if (speculativeType == instruction.instructionType) return false; | 221 if (speculativeType == instruction.instructionType) return false; |
| 197 // If a bailout check is more expensive than doing the actual operation | 222 // If a bailout check is more expensive than doing the actual operation |
| 198 // don't do it either. | 223 // don't do it either. |
| 199 return typeGuardWouldBeValuable(instruction, speculativeType); | 224 return typeGuardWouldBeValuable(instruction, speculativeType); |
| 200 } | 225 } |
| 201 | 226 |
| 227 HInstruction computeFirstDominatingUserWithSelector( | |
| 228 HInstruction instruction) { | |
| 229 // TODO(ngeoffray): We currently only look at the instruction's | |
| 230 // block, so that we know it will be executed. We should lift this | |
| 231 // limitation. | |
| 232 | |
| 233 // (meaning it will be a call), we can put a type check instead | |
|
kasperl
2013/04/23 09:01:43
This comment seems a little incomplete.
ngeoffray
2013/04/23 11:00:56
Wrong copy/paste. Removed the line.
| |
| 234 // For a parameter, we look at the first block that contains | |
| 235 // user instructions. | |
| 236 HBasicBlock userMustBeInBlock = instruction is HParameterValue | |
| 237 ? instruction.block.successors[0] | |
| 238 : instruction.block; | |
| 239 | |
| 240 HInstruction firstUser; | |
| 241 for (HInstruction user in instruction.usedBy) { | |
| 242 if (user.block == userMustBeInBlock && user.selector != null) { | |
| 243 if (firstUser == null || user.dominates(firstUser)) { | |
| 244 firstUser = user; | |
| 245 } | |
| 246 } | |
| 247 } | |
| 248 return firstUser; | |
| 249 } | |
| 250 | |
| 251 /** | |
| 252 * Tries to insert a type conversion instruction for [instruction] | |
| 253 * instead of a type guard if we know an user will throw. Returns | |
| 254 * whether it succeeded at adding a type conversion instruction. | |
| 255 */ | |
| 256 bool tryTypeConversion(HInstruction instruction, HType speculativeType) { | |
| 257 HInstruction firstUser = | |
| 258 computeFirstDominatingUserWithSelector(instruction); | |
| 259 if (firstUser == null) return false; | |
| 260 | |
| 261 // If we have found a user with a selector, we find out if it | |
| 262 // will throw [NoSuchMethodError] or [ArgumentError]. | |
| 263 Selector selector = firstUser.selector; | |
| 264 Selector receiverSelectorOnThrow = null; | |
| 265 HInstruction receiver = firstUser.getDartReceiver(compiler); | |
| 266 bool willThrow = false; | |
| 267 if (receiver == instruction) { | |
| 268 if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) { | |
| 269 receiverSelectorOnThrow = selector; | |
| 270 willThrow = true; | |
| 271 } | |
| 272 } else if (willThrowArgumentError(selector, receiver)) { | |
| 273 willThrow = true; | |
| 274 } | |
| 275 | |
| 276 if (!willThrow) return false; | |
| 277 | |
| 278 HTypeConversion check = new HTypeConversion( | |
| 279 null, | |
| 280 receiverSelectorOnThrow == null | |
| 281 ? HTypeConversion.ARGUMENT_TYPE_CHECK | |
| 282 : HTypeConversion.RECEIVER_TYPE_CHECK, | |
| 283 speculativeType, | |
| 284 instruction, | |
| 285 receiverSelectorOnThrow); | |
| 286 hasInsertedChecks = true; | |
| 287 firstUser.block.addBefore(firstUser, check); | |
| 288 instruction.replaceAllUsersDominatedBy(firstUser, check); | |
| 289 return true; | |
| 290 } | |
| 291 | |
| 202 bool updateType(HInstruction instruction) { | 292 bool updateType(HInstruction instruction) { |
| 203 bool hasChanged = super.updateType(instruction); | 293 bool hasChanged = super.updateType(instruction); |
| 204 HType speculativeType = savedTypes[instruction]; | 294 HType speculativeType = savedTypes[instruction]; |
| 205 if (speculativeType == null) return hasChanged; | 295 if (speculativeType == null) return hasChanged; |
| 206 | 296 |
| 207 if (shouldInsertTypeGuard(instruction, speculativeType)) { | 297 if (shouldInsertTypeGuard(instruction, speculativeType) |
| 298 && !tryTypeConversion(instruction, speculativeType)) { | |
| 208 HInstruction insertionPoint; | 299 HInstruction insertionPoint; |
| 209 if (instruction is HPhi) { | 300 if (instruction is HPhi) { |
| 210 insertionPoint = instruction.block.first; | 301 insertionPoint = instruction.block.first; |
| 211 } else if (instruction is HParameterValue) { | 302 } else if (instruction is HParameterValue) { |
| 212 // We insert the type guard at the end of the entry block | 303 // We insert the type guard at the end of the entry block |
| 213 // because if a parameter is live, it must be kept in the live | 304 // because if a parameter is live, it must be kept in the live |
| 214 // environment. Not doing so would mean we could visit a | 305 // environment. Not doing so would mean we could visit a |
| 215 // parameter and remove it from the environment before | 306 // parameter and remove it from the environment before |
| 216 // visiting a type guard. | 307 // visiting a type guard. |
| 217 insertionPoint = instruction.block.last; | 308 insertionPoint = instruction.block.last; |
| 218 } else { | 309 } else { |
| 219 insertionPoint = instruction.next; | 310 insertionPoint = instruction.next; |
| 220 } | 311 } |
| 221 // If the previous instruction is also a type guard, then both | 312 // If the previous instruction is also a type guard, then both |
| 222 // guards have the same environment, and can therefore share the | 313 // guards have the same environment, and can therefore share the |
| 223 // same state id. | 314 // same state id. |
| 224 HBailoutTarget target; | 315 HBailoutTarget target; |
| 225 int state; | 316 int state; |
| 226 if (insertionPoint.previous is HTypeGuard) { | 317 if (insertionPoint.previous is HTypeGuard) { |
| 227 HTypeGuard other = insertionPoint.previous; | 318 HTypeGuard other = insertionPoint.previous; |
| 228 target = other.bailoutTarget; | 319 target = other.bailoutTarget; |
| 229 } else { | 320 } else { |
| 230 state = stateId++; | 321 state = stateId++; |
| 231 target = new HBailoutTarget(state); | 322 target = new HBailoutTarget(state); |
| 232 insertionPoint.block.addBefore(insertionPoint, target); | 323 insertionPoint.block.addBefore(insertionPoint, target); |
| 233 } | 324 } |
| 234 HTypeGuard guard = new HTypeGuard(speculativeType, instruction, target); | 325 HTypeGuard check = new HTypeGuard(speculativeType, instruction, target); |
|
kasperl
2013/04/23 09:01:43
Undo this change?
ngeoffray
2013/04/23 11:00:56
Done.
| |
| 235 work.guards.add(guard); | 326 work.guards.add(check); |
| 236 // By setting the type of the guard to the speculated type, we | 327 // By setting the type of the guard to the speculated type, we |
| 237 // help the analysis find valuable type guards. This however | 328 // help the analysis find valuable type guards. This however |
| 238 // requires to run a non-speculative type propagation again | 329 // requires to run a non-speculative type propagation again |
| 239 // after this analysis. | 330 // after this analysis. |
| 240 guard.instructionType = speculativeType; | 331 check.instructionType = speculativeType; |
| 241 instruction.block.rewrite(instruction, guard); | 332 instruction.block.rewrite(instruction, check); |
| 242 insertionPoint.block.addBefore(insertionPoint, guard); | 333 insertionPoint.block.addBefore(insertionPoint, check); |
| 243 } | 334 } |
| 244 return hasChanged; | 335 return hasChanged; |
| 245 } | 336 } |
| 246 } | 337 } |
| 247 | 338 |
| 248 /** | 339 /** |
| 249 * Computes the environment for each SSA instruction: visits the graph | 340 * Computes the environment for each SSA instruction: visits the graph |
| 250 * in post-dominator order. Removes an instruction from the environment | 341 * in post-dominator order. Removes an instruction from the environment |
| 251 * and adds its inputs to the environment at the instruction's | 342 * and adds its inputs to the environment at the instruction's |
| 252 * definition. | 343 * definition. |
| (...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 620 hasComplexBailoutTargets = true; | 711 hasComplexBailoutTargets = true; |
| 621 } | 712 } |
| 622 } else { | 713 } else { |
| 623 hasComplexBailoutTargets = true; | 714 hasComplexBailoutTargets = true; |
| 624 blocks.forEach((HBasicBlock block) { | 715 blocks.forEach((HBasicBlock block) { |
| 625 block.bailoutTargets.add(target); | 716 block.bailoutTargets.add(target); |
| 626 }); | 717 }); |
| 627 } | 718 } |
| 628 } | 719 } |
| 629 } | 720 } |
| OLD | NEW |