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

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