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 CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenWorkItem; |
6 import '../common/tasks.dart' show CompilerTask; | 6 import '../common/tasks.dart' show CompilerTask; |
7 import '../compiler.dart' show Compiler; | 7 import '../compiler.dart' show Compiler; |
8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
10 import '../core_types.dart' show CoreClasses; | 10 import '../core_types.dart' show CoreClasses; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 phases.forEach(runPhase); | 117 phases.forEach(runPhase); |
118 }); | 118 }); |
119 } | 119 } |
120 } | 120 } |
121 | 121 |
122 /// Returns `true` if [mask] represents only types that have a length that | 122 /// Returns `true` if [mask] represents only types that have a length that |
123 /// cannot change. The current implementation is conservative for the purpose | 123 /// cannot change. The current implementation is conservative for the purpose |
124 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 124 /// of identifying gvn-able lengths and mis-identifies some unions of fixed |
125 /// length indexables (see TODO) as not fixed length. | 125 /// length indexables (see TODO) as not fixed length. |
126 bool isFixedLength(mask, Compiler compiler) { | 126 bool isFixedLength(mask, Compiler compiler) { |
127 ClassWorld classWorld = compiler.world; | 127 ClassWorld classWorld = compiler.closedWorld; |
128 JavaScriptBackend backend = compiler.backend; | 128 JavaScriptBackend backend = compiler.backend; |
129 if (mask.isContainer && mask.length != null) { | 129 if (mask.isContainer && mask.length != null) { |
130 // A container on which we have inferred the length. | 130 // A container on which we have inferred the length. |
131 return true; | 131 return true; |
132 } | 132 } |
133 // TODO(sra): Recognize any combination of fixed length indexables. | 133 // TODO(sra): Recognize any combination of fixed length indexables. |
134 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || | 134 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || |
135 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || | 135 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || |
136 mask.containsOnlyString(classWorld) || | 136 mask.containsOnlyString(classWorld) || |
137 backend.isTypedArray(mask)) { | 137 backend.isTypedArray(mask)) { |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 // The intersection of double and int return conflicting, and | 180 // The intersection of double and int return conflicting, and |
181 // because of our number implementation for JavaScript, it | 181 // because of our number implementation for JavaScript, it |
182 // might be that an operation thought to return double, can be | 182 // might be that an operation thought to return double, can be |
183 // simplified to an int. For example: | 183 // simplified to an int. For example: |
184 // `2.5 * 10`. | 184 // `2.5 * 10`. |
185 if (!(replacement.isNumberOrNull(compiler) && | 185 if (!(replacement.isNumberOrNull(compiler) && |
186 instruction.isNumberOrNull(compiler))) { | 186 instruction.isNumberOrNull(compiler))) { |
187 // If we can replace [instruction] with [replacement], then | 187 // If we can replace [instruction] with [replacement], then |
188 // [replacement]'s type can be narrowed. | 188 // [replacement]'s type can be narrowed. |
189 TypeMask newType = replacement.instructionType | 189 TypeMask newType = replacement.instructionType |
190 .intersection(instruction.instructionType, compiler.world); | 190 .intersection(instruction.instructionType, compiler.closedWorld); |
191 replacement.instructionType = newType; | 191 replacement.instructionType = newType; |
192 } | 192 } |
193 | 193 |
194 // If the replacement instruction does not know its | 194 // If the replacement instruction does not know its |
195 // source element, use the source element of the | 195 // source element, use the source element of the |
196 // instruction. | 196 // instruction. |
197 if (replacement.sourceElement == null) { | 197 if (replacement.sourceElement == null) { |
198 replacement.sourceElement = instruction.sourceElement; | 198 replacement.sourceElement = instruction.sourceElement; |
199 } | 199 } |
200 if (replacement.sourceInformation == null) { | 200 if (replacement.sourceInformation == null) { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 if (input.isBoolean(compiler)) return input; | 273 if (input.isBoolean(compiler)) return input; |
274 | 274 |
275 // If the code is unreachable, remove the HBoolify. This can happen when | 275 // If the code is unreachable, remove the HBoolify. This can happen when |
276 // there is a throw expression in a short-circuit conditional. Removing the | 276 // there is a throw expression in a short-circuit conditional. Removing the |
277 // unreachable HBoolify makes it easier to reconstruct the short-circuit | 277 // unreachable HBoolify makes it easier to reconstruct the short-circuit |
278 // operation. | 278 // operation. |
279 if (input.instructionType.isEmpty) return input; | 279 if (input.instructionType.isEmpty) return input; |
280 | 280 |
281 // All values that cannot be 'true' are boolified to false. | 281 // All values that cannot be 'true' are boolified to false. |
282 TypeMask mask = input.instructionType; | 282 TypeMask mask = input.instructionType; |
283 if (!mask.contains(helpers.jsBoolClass, compiler.world)) { | 283 if (!mask.contains(helpers.jsBoolClass, compiler.closedWorld)) { |
284 return graph.addConstantBool(false, compiler); | 284 return graph.addConstantBool(false, compiler); |
285 } | 285 } |
286 return node; | 286 return node; |
287 } | 287 } |
288 | 288 |
289 HInstruction visitNot(HNot node) { | 289 HInstruction visitNot(HNot node) { |
290 List<HInstruction> inputs = node.inputs; | 290 List<HInstruction> inputs = node.inputs; |
291 assert(inputs.length == 1); | 291 assert(inputs.length == 1); |
292 HInstruction input = inputs[0]; | 292 HInstruction input = inputs[0]; |
293 if (input is HConstant) { | 293 if (input is HConstant) { |
(...skipping 29 matching lines...) Expand all Loading... |
323 StringConstantValue constant = constantInput.constant; | 323 StringConstantValue constant = constantInput.constant; |
324 return graph.addConstantInt(constant.length, compiler); | 324 return graph.addConstantInt(constant.length, compiler); |
325 } else if (actualReceiver.isConstantList()) { | 325 } else if (actualReceiver.isConstantList()) { |
326 HConstant constantInput = actualReceiver; | 326 HConstant constantInput = actualReceiver; |
327 ListConstantValue constant = constantInput.constant; | 327 ListConstantValue constant = constantInput.constant; |
328 return graph.addConstantInt(constant.length, compiler); | 328 return graph.addConstantInt(constant.length, compiler); |
329 } | 329 } |
330 Element element = helpers.jsIndexableLength; | 330 Element element = helpers.jsIndexableLength; |
331 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); | 331 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); |
332 TypeMask actualType = node.instructionType; | 332 TypeMask actualType = node.instructionType; |
333 ClassWorld classWorld = compiler.world; | 333 ClassWorld classWorld = compiler.closedWorld; |
334 TypeMask resultType = backend.positiveIntType; | 334 TypeMask resultType = backend.positiveIntType; |
335 // If we already have computed a more specific type, keep that type. | 335 // If we already have computed a more specific type, keep that type. |
336 if (HInstruction.isInstanceOf( | 336 if (HInstruction.isInstanceOf( |
337 actualType, helpers.jsUInt31Class, classWorld)) { | 337 actualType, helpers.jsUInt31Class, classWorld)) { |
338 resultType = backend.uint31Type; | 338 resultType = backend.uint31Type; |
339 } else if (HInstruction.isInstanceOf( | 339 } else if (HInstruction.isInstanceOf( |
340 actualType, helpers.jsUInt32Class, classWorld)) { | 340 actualType, helpers.jsUInt32Class, classWorld)) { |
341 resultType = backend.uint32Type; | 341 resultType = backend.uint32Type; |
342 } | 342 } |
343 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, | 343 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, |
(...skipping 19 matching lines...) Expand all Loading... |
363 | 363 |
364 // Try converting the instruction to a builtin instruction. | 364 // Try converting the instruction to a builtin instruction. |
365 HInstruction instruction = | 365 HInstruction instruction = |
366 node.specializer.tryConvertToBuiltin(node, compiler); | 366 node.specializer.tryConvertToBuiltin(node, compiler); |
367 if (instruction != null) return instruction; | 367 if (instruction != null) return instruction; |
368 | 368 |
369 Selector selector = node.selector; | 369 Selector selector = node.selector; |
370 TypeMask mask = node.mask; | 370 TypeMask mask = node.mask; |
371 HInstruction input = node.inputs[1]; | 371 HInstruction input = node.inputs[1]; |
372 | 372 |
373 World world = compiler.world; | 373 ClassWorld world = compiler.closedWorld; |
374 | 374 |
375 bool applies(Element element) { | 375 bool applies(Element element) { |
376 return selector.applies(element, world) && | 376 return selector.applies(element, world) && |
377 (mask == null || mask.canHit(element, selector, world)); | 377 (mask == null || mask.canHit(element, selector, world)); |
378 } | 378 } |
379 | 379 |
380 if (selector.isCall || selector.isOperator) { | 380 if (selector.isCall || selector.isOperator) { |
381 Element target; | 381 Element target; |
382 if (input.isExtendableArray(compiler)) { | 382 if (input.isExtendableArray(compiler)) { |
383 if (applies(helpers.jsArrayRemoveLast)) { | 383 if (applies(helpers.jsArrayRemoveLast)) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 | 433 |
434 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { | 434 HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) { |
435 propagateConstantValueToUses(node); | 435 propagateConstantValueToUses(node); |
436 if (node.isInterceptedCall) { | 436 if (node.isInterceptedCall) { |
437 HInstruction folded = handleInterceptedCall(node); | 437 HInstruction folded = handleInterceptedCall(node); |
438 if (folded != node) return folded; | 438 if (folded != node) return folded; |
439 } | 439 } |
440 | 440 |
441 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; | 441 TypeMask receiverType = node.getDartReceiver(compiler).instructionType; |
442 Element element = | 442 Element element = |
443 compiler.world.locateSingleElement(node.selector, receiverType); | 443 compiler.closedWorld.locateSingleElement(node.selector, receiverType); |
444 // TODO(ngeoffray): Also fold if it's a getter or variable. | 444 // TODO(ngeoffray): Also fold if it's a getter or variable. |
445 if (element != null && | 445 if (element != null && |
446 element.isFunction | 446 element.isFunction |
447 // If we found out that the only target is a [:noSuchMethod:], | 447 // If we found out that the only target is a [:noSuchMethod:], |
448 // we just ignore it. | 448 // we just ignore it. |
449 && | 449 && |
450 element.name == node.selector.name) { | 450 element.name == node.selector.name) { |
451 FunctionElement method = element; | 451 FunctionElement method = element; |
452 | 452 |
453 if (backend.isNative(method)) { | 453 if (backend.isNative(method)) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 HInstruction right = node.right; | 632 HInstruction right = node.right; |
633 TypeMask leftType = left.instructionType; | 633 TypeMask leftType = left.instructionType; |
634 TypeMask rightType = right.instructionType; | 634 TypeMask rightType = right.instructionType; |
635 | 635 |
636 HInstruction makeTrue() => graph.addConstantBool(true, compiler); | 636 HInstruction makeTrue() => graph.addConstantBool(true, compiler); |
637 HInstruction makeFalse() => graph.addConstantBool(false, compiler); | 637 HInstruction makeFalse() => graph.addConstantBool(false, compiler); |
638 | 638 |
639 // Intersection of int and double return conflicting, so | 639 // Intersection of int and double return conflicting, so |
640 // we don't optimize on numbers to preserve the runtime semantics. | 640 // we don't optimize on numbers to preserve the runtime semantics. |
641 if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) { | 641 if (!(left.isNumberOrNull(compiler) && right.isNumberOrNull(compiler))) { |
642 if (leftType.isDisjoint(rightType, compiler.world)) { | 642 if (leftType.isDisjoint(rightType, compiler.closedWorld)) { |
643 return makeFalse(); | 643 return makeFalse(); |
644 } | 644 } |
645 } | 645 } |
646 | 646 |
647 if (left.isNull() && right.isNull()) { | 647 if (left.isNull() && right.isNull()) { |
648 return makeTrue(); | 648 return makeTrue(); |
649 } | 649 } |
650 | 650 |
651 HInstruction compareConstant(HConstant constant, HInstruction input) { | 651 HInstruction compareConstant(HConstant constant, HInstruction input) { |
652 if (constant.constant.isTrue) { | 652 if (constant.constant.isTrue) { |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
723 } else if (type.isTypedef) { | 723 } else if (type.isTypedef) { |
724 return node; | 724 return node; |
725 } else if (element == coreClasses.functionClass) { | 725 } else if (element == coreClasses.functionClass) { |
726 return node; | 726 return node; |
727 } | 727 } |
728 | 728 |
729 if (type.isObject || type.treatAsDynamic) { | 729 if (type.isObject || type.treatAsDynamic) { |
730 return graph.addConstantBool(true, compiler); | 730 return graph.addConstantBool(true, compiler); |
731 } | 731 } |
732 | 732 |
733 ClassWorld classWorld = compiler.world; | 733 ClassWorld classWorld = compiler.closedWorld; |
734 HInstruction expression = node.expression; | 734 HInstruction expression = node.expression; |
735 if (expression.isInteger(compiler)) { | 735 if (expression.isInteger(compiler)) { |
736 if (element == coreClasses.intClass || | 736 if (element == coreClasses.intClass || |
737 element == coreClasses.numClass || | 737 element == coreClasses.numClass || |
738 Elements.isNumberOrStringSupertype(element, compiler)) { | 738 Elements.isNumberOrStringSupertype(element, compiler)) { |
739 return graph.addConstantBool(true, compiler); | 739 return graph.addConstantBool(true, compiler); |
740 } else if (element == coreClasses.doubleClass) { | 740 } else if (element == coreClasses.doubleClass) { |
741 // We let the JS semantics decide for that check. Currently | 741 // We let the JS semantics decide for that check. Currently |
742 // the code we emit will always return true. | 742 // the code we emit will always return true. |
743 return node; | 743 return node; |
(...skipping 29 matching lines...) Expand all Loading... |
773 // a class [:A<T>:], is currently always considered to have the | 773 // a class [:A<T>:], is currently always considered to have the |
774 // raw type. | 774 // raw type. |
775 } else if (!RuntimeTypes.hasTypeArguments(type)) { | 775 } else if (!RuntimeTypes.hasTypeArguments(type)) { |
776 TypeMask expressionMask = expression.instructionType; | 776 TypeMask expressionMask = expression.instructionType; |
777 assert(TypeMask.assertIsNormalized(expressionMask, classWorld)); | 777 assert(TypeMask.assertIsNormalized(expressionMask, classWorld)); |
778 TypeMask typeMask = (element == coreClasses.nullClass) | 778 TypeMask typeMask = (element == coreClasses.nullClass) |
779 ? new TypeMask.subtype(element, classWorld) | 779 ? new TypeMask.subtype(element, classWorld) |
780 : new TypeMask.nonNullSubtype(element, classWorld); | 780 : new TypeMask.nonNullSubtype(element, classWorld); |
781 if (expressionMask.union(typeMask, classWorld) == typeMask) { | 781 if (expressionMask.union(typeMask, classWorld) == typeMask) { |
782 return graph.addConstantBool(true, compiler); | 782 return graph.addConstantBool(true, compiler); |
783 } else if (expressionMask.isDisjoint(typeMask, compiler.world)) { | 783 } else if (expressionMask.isDisjoint(typeMask, compiler.closedWorld)) { |
784 return graph.addConstantBool(false, compiler); | 784 return graph.addConstantBool(false, compiler); |
785 } | 785 } |
786 } | 786 } |
787 return node; | 787 return node; |
788 } | 788 } |
789 | 789 |
790 HInstruction visitTypeConversion(HTypeConversion node) { | 790 HInstruction visitTypeConversion(HTypeConversion node) { |
791 DartType type = node.typeExpression; | 791 DartType type = node.typeExpression; |
792 if (type != null) { | 792 if (type != null) { |
793 if (type.isMalformed) { | 793 if (type.isMalformed) { |
(...skipping 10 matching lines...) Expand all Loading... |
804 } | 804 } |
805 } | 805 } |
806 return removeIfCheckAlwaysSucceeds(node, node.checkedType); | 806 return removeIfCheckAlwaysSucceeds(node, node.checkedType); |
807 } | 807 } |
808 | 808 |
809 HInstruction visitTypeKnown(HTypeKnown node) { | 809 HInstruction visitTypeKnown(HTypeKnown node) { |
810 return removeIfCheckAlwaysSucceeds(node, node.knownType); | 810 return removeIfCheckAlwaysSucceeds(node, node.knownType); |
811 } | 811 } |
812 | 812 |
813 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { | 813 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { |
814 ClassWorld classWorld = compiler.world; | 814 ClassWorld classWorld = compiler.closedWorld; |
815 if (checkedType.containsAll(classWorld)) return node; | 815 if (checkedType.containsAll(classWorld)) return node; |
816 HInstruction input = node.checkedInput; | 816 HInstruction input = node.checkedInput; |
817 TypeMask inputType = input.instructionType; | 817 TypeMask inputType = input.instructionType; |
818 return inputType.isInMask(checkedType, classWorld) ? input : node; | 818 return inputType.isInMask(checkedType, classWorld) ? input : node; |
819 } | 819 } |
820 | 820 |
821 HInstruction removeCheck(HCheck node) => node.checkedInput; | 821 HInstruction removeCheck(HCheck node) => node.checkedInput; |
822 | 822 |
823 VariableElement findConcreteFieldForDynamicAccess( | 823 VariableElement findConcreteFieldForDynamicAccess( |
824 HInstruction receiver, Selector selector) { | 824 HInstruction receiver, Selector selector) { |
825 TypeMask receiverType = receiver.instructionType; | 825 TypeMask receiverType = receiver.instructionType; |
826 return compiler.world.locateSingleField(selector, receiverType); | 826 return compiler.closedWorld.locateSingleField(selector, receiverType); |
827 } | 827 } |
828 | 828 |
829 HInstruction visitFieldGet(HFieldGet node) { | 829 HInstruction visitFieldGet(HFieldGet node) { |
830 if (node.isNullCheck) return node; | 830 if (node.isNullCheck) return node; |
831 var receiver = node.receiver; | 831 var receiver = node.receiver; |
832 if (node.element == helpers.jsIndexableLength) { | 832 if (node.element == helpers.jsIndexableLength) { |
833 if (graph.allocatedFixedLists.contains(receiver)) { | 833 if (graph.allocatedFixedLists.contains(receiver)) { |
834 // TODO(ngeoffray): checking if the second input is an integer | 834 // TODO(ngeoffray): checking if the second input is an integer |
835 // should not be necessary but it currently makes it easier for | 835 // should not be necessary but it currently makes it easier for |
836 // other optimizations to reason about a fixed length constructor | 836 // other optimizations to reason about a fixed length constructor |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
894 HInstruction folded = handleInterceptedCall(node); | 894 HInstruction folded = handleInterceptedCall(node); |
895 if (folded != node) return folded; | 895 if (folded != node) return folded; |
896 } | 896 } |
897 HInstruction receiver = node.getDartReceiver(compiler); | 897 HInstruction receiver = node.getDartReceiver(compiler); |
898 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); | 898 Element field = findConcreteFieldForDynamicAccess(receiver, node.selector); |
899 if (field == null) return node; | 899 if (field == null) return node; |
900 return directFieldGet(receiver, field); | 900 return directFieldGet(receiver, field); |
901 } | 901 } |
902 | 902 |
903 HInstruction directFieldGet(HInstruction receiver, Element field) { | 903 HInstruction directFieldGet(HInstruction receiver, Element field) { |
904 bool isAssignable = !compiler.world.fieldNeverChanges(field); | 904 bool isAssignable = !compiler.closedWorld.fieldNeverChanges(field); |
905 | 905 |
906 TypeMask type; | 906 TypeMask type; |
907 if (backend.isNative(field.enclosingClass)) { | 907 if (backend.isNative(field.enclosingClass)) { |
908 type = TypeMaskFactory.fromNativeBehavior( | 908 type = TypeMaskFactory.fromNativeBehavior( |
909 backend.getNativeFieldLoadBehavior(field), compiler); | 909 backend.getNativeFieldLoadBehavior(field), compiler); |
910 } else { | 910 } else { |
911 type = TypeMaskFactory.inferredTypeForElement(field, compiler); | 911 type = TypeMaskFactory.inferredTypeForElement(field, compiler); |
912 } | 912 } |
913 | 913 |
914 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); | 914 return new HFieldGet(field, receiver, type, isAssignable: isAssignable); |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1025 constantSystem.createString(primitive.toDartString()), compiler); | 1025 constantSystem.createString(primitive.toDartString()), compiler); |
1026 } | 1026 } |
1027 return node; | 1027 return node; |
1028 } | 1028 } |
1029 | 1029 |
1030 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { | 1030 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { |
1031 return handleInterceptedCall(node); | 1031 return handleInterceptedCall(node); |
1032 } | 1032 } |
1033 | 1033 |
1034 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { | 1034 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { |
1035 ClassWorld classWorld = compiler.world; | 1035 ClassWorld classWorld = compiler.closedWorld; |
1036 if (classWorld.isUsedAsMixin(cls)) return true; | 1036 if (classWorld.isUsedAsMixin(cls)) return true; |
1037 | 1037 |
1038 return classWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { | 1038 return classWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { |
1039 return !backend.rti.isTrivialSubstitution(subclass, cls); | 1039 return !backend.rti.isTrivialSubstitution(subclass, cls); |
1040 }); | 1040 }); |
1041 } | 1041 } |
1042 | 1042 |
1043 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { | 1043 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { |
1044 // Identify the case where the type info expression would be of the form: | 1044 // Identify the case where the type info expression would be of the form: |
1045 // | 1045 // |
(...skipping 988 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2034 } | 2034 } |
2035 | 2035 |
2036 List<HInstruction> ifUsers = <HInstruction>[]; | 2036 List<HInstruction> ifUsers = <HInstruction>[]; |
2037 List<HInstruction> notIfUsers = <HInstruction>[]; | 2037 List<HInstruction> notIfUsers = <HInstruction>[]; |
2038 | 2038 |
2039 collectIfUsers(instruction, ifUsers, notIfUsers); | 2039 collectIfUsers(instruction, ifUsers, notIfUsers); |
2040 | 2040 |
2041 if (ifUsers.isEmpty && notIfUsers.isEmpty) return; | 2041 if (ifUsers.isEmpty && notIfUsers.isEmpty) return; |
2042 | 2042 |
2043 TypeMask convertedType = | 2043 TypeMask convertedType = |
2044 new TypeMask.nonNullSubtype(element, compiler.world); | 2044 new TypeMask.nonNullSubtype(element, compiler.closedWorld); |
2045 HInstruction input = instruction.expression; | 2045 HInstruction input = instruction.expression; |
2046 | 2046 |
2047 for (HIf ifUser in ifUsers) { | 2047 for (HIf ifUser in ifUsers) { |
2048 insertTypePropagationForDominatedUsers( | 2048 insertTypePropagationForDominatedUsers( |
2049 ifUser.thenBlock, input, convertedType); | 2049 ifUser.thenBlock, input, convertedType); |
2050 // TODO(ngeoffray): Also change uses for the else block on a type | 2050 // TODO(ngeoffray): Also change uses for the else block on a type |
2051 // that knows it is not of a specific type. | 2051 // that knows it is not of a specific type. |
2052 } | 2052 } |
2053 for (HIf ifUser in notIfUsers) { | 2053 for (HIf ifUser in notIfUsers) { |
2054 insertTypePropagationForDominatedUsers( | 2054 insertTypePropagationForDominatedUsers( |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2335 * Returns whether [first] and [second] may alias to the same object. | 2335 * Returns whether [first] and [second] may alias to the same object. |
2336 */ | 2336 */ |
2337 bool mayAlias(HInstruction first, HInstruction second) { | 2337 bool mayAlias(HInstruction first, HInstruction second) { |
2338 if (mustAlias(first, second)) return true; | 2338 if (mustAlias(first, second)) return true; |
2339 if (isConcrete(first) && isConcrete(second)) return false; | 2339 if (isConcrete(first) && isConcrete(second)) return false; |
2340 if (nonEscapingReceivers.contains(first)) return false; | 2340 if (nonEscapingReceivers.contains(first)) return false; |
2341 if (nonEscapingReceivers.contains(second)) return false; | 2341 if (nonEscapingReceivers.contains(second)) return false; |
2342 // Typed arrays of different types might have a shared buffer. | 2342 // Typed arrays of different types might have a shared buffer. |
2343 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; | 2343 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; |
2344 return !first.instructionType | 2344 return !first.instructionType |
2345 .isDisjoint(second.instructionType, compiler.world); | 2345 .isDisjoint(second.instructionType, compiler.closedWorld); |
2346 } | 2346 } |
2347 | 2347 |
2348 bool isFinal(Element element) { | 2348 bool isFinal(Element element) { |
2349 return compiler.world.fieldNeverChanges(element); | 2349 return compiler.closedWorld.fieldNeverChanges(element); |
2350 } | 2350 } |
2351 | 2351 |
2352 bool isConcrete(HInstruction instruction) { | 2352 bool isConcrete(HInstruction instruction) { |
2353 return instruction is HCreate || | 2353 return instruction is HCreate || |
2354 instruction is HConstant || | 2354 instruction is HConstant || |
2355 instruction is HLiteralList; | 2355 instruction is HLiteralList; |
2356 } | 2356 } |
2357 | 2357 |
2358 bool couldBeTypedArray(HInstruction receiver) { | 2358 bool couldBeTypedArray(HInstruction receiver) { |
2359 JavaScriptBackend backend = compiler.backend; | 2359 JavaScriptBackend backend = compiler.backend; |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2500 | 2500 |
2501 /** | 2501 /** |
2502 * Returns null if either [first] or [second] is null. Otherwise | 2502 * Returns null if either [first] or [second] is null. Otherwise |
2503 * returns [first] if [first] and [second] are equal. Otherwise | 2503 * returns [first] if [first] and [second] are equal. Otherwise |
2504 * creates or re-uses a phi in [block] that holds [first] and [second]. | 2504 * creates or re-uses a phi in [block] that holds [first] and [second]. |
2505 */ | 2505 */ |
2506 HInstruction findCommonInstruction(HInstruction first, HInstruction second, | 2506 HInstruction findCommonInstruction(HInstruction first, HInstruction second, |
2507 HBasicBlock block, int predecessorIndex) { | 2507 HBasicBlock block, int predecessorIndex) { |
2508 if (first == null || second == null) return null; | 2508 if (first == null || second == null) return null; |
2509 if (first == second) return first; | 2509 if (first == second) return first; |
2510 TypeMask phiType = | 2510 TypeMask phiType = second.instructionType |
2511 second.instructionType.union(first.instructionType, compiler.world); | 2511 .union(first.instructionType, compiler.closedWorld); |
2512 if (first is HPhi && first.block == block) { | 2512 if (first is HPhi && first.block == block) { |
2513 HPhi phi = first; | 2513 HPhi phi = first; |
2514 phi.addInput(second); | 2514 phi.addInput(second); |
2515 phi.instructionType = phiType; | 2515 phi.instructionType = phiType; |
2516 return phi; | 2516 return phi; |
2517 } else { | 2517 } else { |
2518 HPhi phi = new HPhi.noInputs(null, phiType); | 2518 HPhi phi = new HPhi.noInputs(null, phiType); |
2519 block.addPhi(phi); | 2519 block.addPhi(phi); |
2520 // Previous predecessors had the same input. A phi must have | 2520 // Previous predecessors had the same input. A phi must have |
2521 // the same number of inputs as its block has predecessors. | 2521 // the same number of inputs as its block has predecessors. |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2580 | 2580 |
2581 keyedValues.forEach((receiver, values) { | 2581 keyedValues.forEach((receiver, values) { |
2582 result.keyedValues[receiver] = | 2582 result.keyedValues[receiver] = |
2583 new Map<HInstruction, HInstruction>.from(values); | 2583 new Map<HInstruction, HInstruction>.from(values); |
2584 }); | 2584 }); |
2585 | 2585 |
2586 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2586 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
2587 return result; | 2587 return result; |
2588 } | 2588 } |
2589 } | 2589 } |
OLD | NEW |