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

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

Issue 11412105: - Move length getter and setter interceptors to the new interceptor scheme. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 1 month 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 26 matching lines...) Expand all
37 // Run trivial constant folding first to optimize 37 // Run trivial constant folding first to optimize
38 // some patterns useful for type conversion. 38 // some patterns useful for type conversion.
39 new SsaConstantFolder(constantSystem, backend, work, types), 39 new SsaConstantFolder(constantSystem, backend, work, types),
40 new SsaTypeConversionInserter(compiler), 40 new SsaTypeConversionInserter(compiler),
41 new SsaTypePropagator(compiler, types), 41 new SsaTypePropagator(compiler, types),
42 new SsaCheckInserter(backend, work, types, context.boundsChecked), 42 new SsaCheckInserter(backend, work, types, context.boundsChecked),
43 new SsaConstantFolder(constantSystem, backend, work, types), 43 new SsaConstantFolder(constantSystem, backend, work, types),
44 new SsaRedundantPhiEliminator(), 44 new SsaRedundantPhiEliminator(),
45 new SsaDeadPhiEliminator(), 45 new SsaDeadPhiEliminator(),
46 new SsaConstantFolder(constantSystem, backend, work, types), 46 new SsaConstantFolder(constantSystem, backend, work, types),
47 new SsaTypePropagator(compiler, types),
47 new SsaGlobalValueNumberer(compiler, types), 48 new SsaGlobalValueNumberer(compiler, types),
48 new SsaCodeMotion(), 49 new SsaCodeMotion(),
49 new SsaValueRangeAnalyzer(constantSystem, types, work), 50 new SsaValueRangeAnalyzer(constantSystem, types, work),
50 // Previous optimizations may have generated new 51 // Previous optimizations may have generated new
51 // opportunities for constant folding. 52 // opportunities for constant folding.
52 new SsaConstantFolder(constantSystem, backend, work, types), 53 new SsaConstantFolder(constantSystem, backend, work, types),
53 new SsaDeadCodeEliminator(types)]; 54 new SsaDeadCodeEliminator(types)];
54 runPhases(graph, phases); 55 runPhases(graph, phases);
55 if (!speculative) { 56 if (!speculative) {
56 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types)); 57 runPhase(graph, new SsaConstructionFieldTypes(backend, work, types));
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 HInstruction operand = node.operand; 198 HInstruction operand = node.operand;
198 if (operand is HConstant) { 199 if (operand is HConstant) {
199 UnaryOperation operation = node.operation(constantSystem); 200 UnaryOperation operation = node.operation(constantSystem);
200 HConstant receiver = operand; 201 HConstant receiver = operand;
201 Constant folded = operation.fold(receiver.constant); 202 Constant folded = operation.fold(receiver.constant);
202 if (folded != null) return graph.addConstant(folded); 203 if (folded != null) return graph.addConstant(folded);
203 } 204 }
204 return node; 205 return node;
205 } 206 }
206 207
207 HInstruction visitInvokeInterceptor(HInvokeInterceptor node) { 208 HInstruction handleInterceptorCall(HInvokeDynamic node) {
208 // Try to recognize the length interceptor with input [:new List(int):].
209 if (node.isLengthGetter() && node.inputs[1] is HInvokeStatic) {
210 HInvokeStatic call = node.inputs[1];
211 if (isFixedSizeListConstructor(call)) {
212 return call.inputs[1];
213 }
214 }
215 HInstruction input = node.inputs[1]; 209 HInstruction input = node.inputs[1];
216 if (node.isLengthGetter()) {
217 if (input.isConstantString()) {
218 HConstant constantInput = input;
219 StringConstant constant = constantInput.constant;
220 return graph.addConstantInt(constant.length, constantSystem);
221 } else if (input.isConstantList()) {
222 HConstant constantInput = input;
223 ListConstant constant = constantInput.constant;
224 return graph.addConstantInt(constant.length, constantSystem);
225 } else if (input.isConstantMap()) {
226 HConstant constantInput = input;
227 MapConstant constant = constantInput.constant;
228 return graph.addConstantInt(constant.length, constantSystem);
229 }
230 }
231
232 if (input.isString(types) 210 if (input.isString(types)
233 && node.selector.name == const SourceString('toString')) { 211 && node.selector.name == const SourceString('toString')) {
234 return node.inputs[1]; 212 return node.inputs[1];
235 } 213 }
236
237 if (!input.canBePrimitive(types) && node.selector.isCall()) {
238 bool transformToDynamicInvocation = true;
239 if (input.canBeNull(types)) {
240 // Check if the method exists on Null. If yes we must not transform
241 // the static interceptor call to a dynamic invocation.
242 // TODO(floitsch): get a list of methods that exist on 'null' and only
243 // bail out on them.
244 transformToDynamicInvocation = false;
245 }
246 if (transformToDynamicInvocation) {
247 return fromInterceptorToDynamicInvocation(node, node.selector);
248 }
249 }
250
251 return node; 214 return node;
252 } 215 }
253 216
254 bool isFixedSizeListConstructor(HInvokeStatic node) { 217 bool isFixedSizeListConstructor(HInvokeStatic node) {
255 Element element = node.target.element; 218 Element element = node.target.element;
256 DartType defaultClass = compiler.listClass.defaultClass; 219 DartType defaultClass = compiler.listClass.defaultClass;
257 // TODO(ngeoffray): make sure that the only reason the List class is 220 // TODO(ngeoffray): make sure that the only reason the List class is
258 // not resolved is because it's not being used. 221 // not resolved is because it's not being used.
259 return element.isConstructor() 222 return element.isConstructor()
260 && defaultClass != null 223 && defaultClass != null
261 && element.enclosingElement.declaration == defaultClass.element 224 && element.enclosingElement.declaration == defaultClass.element
262 && node.inputs.length == 2 225 && node.inputs.length == 2
263 && node.inputs[1].isInteger(types); 226 && node.inputs[1].isInteger(types);
264 } 227 }
265 228
266 HInstruction visitInvokeStatic(HInvokeStatic node) { 229 HInstruction visitInvokeStatic(HInvokeStatic node) {
267 if (isFixedSizeListConstructor(node)) { 230 if (isFixedSizeListConstructor(node)) {
268 node.guaranteedType = HType.FIXED_ARRAY; 231 node.guaranteedType = HType.FIXED_ARRAY;
269 } 232 }
270 return node; 233 return node;
271 } 234 }
272 235
273 HInstruction visitInvokeDynamic(HInvokeDynamic node) { 236 HInstruction visitInvokeDynamic(HInvokeDynamic node) {
237 if (node.isInterceptorCall) return handleInterceptorCall(node);
274 HType receiverType = types[node.receiver]; 238 HType receiverType = types[node.receiver];
275 if (receiverType.isExact()) { 239 if (receiverType.isExact()) {
276 HBoundedType type = receiverType; 240 HBoundedType type = receiverType;
277 Element element = type.lookupMember(node.selector.name); 241 Element element = type.lookupMember(node.selector.name);
278 // TODO(ngeoffray): Also fold if it's a getter or variable. 242 // TODO(ngeoffray): Also fold if it's a getter or variable.
279 if (element != null && element.isFunction()) { 243 if (element != null && element.isFunction()) {
280 if (node.selector.applies(element, compiler)) { 244 if (node.selector.applies(element, compiler)) {
281 FunctionElement method = element; 245 FunctionElement method = element;
282 FunctionSignature parameters = method.computeSignature(compiler); 246 FunctionSignature parameters = method.computeSignature(compiler);
283 if (parameters.optionalParameterCount == 0) { 247 if (parameters.optionalParameterCount == 0) {
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 Element findConcreteFieldForDynamicAccess(HInstruction receiver, 549 Element findConcreteFieldForDynamicAccess(HInstruction receiver,
586 Selector selector) { 550 Selector selector) {
587 HType receiverType = types[receiver]; 551 HType receiverType = types[receiver];
588 if (!receiverType.isUseful()) return null; 552 if (!receiverType.isUseful()) return null;
589 if (receiverType.canBeNull()) return null; 553 if (receiverType.canBeNull()) return null;
590 DartType type = receiverType.computeType(compiler); 554 DartType type = receiverType.computeType(compiler);
591 if (type == null) return null; 555 if (type == null) return null;
592 return compiler.world.locateSingleField(type, selector); 556 return compiler.world.locateSingleField(type, selector);
593 } 557 }
594 558
559 HInstruction visitFieldGet(HFieldGet node) {
560 if (node.element == backend.jsArrayLength) {
561 if (node.receiver is HInvokeStatic) {
562 // Try to recognize the length getter with input [:new List(int):].
563 HInvokeStatic call = node.receiver;
564 if (isFixedSizeListConstructor(call)) {
565 return call.inputs[1];
566 }
567 }
568 }
569 return node;
570 }
571
572 HInstruction optimizeLengthInterceptedCall(HInvokeDynamicGetter node) {
573 HInstruction actualReceiver = node.inputs[1];
574 if (actualReceiver.isIndexablePrimitive(types)) {
575 if (actualReceiver.isConstantString()) {
576 HConstant constantInput = actualReceiver;
577 StringConstant constant = constantInput.constant;
578 return graph.addConstantInt(constant.length, constantSystem);
579 } else if (actualReceiver.isConstantList()) {
580 HConstant constantInput = actualReceiver;
581 ListConstant constant = constantInput.constant;
582 return graph.addConstantInt(constant.length, constantSystem);
583 }
584 Element element;
585 bool isAssignable;
586 if (actualReceiver.isString(types)) {
587 element = backend.jsStringLength;
588 isAssignable = false;
589 } else {
590 element = backend.jsArrayLength;
591 isAssignable = !actualReceiver.isFixedArray(types);
592 }
593 HFieldGet result = new HFieldGet(
594 element, actualReceiver, isAssignable: isAssignable);
595 result.guaranteedType = HType.INTEGER;
596 types[result] = HType.INTEGER;
597 return result;
598 } else if (actualReceiver.isConstantMap()) {
599 HConstant constantInput = actualReceiver;
600 MapConstant constant = constantInput.constant;
601 return graph.addConstantInt(constant.length, constantSystem);
602 }
603 return node;
604 }
605
595 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 606 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
607 if (node.selector.name == const SourceString('length')
608 && node.isInterceptorCall) {
609 return optimizeLengthInterceptedCall(node);
610 }
611
596 Element field = 612 Element field =
597 findConcreteFieldForDynamicAccess(node.receiver, node.selector); 613 findConcreteFieldForDynamicAccess(node.receiver, node.selector);
598 if (field == null) return node; 614 if (field == null) return node;
599 615
600 Modifiers modifiers = field.modifiers; 616 Modifiers modifiers = field.modifiers;
601 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); 617 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst();
602 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { 618 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) {
603 // If no setter is ever used for this field it is only initialized in the 619 // If no setter is ever used for this field it is only initialized in the
604 // initializer list. 620 // initializer list.
605 isFinalOrConst = true; 621 isFinalOrConst = true;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 } 664 }
649 665
650 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { 666 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
651 final HTypeMap types; 667 final HTypeMap types;
652 final ConstantSystem constantSystem; 668 final ConstantSystem constantSystem;
653 final Set<HInstruction> boundsChecked; 669 final Set<HInstruction> boundsChecked;
654 final WorkItem work; 670 final WorkItem work;
655 final String name = "SsaCheckInserter"; 671 final String name = "SsaCheckInserter";
656 HGraph graph; 672 HGraph graph;
657 Element lengthInterceptor; 673 Element lengthInterceptor;
658 Selector lengthSelector;
659 674
660 SsaCheckInserter(JavaScriptBackend backend, 675 SsaCheckInserter(JavaScriptBackend backend,
661 this.work, 676 this.work,
662 this.types, 677 this.types,
663 this.boundsChecked) 678 this.boundsChecked)
664 : constantSystem = backend.constantSystem { 679 : constantSystem = backend.constantSystem {
665 SourceString lengthString = const SourceString('length'); 680 lengthInterceptor = backend.jsArrayLength;
666 lengthSelector =
667 new Selector.getter(lengthString, work.element.getLibrary());
668 lengthInterceptor =
669 backend.builder.interceptors.getStaticInterceptor(lengthSelector);
670 } 681 }
671 682
672 void visitGraph(HGraph graph) { 683 void visitGraph(HGraph graph) {
673 this.graph = graph; 684 this.graph = graph;
674 visitDominatorTree(graph); 685 visitDominatorTree(graph);
675 } 686 }
676 687
677 void visitBasicBlock(HBasicBlock block) { 688 void visitBasicBlock(HBasicBlock block) {
678 HInstruction instruction = block.first; 689 HInstruction instruction = block.first;
679 while (instruction != null) { 690 while (instruction != null) {
680 HInstruction next = instruction.next; 691 HInstruction next = instruction.next;
681 instruction = instruction.accept(this); 692 instruction = instruction.accept(this);
682 instruction = next; 693 instruction = next;
683 } 694 }
684 } 695 }
685 696
686 HBoundsCheck insertBoundsCheck(HInstruction node, 697 HBoundsCheck insertBoundsCheck(HInstruction node,
687 HInstruction receiver, 698 HInstruction receiver,
688 HInstruction index) { 699 HInstruction index) {
689 HStatic interceptor = new HStatic(lengthInterceptor); 700 bool isAssignable = !receiver.isFixedArray(types);
690 node.block.addBefore(node, interceptor); 701 HFieldGet length =
691 HInvokeInterceptor length = new HInvokeInterceptor( 702 new HFieldGet(lengthInterceptor, receiver, isAssignable: isAssignable);
692 lengthSelector, <HInstruction>[interceptor, receiver], true); 703 length.guaranteedType = HType.INTEGER;
693 types[length] = HType.INTEGER; 704 types[length] = HType.INTEGER;
694 node.block.addBefore(node, length); 705 node.block.addBefore(node, length);
695 706
696 HBoundsCheck check = new HBoundsCheck(index, length); 707 HBoundsCheck check = new HBoundsCheck(index, length);
697 node.block.addBefore(node, check); 708 node.block.addBefore(node, check);
698 boundsChecked.add(node); 709 boundsChecked.add(node);
699 return check; 710 return check;
700 } 711 }
701 712
702 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { 713 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) {
(...skipping 22 matching lines...) Expand all
725 if (!node.receiver.isMutableArray(types)) return; 736 if (!node.receiver.isMutableArray(types)) return;
726 if (boundsChecked.contains(node)) return; 737 if (boundsChecked.contains(node)) return;
727 HInstruction index = node.index; 738 HInstruction index = node.index;
728 if (!node.index.isInteger(types)) { 739 if (!node.index.isInteger(types)) {
729 index = insertIntegerCheck(node, index); 740 index = insertIntegerCheck(node, index);
730 } 741 }
731 index = insertBoundsCheck(node, node.receiver, index); 742 index = insertBoundsCheck(node, node.receiver, index);
732 node.changeUse(node.index, index); 743 node.changeUse(node.index, index);
733 assert(node.isBuiltin(types)); 744 assert(node.isBuiltin(types));
734 } 745 }
735
736 void visitInvokeInterceptor(HInvokeInterceptor node) {
737 if (!node.isPopCall(types)) return;
738 if (boundsChecked.contains(node)) return;
739 HInstruction receiver = node.inputs[1];
740 insertBoundsCheck(node, receiver, graph.addConstantInt(0, constantSystem));
741 }
742 } 746 }
743 747
744 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { 748 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
745 final HTypeMap types; 749 final HTypeMap types;
746 final String name = "SsaDeadCodeEliminator"; 750 final String name = "SsaDeadCodeEliminator";
747 751
748 SsaDeadCodeEliminator(this.types); 752 SsaDeadCodeEliminator(this.types);
749 753
750 bool isDeadCode(HInstruction instruction) { 754 bool isDeadCode(HInstruction instruction) {
751 return !instruction.hasSideEffects(types) 755 return !instruction.hasSideEffects(types)
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
1354 } 1358 }
1355 1359
1356 // For other fields having setters in the generative constructor body, set 1360 // For other fields having setters in the generative constructor body, set
1357 // the type to UNKNOWN to avoid relying on the type set in the initializer 1361 // the type to UNKNOWN to avoid relying on the type set in the initializer
1358 // list. 1362 // list.
1359 allSetters.forEach((Element element) { 1363 allSetters.forEach((Element element) {
1360 backend.registerFieldConstructor(element, HType.UNKNOWN); 1364 backend.registerFieldConstructor(element, HType.UNKNOWN);
1361 }); 1365 });
1362 } 1366 }
1363 } 1367 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698