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

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

Issue 14253008: Optimize length access on all JSIndexable things. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix test. Created 7 years, 8 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 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 if (operand is HConstant) { 227 if (operand is HConstant) {
228 HConstant receiver = operand; 228 HConstant receiver = operand;
229 Constant folded = operation.fold(receiver.constant); 229 Constant folded = operation.fold(receiver.constant);
230 if (folded != null) return graph.addConstant(folded); 230 if (folded != null) return graph.addConstant(folded);
231 } 231 }
232 return null; 232 return null;
233 } 233 }
234 234
235 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) { 235 HInstruction tryOptimizeLengthInterceptedGetter(HInvokeDynamic node) {
236 HInstruction actualReceiver = node.inputs[1]; 236 HInstruction actualReceiver = node.inputs[1];
237 if (actualReceiver.isIndexablePrimitive()) { 237
238 // TODO(kasperl): Get rid of HType.isIndexablePrimitive() and use
239 // something like this everywhere instead.
240 TypeMask mask = actualReceiver.instructionType.computeMask(compiler);
241 DartType base = backend.jsIndexableClass.computeType(compiler);
242 TypeMask indexable = new TypeMask.nonNullSubtype(base);
243 TypeMask union = indexable.union(mask, compiler);
244 bool isIndexable = (union == indexable);
245
246 if (isIndexable) {
238 if (actualReceiver.isConstantString()) { 247 if (actualReceiver.isConstantString()) {
239 HConstant constantInput = actualReceiver; 248 HConstant constantInput = actualReceiver;
240 StringConstant constant = constantInput.constant; 249 StringConstant constant = constantInput.constant;
241 return graph.addConstantInt(constant.length, constantSystem); 250 return graph.addConstantInt(constant.length, constantSystem);
242 } else if (actualReceiver.isConstantList()) { 251 } else if (actualReceiver.isConstantList()) {
243 HConstant constantInput = actualReceiver; 252 HConstant constantInput = actualReceiver;
244 ListConstant constant = constantInput.constant; 253 ListConstant constant = constantInput.constant;
245 return graph.addConstantInt(constant.length, constantSystem); 254 return graph.addConstantInt(constant.length, constantSystem);
246 } 255 }
247 Element element; 256 Element element = backend.jsIndexableLength;
248 bool isAssignable; 257 bool isAssignable = !actualReceiver.isFixedArray() &&
249 if (actualReceiver.isString()) { 258 !actualReceiver.isString();
250 element = backend.jsStringLength;
251 isAssignable = false;
252 } else {
253 element = backend.jsArrayLength;
254 isAssignable = !actualReceiver.isFixedArray();
255 }
256 HFieldGet result = new HFieldGet( 259 HFieldGet result = new HFieldGet(
257 element, actualReceiver, isAssignable: isAssignable); 260 element, actualReceiver, isAssignable: isAssignable);
258 result.instructionType = HType.INTEGER; 261 result.instructionType = HType.INTEGER;
259 return result; 262 return result;
260 } else if (actualReceiver.isConstantMap()) { 263 } else if (actualReceiver.isConstantMap()) {
261 HConstant constantInput = actualReceiver; 264 HConstant constantInput = actualReceiver;
262 MapConstant constant = constantInput.constant; 265 MapConstant constant = constantInput.constant;
263 return graph.addConstantInt(constant.length, constantSystem); 266 return graph.addConstantInt(constant.length, constantSystem);
264 } 267 }
265 return null; 268 return null;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 // HForeign is too opaque for the SsaCheckInserter (that adds a 319 // HForeign is too opaque for the SsaCheckInserter (that adds a
317 // bounds check on removeLast). Once we start inlining, the 320 // bounds check on removeLast). Once we start inlining, the
318 // bounds check will become explicit, so we won't need this 321 // bounds check will become explicit, so we won't need this
319 // optimization. 322 // optimization.
320 HInvokeDynamicMethod result = new HInvokeDynamicMethod( 323 HInvokeDynamicMethod result = new HInvokeDynamicMethod(
321 node.selector, node.inputs.sublist(1)); 324 node.selector, node.inputs.sublist(1));
322 result.element = target; 325 result.element = target;
323 return result; 326 return result;
324 } 327 }
325 } else if (selector.isGetter()) { 328 } else if (selector.isGetter()) {
326 if (selector.applies(backend.jsArrayLength, compiler) 329 if (selector.asUntyped.applies(backend.jsIndexableLength, compiler)) {
327 || selector.applies(backend.jsStringLength, compiler)) {
328 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node); 330 HInstruction optimized = tryOptimizeLengthInterceptedGetter(node);
329 if (optimized != null) return optimized; 331 if (optimized != null) return optimized;
330 } 332 }
331 } 333 }
332 334
333 return node; 335 return node;
334 } 336 }
335 337
336 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { 338 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
337 if (node.isInterceptedCall) { 339 if (node.isInterceptedCall) {
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after
618 } 620 }
619 621
620 Element findConcreteFieldForDynamicAccess(HInstruction receiver, 622 Element findConcreteFieldForDynamicAccess(HInstruction receiver,
621 Selector selector) { 623 Selector selector) {
622 HType receiverType = receiver.instructionType; 624 HType receiverType = receiver.instructionType;
623 return compiler.world.locateSingleField( 625 return compiler.world.locateSingleField(
624 receiverType.refine(selector, compiler)); 626 receiverType.refine(selector, compiler));
625 } 627 }
626 628
627 HInstruction visitFieldGet(HFieldGet node) { 629 HInstruction visitFieldGet(HFieldGet node) {
628 if (node.element == backend.jsArrayLength) { 630 if (node.element == backend.jsIndexableLength) {
629 if (node.receiver is HInvokeStatic) { 631 if (node.receiver is HInvokeStatic) {
630 // Try to recognize the length getter with input 632 // Try to recognize the length getter with input
631 // [:new List(int):]. 633 // [:new List(int):].
632 HInvokeStatic call = node.receiver; 634 HInvokeStatic call = node.receiver;
633 Element element = call.target.element; 635 Element element = call.target.element;
634 // TODO(ngeoffray): checking if the second input is an integer 636 // TODO(ngeoffray): checking if the second input is an integer
635 // should not be necessary but it currently makes it easier for 637 // should not be necessary but it currently makes it easier for
636 // other optimizations to reason about a fixed length constructor 638 // other optimizations to reason about a fixed length constructor
637 // that we know takes an int. 639 // that we know takes an int.
638 if (element == compiler.unnamedListConstructor 640 if (element == compiler.unnamedListConstructor
639 && call.inputs.length == 2 641 && call.inputs.length == 2
640 && call.inputs[1].isInteger()) { 642 && call.inputs[1].isInteger()) {
641 return call.inputs[1]; 643 return call.inputs[1];
642 } 644 }
643 } else if (node.receiver.isConstantList()) { 645 } else if (node.receiver.isConstantList() ||
646 node.receiver.isConstantString()) {
644 var instruction = node.receiver; 647 var instruction = node.receiver;
645 return graph.addConstantInt( 648 return graph.addConstantInt(
646 instruction.constant.length, backend.constantSystem); 649 instruction.constant.length, backend.constantSystem);
647 } 650 }
648 } else if (node.element == backend.jsStringLength
649 && node.receiver.isConstantString()) {
650 var instruction = node.receiver;
651 return graph.addConstantInt(
652 instruction.constant.length, backend.constantSystem);
653 } 651 }
654 return node; 652 return node;
655 } 653 }
656 654
657 HInstruction visitIndex(HIndex node) { 655 HInstruction visitIndex(HIndex node) {
658 if (node.receiver.isConstantList() && node.index.isConstantInteger()) { 656 if (node.receiver.isConstantList() && node.index.isConstantInteger()) {
659 var instruction = node.receiver; 657 var instruction = node.receiver;
660 List<Constant> entries = instruction.constant.entries; 658 List<Constant> entries = instruction.constant.entries;
661 instruction = node.index; 659 instruction = node.index;
662 int index = instruction.constant.value; 660 int index = instruction.constant.value;
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after
934 HInstruction next = instruction.next; 932 HInstruction next = instruction.next;
935 instruction = instruction.accept(this); 933 instruction = instruction.accept(this);
936 instruction = next; 934 instruction = next;
937 } 935 }
938 } 936 }
939 937
940 HBoundsCheck insertBoundsCheck(HInstruction node, 938 HBoundsCheck insertBoundsCheck(HInstruction node,
941 HInstruction receiver, 939 HInstruction receiver,
942 HInstruction index) { 940 HInstruction index) {
943 bool isAssignable = !receiver.isFixedArray() && !receiver.isString(); 941 bool isAssignable = !receiver.isFixedArray() && !receiver.isString();
944 Element element = receiver.isString()
945 ? backend.jsStringLength
946 : backend.jsArrayLength;
947 HFieldGet length = new HFieldGet( 942 HFieldGet length = new HFieldGet(
948 element, receiver, isAssignable: isAssignable); 943 backend.jsIndexableLength, receiver, isAssignable: isAssignable);
949 length.instructionType = HType.INTEGER;
950 length.instructionType = HType.INTEGER; 944 length.instructionType = HType.INTEGER;
951 node.block.addBefore(node, length); 945 node.block.addBefore(node, length);
952 946
953 HBoundsCheck check = new HBoundsCheck(index, length); 947 HBoundsCheck check = new HBoundsCheck(index, length);
954 node.block.addBefore(node, check); 948 node.block.addBefore(node, check);
955 boundsChecked.add(node); 949 boundsChecked.add(node);
956 return check; 950 return check;
957 } 951 }
958 952
959 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) { 953 HIntegerCheck insertIntegerCheck(HInstruction node, HInstruction value) {
(...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after
1703 HBasicBlock block = user.block; 1697 HBasicBlock block = user.block;
1704 block.addAfter(user, interceptor); 1698 block.addAfter(user, interceptor);
1705 block.rewrite(user, interceptor); 1699 block.rewrite(user, interceptor);
1706 block.remove(user); 1700 block.remove(user);
1707 1701
1708 // The interceptor will be removed in the dead code elimination 1702 // The interceptor will be removed in the dead code elimination
1709 // phase. Note that removing it here would not work because of how 1703 // phase. Note that removing it here would not work because of how
1710 // the [visitBasicBlock] is implemented. 1704 // the [visitBasicBlock] is implemented.
1711 } 1705 }
1712 } 1706 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/ssa/codegen.dart ('k') | tests/compiler/dart2js/mock_compiler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698