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

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 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 HInstruction operand = node.operand; 197 HInstruction operand = node.operand;
198 if (operand is HConstant) { 198 if (operand is HConstant) {
199 UnaryOperation operation = node.operation(constantSystem); 199 UnaryOperation operation = node.operation(constantSystem);
200 HConstant receiver = operand; 200 HConstant receiver = operand;
201 Constant folded = operation.fold(receiver.constant); 201 Constant folded = operation.fold(receiver.constant);
202 if (folded != null) return graph.addConstant(folded); 202 if (folded != null) return graph.addConstant(folded);
203 } 203 }
204 return node; 204 return node;
205 } 205 }
206 206
207 HInstruction visitInvokeInterceptor(HInvokeInterceptor node) { 207 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]; 208 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) 209 if (input.isString(types)
233 && node.selector.name == const SourceString('toString')) { 210 && node.selector.name == const SourceString('toString')) {
234 return node.inputs[1]; 211 return node.inputs[1];
235 } 212 }
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; 213 return node;
252 } 214 }
253 215
254 bool isFixedSizeListConstructor(HInvokeStatic node) { 216 bool isFixedSizeListConstructor(HInvokeStatic node) {
255 Element element = node.target.element; 217 Element element = node.target.element;
256 DartType defaultClass = compiler.listClass.defaultClass; 218 DartType defaultClass = compiler.listClass.defaultClass;
257 // TODO(ngeoffray): make sure that the only reason the List class is 219 // TODO(ngeoffray): make sure that the only reason the List class is
258 // not resolved is because it's not being used. 220 // not resolved is because it's not being used.
259 return element.isConstructor() 221 return element.isConstructor()
260 && defaultClass != null 222 && defaultClass != null
261 && element.enclosingElement.declaration == defaultClass.element 223 && element.enclosingElement.declaration == defaultClass.element
262 && node.inputs.length == 2 224 && node.inputs.length == 2
263 && node.inputs[1].isInteger(types); 225 && node.inputs[1].isInteger(types);
264 } 226 }
265 227
266 HInstruction visitInvokeStatic(HInvokeStatic node) { 228 HInstruction visitInvokeStatic(HInvokeStatic node) {
267 if (isFixedSizeListConstructor(node)) { 229 if (isFixedSizeListConstructor(node)) {
268 node.guaranteedType = HType.FIXED_ARRAY; 230 node.guaranteedType = HType.FIXED_ARRAY;
269 } 231 }
270 return node; 232 return node;
271 } 233 }
272 234
273 HInstruction visitInvokeDynamic(HInvokeDynamic node) { 235 HInstruction visitInvokeDynamic(HInvokeDynamic node) {
236 if (node.isInterceptorCall) return handleInterceptorCall(node);
274 HType receiverType = types[node.receiver]; 237 HType receiverType = types[node.receiver];
275 if (receiverType.isExact()) { 238 if (receiverType.isExact()) {
276 HBoundedType type = receiverType; 239 HBoundedType type = receiverType;
277 Element element = type.lookupMember(node.selector.name); 240 Element element = type.lookupMember(node.selector.name);
278 // TODO(ngeoffray): Also fold if it's a getter or variable. 241 // TODO(ngeoffray): Also fold if it's a getter or variable.
279 if (element != null && element.isFunction()) { 242 if (element != null && element.isFunction()) {
280 if (node.selector.applies(element, compiler)) { 243 if (node.selector.applies(element, compiler)) {
281 FunctionElement method = element; 244 FunctionElement method = element;
282 FunctionSignature parameters = method.computeSignature(compiler); 245 FunctionSignature parameters = method.computeSignature(compiler);
283 if (parameters.optionalParameterCount == 0) { 246 if (parameters.optionalParameterCount == 0) {
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 Element findConcreteFieldForDynamicAccess(HInstruction receiver, 548 Element findConcreteFieldForDynamicAccess(HInstruction receiver,
586 Selector selector) { 549 Selector selector) {
587 HType receiverType = types[receiver]; 550 HType receiverType = types[receiver];
588 if (!receiverType.isUseful()) return null; 551 if (!receiverType.isUseful()) return null;
589 if (receiverType.canBeNull()) return null; 552 if (receiverType.canBeNull()) return null;
590 DartType type = receiverType.computeType(compiler); 553 DartType type = receiverType.computeType(compiler);
591 if (type == null) return null; 554 if (type == null) return null;
592 return compiler.world.locateSingleField(type, selector); 555 return compiler.world.locateSingleField(type, selector);
593 } 556 }
594 557
558 HInstruction optimizeLengthInterceptedCall(HInvokeDynamicGetter node) {
559 HInstruction actualReceiver = node.inputs[1];
560 if (actualReceiver.isIndexablePrimitive(types)) {
561 // Try to recognize the length getter with input [:new List(int):].
562 if (actualReceiver is HInvokeStatic) {
563 HInvokeStatic call = node.inputs[1];
564 if (isFixedSizeListConstructor(call)) {
565 return call.inputs[1];
566 }
567 } else if (actualReceiver.isConstantString()) {
568 HConstant constantInput = actualReceiver;
569 StringConstant constant = constantInput.constant;
570 return graph.addConstantInt(constant.length, constantSystem);
571 } else if (actualReceiver.isConstantList()) {
572 HConstant constantInput = actualReceiver;
573 ListConstant constant = constantInput.constant;
574 return graph.addConstantInt(constant.length, constantSystem);
575 }
576 Element element;
577 bool isAssignable;
578 if (actualReceiver.isString(types)) {
579 element = backend.jsStringLength;
580 isAssignable = false;
581 } else {
582 element = backend.jsArrayLength;
583 isAssignable = !actualReceiver.isFixedArray(types);
584 }
585 HFieldGet result = new HFieldGet(
586 element, actualReceiver, isAssignable: isAssignable);
587 result.guaranteedType = HType.INTEGER;
588 return result;
589 } else if (actualReceiver.isConstantMap()) {
590 HConstant constantInput = actualReceiver;
591 MapConstant constant = constantInput.constant;
592 return graph.addConstantInt(constant.length, constantSystem);
593 }
594 return node;
595 }
596
595 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { 597 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
598 if (node.selector.name == const SourceString('length')
599 && node.isInterceptorCall) {
600 return optimizeLengthInterceptedCall(node);
601 }
602
596 Element field = 603 Element field =
597 findConcreteFieldForDynamicAccess(node.receiver, node.selector); 604 findConcreteFieldForDynamicAccess(node.receiver, node.selector);
598 if (field == null) return node; 605 if (field == null) return node;
599 606
600 Modifiers modifiers = field.modifiers; 607 Modifiers modifiers = field.modifiers;
601 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst(); 608 bool isFinalOrConst = modifiers.isFinal() || modifiers.isConst();
602 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) { 609 if (!compiler.resolverWorld.hasInvokedSetter(field, compiler)) {
603 // If no setter is ever used for this field it is only initialized in the 610 // If no setter is ever used for this field it is only initialized in the
604 // initializer list. 611 // initializer list.
605 isFinalOrConst = true; 612 isFinalOrConst = true;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 } 655 }
649 656
650 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase { 657 class SsaCheckInserter extends HBaseVisitor implements OptimizationPhase {
651 final HTypeMap types; 658 final HTypeMap types;
652 final ConstantSystem constantSystem; 659 final ConstantSystem constantSystem;
653 final Set<HInstruction> boundsChecked; 660 final Set<HInstruction> boundsChecked;
654 final WorkItem work; 661 final WorkItem work;
655 final String name = "SsaCheckInserter"; 662 final String name = "SsaCheckInserter";
656 HGraph graph; 663 HGraph graph;
657 Element lengthInterceptor; 664 Element lengthInterceptor;
658 Selector lengthSelector;
659 665
660 SsaCheckInserter(JavaScriptBackend backend, 666 SsaCheckInserter(JavaScriptBackend backend,
661 this.work, 667 this.work,
662 this.types, 668 this.types,
663 this.boundsChecked) 669 this.boundsChecked)
664 : constantSystem = backend.constantSystem { 670 : constantSystem = backend.constantSystem {
665 SourceString lengthString = const SourceString('length'); 671 lengthInterceptor = backend.jsArrayLength;
666 lengthSelector =
667 new Selector.getter(lengthString, work.element.getLibrary());
668 lengthInterceptor =
669 backend.builder.interceptors.getStaticInterceptor(lengthSelector);
670 } 672 }
671 673
672 void visitGraph(HGraph graph) { 674 void visitGraph(HGraph graph) {
673 this.graph = graph; 675 this.graph = graph;
674 visitDominatorTree(graph); 676 visitDominatorTree(graph);
675 } 677 }
676 678
677 void visitBasicBlock(HBasicBlock block) { 679 void visitBasicBlock(HBasicBlock block) {
678 HInstruction instruction = block.first; 680 HInstruction instruction = block.first;
679 while (instruction != null) { 681 while (instruction != null) {
680 HInstruction next = instruction.next; 682 HInstruction next = instruction.next;
681 instruction = instruction.accept(this); 683 instruction = instruction.accept(this);
682 instruction = next; 684 instruction = next;
683 } 685 }
684 } 686 }
685 687
686 HBoundsCheck insertBoundsCheck(HInstruction node, 688 HBoundsCheck insertBoundsCheck(HInstruction node,
687 HInstruction receiver, 689 HInstruction receiver,
688 HInstruction index) { 690 HInstruction index) {
689 HStatic interceptor = new HStatic(lengthInterceptor); 691 bool isAssignable = !receiver.isFixedArray(types);
690 node.block.addBefore(node, interceptor); 692 HFieldGet length =
691 HInvokeInterceptor length = new HInvokeInterceptor( 693 new HFieldGet(lengthInterceptor, receiver, isAssignable: isAssignable);
692 lengthSelector, <HInstruction>[interceptor, receiver], true); 694 length.guaranteedType = HType.INTEGER;
693 types[length] = HType.INTEGER; 695 types[length] = HType.INTEGER;
694 node.block.addBefore(node, length); 696 node.block.addBefore(node, length);
695 697
696 HBoundsCheck check = new HBoundsCheck(index, length); 698 HBoundsCheck check = new HBoundsCheck(index, length);
697 node.block.addBefore(node, check); 699 node.block.addBefore(node, check);
698 boundsChecked.add(node); 700 boundsChecked.add(node);
699 return check; 701 return check;
700 } 702 }
701 703
702 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { 704 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) {
(...skipping 22 matching lines...) Expand all
725 if (!node.receiver.isMutableArray(types)) return; 727 if (!node.receiver.isMutableArray(types)) return;
726 if (boundsChecked.contains(node)) return; 728 if (boundsChecked.contains(node)) return;
727 HInstruction index = node.index; 729 HInstruction index = node.index;
728 if (!node.index.isInteger(types)) { 730 if (!node.index.isInteger(types)) {
729 index = insertIntegerCheck(node, index); 731 index = insertIntegerCheck(node, index);
730 } 732 }
731 index = insertBoundsCheck(node, node.receiver, index); 733 index = insertBoundsCheck(node, node.receiver, index);
732 node.changeUse(node.index, index); 734 node.changeUse(node.index, index);
733 assert(node.isBuiltin(types)); 735 assert(node.isBuiltin(types));
734 } 736 }
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 } 737 }
743 738
744 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase { 739 class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
745 final HTypeMap types; 740 final HTypeMap types;
746 final String name = "SsaDeadCodeEliminator"; 741 final String name = "SsaDeadCodeEliminator";
747 742
748 SsaDeadCodeEliminator(this.types); 743 SsaDeadCodeEliminator(this.types);
749 744
750 bool isDeadCode(HInstruction instruction) { 745 bool isDeadCode(HInstruction instruction) {
751 return !instruction.hasSideEffects(types) 746 return !instruction.hasSideEffects(types)
(...skipping 602 matching lines...) Expand 10 before | Expand all | Expand 10 after
1354 } 1349 }
1355 1350
1356 // For other fields having setters in the generative constructor body, set 1351 // 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 1352 // the type to UNKNOWN to avoid relying on the type set in the initializer
1358 // list. 1353 // list.
1359 allSetters.forEach((Element element) { 1354 allSetters.forEach((Element element) {
1360 backend.registerFieldConstructor(element, HType.UNKNOWN); 1355 backend.registerFieldConstructor(element, HType.UNKNOWN);
1361 }); 1356 });
1362 } 1357 }
1363 } 1358 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698