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 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 && typeGuardWouldBeValuable(user, speculativeType)) { | 207 && typeGuardWouldBeValuable(user, speculativeType)) { |
| 208 return true; | 208 return true; |
| 209 } | 209 } |
| 210 } | 210 } |
| 211 | 211 |
| 212 // Insert type guards if the method is likely to be called in a | 212 // Insert type guards if the method is likely to be called in a |
| 213 // loop. | 213 // loop. |
| 214 return calledInLoop; | 214 return calledInLoop; |
| 215 } | 215 } |
| 216 | 216 |
| 217 // Returns whether an invocation of [selector] on [receiver] will throw a | |
| 218 // [ArgumentError] if the argument is not of the right type. | |
| 219 bool willThrowArgumentError(Selector selector, | |
| 220 HInstruction receiver, | |
| 221 HType speculativeType) { | |
| 222 if (receiver != null | |
| 223 && (receiver.isInteger() || receiver.isString(compiler))) { | |
| 224 return selector.isOperator() | |
| 225 && selector.name != const SourceString('==') | |
| 226 && (speculativeType.isNumber() && !speculativeType.isInteger()); | |
| 227 } | |
| 228 return false; | |
| 229 } | |
| 230 | |
| 231 // Returns whether an invocation of [selector] will throw a | |
| 232 // [NoSuchMethodError] if the receiver is not of the type | |
| 233 // [speculativeType]. | |
| 234 bool willThrowNoSuchMethodErrorIfNot(Selector selector, | |
| 235 HType speculativeType) { | |
| 236 return compiler.world.hasSingleMatch(selector) | |
| 237 // In some cases, we want the receiver to be an integer, | |
| 238 // but that does not mean we will get a NoSuchMethodError | |
| 239 // if it's not: the receiver could be a double. | |
| 240 && !speculativeType.isInteger() | |
| 241 // We speculate on the [operator==] instruction, but we know it | |
| 242 // will never throw a [NoSuchMethodError]. | |
| 243 && selector.name != const SourceString('=='); | |
| 244 } | |
| 245 | |
| 246 bool shouldInsertTypeGuard(HInstruction instruction, HType speculativeType) { | |
| 247 if (!speculativeType.isUseful()) return false; | |
| 248 // If the types agree we don't need to check. | |
| 249 if (speculativeType == instruction.instructionType) return false; | |
| 250 // If a bailout check is more expensive than doing the actual operation | |
| 251 // don't do it either. | |
| 252 return typeGuardWouldBeValuable(instruction, speculativeType); | |
| 253 } | |
| 254 | |
| 255 HInstruction computeFirstDominatingUserWithSelector( | 217 HInstruction computeFirstDominatingUserWithSelector( |
| 256 HInstruction instruction) { | 218 HInstruction instruction) { |
| 257 // TODO(ngeoffray): We currently only look at the instruction's | 219 // TODO(ngeoffray): We currently only look at the instruction's |
| 258 // block, so that we know it will be executed. We should lift this | 220 // block, so that we know it will be executed. We should lift this |
| 259 // limitation. | 221 // limitation. |
| 260 | 222 |
| 261 // For a parameter, we look at the first block that contains | 223 // For a parameter, we look at the first block that contains |
| 262 // user instructions. | 224 // user instructions. |
| 263 HBasicBlock userMustBeInBlock = instruction is HParameterValue | 225 HBasicBlock userMustBeInBlock = instruction is HParameterValue |
| 264 ? instruction.block.successors[0] | 226 ? instruction.block.successors[0] |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 276 } | 238 } |
| 277 | 239 |
| 278 /** | 240 /** |
| 279 * Tries to insert a type conversion instruction for [instruction] | 241 * Tries to insert a type conversion instruction for [instruction] |
| 280 * instead of a type guard if we know an user will throw. Returns | 242 * instead of a type guard if we know an user will throw. Returns |
| 281 * whether it succeeded at adding a type conversion instruction. | 243 * whether it succeeded at adding a type conversion instruction. |
| 282 */ | 244 */ |
| 283 bool tryTypeConversion(HInstruction instruction, HType speculativeType) { | 245 bool tryTypeConversion(HInstruction instruction, HType speculativeType) { |
| 284 HInstruction firstUser = | 246 HInstruction firstUser = |
| 285 computeFirstDominatingUserWithSelector(instruction); | 247 computeFirstDominatingUserWithSelector(instruction); |
| 286 if (firstUser == null) return false; | 248 if (firstUser is !HInvokeDynamic) return false; |
| 287 | 249 |
| 288 // If we have found a user with a selector, we find out if it | 250 // If we have found a user with a selector, we find out if it |
| 289 // will throw [NoSuchMethodError] or [ArgumentError]. | 251 // will throw [NoSuchMethodError] or [ArgumentError]. |
| 290 Selector selector = firstUser.selector; | 252 Selector selector = firstUser.selector; |
| 291 Selector receiverSelectorOnThrow = null; | 253 if (!selector.isOperator()) return false; |
| 292 HInstruction receiver = firstUser.getDartReceiver(compiler); | 254 HInstruction receiver = firstUser.getDartReceiver(compiler); |
| 293 bool willThrow = false; | 255 if (instruction == receiver) { |
|
kasperl
2013/06/14 06:19:08
Add a comment that explains what you're doing here
ngeoffray
2013/06/14 06:58:34
Done.
| |
| 294 if (receiver == instruction) { | 256 return checkReceiver(firstUser); |
| 295 if (willThrowNoSuchMethodErrorIfNot(selector, speculativeType)) { | 257 } else if (!selector.isUnaryOperator() |
| 296 receiverSelectorOnThrow = selector; | 258 && instruction == firstUser.inputs[2]) { |
| 297 willThrow = true; | 259 return checkArgument(firstUser); |
| 298 } | |
| 299 // We need to call the actual method in checked mode to get | |
| 300 // the right type error. | |
| 301 } else if (!compiler.enableTypeAssertions | |
| 302 && willThrowArgumentError(selector, receiver, speculativeType)) { | |
| 303 willThrow = true; | |
| 304 } | 260 } |
| 305 | 261 return false; |
| 306 if (!willThrow) return false; | |
| 307 | |
| 308 HTypeConversion check = new HTypeConversion( | |
| 309 null, | |
| 310 receiverSelectorOnThrow == null | |
| 311 ? HTypeConversion.ARGUMENT_TYPE_CHECK | |
| 312 : HTypeConversion.RECEIVER_TYPE_CHECK, | |
| 313 speculativeType, | |
| 314 instruction, | |
| 315 receiverSelectorOnThrow); | |
| 316 hasInsertedChecks = true; | |
| 317 firstUser.block.addBefore(firstUser, check); | |
| 318 instruction.replaceAllUsersDominatedBy(firstUser, check); | |
| 319 return true; | |
| 320 } | 262 } |
| 321 | 263 |
| 322 bool updateType(HInstruction instruction) { | 264 bool updateType(HInstruction instruction) { |
| 323 bool hasChanged = super.updateType(instruction); | 265 bool hasChanged = super.updateType(instruction); |
| 324 HType speculativeType = savedTypes[instruction]; | 266 HType speculativeType = savedTypes[instruction]; |
| 325 if (speculativeType == null) return hasChanged; | 267 if (speculativeType == null |
| 268 || !speculativeType.isUseful() | |
| 269 || speculativeType == instruction.instructionType) { | |
| 270 return hasChanged; | |
| 271 } | |
| 326 | 272 |
| 327 if (shouldInsertTypeGuard(instruction, speculativeType) | 273 if (!tryTypeConversion(instruction, speculativeType) |
| 328 && !tryTypeConversion(instruction, speculativeType)) { | 274 && typeGuardWouldBeValuable(instruction, speculativeType)) { |
| 329 HInstruction insertionPoint; | 275 HInstruction insertionPoint; |
| 330 if (instruction is HPhi) { | 276 if (instruction is HPhi) { |
| 331 insertionPoint = instruction.block.first; | 277 insertionPoint = instruction.block.first; |
| 332 } else if (instruction is HParameterValue) { | 278 } else if (instruction is HParameterValue) { |
| 333 // We insert the type guard at the end of the entry block | 279 // We insert the type guard at the end of the entry block |
| 334 // because if a parameter is live, it must be kept in the live | 280 // because if a parameter is live, it must be kept in the live |
| 335 // environment. Not doing so would mean we could visit a | 281 // environment. Not doing so would mean we could visit a |
| 336 // parameter and remove it from the environment before | 282 // parameter and remove it from the environment before |
| 337 // visiting a type guard. | 283 // visiting a type guard. |
| 338 insertionPoint = instruction.block.last; | 284 insertionPoint = instruction.block.last; |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 744 hasComplexBailoutTargets = true; | 690 hasComplexBailoutTargets = true; |
| 745 } | 691 } |
| 746 } else { | 692 } else { |
| 747 hasComplexBailoutTargets = true; | 693 hasComplexBailoutTargets = true; |
| 748 blocks.forEach((HBasicBlock block) { | 694 blocks.forEach((HBasicBlock block) { |
| 749 block.bailoutTargets.add(target); | 695 block.bailoutTargets.add(target); |
| 750 }); | 696 }); |
| 751 } | 697 } |
| 752 } | 698 } |
| 753 } | 699 } |
| OLD | NEW |