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

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
« no previous file with comments | « pkg/compiler/lib/src/ssa/codegen_helpers.dart ('k') | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 an interceptor are replaced with a HIs version that
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 //return false;
floitsch 2015/01/20 20:15:42 commented code.
56 if (!invoke.isInterceptedCall) return false; 60 if (!invoke.isInterceptedCall) return false;
57 var interceptor = invoke.inputs[0]; 61 var interceptor = invoke.inputs[0];
58 if (interceptor is! HInterceptor) return false; 62 if (interceptor is! HInterceptor) return false;
63
64 // TODO(sra): Move this per-call code to visitInterceptor.
65 //
66 // The interceptor is visited first, so we get here only when the
67 // interceptor was not rewritten to a single shared replacement. I'm not
68 // sure we should substitute a constant interceptor on a per-call basis if
69 // the interceptor is already available in a local variable, but it is
70 // possible that all uses can be rewritten to use different constants.
71
72 // TODO(sra): Also do self-interceptor rewrites on a per-use basis.
73
59 HInstruction constant = tryComputeConstantInterceptor( 74 HInstruction constant = tryComputeConstantInterceptor(
60 invoke.inputs[1], interceptor.interceptedClasses); 75 invoke.inputs[1], interceptor.interceptedClasses);
61 if (constant != null) { 76 if (constant != null) {
62 invoke.changeUse(interceptor, constant); 77 invoke.changeUse(interceptor, constant);
63 } 78 }
64 return false; 79 return false;
65 } 80 }
66 81
67 bool canUseSelfForInterceptor(HInstruction receiver, 82 bool canUseSelfForInterceptor(HInstruction receiver,
68 Set<ClassElement> interceptedClasses) { 83 Set<ClassElement> interceptedClasses) {
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 backend.getInterceptedClassesOn(user.selector.name)); 246 backend.getInterceptedClassesOn(user.selector.name));
232 } else { 247 } else {
233 // Use a most general interceptor for other instructions, example, 248 // Use a most general interceptor for other instructions, example,
234 // is-checks and escaping interceptors. 249 // is-checks and escaping interceptors.
235 interceptedClasses.addAll(backend.interceptedClasses); 250 interceptedClasses.addAll(backend.interceptedClasses);
236 break; 251 break;
237 } 252 }
238 } 253 }
239 } 254 }
240 255
256 node.interceptedClasses = interceptedClasses;
257
241 HInstruction receiver = node.receiver; 258 HInstruction receiver = node.receiver;
242 259
260 // TODO(sra): We should consider each use individually and then all uses
261 // together. Each use might permit a different rewrite due to a refined
262 // receiver type. Self-interceptor rewrites are always beneficial since the
263 // receiver is live at a invocation. Constant-interceptor rewrites are only
264 // guaranteed to be beneficial if they can eliminate the need for the
265 // interceptor or reduce the uses to one that can be simplified with a
266 // one-shot interceptor or optimized is-check.
267
243 if (canUseSelfForInterceptor(receiver, interceptedClasses)) { 268 if (canUseSelfForInterceptor(receiver, interceptedClasses)) {
244 return rewriteToUseSelfAsInterceptor(node, receiver); 269 return rewriteToUseSelfAsInterceptor(node, receiver);
245 } 270 }
246 271
247 // Try computing a constant interceptor. 272 // Try computing a constant interceptor.
248 HInstruction constantInterceptor = 273 HInstruction constantInterceptor =
249 tryComputeConstantInterceptor(receiver, interceptedClasses); 274 tryComputeConstantInterceptor(receiver, interceptedClasses);
250 if (constantInterceptor != null) { 275 if (constantInterceptor != null) {
251 node.block.rewrite(node, constantInterceptor); 276 node.block.rewrite(node, constantInterceptor);
252 return false; 277 return false;
253 } 278 }
254 279
255 node.interceptedClasses = interceptedClasses; 280 // Try creating a one-shot interceptor or optimized is-check
256
257 // Try creating a one-shot interceptor.
258 if (compiler.hasIncrementalSupport) return false; 281 if (compiler.hasIncrementalSupport) return false;
259 if (node.usedBy.length != 1) return false; 282 if (node.usedBy.length != 1) return false;
260 if (node.usedBy[0] is !HInvokeDynamic) return false; 283 HInstruction user = node.usedBy.single;
261 284
262 HInvokeDynamic user = node.usedBy[0]; 285 // 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; 286 if (!user.hasSameLoopHeaderAs(node)) return false;
266 287
267 // Replace the user with a [HOneShotInterceptor]. 288 bool replaceUserWith(HInstruction replacement) {
268 HConstant nullConstant = graph.addConstantNull(compiler); 289 HBasicBlock block = user.block;
269 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs); 290 block.addAfter(user, replacement);
270 inputs[0] = nullConstant; 291 block.rewrite(user, replacement);
271 HOneShotInterceptor interceptor = new HOneShotInterceptor( 292 block.remove(user);
272 user.selector, inputs, user.instructionType, node.interceptedClasses); 293 return false;
273 interceptor.sourcePosition = user.sourcePosition; 294 }
274 interceptor.sourceElement = user.sourceElement;
275 295
276 HBasicBlock block = user.block; 296 if (user is HIs) {
277 block.addAfter(user, interceptor); 297 // See if we can rewrite the is-check to use 'instanceof', i.e. rewrite
278 block.rewrite(user, interceptor); 298 // "getInterceptor(x).$isT" to "x instanceof T".
279 block.remove(user); 299 if (node == user.interceptor) {
280 return true; 300 JavaScriptBackend backend = compiler.backend;
301 if (backend.mayGenerateInstanceofCheck(user.typeExpression)) {
302 HInstruction instanceofCheck = new HIs.instanceOf(
303 user.typeExpression, user.expression, user.instructionType);
304 instanceofCheck.sourcePosition = user.sourcePosition;
305 instanceofCheck.sourceElement = user.sourceElement;
306 return replaceUserWith(instanceofCheck);
307 }
308 }
309 } else if (user is HInvokeDynamic) {
310 if (node == user.inputs[0]) {
311 // Replace the user with a [HOneShotInterceptor].
312 HConstant nullConstant = graph.addConstantNull(compiler);
313 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
314 inputs[0] = nullConstant;
315 HOneShotInterceptor oneShotInterceptor = new HOneShotInterceptor(
316 user.selector, inputs, user.instructionType, interceptedClasses);
317 oneShotInterceptor.sourcePosition = user.sourcePosition;
318 oneShotInterceptor.sourceElement = user.sourceElement;
319 return replaceUserWith(oneShotInterceptor);
320 }
321 }
322
323 return false;
281 } 324 }
282 325
283 bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) { 326 bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) {
284 for (HInstruction user in node.usedBy.toList()) { 327 for (HInstruction user in node.usedBy.toList()) {
285 if (user is HIs) { 328 if (user is HIs) {
286 user.changeUse(node, receiver); 329 user.changeUse(node, receiver);
287 } else { 330 } else {
288 // Use the potentially self-argument as new receiver. Note that the 331 // Use the potentially self-argument as new receiver. Note that the
289 // self-argument could potentially have a tighter type than the 332 // self-argument could potentially have a tighter type than the
290 // receiver which was the input to the interceptor. 333 // receiver which was the input to the interceptor.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
322 instruction = new HInvokeDynamicMethod( 365 instruction = new HInvokeDynamicMethod(
323 selector, inputs, node.instructionType, true); 366 selector, inputs, node.instructionType, true);
324 } 367 }
325 368
326 HBasicBlock block = node.block; 369 HBasicBlock block = node.block;
327 block.addAfter(node, instruction); 370 block.addAfter(node, instruction);
328 block.rewrite(node, instruction); 371 block.rewrite(node, instruction);
329 return true; 372 return true;
330 } 373 }
331 } 374 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/codegen_helpers.dart ('k') | pkg/compiler/lib/src/ssa/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698