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

Side by Side Diff: pkg/compiler/lib/src/ssa/optimize.dart

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

Powered by Google App Engine
This is Rietveld 408576698