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 |