Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 /** | 7 /** |
| 8 * This phase simplifies interceptors in multiple ways: | 8 * This phase simplifies interceptors in multiple ways: |
| 9 * | 9 * |
| 10 * 1) If the interceptor is for an object whose type is known, it | 10 * 1) If the interceptor is for an object whose type is known, it |
| 11 * tries to use a constant interceptor instead. | 11 * tries to use a constant interceptor instead. |
| 12 * | 12 * |
| 13 * 2) It specializes interceptors based on the selectors it is being | 13 * 2) Interceptors are specialized based on the selector it is used with. |
| 14 * called with. | |
| 15 * | 14 * |
| 16 * 3) If we know the object is not intercepted, we just use it | 15 * 3) If we know the object is not intercepted, we just use the object |
| 17 * instead. | 16 * instead. |
| 18 * | 17 * |
| 19 * 4) It replaces all interceptors that are used only once with | 18 * 4) Single use interceptors at dynamic invoke sites are replaced with 'one |
| 20 * one-shot interceptors. It saves code size and makes the receiver of | 19 * shot interceptors' which are synthesized static helper functions that fetch |
| 21 * an intercepted call a candidate for being generated at use site. | 20 * the interceptor and then call the method. This saves code size and makes the |
| 21 * receiver of an intercepted call a candidate for being generated at use site. | |
| 22 * | |
| 23 * 5) Some HIs operations on a interceptor are replaced with a HIs version that | |
|
floitsch
2015/01/16 14:14:34
on an interceptor
sra1
2015/01/20 20:07:27
Done.
| |
| 24 * uses 'instanceof' rather than testing a type flag. | |
| 22 * | 25 * |
| 23 */ | 26 */ |
| 24 class SsaSimplifyInterceptors extends HBaseVisitor | 27 class SsaSimplifyInterceptors extends HBaseVisitor |
| 25 implements OptimizationPhase { | 28 implements OptimizationPhase { |
| 26 final String name = "SsaSimplifyInterceptors"; | 29 final String name = "SsaSimplifyInterceptors"; |
| 27 final ConstantSystem constantSystem; | 30 final ConstantSystem constantSystem; |
| 28 final Compiler compiler; | 31 final Compiler compiler; |
| 29 final CodegenWorkItem work; | 32 final CodegenWorkItem work; |
| 30 HGraph graph; | 33 HGraph graph; |
| 31 | 34 |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 46 if (shouldRemove) { | 49 if (shouldRemove) { |
| 47 instruction.block.remove(instruction); | 50 instruction.block.remove(instruction); |
| 48 } | 51 } |
| 49 instruction = next; | 52 instruction = next; |
| 50 } | 53 } |
| 51 } | 54 } |
| 52 | 55 |
| 53 bool visitInstruction(HInstruction instruction) => false; | 56 bool visitInstruction(HInstruction instruction) => false; |
| 54 | 57 |
| 55 bool visitInvoke(HInvoke invoke) { | 58 bool visitInvoke(HInvoke invoke) { |
| 59 // TODO(sra): The interceptor is visited first, so this only does something | |
| 60 // when the interceptor was not replaced for all uses. I'm not sure we | |
| 61 // should substitute a constant interceptor if the interceptor is already | |
| 62 // available in a local variable. | |
|
floitsch
2015/01/16 14:14:34
If it's already in a local, let's just use it.
But
sra1
2015/01/20 20:07:27
I was able to contrive an example where this remov
| |
| 63 | |
| 56 if (!invoke.isInterceptedCall) return false; | 64 if (!invoke.isInterceptedCall) return false; |
| 57 var interceptor = invoke.inputs[0]; | 65 var interceptor = invoke.inputs[0]; |
| 58 if (interceptor is! HInterceptor) return false; | 66 if (interceptor is! HInterceptor) return false; |
| 59 HInstruction constant = tryComputeConstantInterceptor( | 67 HInstruction constant = tryComputeConstantInterceptor( |
| 60 invoke.inputs[1], interceptor.interceptedClasses); | 68 invoke.inputs[1], interceptor.interceptedClasses); |
| 61 if (constant != null) { | 69 if (constant != null) { |
| 62 invoke.changeUse(interceptor, constant); | 70 invoke.changeUse(interceptor, constant); |
| 63 } | 71 } |
| 64 return false; | 72 return false; |
| 65 } | 73 } |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 233 // Use a most general interceptor for other instructions, example, | 241 // Use a most general interceptor for other instructions, example, |
| 234 // is-checks and escaping interceptors. | 242 // is-checks and escaping interceptors. |
| 235 interceptedClasses.addAll(backend.interceptedClasses); | 243 interceptedClasses.addAll(backend.interceptedClasses); |
| 236 break; | 244 break; |
| 237 } | 245 } |
| 238 } | 246 } |
| 239 } | 247 } |
| 240 | 248 |
| 241 HInstruction receiver = node.receiver; | 249 HInstruction receiver = node.receiver; |
| 242 | 250 |
| 251 // TODO(sra): We should consider all uses together and do edits here, rather | |
| 252 // than at the use node (e.g. visitInvoke). That would achieve an accurate | |
| 253 // usedBy count for the one-shot interceptor logic. | |
| 254 | |
| 243 if (canUseSelfForInterceptor(receiver, interceptedClasses)) { | 255 if (canUseSelfForInterceptor(receiver, interceptedClasses)) { |
| 244 return rewriteToUseSelfAsInterceptor(node, receiver); | 256 return rewriteToUseSelfAsInterceptor(node, receiver); |
| 245 } | 257 } |
| 246 | 258 |
| 247 // Try computing a constant interceptor. | 259 // Try computing a constant interceptor. |
| 248 HInstruction constantInterceptor = | 260 HInstruction constantInterceptor = |
| 249 tryComputeConstantInterceptor(receiver, interceptedClasses); | 261 tryComputeConstantInterceptor(receiver, interceptedClasses); |
| 250 if (constantInterceptor != null) { | 262 if (constantInterceptor != null) { |
| 251 node.block.rewrite(node, constantInterceptor); | 263 node.block.rewrite(node, constantInterceptor); |
| 252 return false; | 264 return false; |
| 253 } | 265 } |
| 254 | 266 |
| 255 node.interceptedClasses = interceptedClasses; | 267 node.interceptedClasses = interceptedClasses; |
| 256 | 268 |
| 257 // Try creating a one-shot interceptor. | 269 // Try creating a one-shot interceptor or optimized is-check |
| 258 if (compiler.hasIncrementalSupport) return false; | 270 if (compiler.hasIncrementalSupport) return false; |
| 259 if (node.usedBy.length != 1) return false; | 271 if (node.usedBy.length != 1) return false; |
| 260 if (node.usedBy[0] is !HInvokeDynamic) return false; | 272 HInstruction user = node.usedBy.single; |
| 261 | 273 |
| 262 HInvokeDynamic user = node.usedBy[0]; | 274 // If the interceptor [node] was loop hoisted, we keep the interceptor. |
| 263 | |
| 264 // If [node] was loop hoisted, we keep the interceptor. | |
| 265 if (!user.hasSameLoopHeaderAs(node)) return false; | 275 if (!user.hasSameLoopHeaderAs(node)) return false; |
| 266 | 276 |
| 267 // Replace the user with a [HOneShotInterceptor]. | 277 bool replaceUserWith(HInstruction replacement) { |
| 268 HConstant nullConstant = graph.addConstantNull(compiler); | 278 HBasicBlock block = user.block; |
| 269 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); | 279 block.addAfter(user, replacement); |
| 270 inputs[0] = nullConstant; | 280 block.rewrite(user, replacement); |
| 271 HOneShotInterceptor interceptor = new HOneShotInterceptor( | 281 block.remove(user); |
| 272 user.selector, inputs, user.instructionType, node.interceptedClasses); | 282 return false; |
| 273 interceptor.sourcePosition = user.sourcePosition; | 283 } |
| 274 interceptor.sourceElement = user.sourceElement; | |
| 275 | 284 |
| 276 HBasicBlock block = user.block; | 285 if (user is HIs) { |
| 277 block.addAfter(user, interceptor); | 286 if (node == user.interceptor) { |
| 278 block.rewrite(user, interceptor); | 287 JavaScriptBackend backend = compiler.backend; |
| 279 block.remove(user); | 288 if (backend.mayGenerateInstanceofCheck(user.typeExpression)) { |
| 280 return true; | 289 HInstruction instanceofCheck = new HIs.instanceOf( |
| 290 user.typeExpression, user.expression, user.instructionType); | |
| 291 instanceofCheck.sourcePosition = user.sourcePosition; | |
| 292 instanceofCheck.sourceElement = user.sourceElement; | |
| 293 return replaceUserWith(instanceofCheck); | |
| 294 } | |
| 295 } | |
| 296 } else if (user is HInvokeDynamic) { | |
| 297 if (node == user.inputs[0]) { | |
| 298 // Replace the user with a [HOneShotInterceptor]. | |
| 299 HConstant nullConstant = graph.addConstantNull(compiler); | |
| 300 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); | |
| 301 inputs[0] = nullConstant; | |
| 302 HOneShotInterceptor oneShotInterceptor = new HOneShotInterceptor( | |
| 303 user.selector, inputs, user.instructionType, interceptedClasses); | |
| 304 oneShotInterceptor.sourcePosition = user.sourcePosition; | |
| 305 oneShotInterceptor.sourceElement = user.sourceElement; | |
| 306 return replaceUserWith(oneShotInterceptor); | |
| 307 } | |
| 308 } | |
| 309 | |
| 310 return false; | |
| 281 } | 311 } |
| 282 | 312 |
| 283 bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) { | 313 bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) { |
| 284 for (HInstruction user in node.usedBy.toList()) { | 314 for (HInstruction user in node.usedBy.toList()) { |
| 285 if (user is HIs) { | 315 if (user is HIs) { |
| 286 user.changeUse(node, receiver); | 316 user.changeUse(node, receiver); |
| 287 } else { | 317 } else { |
| 288 // Use the potentially self-argument as new receiver. Note that the | 318 // Use the potentially self-argument as new receiver. Note that the |
| 289 // self-argument could potentially have a tighter type than the | 319 // self-argument could potentially have a tighter type than the |
| 290 // receiver which was the input to the interceptor. | 320 // receiver which was the input to the interceptor. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 instruction = new HInvokeDynamicMethod( | 352 instruction = new HInvokeDynamicMethod( |
| 323 selector, inputs, node.instructionType, true); | 353 selector, inputs, node.instructionType, true); |
| 324 } | 354 } |
| 325 | 355 |
| 326 HBasicBlock block = node.block; | 356 HBasicBlock block = node.block; |
| 327 block.addAfter(node, instruction); | 357 block.addAfter(node, instruction); |
| 328 block.rewrite(node, instruction); | 358 block.rewrite(node, instruction); |
| 329 return true; | 359 return true; |
| 330 } | 360 } |
| 331 } | 361 } |
| OLD | NEW |