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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart

Issue 12033056: Implement "one-shot" interceptors. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 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) 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 abstract class OptimizationPhase { 7 abstract class OptimizationPhase {
8 String get name; 8 String get name;
9 void visitGraph(HGraph graph); 9 void visitGraph(HGraph graph);
10 } 10 }
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 new SsaDeadPhiEliminator(), 51 new SsaDeadPhiEliminator(),
52 new SsaConstantFolder(constantSystem, backend, work, types), 52 new SsaConstantFolder(constantSystem, backend, work, types),
53 new SsaTypePropagator(compiler, types), 53 new SsaTypePropagator(compiler, types),
54 new SsaReceiverSpecialization(compiler), 54 new SsaReceiverSpecialization(compiler),
55 new SsaGlobalValueNumberer(compiler, types), 55 new SsaGlobalValueNumberer(compiler, types),
56 new SsaCodeMotion(), 56 new SsaCodeMotion(),
57 new SsaValueRangeAnalyzer(constantSystem, types, work), 57 new SsaValueRangeAnalyzer(constantSystem, types, work),
58 // Previous optimizations may have generated new 58 // Previous optimizations may have generated new
59 // opportunities for constant folding. 59 // opportunities for constant folding.
60 new SsaConstantFolder(constantSystem, backend, work, types), 60 new SsaConstantFolder(constantSystem, backend, work, types),
61 new SsaSimplifyInterceptors(constantSystem),
61 new SsaDeadCodeEliminator(types)]; 62 new SsaDeadCodeEliminator(types)];
62 runPhases(graph, phases); 63 runPhases(graph, phases);
63 if (!speculative) { 64 if (!speculative) {
64 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types)); 65 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types));
65 } 66 }
66 }); 67 });
67 } 68 }
68 69
69 bool trySpeculativeOptimizations(CodegenWorkItem work, HGraph graph) { 70 bool trySpeculativeOptimizations(CodegenWorkItem work, HGraph graph) {
70 if (work.element.isField()) { 71 if (work.element.isField()) {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
212 213
213 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) { 214 HInstruction foldUnary(UnaryOperation operation, HInstruction operand) {
214 if (operand is HConstant) { 215 if (operand is HConstant) {
215 HConstant receiver = operand; 216 HConstant receiver = operand;
216 Constant folded = operation.fold(receiver.constant); 217 Constant folded = operation.fold(receiver.constant);
217 if (folded != null) return graph.addConstant(folded); 218 if (folded != null) return graph.addConstant(folded);
218 } 219 }
219 return null; 220 return null;
220 } 221 }
221 222
222 HInstruction handleInterceptorCall(HInvokeDynamicMethod node) { 223 HInstruction handleInterceptorCall(HInvokeDynamic node) {
224 // We only optimize for intercepted method calls in this method.
225 if (node.selector.isGetter() || node.selector.isSetter()) return node;
226
223 HInstruction input = node.inputs[1]; 227 HInstruction input = node.inputs[1];
224 if (input.isString(types) 228 if (input.isString(types)
225 && node.selector.name == const SourceString('toString')) { 229 && node.selector.name == const SourceString('toString')) {
226 return node.inputs[1]; 230 return node.inputs[1];
227 } 231 }
228 232
229 // Try constant folding the instruction. 233 // Try constant folding the instruction.
230 Operation operation = node.specializer.operation(constantSystem); 234 Operation operation = node.specializer.operation(constantSystem);
231 if (operation != null) { 235 if (operation != null) {
232 HInstruction instruction = node.inputs.length == 2 236 HInstruction instruction = node.inputs.length == 2
233 ? foldUnary(operation, node.inputs[1]) 237 ? foldUnary(operation, node.inputs[1])
234 : foldBinary(operation, node.inputs[1], node.inputs[2]); 238 : foldBinary(operation, node.inputs[1], node.inputs[2]);
235 if (instruction != null) return instruction; 239 if (instruction != null) return instruction;
236 } 240 }
237 241
238 // Try converting the instruction to a builtin instruction. 242 // Try converting the instruction to a builtin instruction.
239 HInstruction instruction = 243 HInstruction instruction =
240 node.specializer.tryConvertToBuiltin(node, types); 244 node.specializer.tryConvertToBuiltin(node, types);
241 if (instruction != null) return instruction; 245 if (instruction != null) return instruction;
242 246
243 // Check if this call does not need to be intercepted. 247 // Check if this call does not need to be intercepted.
244 HType type = types[input]; 248 HType type = types[input];
245 var interceptor = node.inputs[0]; 249 var interceptor = node.inputs[0];
246 if (interceptor is !HThis && !type.canBePrimitive()) { 250 if (interceptor is !HThis && !type.canBePrimitive()) {
247 // If the type can be null, and the intercepted method can be in 251 // If the type can be null, and the intercepted method can be in
248 // the object class, keep the interceptor. 252 // the object class, keep the interceptor.
249 if (type.canBeNull() 253 if (type.canBeNull()) {
250 && interceptor.interceptedClasses.contains(compiler.objectClass)) { 254 Set<ClassElement> interceptedClasses;
251 return node; 255 if (interceptor is HInterceptor) {
256 interceptedClasses = interceptor.interceptedClasses;
257 } else if (node is HOneShotInterceptor) {
258 var oneShotInterceptor = node;
259 interceptedClasses = oneShotInterceptor.interceptedClasses;
260 }
261 if (interceptedClasses.contains(compiler.objectClass)) return node;
252 } 262 }
253 // Change the call to a regular invoke dynamic call. 263 // Change the call to a regular invoke dynamic call.
254 return new HInvokeDynamicMethod( 264 return new HInvokeDynamicMethod(
255 node.selector, node.inputs.getRange(1, node.inputs.length - 1)); 265 node.selector, node.inputs.getRange(1, node.inputs.length - 1));
256 } 266 }
257 267
258 Selector selector = node.selector; 268 Selector selector = node.selector;
259 SourceString selectorName = selector.name; 269 SourceString selectorName = selector.name;
260 Element target; 270 Element target;
261 if (input.isExtendableArray(types)) { 271 if (input.isExtendableArray(types)) {
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after
662 HConstant constant = part; 672 HConstant constant = part;
663 if (!constant.constant.isPrimitive()) return node; 673 if (!constant.constant.isPrimitive()) return node;
664 PrimitiveConstant primitive = constant.constant; 674 PrimitiveConstant primitive = constant.constant;
665 folded = new DartString.concat(folded, primitive.toDartString()); 675 folded = new DartString.concat(folded, primitive.toDartString());
666 } 676 }
667 return graph.addConstant(constantSystem.createString(folded, node.node)); 677 return graph.addConstant(constantSystem.createString(folded, node.node));
668 } 678 }
669 679
670 HInstruction visitInterceptor(HInterceptor node) { 680 HInstruction visitInterceptor(HInterceptor node) {
671 if (node.isConstant()) return node; 681 if (node.isConstant()) return node;
672 HType type = types[node.inputs[0]]; 682 HInstruction constant = tryComputeConstantInterceptor(
683 node.inputs[0], node.interceptedClasses);
684 if (constant == null) return node;
685 return constant;
686 }
687
688 HInstruction tryComputeConstantInterceptor(HInstruction input,
689 Set<ClassElement> intercepted) {
690 HType type = types[input];
673 ClassElement constantInterceptor; 691 ClassElement constantInterceptor;
674 if (type.isInteger()) { 692 if (type.isInteger()) {
675 constantInterceptor = backend.jsIntClass; 693 constantInterceptor = backend.jsIntClass;
676 } else if (type.isDouble()) { 694 } else if (type.isDouble()) {
677 constantInterceptor = backend.jsDoubleClass; 695 constantInterceptor = backend.jsDoubleClass;
678 } else if (type.isBoolean()) { 696 } else if (type.isBoolean()) {
679 constantInterceptor = backend.jsBoolClass; 697 constantInterceptor = backend.jsBoolClass;
680 } else if (type.isString()) { 698 } else if (type.isString()) {
681 constantInterceptor = backend.jsStringClass; 699 constantInterceptor = backend.jsStringClass;
682 } else if (type.isArray()) { 700 } else if (type.isArray()) {
683 constantInterceptor = backend.jsArrayClass; 701 constantInterceptor = backend.jsArrayClass;
684 } else if (type.isNull()) { 702 } else if (type.isNull()) {
685 constantInterceptor = backend.jsIntClass; 703 constantInterceptor = backend.jsIntClass;
686 } else if (type.isNumber()) { 704 } else if (type.isNumber()) {
687 Set<ClassElement> intercepted = node.interceptedClasses;
688 // If the method being intercepted is not defined in [int] or 705 // If the method being intercepted is not defined in [int] or
689 // [double] we can safely use the number interceptor. 706 // [double] we can safely use the number interceptor.
690 if (!intercepted.contains(compiler.intClass) 707 if (!intercepted.contains(compiler.intClass)
691 && !intercepted.contains(compiler.doubleClass)) { 708 && !intercepted.contains(compiler.doubleClass)) {
692 constantInterceptor = backend.jsNumberClass; 709 constantInterceptor = backend.jsNumberClass;
693 } 710 }
694 } 711 }
695 712
696 if (constantInterceptor == null) return node; 713 if (constantInterceptor == null) return null;
697 if (constantInterceptor == work.element.getEnclosingClass()) { 714 if (constantInterceptor == work.element.getEnclosingClass()) {
698 return graph.thisInstruction; 715 return graph.thisInstruction;
699 } 716 }
700 717
701 Constant constant = new ConstructedConstant( 718 Constant constant = new ConstructedConstant(
702 constantInterceptor.computeType(compiler), <Constant>[]); 719 constantInterceptor.computeType(compiler), <Constant>[]);
703 return graph.addConstant(constant); 720 return graph.addConstant(constant);
704 } 721 }
722
723 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) {
724 HInstruction newInstruction = handleInterceptorCall(node);
725 if (newInstruction != null) return newInstruction;
726
727 HInstruction constant = tryComputeConstantInterceptor(
728 node.inputs[1], node.interceptedClasses);
729
730 if (constant == null) return node;
731
732 Selector selector = node.selector;
733 // TODO(ngeoffray): make one shot interceptors know whether
734 // they have side effects.
735 if (selector.isGetter()) {
736 HInstruction res = new HInvokeDynamicGetter(
737 selector, node.element, constant, false);
738 res.inputs.add(node.intputs[1]);
739 return res;
740 } else if (node.selector.isSetter()) {
741 HInstruction res = new HInvokeDynamicSetter(
742 selector, node.element, constant, node.inputs[1], false);
743 res.inputs.add(node.intputs[2]);
744 return res;
745 } else {
746 List<HInstruction> inputs = new List<HInstruction>.from(node.inputs);
747 inputs[0] = constant;
748 return new HInvokeDynamicMethod(selector, inputs, true);
749 }
750 }
705 } 751 }
706 752
707 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { 753 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
708 final HTypeMap types; 754 final HTypeMap types;
709 final Set<HInstruction> boundsChecked; 755 final Set<HInstruction> boundsChecked;
710 final CodegenWorkItem work; 756 final CodegenWorkItem work;
711 final JavaScriptBackend backend; 757 final JavaScriptBackend backend;
712 final String name = "SsaCheckInserter"; 758 final String name = "SsaCheckInserter";
713 HGraph graph; 759 HGraph graph;
714 760
(...skipping 723 matching lines...) Expand 10 before | Expand all | Expand 10 after
1438 || otherIntercepted.contains(backend.jsDoubleClass)) { 1484 || otherIntercepted.contains(backend.jsDoubleClass)) {
1439 interceptor.interceptedClasses.addAll(user.interceptedClasses); 1485 interceptor.interceptedClasses.addAll(user.interceptedClasses);
1440 } 1486 }
1441 user.interceptedClasses = interceptor.interceptedClasses; 1487 user.interceptedClasses = interceptor.interceptedClasses;
1442 } 1488 }
1443 } 1489 }
1444 } 1490 }
1445 1491
1446 // TODO(ngeoffray): Also implement it for non-intercepted calls. 1492 // TODO(ngeoffray): Also implement it for non-intercepted calls.
1447 } 1493 }
1494
1495 /**
1496 * This phase replaces all interceptors that are used only once with
1497 * one-shot interceptors. It saves code size and makes the receiver of
1498 * an intercepted call a candidate for being generated at use site.
1499 */
1500 class SsaSimplifyInterceptors extends HBaseVisitor
1501 implements OptimizationPhase {
1502 final String name = "SsaSimplifyInterceptors";
1503 final ConstantSystem constantSystem;
1504 HGraph graph;
1505
1506 SsaSimplifyInterceptors(this.constantSystem);
1507
1508 void visitGraph(HGraph graph) {
1509 this.graph = graph;
1510 visitDominatorTree(graph);
1511 }
1512
1513 void visitInterceptor(HInterceptor node) {
1514 if (node.usedBy.length != 1) return;
1515 // [HBailoutTarget] instructions might have the interceptor as
1516 // input. In such situation we let the dead code analyzer find out
1517 // the interceptor is not needed.
1518 if (node.usedBy[0] is !HInvokeDynamic) return;
1519
1520 HInvokeDynamic user = node.usedBy[0];
1521
1522 // If [node] was loop hoisted, we keep the interceptor.
1523 if (!user.hasSameLoopHeaderAs(node)) return;
1524
1525 // Replace the user with a [HOneShotInterceptor].
1526 HConstant nullConstant = graph.addConstantNull(constantSystem);
1527 List<HInstruction> inputs = new List<HInstruction>.from(user.inputs);
1528 inputs[0] = nullConstant;
1529 HOneShotInterceptor interceptor = new HOneShotInterceptor(
1530 user.selector, inputs, node.interceptedClasses);
1531 interceptor.sourcePosition = user.sourcePosition;
1532
1533 HBasicBlock block = user.block;
1534 block.addAfter(user, interceptor);
1535 block.rewrite(user, interceptor);
1536 block.remove(user);
1537
1538 // The interceptor will be removed in the dead code elimination
1539 // phase. Note that removing it here would not work because of how
1540 // the [visitBasicBlock] is implemented.
1541 }
1542 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/ssa/nodes.dart ('k') | sdk/lib/_internal/compiler/implementation/ssa/tracer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698