OLD | NEW |
---|---|
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 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
6 import '../common/names.dart' show Selectors; | 6 import '../common/names.dart' show Selectors; |
7 import '../common/tasks.dart' show CompilerTask; | 7 import '../common/tasks.dart' show CompilerTask; |
8 import '../compiler.dart' show Compiler; | 8 import '../compiler.dart' show Compiler; |
9 import '../constants/constant_system.dart'; | 9 import '../constants/constant_system.dart'; |
10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
11 import '../core_types.dart' show CoreClasses; | 11 import '../core_types.dart' show CommonElements, CoreClasses; |
12 import '../dart_types.dart'; | 12 import '../dart_types.dart'; |
13 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
14 import '../js/js.dart' as js; | 14 import '../js/js.dart' as js; |
15 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 15 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
16 import '../js_backend/js_backend.dart'; | 16 import '../js_backend/js_backend.dart'; |
17 import '../native/native.dart' as native; | 17 import '../native/native.dart' as native; |
18 import '../tree/dartstring.dart' as ast; | 18 import '../tree/dartstring.dart' as ast; |
19 import '../types/types.dart'; | 19 import '../types/types.dart'; |
20 import '../universe/selector.dart' show Selector; | 20 import '../universe/selector.dart' show Selector; |
21 import '../universe/side_effects.dart' show SideEffects; | 21 import '../universe/side_effects.dart' show SideEffects; |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 132 /// of identifying gvn-able lengths and mis-identifies some unions of fixed |
133 /// length indexables (see TODO) as not fixed length. | 133 /// length indexables (see TODO) as not fixed length. |
134 bool isFixedLength(mask, Compiler compiler) { | 134 bool isFixedLength(mask, Compiler compiler) { |
135 ClosedWorld closedWorld = compiler.closedWorld; | 135 ClosedWorld closedWorld = compiler.closedWorld; |
136 JavaScriptBackend backend = compiler.backend; | 136 JavaScriptBackend backend = compiler.backend; |
137 if (mask.isContainer && mask.length != null) { | 137 if (mask.isContainer && mask.length != null) { |
138 // A container on which we have inferred the length. | 138 // A container on which we have inferred the length. |
139 return true; | 139 return true; |
140 } | 140 } |
141 // TODO(sra): Recognize any combination of fixed length indexables. | 141 // TODO(sra): Recognize any combination of fixed length indexables. |
142 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || | 142 if (mask.containsOnly(closedWorld.backendClasses.fixedListImplementation) || |
143 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || | 143 mask.containsOnly(closedWorld.backendClasses.constListImplementation) || |
144 mask.containsOnlyString(closedWorld) || | 144 mask.containsOnlyString(closedWorld) || |
145 backend.isTypedArray(mask)) { | 145 closedWorld.commonMasks.isTypedArray(mask)) { |
146 return true; | 146 return true; |
147 } | 147 } |
148 return false; | 148 return false; |
149 } | 149 } |
150 | 150 |
151 /** | 151 /** |
152 * If both inputs to known operations are available execute the operation at | 152 * If both inputs to known operations are available execute the operation at |
153 * compile-time. | 153 * compile-time. |
154 */ | 154 */ |
155 class SsaInstructionSimplifier extends HBaseVisitor | 155 class SsaInstructionSimplifier extends HBaseVisitor |
156 implements OptimizationPhase { | 156 implements OptimizationPhase { |
157 // We don't produce constant-folded strings longer than this unless they have | 157 // We don't produce constant-folded strings longer than this unless they have |
158 // a single use. This protects against exponentially large constant folded | 158 // a single use. This protects against exponentially large constant folded |
159 // strings. | 159 // strings. |
160 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; | 160 static const MAX_SHARED_CONSTANT_FOLDED_STRING_LENGTH = 512; |
161 | 161 |
162 final String name = "SsaInstructionSimplifier"; | 162 final String name = "SsaInstructionSimplifier"; |
163 final JavaScriptBackend backend; | 163 final JavaScriptBackend backend; |
164 final ConstantSystem constantSystem; | 164 final ConstantSystem constantSystem; |
165 final CodegenRegistry registry; | 165 final CodegenRegistry registry; |
166 HGraph graph; | 166 HGraph graph; |
167 Compiler get compiler => backend.compiler; | 167 Compiler get compiler => backend.compiler; |
168 final SsaOptimizerTask optimizer; | 168 final SsaOptimizerTask optimizer; |
169 | 169 |
170 SsaInstructionSimplifier( | 170 SsaInstructionSimplifier( |
171 this.constantSystem, this.backend, this.optimizer, this.registry); | 171 this.constantSystem, this.backend, this.optimizer, this.registry); |
172 | 172 |
173 CoreClasses get coreClasses => compiler.coreClasses; | 173 CoreClasses get coreClasses => closedWorld.coreClasses; |
Siggi Cherem (dart-lang)
2016/12/12 15:50:16
should we remove this one and use commonElements i
Johnni Winther
2016/12/13 11:20:28
Done.
| |
174 | 174 |
175 ClosedWorld get closedWorld => compiler.closedWorld; | 175 ClosedWorld get closedWorld => compiler.closedWorld; |
176 | 176 |
177 CommonElements get commonElements => closedWorld.commonElements; | |
178 | |
177 BackendHelpers get helpers => backend.helpers; | 179 BackendHelpers get helpers => backend.helpers; |
178 | 180 |
181 GlobalTypeInferenceResults get globalInferenceResults => | |
182 compiler.globalInference.results; | |
183 | |
179 void visitGraph(HGraph visitee) { | 184 void visitGraph(HGraph visitee) { |
180 graph = visitee; | 185 graph = visitee; |
181 visitDominatorTree(visitee); | 186 visitDominatorTree(visitee); |
182 } | 187 } |
183 | 188 |
184 visitBasicBlock(HBasicBlock block) { | 189 visitBasicBlock(HBasicBlock block) { |
185 HInstruction instruction = block.first; | 190 HInstruction instruction = block.first; |
186 while (instruction != null) { | 191 while (instruction != null) { |
187 HInstruction next = instruction.next; | 192 HInstruction next = instruction.next; |
188 HInstruction replacement = instruction.accept(this); | 193 HInstruction replacement = instruction.accept(this); |
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
440 return node; | 445 return node; |
441 } | 446 } |
442 | 447 |
443 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 448 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
444 propagateConstantValueToUses(node); | 449 propagateConstantValueToUses(node); |
445 if (node.isInterceptedCall) { | 450 if (node.isInterceptedCall) { |
446 HInstruction folded = handleInterceptedCall(node); | 451 HInstruction folded = handleInterceptedCall(node); |
447 if (folded != node) return folded; | 452 if (folded != node) return folded; |
448 } | 453 } |
449 | 454 |
450 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; | 455 TypeMask receiverType = node.getDartReceiver(closedWorld).instructionType; |
451 Element element = | 456 Element element = |
452 compiler.closedWorld.locateSingleElement(node.selector, receiverType); | 457 closedWorld.locateSingleElement(node.selector, receiverType); |
453 // TODO(ngeoffray): Also fold if it's a getter or variable. | 458 // TODO(ngeoffray): Also fold if it's a getter or variable. |
454 if (element != null && | 459 if (element != null && |
455 element.isFunction | 460 element.isFunction |
456 // If we found out that the only target is an implicitly called | 461 // If we found out that the only target is an implicitly called |
457 // [:noSuchMethod:] we just ignore it. | 462 // [:noSuchMethod:] we just ignore it. |
458 && | 463 && |
459 node.selector.applies(element)) { | 464 node.selector.applies(element)) { |
460 MethodElement method = element; | 465 MethodElement method = element; |
461 | 466 |
462 if (backend.isNative(method)) { | 467 if (backend.isNative(method)) { |
(...skipping 12 matching lines...) Expand all Loading... | |
475 } | 480 } |
476 | 481 |
477 // Replace method calls through fields with a closure call on the value of | 482 // Replace method calls through fields with a closure call on the value of |
478 // the field. This usually removes the demand for the call-through stub and | 483 // the field. This usually removes the demand for the call-through stub and |
479 // makes the field load available to further optimization, e.g. LICM. | 484 // makes the field load available to further optimization, e.g. LICM. |
480 | 485 |
481 if (element != null && | 486 if (element != null && |
482 element.isField && | 487 element.isField && |
483 element.name == node.selector.name) { | 488 element.name == node.selector.name) { |
484 FieldElement field = element; | 489 FieldElement field = element; |
485 if (!backend.isNative(field) && !node.isCallOnInterceptor(compiler)) { | 490 if (!backend.isNative(field) && !node.isCallOnInterceptor(closedWorld)) { |
486 HInstruction receiver = node.getDartReceiver(compiler); | 491 HInstruction receiver = node.getDartReceiver(closedWorld); |
487 TypeMask type = TypeMaskFactory.inferredTypeForElement(field, compiler); | 492 TypeMask type = TypeMaskFactory.inferredTypeForElement( |
493 field, globalInferenceResults); | |
488 HInstruction load = new HFieldGet(field, receiver, type); | 494 HInstruction load = new HFieldGet(field, receiver, type); |
489 node.block.addBefore(node, load); | 495 node.block.addBefore(node, load); |
490 Selector callSelector = new Selector.callClosureFrom(node.selector); | 496 Selector callSelector = new Selector.callClosureFrom(node.selector); |
491 List<HInstruction> inputs = <HInstruction>[load] | 497 List<HInstruction> inputs = <HInstruction>[load] |
492 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); | 498 ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1)); |
493 HInstruction closureCall = | 499 HInstruction closureCall = |
494 new HInvokeClosure(callSelector, inputs, node.instructionType) | 500 new HInvokeClosure(callSelector, inputs, node.instructionType) |
495 ..sourceInformation = node.sourceInformation; | 501 ..sourceInformation = node.sourceInformation; |
496 node.block.addAfter(load, closureCall); | 502 node.block.addAfter(load, closureCall); |
497 return closureCall; | 503 return closureCall; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
547 } | 553 } |
548 }); | 554 }); |
549 | 555 |
550 if (!canInline) return null; | 556 if (!canInline) return null; |
551 | 557 |
552 // Strengthen instruction type from annotations to help optimize | 558 // Strengthen instruction type from annotations to help optimize |
553 // dependent instructions. | 559 // dependent instructions. |
554 native.NativeBehavior nativeBehavior = | 560 native.NativeBehavior nativeBehavior = |
555 backend.getNativeMethodBehavior(method); | 561 backend.getNativeMethodBehavior(method); |
556 TypeMask returnType = | 562 TypeMask returnType = |
557 TypeMaskFactory.fromNativeBehavior(nativeBehavior, compiler); | 563 TypeMaskFactory.fromNativeBehavior(nativeBehavior, closedWorld); |
558 HInvokeDynamicMethod result = | 564 HInvokeDynamicMethod result = |
559 new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType); | 565 new HInvokeDynamicMethod(node.selector, node.mask, inputs, returnType); |
560 result.element = method; | 566 result.element = method; |
561 return result; | 567 return result; |
562 } | 568 } |
563 | 569 |
564 HInstruction visitBoundsCheck(HBoundsCheck node) { | 570 HInstruction visitBoundsCheck(HBoundsCheck node) { |
565 HInstruction index = node.index; | 571 HInstruction index = node.index; |
566 if (index.isInteger(closedWorld)) return node; | 572 if (index.isInteger(closedWorld)) return node; |
567 if (index.isConstant()) { | 573 if (index.isConstant()) { |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
737 } | 743 } |
738 | 744 |
739 if (type.isObject || type.treatAsDynamic) { | 745 if (type.isObject || type.treatAsDynamic) { |
740 return graph.addConstantBool(true, compiler); | 746 return graph.addConstantBool(true, compiler); |
741 } | 747 } |
742 | 748 |
743 HInstruction expression = node.expression; | 749 HInstruction expression = node.expression; |
744 if (expression.isInteger(closedWorld)) { | 750 if (expression.isInteger(closedWorld)) { |
745 if (element == coreClasses.intClass || | 751 if (element == coreClasses.intClass || |
746 element == coreClasses.numClass || | 752 element == coreClasses.numClass || |
747 Elements.isNumberOrStringSupertype(element, compiler)) { | 753 Elements.isNumberOrStringSupertype(element, commonElements)) { |
748 return graph.addConstantBool(true, compiler); | 754 return graph.addConstantBool(true, compiler); |
749 } else if (element == coreClasses.doubleClass) { | 755 } else if (element == coreClasses.doubleClass) { |
750 // We let the JS semantics decide for that check. Currently | 756 // We let the JS semantics decide for that check. Currently |
751 // the code we emit will always return true. | 757 // the code we emit will always return true. |
752 return node; | 758 return node; |
753 } else { | 759 } else { |
754 return graph.addConstantBool(false, compiler); | 760 return graph.addConstantBool(false, compiler); |
755 } | 761 } |
756 } else if (expression.isDouble(closedWorld)) { | 762 } else if (expression.isDouble(closedWorld)) { |
757 if (element == coreClasses.doubleClass || | 763 if (element == coreClasses.doubleClass || |
758 element == coreClasses.numClass || | 764 element == coreClasses.numClass || |
759 Elements.isNumberOrStringSupertype(element, compiler)) { | 765 Elements.isNumberOrStringSupertype(element, commonElements)) { |
760 return graph.addConstantBool(true, compiler); | 766 return graph.addConstantBool(true, compiler); |
761 } else if (element == coreClasses.intClass) { | 767 } else if (element == coreClasses.intClass) { |
762 // We let the JS semantics decide for that check. Currently | 768 // We let the JS semantics decide for that check. Currently |
763 // the code we emit will return true for a double that can be | 769 // the code we emit will return true for a double that can be |
764 // represented as a 31-bit integer and for -0.0. | 770 // represented as a 31-bit integer and for -0.0. |
765 return node; | 771 return node; |
766 } else { | 772 } else { |
767 return graph.addConstantBool(false, compiler); | 773 return graph.addConstantBool(false, compiler); |
768 } | 774 } |
769 } else if (expression.isNumber(closedWorld)) { | 775 } else if (expression.isNumber(closedWorld)) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
838 HInstruction input = node.checkedInput; | 844 HInstruction input = node.checkedInput; |
839 TypeMask inputType = input.instructionType; | 845 TypeMask inputType = input.instructionType; |
840 return inputType.isInMask(checkedType, closedWorld) ? input : node; | 846 return inputType.isInMask(checkedType, closedWorld) ? input : node; |
841 } | 847 } |
842 | 848 |
843 HInstruction removeCheck(HCheck node) => node.checkedInput; | 849 HInstruction removeCheck(HCheck node) => node.checkedInput; |
844 | 850 |
845 FieldElement findConcreteFieldForDynamicAccess( | 851 FieldElement findConcreteFieldForDynamicAccess( |
846 HInstruction receiver, Selector selector) { | 852 HInstruction receiver, Selector selector) { |
847 TypeMask receiverType = receiver.instructionType; | 853 TypeMask receiverType = receiver.instructionType; |
848 return compiler.closedWorld.locateSingleField(selector, receiverType); | 854 return closedWorld.locateSingleField(selector, receiverType); |
849 } | 855 } |
850 | 856 |
851 HInstruction visitFieldGet(HFieldGet node) { | 857 HInstruction visitFieldGet(HFieldGet node) { |
852 if (node.isNullCheck) return node; | 858 if (node.isNullCheck) return node; |
853 var receiver = node.receiver; | 859 var receiver = node.receiver; |
854 if (node.element == helpers.jsIndexableLength) { | 860 if (node.element == helpers.jsIndexableLength) { |
855 if (graph.allocatedFixedLists.contains(receiver)) { | 861 if (graph.allocatedFixedLists.contains(receiver)) { |
856 // TODO(ngeoffray): checking if the second input is an integer | 862 // TODO(ngeoffray): checking if the second input is an integer |
857 // should not be necessary but it currently makes it easier for | 863 // should not be necessary but it currently makes it easier for |
858 // other optimizations to reason about a fixed length constructor | 864 // other optimizations to reason about a fixed length constructor |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
909 } | 915 } |
910 return node; | 916 return node; |
911 } | 917 } |
912 | 918 |
913 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { | 919 HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) { |
914 propagateConstantValueToUses(node); | 920 propagateConstantValueToUses(node); |
915 if (node.isInterceptedCall) { | 921 if (node.isInterceptedCall) { |
916 HInstruction folded = handleInterceptedCall(node); | 922 HInstruction folded = handleInterceptedCall(node); |
917 if (folded != node) return folded; | 923 if (folded != node) return folded; |
918 } | 924 } |
919 HInstruction receiver = node.getDartReceiver(compiler); | 925 HInstruction receiver = node.getDartReceiver(closedWorld); |
920 FieldElement field = | 926 FieldElement field = |
921 findConcreteFieldForDynamicAccess(receiver, node.selector); | 927 findConcreteFieldForDynamicAccess(receiver, node.selector); |
922 if (field != null) return directFieldGet(receiver, field); | 928 if (field != null) return directFieldGet(receiver, field); |
923 | 929 |
924 if (node.element == null) { | 930 if (node.element == null) { |
925 MemberElement element = closedWorld.locateSingleElement( | 931 MemberElement element = closedWorld.locateSingleElement( |
926 node.selector, receiver.instructionType); | 932 node.selector, receiver.instructionType); |
927 if (element != null && element.name == node.selector.name) { | 933 if (element != null && element.name == node.selector.name) { |
928 node.element = element; | 934 node.element = element; |
929 if (element.isFunction) { | 935 if (element.isFunction) { |
930 // A property extraction getter, aka a tear-off. | 936 // A property extraction getter, aka a tear-off. |
931 node.sideEffects.clearAllDependencies(); | 937 node.sideEffects.clearAllDependencies(); |
932 node.sideEffects.clearAllSideEffects(); | 938 node.sideEffects.clearAllSideEffects(); |
933 node.setUseGvn(); // We don't care about identity of tear-offs. | 939 node.setUseGvn(); // We don't care about identity of tear-offs. |
934 } | 940 } |
935 } | 941 } |
936 } | 942 } |
937 return node; | 943 return node; |
938 } | 944 } |
939 | 945 |
940 HInstruction directFieldGet(HInstruction receiver, FieldElement field) { | 946 HInstruction directFieldGet(HInstruction receiver, FieldElement field) { |
941 bool isAssignable = !closedWorld.fieldNeverChanges(field); | 947 bool isAssignable = !closedWorld.fieldNeverChanges(field); |
942 | 948 |
943 TypeMask type; | 949 TypeMask type; |
944 if (backend.isNative(field.enclosingClass)) { | 950 if (backend.isNative(field.enclosingClass)) { |
945 type = TypeMaskFactory.fromNativeBehavior( | 951 type = TypeMaskFactory.fromNativeBehavior( |
946 backend.getNativeFieldLoadBehavior(field), compiler); | 952 backend.getNativeFieldLoadBehavior(field), closedWorld); |
947 } else { | 953 } else { |
948 type = TypeMaskFactory.inferredTypeForElement(field, compiler); | 954 type = |
955 TypeMaskFactory.inferredTypeForElement(field, globalInferenceResults); | |
949 } | 956 } |
950 | 957 |
951 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); | 958 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); |
952 } | 959 } |
953 | 960 |
954 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { | 961 HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) { |
955 if (node.isInterceptedCall) { | 962 if (node.isInterceptedCall) { |
956 HInstruction folded = handleInterceptedCall(node); | 963 HInstruction folded = handleInterceptedCall(node); |
957 if (folded != node) return folded; | 964 if (folded != node) return folded; |
958 } | 965 } |
959 | 966 |
960 HInstruction receiver = node.getDartReceiver(compiler); | 967 HInstruction receiver = node.getDartReceiver(closedWorld); |
961 FieldElement field = | 968 FieldElement field = |
962 findConcreteFieldForDynamicAccess(receiver, node.selector); | 969 findConcreteFieldForDynamicAccess(receiver, node.selector); |
963 if (field == null || !field.isAssignable) return node; | 970 if (field == null || !field.isAssignable) return node; |
964 // Use `node.inputs.last` in case the call follows the interceptor calling | 971 // Use `node.inputs.last` in case the call follows the interceptor calling |
965 // convention, but is not a call on an interceptor. | 972 // convention, but is not a call on an interceptor. |
966 HInstruction value = node.inputs.last; | 973 HInstruction value = node.inputs.last; |
967 if (compiler.options.enableTypeAssertions) { | 974 if (compiler.options.enableTypeAssertions) { |
968 DartType type = field.type; | 975 DartType type = field.type; |
969 if (!type.treatAsRaw || | 976 if (!type.treatAsRaw || |
970 type.isTypeVariable || | 977 type.isTypeVariable || |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1087 | 1094 |
1088 HInstruction tryToString() { | 1095 HInstruction tryToString() { |
1089 // If the `toString` method is guaranteed to return a string we can call | 1096 // If the `toString` method is guaranteed to return a string we can call |
1090 // it directly. Keep the stringifier for primitives (since they have fast | 1097 // it directly. Keep the stringifier for primitives (since they have fast |
1091 // path code in the stringifier) and for classes requiring interceptors | 1098 // path code in the stringifier) and for classes requiring interceptors |
1092 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). | 1099 // (since SsaInstructionSimplifier runs after SsaSimplifyInterceptors). |
1093 if (input.canBePrimitive(closedWorld)) return null; | 1100 if (input.canBePrimitive(closedWorld)) return null; |
1094 if (input.canBeNull()) return null; | 1101 if (input.canBeNull()) return null; |
1095 Selector selector = Selectors.toString_; | 1102 Selector selector = Selectors.toString_; |
1096 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector( | 1103 TypeMask toStringType = TypeMaskFactory.inferredTypeForSelector( |
1097 selector, input.instructionType, compiler); | 1104 selector, input.instructionType, globalInferenceResults); |
1098 if (!toStringType.containsOnlyString(closedWorld)) return null; | 1105 if (!toStringType.containsOnlyString(closedWorld)) return null; |
1099 // All intercepted classes extend `Interceptor`, so if the receiver can't | 1106 // All intercepted classes extend `Interceptor`, so if the receiver can't |
1100 // be a class extending `Interceptor` then it can be called directly. | 1107 // be a class extending `Interceptor` then it can be called directly. |
1101 if (new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld) | 1108 if (new TypeMask.nonNullSubclass(helpers.jsInterceptorClass, closedWorld) |
1102 .isDisjoint(input.instructionType, closedWorld)) { | 1109 .isDisjoint(input.instructionType, closedWorld)) { |
1103 var inputs = <HInstruction>[input, input]; // [interceptor, receiver]. | 1110 var inputs = <HInstruction>[input, input]; // [interceptor, receiver]. |
1104 HInstruction result = new HInvokeDynamicMethod( | 1111 HInstruction result = new HInvokeDynamicMethod( |
1105 selector, | 1112 selector, |
1106 input.instructionType, // receiver mask. | 1113 input.instructionType, // receiver mask. |
1107 inputs, | 1114 inputs, |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1430 return hole.isPositional && hole.nameOrPosition == 0; | 1437 return hole.isPositional && hole.nameOrPosition == 0; |
1431 } | 1438 } |
1432 } | 1439 } |
1433 return false; | 1440 return false; |
1434 } | 1441 } |
1435 | 1442 |
1436 /// Returns whether the next throwing instruction that may have side | 1443 /// Returns whether the next throwing instruction that may have side |
1437 /// effects after [instruction], throws [NoSuchMethodError] on the | 1444 /// effects after [instruction], throws [NoSuchMethodError] on the |
1438 /// same receiver of [instruction]. | 1445 /// same receiver of [instruction]. |
1439 bool hasFollowingThrowingNSM(HInstruction instruction) { | 1446 bool hasFollowingThrowingNSM(HInstruction instruction) { |
1440 HInstruction receiver = instruction.getDartReceiver(compiler); | 1447 HInstruction receiver = instruction.getDartReceiver(closedWorld); |
1441 HInstruction current = instruction.next; | 1448 HInstruction current = instruction.next; |
1442 do { | 1449 do { |
1443 if ((current.getDartReceiver(compiler) == receiver) && | 1450 if ((current.getDartReceiver(closedWorld) == receiver) && |
1444 current.canThrow()) { | 1451 current.canThrow()) { |
1445 return true; | 1452 return true; |
1446 } | 1453 } |
1447 if (current is HForeignCode && | 1454 if (current is HForeignCode && |
1448 templateThrowsNSMonNull(current, receiver)) { | 1455 templateThrowsNSMonNull(current, receiver)) { |
1449 return true; | 1456 return true; |
1450 } | 1457 } |
1451 if (current.canThrow() || current.sideEffects.hasSideEffects()) { | 1458 if (current.canThrow() || current.sideEffects.hasSideEffects()) { |
1452 return false; | 1459 return false; |
1453 } | 1460 } |
(...skipping 23 matching lines...) Expand all Loading... | |
1477 } | 1484 } |
1478 | 1485 |
1479 bool isTrivialDeadStoreReceiver(HInstruction instruction) { | 1486 bool isTrivialDeadStoreReceiver(HInstruction instruction) { |
1480 // For an allocation, if all the loads are dead (awaiting removal after | 1487 // For an allocation, if all the loads are dead (awaiting removal after |
1481 // SsaLoadElimination) and the only other uses are stores, then the | 1488 // SsaLoadElimination) and the only other uses are stores, then the |
1482 // allocation does not escape which makes all the stores dead too. | 1489 // allocation does not escape which makes all the stores dead too. |
1483 bool isDeadUse(HInstruction use) { | 1490 bool isDeadUse(HInstruction use) { |
1484 if (use is HFieldSet) { | 1491 if (use is HFieldSet) { |
1485 // The use must be the receiver. Even if the use is also the argument, | 1492 // The use must be the receiver. Even if the use is also the argument, |
1486 // i.e. a.x = a, the store is still dead if all other uses are dead. | 1493 // i.e. a.x = a, the store is still dead if all other uses are dead. |
1487 if (use.getDartReceiver(compiler) == instruction) return true; | 1494 if (use.getDartReceiver(closedWorld) == instruction) return true; |
1488 } else if (use is HFieldGet) { | 1495 } else if (use is HFieldGet) { |
1489 assert(use.getDartReceiver(compiler) == instruction); | 1496 assert(use.getDartReceiver(closedWorld) == instruction); |
1490 if (isDeadCode(use)) return true; | 1497 if (isDeadCode(use)) return true; |
1491 } | 1498 } |
1492 return false; | 1499 return false; |
1493 } | 1500 } |
1494 | 1501 |
1495 return instruction.isAllocation && | 1502 return instruction.isAllocation && |
1496 instruction.isPure() && | 1503 instruction.isPure() && |
1497 trivialDeadStoreReceivers.putIfAbsent( | 1504 trivialDeadStoreReceivers.putIfAbsent( |
1498 instruction, () => instruction.usedBy.every(isDeadUse)); | 1505 instruction, () => instruction.usedBy.every(isDeadUse)); |
1499 } | 1506 } |
1500 | 1507 |
1501 bool isTrivialDeadStore(HInstruction instruction) { | 1508 bool isTrivialDeadStore(HInstruction instruction) { |
1502 return instruction is HFieldSet && | 1509 return instruction is HFieldSet && |
1503 isTrivialDeadStoreReceiver(instruction.getDartReceiver(compiler)); | 1510 isTrivialDeadStoreReceiver(instruction.getDartReceiver(closedWorld)); |
1504 } | 1511 } |
1505 | 1512 |
1506 bool isDeadCode(HInstruction instruction) { | 1513 bool isDeadCode(HInstruction instruction) { |
1507 if (!instruction.usedBy.isEmpty) return false; | 1514 if (!instruction.usedBy.isEmpty) return false; |
1508 if (isTrivialDeadStore(instruction)) return true; | 1515 if (isTrivialDeadStore(instruction)) return true; |
1509 if (instruction.sideEffects.hasSideEffects()) return false; | 1516 if (instruction.sideEffects.hasSideEffects()) return false; |
1510 if (instruction.canThrow() && | 1517 if (instruction.canThrow() && |
1511 instruction.onlyThrowsNSM() && | 1518 instruction.onlyThrowsNSM() && |
1512 hasFollowingThrowingNSM(instruction)) { | 1519 hasFollowingThrowingNSM(instruction)) { |
1513 return true; | 1520 return true; |
(...skipping 708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2222 * location. | 2229 * location. |
2223 */ | 2230 */ |
2224 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { | 2231 class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase { |
2225 final Compiler compiler; | 2232 final Compiler compiler; |
2226 final String name = "SsaLoadElimination"; | 2233 final String name = "SsaLoadElimination"; |
2227 MemorySet memorySet; | 2234 MemorySet memorySet; |
2228 List<MemorySet> memories; | 2235 List<MemorySet> memories; |
2229 | 2236 |
2230 SsaLoadElimination(this.compiler); | 2237 SsaLoadElimination(this.compiler); |
2231 | 2238 |
2239 ClosedWorld get closedWorld => compiler.closedWorld; | |
2240 | |
2232 void visitGraph(HGraph graph) { | 2241 void visitGraph(HGraph graph) { |
2233 memories = new List<MemorySet>(graph.blocks.length); | 2242 memories = new List<MemorySet>(graph.blocks.length); |
2234 List<HBasicBlock> blocks = graph.blocks; | 2243 List<HBasicBlock> blocks = graph.blocks; |
2235 for (int i = 0; i < blocks.length; i++) { | 2244 for (int i = 0; i < blocks.length; i++) { |
2236 HBasicBlock block = blocks[i]; | 2245 HBasicBlock block = blocks[i]; |
2237 visitBasicBlock(block); | 2246 visitBasicBlock(block); |
2238 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { | 2247 if (block.successors.isNotEmpty && block.successors[0].isLoopHeader()) { |
2239 // We've reached the ending block of a loop. Iterate over the | 2248 // We've reached the ending block of a loop. Iterate over the |
2240 // blocks of the loop again to take values that flow from that | 2249 // blocks of the loop again to take values that flow from that |
2241 // ending block into account. | 2250 // ending block into account. |
2242 for (int j = block.successors[0].id; j <= block.id; j++) { | 2251 for (int j = block.successors[0].id; j <= block.id; j++) { |
2243 visitBasicBlock(blocks[j]); | 2252 visitBasicBlock(blocks[j]); |
2244 } | 2253 } |
2245 } | 2254 } |
2246 } | 2255 } |
2247 } | 2256 } |
2248 | 2257 |
2249 void visitBasicBlock(HBasicBlock block) { | 2258 void visitBasicBlock(HBasicBlock block) { |
2250 if (block.predecessors.length == 0) { | 2259 if (block.predecessors.length == 0) { |
2251 // Entry block. | 2260 // Entry block. |
2252 memorySet = new MemorySet(compiler); | 2261 memorySet = new MemorySet(closedWorld); |
2253 } else if (block.predecessors.length == 1 && | 2262 } else if (block.predecessors.length == 1 && |
2254 block.predecessors[0].successors.length == 1) { | 2263 block.predecessors[0].successors.length == 1) { |
2255 // No need to clone, there is no other successor for | 2264 // No need to clone, there is no other successor for |
2256 // `block.predecessors[0]`, and this block has only one | 2265 // `block.predecessors[0]`, and this block has only one |
2257 // predecessor. Since we are not going to visit | 2266 // predecessor. Since we are not going to visit |
2258 // `block.predecessors[0]` again, we can just re-use its | 2267 // `block.predecessors[0]` again, we can just re-use its |
2259 // [memorySet]. | 2268 // [memorySet]. |
2260 memorySet = memories[block.predecessors[0].id]; | 2269 memorySet = memories[block.predecessors[0].id]; |
2261 } else if (block.predecessors.length == 1) { | 2270 } else if (block.predecessors.length == 1) { |
2262 // Clone the memorySet of the predecessor, because it is also used | 2271 // Clone the memorySet of the predecessor, because it is also used |
(...skipping 13 matching lines...) Expand all Loading... | |
2276 while (instruction != null) { | 2285 while (instruction != null) { |
2277 HInstruction next = instruction.next; | 2286 HInstruction next = instruction.next; |
2278 instruction.accept(this); | 2287 instruction.accept(this); |
2279 instruction = next; | 2288 instruction = next; |
2280 } | 2289 } |
2281 } | 2290 } |
2282 | 2291 |
2283 void visitFieldGet(HFieldGet instruction) { | 2292 void visitFieldGet(HFieldGet instruction) { |
2284 if (instruction.isNullCheck) return; | 2293 if (instruction.isNullCheck) return; |
2285 MemberElement element = instruction.element; | 2294 MemberElement element = instruction.element; |
2286 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); | 2295 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); |
2287 HInstruction existing = memorySet.lookupFieldValue(element, receiver); | 2296 HInstruction existing = memorySet.lookupFieldValue(element, receiver); |
2288 if (existing != null) { | 2297 if (existing != null) { |
2289 instruction.block.rewriteWithBetterUser(instruction, existing); | 2298 instruction.block.rewriteWithBetterUser(instruction, existing); |
2290 instruction.block.remove(instruction); | 2299 instruction.block.remove(instruction); |
2291 } else { | 2300 } else { |
2292 memorySet.registerFieldValue(element, receiver, instruction); | 2301 memorySet.registerFieldValue(element, receiver, instruction); |
2293 } | 2302 } |
2294 } | 2303 } |
2295 | 2304 |
2296 void visitFieldSet(HFieldSet instruction) { | 2305 void visitFieldSet(HFieldSet instruction) { |
2297 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); | 2306 HInstruction receiver = instruction.getDartReceiver(closedWorld).nonCheck(); |
2298 memorySet.registerFieldValueUpdate( | 2307 memorySet.registerFieldValueUpdate( |
2299 instruction.element, receiver, instruction.inputs.last); | 2308 instruction.element, receiver, instruction.inputs.last); |
2300 } | 2309 } |
2301 | 2310 |
2302 void visitCreate(HCreate instruction) { | 2311 void visitCreate(HCreate instruction) { |
2303 memorySet.registerAllocation(instruction); | 2312 memorySet.registerAllocation(instruction); |
2304 if (shouldTrackInitialValues(instruction)) { | 2313 if (shouldTrackInitialValues(instruction)) { |
2305 int argumentIndex = 0; | 2314 int argumentIndex = 0; |
2306 instruction.element.forEachInstanceField((_, FieldElement member) { | 2315 instruction.element.forEachInstanceField((_, FieldElement member) { |
2307 if (compiler.elementHasCompileTimeError(member)) return; | 2316 if (compiler.elementHasCompileTimeError(member)) return; |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2427 | 2436 |
2428 /** | 2437 /** |
2429 * Holds values of memory places. | 2438 * Holds values of memory places. |
2430 * | 2439 * |
2431 * Generally, values that name a place (a receiver) have type refinements and | 2440 * Generally, values that name a place (a receiver) have type refinements and |
2432 * other checks removed to ensure that checks and type refinements do not | 2441 * other checks removed to ensure that checks and type refinements do not |
2433 * confuse aliasing. Values stored into a memory place keep the type | 2442 * confuse aliasing. Values stored into a memory place keep the type |
2434 * refinements to help further optimizations. | 2443 * refinements to help further optimizations. |
2435 */ | 2444 */ |
2436 class MemorySet { | 2445 class MemorySet { |
2437 final Compiler compiler; | 2446 final ClosedWorld closedWorld; |
2438 | 2447 |
2439 /** | 2448 /** |
2440 * Maps a field to a map of receiver to value. | 2449 * Maps a field to a map of receiver to value. |
2441 */ | 2450 */ |
2442 final Map<Element, Map<HInstruction, HInstruction>> fieldValues = | 2451 final Map<Element, Map<HInstruction, HInstruction>> fieldValues = |
2443 <Element, Map<HInstruction, HInstruction>>{}; | 2452 <Element, Map<HInstruction, HInstruction>>{}; |
2444 | 2453 |
2445 /** | 2454 /** |
2446 * Maps a receiver to a map of keys to value. | 2455 * Maps a receiver to a map of keys to value. |
2447 */ | 2456 */ |
2448 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues = | 2457 final Map<HInstruction, Map<HInstruction, HInstruction>> keyedValues = |
2449 <HInstruction, Map<HInstruction, HInstruction>>{}; | 2458 <HInstruction, Map<HInstruction, HInstruction>>{}; |
2450 | 2459 |
2451 /** | 2460 /** |
2452 * Set of objects that we know don't escape the current function. | 2461 * Set of objects that we know don't escape the current function. |
2453 */ | 2462 */ |
2454 final Setlet<HInstruction> nonEscapingReceivers = new Setlet<HInstruction>(); | 2463 final Setlet<HInstruction> nonEscapingReceivers = new Setlet<HInstruction>(); |
2455 | 2464 |
2456 MemorySet(this.compiler); | 2465 MemorySet(this.closedWorld); |
2457 | |
2458 JavaScriptBackend get backend => compiler.backend; | |
2459 | 2466 |
2460 /** | 2467 /** |
2461 * Returns whether [first] and [second] always alias to the same object. | 2468 * Returns whether [first] and [second] always alias to the same object. |
2462 */ | 2469 */ |
2463 bool mustAlias(HInstruction first, HInstruction second) { | 2470 bool mustAlias(HInstruction first, HInstruction second) { |
2464 return first == second; | 2471 return first == second; |
2465 } | 2472 } |
2466 | 2473 |
2467 /** | 2474 /** |
2468 * Returns whether [first] and [second] may alias to the same object. | 2475 * Returns whether [first] and [second] may alias to the same object. |
2469 */ | 2476 */ |
2470 bool mayAlias(HInstruction first, HInstruction second) { | 2477 bool mayAlias(HInstruction first, HInstruction second) { |
2471 if (mustAlias(first, second)) return true; | 2478 if (mustAlias(first, second)) return true; |
2472 if (isConcrete(first) && isConcrete(second)) return false; | 2479 if (isConcrete(first) && isConcrete(second)) return false; |
2473 if (nonEscapingReceivers.contains(first)) return false; | 2480 if (nonEscapingReceivers.contains(first)) return false; |
2474 if (nonEscapingReceivers.contains(second)) return false; | 2481 if (nonEscapingReceivers.contains(second)) return false; |
2475 // Typed arrays of different types might have a shared buffer. | 2482 // Typed arrays of different types might have a shared buffer. |
2476 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; | 2483 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; |
2477 return !first.instructionType | 2484 return !first.instructionType |
2478 .isDisjoint(second.instructionType, compiler.closedWorld); | 2485 .isDisjoint(second.instructionType, closedWorld); |
2479 } | 2486 } |
2480 | 2487 |
2481 bool isFinal(Element element) { | 2488 bool isFinal(Element element) { |
2482 return compiler.closedWorld.fieldNeverChanges(element); | 2489 return closedWorld.fieldNeverChanges(element); |
2483 } | 2490 } |
2484 | 2491 |
2485 bool isConcrete(HInstruction instruction) { | 2492 bool isConcrete(HInstruction instruction) { |
2486 return instruction is HCreate || | 2493 return instruction is HCreate || |
2487 instruction is HConstant || | 2494 instruction is HConstant || |
2488 instruction is HLiteralList; | 2495 instruction is HLiteralList; |
2489 } | 2496 } |
2490 | 2497 |
2491 bool couldBeTypedArray(HInstruction receiver) { | 2498 bool couldBeTypedArray(HInstruction receiver) { |
2492 JavaScriptBackend backend = compiler.backend; | 2499 return closedWorld.commonMasks.couldBeTypedArray(receiver.instructionType); |
2493 return backend.couldBeTypedArray(receiver.instructionType); | |
2494 } | 2500 } |
2495 | 2501 |
2496 /** | 2502 /** |
2497 * Returns whether [receiver] escapes the current function. | 2503 * Returns whether [receiver] escapes the current function. |
2498 */ | 2504 */ |
2499 bool escapes(HInstruction receiver) { | 2505 bool escapes(HInstruction receiver) { |
2500 assert(receiver == null || receiver == receiver.nonCheck()); | 2506 assert(receiver == null || receiver == receiver.nonCheck()); |
2501 return !nonEscapingReceivers.contains(receiver); | 2507 return !nonEscapingReceivers.contains(receiver); |
2502 } | 2508 } |
2503 | 2509 |
2504 void registerAllocation(HInstruction instruction) { | 2510 void registerAllocation(HInstruction instruction) { |
2505 assert(instruction == instruction.nonCheck()); | 2511 assert(instruction == instruction.nonCheck()); |
2506 nonEscapingReceivers.add(instruction); | 2512 nonEscapingReceivers.add(instruction); |
2507 } | 2513 } |
2508 | 2514 |
2509 /** | 2515 /** |
2510 * Sets `receiver.element` to contain [value]. Kills all potential places that | 2516 * Sets `receiver.element` to contain [value]. Kills all potential places that |
2511 * may be affected by this update. | 2517 * may be affected by this update. |
2512 */ | 2518 */ |
2513 void registerFieldValueUpdate( | 2519 void registerFieldValueUpdate( |
2514 MemberElement element, HInstruction receiver, HInstruction value) { | 2520 MemberElement element, HInstruction receiver, HInstruction value) { |
2515 assert(receiver == null || receiver == receiver.nonCheck()); | 2521 assert(receiver == null || receiver == receiver.nonCheck()); |
2516 if (backend.isNative(element)) { | 2522 if (closedWorld.backendClasses.isNative(element)) { |
2517 return; // TODO(14955): Remove this restriction? | 2523 return; // TODO(14955): Remove this restriction? |
2518 } | 2524 } |
2519 // [value] is being set in some place in memory, we remove it from | 2525 // [value] is being set in some place in memory, we remove it from |
2520 // the non-escaping set. | 2526 // the non-escaping set. |
2521 nonEscapingReceivers.remove(value.nonCheck()); | 2527 nonEscapingReceivers.remove(value.nonCheck()); |
2522 Map<HInstruction, HInstruction> map = | 2528 Map<HInstruction, HInstruction> map = |
2523 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2529 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
2524 map.forEach((key, value) { | 2530 map.forEach((key, value) { |
2525 if (mayAlias(receiver, key)) map[key] = null; | 2531 if (mayAlias(receiver, key)) map[key] = null; |
2526 }); | 2532 }); |
2527 map[receiver] = value; | 2533 map[receiver] = value; |
2528 } | 2534 } |
2529 | 2535 |
2530 /** | 2536 /** |
2531 * Registers that `receiver.element` is now [value]. | 2537 * Registers that `receiver.element` is now [value]. |
2532 */ | 2538 */ |
2533 void registerFieldValue( | 2539 void registerFieldValue( |
2534 MemberElement element, HInstruction receiver, HInstruction value) { | 2540 MemberElement element, HInstruction receiver, HInstruction value) { |
2535 assert(receiver == null || receiver == receiver.nonCheck()); | 2541 assert(receiver == null || receiver == receiver.nonCheck()); |
2536 if (backend.isNative(element)) { | 2542 if (closedWorld.backendClasses.isNative(element)) { |
2537 return; // TODO(14955): Remove this restriction? | 2543 return; // TODO(14955): Remove this restriction? |
2538 } | 2544 } |
2539 Map<HInstruction, HInstruction> map = | 2545 Map<HInstruction, HInstruction> map = |
2540 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2546 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
2541 map[receiver] = value; | 2547 map[receiver] = value; |
2542 } | 2548 } |
2543 | 2549 |
2544 /** | 2550 /** |
2545 * Returns the value stored in `receiver.element`. Returns `null` if we don't | 2551 * Returns the value stored in `receiver.element`. Returns `null` if we don't |
2546 * know. | 2552 * know. |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2636 | 2642 |
2637 /** | 2643 /** |
2638 * Returns null if either [first] or [second] is null. Otherwise | 2644 * Returns null if either [first] or [second] is null. Otherwise |
2639 * returns [first] if [first] and [second] are equal. Otherwise | 2645 * returns [first] if [first] and [second] are equal. Otherwise |
2640 * creates or re-uses a phi in [block] that holds [first] and [second]. | 2646 * creates or re-uses a phi in [block] that holds [first] and [second]. |
2641 */ | 2647 */ |
2642 HInstruction findCommonInstruction(HInstruction first, HInstruction second, | 2648 HInstruction findCommonInstruction(HInstruction first, HInstruction second, |
2643 HBasicBlock block, int predecessorIndex) { | 2649 HBasicBlock block, int predecessorIndex) { |
2644 if (first == null || second == null) return null; | 2650 if (first == null || second == null) return null; |
2645 if (first == second) return first; | 2651 if (first == second) return first; |
2646 TypeMask phiType = second.instructionType | 2652 TypeMask phiType = |
2647 .union(first.instructionType, compiler.closedWorld); | 2653 second.instructionType.union(first.instructionType, closedWorld); |
2648 if (first is HPhi && first.block == block) { | 2654 if (first is HPhi && first.block == block) { |
2649 HPhi phi = first; | 2655 HPhi phi = first; |
2650 phi.addInput(second); | 2656 phi.addInput(second); |
2651 phi.instructionType = phiType; | 2657 phi.instructionType = phiType; |
2652 return phi; | 2658 return phi; |
2653 } else { | 2659 } else { |
2654 HPhi phi = new HPhi.noInputs(null, phiType); | 2660 HPhi phi = new HPhi.noInputs(null, phiType); |
2655 block.addPhi(phi); | 2661 block.addPhi(phi); |
2656 // Previous predecessors had the same input. A phi must have | 2662 // Previous predecessors had the same input. A phi must have |
2657 // the same number of inputs as its block has predecessors. | 2663 // the same number of inputs as its block has predecessors. |
2658 for (int i = 0; i < predecessorIndex; i++) { | 2664 for (int i = 0; i < predecessorIndex; i++) { |
2659 phi.addInput(first); | 2665 phi.addInput(first); |
2660 } | 2666 } |
2661 phi.addInput(second); | 2667 phi.addInput(second); |
2662 return phi; | 2668 return phi; |
2663 } | 2669 } |
2664 } | 2670 } |
2665 | 2671 |
2666 /** | 2672 /** |
2667 * Returns the intersection between [this] and [other]. | 2673 * Returns the intersection between [this] and [other]. |
2668 */ | 2674 */ |
2669 MemorySet intersectionFor( | 2675 MemorySet intersectionFor( |
2670 MemorySet other, HBasicBlock block, int predecessorIndex) { | 2676 MemorySet other, HBasicBlock block, int predecessorIndex) { |
2671 MemorySet result = new MemorySet(compiler); | 2677 MemorySet result = new MemorySet(closedWorld); |
2672 if (other == null) { | 2678 if (other == null) { |
2673 // This is the first visit to a loop header ([other] is `null` because we | 2679 // This is the first visit to a loop header ([other] is `null` because we |
2674 // have not visited the back edge). Copy the nonEscapingReceivers that are | 2680 // have not visited the back edge). Copy the nonEscapingReceivers that are |
2675 // guaranteed to survive the loop because they are not escaped before | 2681 // guaranteed to survive the loop because they are not escaped before |
2676 // method exit. | 2682 // method exit. |
2677 // TODO(sra): We should do a proper dataflow to find the maximal | 2683 // TODO(sra): We should do a proper dataflow to find the maximal |
2678 // nonEscapingReceivers (a variant of Available-Expressions), which must | 2684 // nonEscapingReceivers (a variant of Available-Expressions), which must |
2679 // converge before we edit the program in [findCommonInstruction]. | 2685 // converge before we edit the program in [findCommonInstruction]. |
2680 for (HInstruction instruction in nonEscapingReceivers) { | 2686 for (HInstruction instruction in nonEscapingReceivers) { |
2681 bool isNonEscapingUse(HInstruction use) { | 2687 bool isNonEscapingUse(HInstruction use) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2726 result.nonEscapingReceivers.add(receiver); | 2732 result.nonEscapingReceivers.add(receiver); |
2727 } | 2733 } |
2728 }); | 2734 }); |
2729 return result; | 2735 return result; |
2730 } | 2736 } |
2731 | 2737 |
2732 /** | 2738 /** |
2733 * Returns a copy of [this]. | 2739 * Returns a copy of [this]. |
2734 */ | 2740 */ |
2735 MemorySet clone() { | 2741 MemorySet clone() { |
2736 MemorySet result = new MemorySet(compiler); | 2742 MemorySet result = new MemorySet(closedWorld); |
2737 | 2743 |
2738 fieldValues.forEach((element, values) { | 2744 fieldValues.forEach((element, values) { |
2739 result.fieldValues[element] = | 2745 result.fieldValues[element] = |
2740 new Map<HInstruction, HInstruction>.from(values); | 2746 new Map<HInstruction, HInstruction>.from(values); |
2741 }); | 2747 }); |
2742 | 2748 |
2743 keyedValues.forEach((receiver, values) { | 2749 keyedValues.forEach((receiver, values) { |
2744 result.keyedValues[receiver] = | 2750 result.keyedValues[receiver] = |
2745 new Map<HInstruction, HInstruction>.from(values); | 2751 new Map<HInstruction, HInstruction>.from(values); |
2746 }); | 2752 }); |
2747 | 2753 |
2748 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2754 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
2749 return result; | 2755 return result; |
2750 } | 2756 } |
2751 } | 2757 } |
OLD | NEW |