| 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/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; |
| 11 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
| 12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
| 13 import '../js/js.dart' as js; | 13 import '../js/js.dart' as js; |
| 14 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 14 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 15 import '../js_backend/js_backend.dart'; | 15 import '../js_backend/js_backend.dart'; |
| 16 import '../native/native.dart' as native; | 16 import '../native/native.dart' as native; |
| 17 import '../tree/dartstring.dart' as ast; | 17 import '../tree/dartstring.dart' as ast; |
| 18 import '../types/types.dart'; | 18 import '../types/types.dart'; |
| 19 import '../universe/selector.dart' show Selector; | 19 import '../universe/selector.dart' show Selector; |
| 20 import '../universe/side_effects.dart' show SideEffects; | 20 import '../universe/side_effects.dart' show SideEffects; |
| 21 import '../util/util.dart'; | 21 import '../util/util.dart'; |
| 22 import '../world.dart' show ClassWorld; | 22 import '../world.dart' show ClosedWorld; |
| 23 import 'interceptor_simplifier.dart'; | 23 import 'interceptor_simplifier.dart'; |
| 24 import 'nodes.dart'; | 24 import 'nodes.dart'; |
| 25 import 'types.dart'; | 25 import 'types.dart'; |
| 26 import 'types_propagation.dart'; | 26 import 'types_propagation.dart'; |
| 27 import 'value_range_analyzer.dart'; | 27 import 'value_range_analyzer.dart'; |
| 28 import 'value_set.dart'; | 28 import 'value_set.dart'; |
| 29 | 29 |
| 30 abstract class OptimizationPhase { | 30 abstract class OptimizationPhase { |
| 31 String get name; | 31 String get name; |
| 32 void visitGraph(HGraph graph); | 32 void visitGraph(HGraph graph); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 phases.forEach(runPhase); | 119 phases.forEach(runPhase); |
| 120 }); | 120 }); |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 | 123 |
| 124 /// Returns `true` if [mask] represents only types that have a length that | 124 /// Returns `true` if [mask] represents only types that have a length that |
| 125 /// cannot change. The current implementation is conservative for the purpose | 125 /// cannot change. The current implementation is conservative for the purpose |
| 126 /// of identifying gvn-able lengths and mis-identifies some unions of fixed | 126 /// of identifying gvn-able lengths and mis-identifies some unions of fixed |
| 127 /// length indexables (see TODO) as not fixed length. | 127 /// length indexables (see TODO) as not fixed length. |
| 128 bool isFixedLength(mask, Compiler compiler) { | 128 bool isFixedLength(mask, Compiler compiler) { |
| 129 ClassWorld classWorld = compiler.closedWorld; | 129 ClosedWorld closedWorld = compiler.closedWorld; |
| 130 JavaScriptBackend backend = compiler.backend; | 130 JavaScriptBackend backend = compiler.backend; |
| 131 if (mask.isContainer && mask.length != null) { | 131 if (mask.isContainer && mask.length != null) { |
| 132 // A container on which we have inferred the length. | 132 // A container on which we have inferred the length. |
| 133 return true; | 133 return true; |
| 134 } | 134 } |
| 135 // TODO(sra): Recognize any combination of fixed length indexables. | 135 // TODO(sra): Recognize any combination of fixed length indexables. |
| 136 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || | 136 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || |
| 137 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || | 137 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || |
| 138 mask.containsOnlyString(classWorld) || | 138 mask.containsOnlyString(closedWorld) || |
| 139 backend.isTypedArray(mask)) { | 139 backend.isTypedArray(mask)) { |
| 140 return true; | 140 return true; |
| 141 } | 141 } |
| 142 return false; | 142 return false; |
| 143 } | 143 } |
| 144 | 144 |
| 145 /** | 145 /** |
| 146 * If both inputs to known operations are available execute the operation at | 146 * If both inputs to known operations are available execute the operation at |
| 147 * compile-time. | 147 * compile-time. |
| 148 */ | 148 */ |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 StringConstantValue constant = constantInput.constant; | 327 StringConstantValue constant = constantInput.constant; |
| 328 return graph.addConstantInt(constant.length, compiler); | 328 return graph.addConstantInt(constant.length, compiler); |
| 329 } else if (actualReceiver.isConstantList()) { | 329 } else if (actualReceiver.isConstantList()) { |
| 330 HConstant constantInput = actualReceiver; | 330 HConstant constantInput = actualReceiver; |
| 331 ListConstantValue constant = constantInput.constant; | 331 ListConstantValue constant = constantInput.constant; |
| 332 return graph.addConstantInt(constant.length, compiler); | 332 return graph.addConstantInt(constant.length, compiler); |
| 333 } | 333 } |
| 334 Element element = helpers.jsIndexableLength; | 334 Element element = helpers.jsIndexableLength; |
| 335 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); | 335 bool isFixed = isFixedLength(actualReceiver.instructionType, compiler); |
| 336 TypeMask actualType = node.instructionType; | 336 TypeMask actualType = node.instructionType; |
| 337 ClassWorld classWorld = compiler.closedWorld; | 337 ClosedWorld closedWorld = compiler.closedWorld; |
| 338 TypeMask resultType = backend.positiveIntType; | 338 TypeMask resultType = backend.positiveIntType; |
| 339 // If we already have computed a more specific type, keep that type. | 339 // If we already have computed a more specific type, keep that type. |
| 340 if (HInstruction.isInstanceOf( | 340 if (HInstruction.isInstanceOf( |
| 341 actualType, helpers.jsUInt31Class, classWorld)) { | 341 actualType, helpers.jsUInt31Class, closedWorld)) { |
| 342 resultType = backend.uint31Type; | 342 resultType = backend.uint31Type; |
| 343 } else if (HInstruction.isInstanceOf( | 343 } else if (HInstruction.isInstanceOf( |
| 344 actualType, helpers.jsUInt32Class, classWorld)) { | 344 actualType, helpers.jsUInt32Class, closedWorld)) { |
| 345 resultType = backend.uint32Type; | 345 resultType = backend.uint32Type; |
| 346 } | 346 } |
| 347 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, | 347 HFieldGet result = new HFieldGet(element, actualReceiver, resultType, |
| 348 isAssignable: !isFixed); | 348 isAssignable: !isFixed); |
| 349 return result; | 349 return result; |
| 350 } else if (actualReceiver.isConstantMap()) { | 350 } else if (actualReceiver.isConstantMap()) { |
| 351 HConstant constantInput = actualReceiver; | 351 HConstant constantInput = actualReceiver; |
| 352 MapConstantValue constant = constantInput.constant; | 352 MapConstantValue constant = constantInput.constant; |
| 353 return graph.addConstantInt(constant.length, compiler); | 353 return graph.addConstantInt(constant.length, compiler); |
| 354 } | 354 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 367 | 367 |
| 368 // Try converting the instruction to a builtin instruction. | 368 // Try converting the instruction to a builtin instruction. |
| 369 HInstruction instruction = | 369 HInstruction instruction = |
| 370 node.specializer.tryConvertToBuiltin(node, compiler); | 370 node.specializer.tryConvertToBuiltin(node, compiler); |
| 371 if (instruction != null) return instruction; | 371 if (instruction != null) return instruction; |
| 372 | 372 |
| 373 Selector selector = node.selector; | 373 Selector selector = node.selector; |
| 374 TypeMask mask = node.mask; | 374 TypeMask mask = node.mask; |
| 375 HInstruction input = node.inputs[1]; | 375 HInstruction input = node.inputs[1]; |
| 376 | 376 |
| 377 ClassWorld world = compiler.closedWorld; | 377 ClosedWorld world = compiler.closedWorld; |
| 378 | 378 |
| 379 bool applies(Element element) { | 379 bool applies(Element element) { |
| 380 return selector.applies(element, backend) && | 380 return selector.applies(element, backend) && |
| 381 (mask == null || mask.canHit(element, selector, world)); | 381 (mask == null || mask.canHit(element, selector, world)); |
| 382 } | 382 } |
| 383 | 383 |
| 384 if (selector.isCall || selector.isOperator) { | 384 if (selector.isCall || selector.isOperator) { |
| 385 Element target; | 385 Element target; |
| 386 if (input.isExtendableArray(compiler)) { | 386 if (input.isExtendableArray(compiler)) { |
| 387 if (applies(helpers.jsArrayRemoveLast)) { | 387 if (applies(helpers.jsArrayRemoveLast)) { |
| (...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 727 } else if (type.isTypedef) { | 727 } else if (type.isTypedef) { |
| 728 return node; | 728 return node; |
| 729 } else if (element == coreClasses.functionClass) { | 729 } else if (element == coreClasses.functionClass) { |
| 730 return node; | 730 return node; |
| 731 } | 731 } |
| 732 | 732 |
| 733 if (type.isObject || type.treatAsDynamic) { | 733 if (type.isObject || type.treatAsDynamic) { |
| 734 return graph.addConstantBool(true, compiler); | 734 return graph.addConstantBool(true, compiler); |
| 735 } | 735 } |
| 736 | 736 |
| 737 ClassWorld classWorld = compiler.closedWorld; | 737 ClosedWorld closedWorld = compiler.closedWorld; |
| 738 HInstruction expression = node.expression; | 738 HInstruction expression = node.expression; |
| 739 if (expression.isInteger(compiler)) { | 739 if (expression.isInteger(compiler)) { |
| 740 if (element == coreClasses.intClass || | 740 if (element == coreClasses.intClass || |
| 741 element == coreClasses.numClass || | 741 element == coreClasses.numClass || |
| 742 Elements.isNumberOrStringSupertype(element, compiler)) { | 742 Elements.isNumberOrStringSupertype(element, compiler)) { |
| 743 return graph.addConstantBool(true, compiler); | 743 return graph.addConstantBool(true, compiler); |
| 744 } else if (element == coreClasses.doubleClass) { | 744 } else if (element == coreClasses.doubleClass) { |
| 745 // We let the JS semantics decide for that check. Currently | 745 // We let the JS semantics decide for that check. Currently |
| 746 // the code we emit will always return true. | 746 // the code we emit will always return true. |
| 747 return node; | 747 return node; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 771 } else if (expression.canBePrimitiveNumber(compiler) && | 771 } else if (expression.canBePrimitiveNumber(compiler) && |
| 772 element == coreClasses.intClass) { | 772 element == coreClasses.intClass) { |
| 773 // We let the JS semantics decide for that check. | 773 // We let the JS semantics decide for that check. |
| 774 return node; | 774 return node; |
| 775 // We need the [:hasTypeArguments:] check because we don't have | 775 // We need the [:hasTypeArguments:] check because we don't have |
| 776 // the notion of generics in the backend. For example, [:this:] in | 776 // the notion of generics in the backend. For example, [:this:] in |
| 777 // a class [:A<T>:], is currently always considered to have the | 777 // a class [:A<T>:], is currently always considered to have the |
| 778 // raw type. | 778 // raw type. |
| 779 } else if (!RuntimeTypes.hasTypeArguments(type)) { | 779 } else if (!RuntimeTypes.hasTypeArguments(type)) { |
| 780 TypeMask expressionMask = expression.instructionType; | 780 TypeMask expressionMask = expression.instructionType; |
| 781 assert(TypeMask.assertIsNormalized(expressionMask, classWorld)); | 781 assert(TypeMask.assertIsNormalized(expressionMask, closedWorld)); |
| 782 TypeMask typeMask = (element == coreClasses.nullClass) | 782 TypeMask typeMask = (element == coreClasses.nullClass) |
| 783 ? new TypeMask.subtype(element, classWorld) | 783 ? new TypeMask.subtype(element, closedWorld) |
| 784 : new TypeMask.nonNullSubtype(element, classWorld); | 784 : new TypeMask.nonNullSubtype(element, closedWorld); |
| 785 if (expressionMask.union(typeMask, classWorld) == typeMask) { | 785 if (expressionMask.union(typeMask, closedWorld) == typeMask) { |
| 786 return graph.addConstantBool(true, compiler); | 786 return graph.addConstantBool(true, compiler); |
| 787 } else if (expressionMask.isDisjoint(typeMask, compiler.closedWorld)) { | 787 } else if (expressionMask.isDisjoint(typeMask, compiler.closedWorld)) { |
| 788 return graph.addConstantBool(false, compiler); | 788 return graph.addConstantBool(false, compiler); |
| 789 } | 789 } |
| 790 } | 790 } |
| 791 return node; | 791 return node; |
| 792 } | 792 } |
| 793 | 793 |
| 794 HInstruction visitTypeConversion(HTypeConversion node) { | 794 HInstruction visitTypeConversion(HTypeConversion node) { |
| 795 DartType type = node.typeExpression; | 795 DartType type = node.typeExpression; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 808 } | 808 } |
| 809 } | 809 } |
| 810 return removeIfCheckAlwaysSucceeds(node, node.checkedType); | 810 return removeIfCheckAlwaysSucceeds(node, node.checkedType); |
| 811 } | 811 } |
| 812 | 812 |
| 813 HInstruction visitTypeKnown(HTypeKnown node) { | 813 HInstruction visitTypeKnown(HTypeKnown node) { |
| 814 return removeIfCheckAlwaysSucceeds(node, node.knownType); | 814 return removeIfCheckAlwaysSucceeds(node, node.knownType); |
| 815 } | 815 } |
| 816 | 816 |
| 817 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { | 817 HInstruction removeIfCheckAlwaysSucceeds(HCheck node, TypeMask checkedType) { |
| 818 ClassWorld classWorld = compiler.closedWorld; | 818 ClosedWorld closedWorld = compiler.closedWorld; |
| 819 if (checkedType.containsAll(classWorld)) return node; | 819 if (checkedType.containsAll(closedWorld)) return node; |
| 820 HInstruction input = node.checkedInput; | 820 HInstruction input = node.checkedInput; |
| 821 TypeMask inputType = input.instructionType; | 821 TypeMask inputType = input.instructionType; |
| 822 return inputType.isInMask(checkedType, classWorld) ? input : node; | 822 return inputType.isInMask(checkedType, closedWorld) ? input : node; |
| 823 } | 823 } |
| 824 | 824 |
| 825 HInstruction removeCheck(HCheck node) => node.checkedInput; | 825 HInstruction removeCheck(HCheck node) => node.checkedInput; |
| 826 | 826 |
| 827 VariableElement findConcreteFieldForDynamicAccess( | 827 VariableElement findConcreteFieldForDynamicAccess( |
| 828 HInstruction receiver, Selector selector) { | 828 HInstruction receiver, Selector selector) { |
| 829 TypeMask receiverType = receiver.instructionType; | 829 TypeMask receiverType = receiver.instructionType; |
| 830 return compiler.closedWorld.locateSingleField(selector, receiverType); | 830 return compiler.closedWorld.locateSingleField(selector, receiverType); |
| 831 } | 831 } |
| 832 | 832 |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1029 constantSystem.createString(primitive.toDartString()), compiler); | 1029 constantSystem.createString(primitive.toDartString()), compiler); |
| 1030 } | 1030 } |
| 1031 return node; | 1031 return node; |
| 1032 } | 1032 } |
| 1033 | 1033 |
| 1034 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { | 1034 HInstruction visitOneShotInterceptor(HOneShotInterceptor node) { |
| 1035 return handleInterceptedCall(node); | 1035 return handleInterceptedCall(node); |
| 1036 } | 1036 } |
| 1037 | 1037 |
| 1038 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { | 1038 bool needsSubstitutionForTypeVariableAccess(ClassElement cls) { |
| 1039 ClassWorld classWorld = compiler.closedWorld; | 1039 ClosedWorld closedWorld = compiler.closedWorld; |
| 1040 if (classWorld.isUsedAsMixin(cls)) return true; | 1040 if (closedWorld.isUsedAsMixin(cls)) return true; |
| 1041 | 1041 |
| 1042 return classWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { | 1042 return closedWorld.anyStrictSubclassOf(cls, (ClassElement subclass) { |
| 1043 return !backend.rti.isTrivialSubstitution(subclass, cls); | 1043 return !backend.rti.isTrivialSubstitution(subclass, cls); |
| 1044 }); | 1044 }); |
| 1045 } | 1045 } |
| 1046 | 1046 |
| 1047 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { | 1047 HInstruction visitTypeInfoExpression(HTypeInfoExpression node) { |
| 1048 // Identify the case where the type info expression would be of the form: | 1048 // Identify the case where the type info expression would be of the form: |
| 1049 // | 1049 // |
| 1050 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] | 1050 // [getTypeArgumentByIndex(this, 0), .., getTypeArgumentByIndex(this, k)] |
| 1051 // | 1051 // |
| 1052 // and k is the number of type arguments of 'this'. We can simply copy the | 1052 // and k is the number of type arguments of 'this'. We can simply copy the |
| (...skipping 1568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2621 | 2621 |
| 2622 keyedValues.forEach((receiver, values) { | 2622 keyedValues.forEach((receiver, values) { |
| 2623 result.keyedValues[receiver] = | 2623 result.keyedValues[receiver] = |
| 2624 new Map<HInstruction, HInstruction>.from(values); | 2624 new Map<HInstruction, HInstruction>.from(values); |
| 2625 }); | 2625 }); |
| 2626 | 2626 |
| 2627 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2627 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2628 return result; | 2628 return result; |
| 2629 } | 2629 } |
| 2630 } | 2630 } |
| OLD | NEW |