Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(212)

Side by Side Diff: pkg/compiler/lib/src/ssa/interceptor_simplifier.dart

Issue 829913006: Optimize is-check to instanceof when it eliminates an interceptor (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698