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 library dart2js.world; | 5 library dart2js.world; |
6 | 6 |
7 import 'closure.dart' show SynthesizedCallMethodElementX; | 7 import 'closure.dart' show SynthesizedCallMethodElementX; |
8 import 'common/backend_api.dart' show BackendClasses; | 8 import 'common/backend_api.dart' show BackendClasses; |
9 import 'common.dart'; | 9 import 'common.dart'; |
10 import 'compiler.dart' show Compiler; | 10 import 'compiler.dart' show Compiler; |
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 @override | 721 @override |
722 bool hasElementIn(ClassElement cls, Selector selector, Element element) { | 722 bool hasElementIn(ClassElement cls, Selector selector, Element element) { |
723 // Use [:implementation:] of [element] | 723 // Use [:implementation:] of [element] |
724 // because our function set only stores declarations. | 724 // because our function set only stores declarations. |
725 Element result = findMatchIn(cls, selector); | 725 Element result = findMatchIn(cls, selector); |
726 return result == null | 726 return result == null |
727 ? false | 727 ? false |
728 : result.implementation == element.implementation; | 728 : result.implementation == element.implementation; |
729 } | 729 } |
730 | 730 |
731 Element findMatchIn(ClassElement cls, Selector selector, | 731 Element findMatchIn(ClassElement cls, Selector selector) { |
732 {ClassElement stopAtSuperclass}) { | |
733 // Use the [:implementation] of [cls] in case the found [element] | 732 // Use the [:implementation] of [cls] in case the found [element] |
734 // is in the patch class. | 733 // is in the patch class. |
735 var result = cls.implementation | 734 var result = cls.implementation.lookupByName(selector.memberName); |
736 .lookupByName(selector.memberName, stopAt: stopAtSuperclass); | |
737 return result; | 735 return result; |
738 } | 736 } |
739 | 737 |
740 /// Returns whether a [selector] call on an instance of [cls] | 738 /// Returns whether a [selector] call on an instance of [cls] |
741 /// will hit a method at runtime, and not go through [noSuchMethod]. | 739 /// will hit a method at runtime, and not go through [noSuchMethod]. |
742 bool hasConcreteMatch(ClassElement cls, Selector selector, | 740 bool hasConcreteMatch(ClassElement cls, Selector selector) { |
743 {ClassElement stopAtSuperclass}) { | |
744 assert(invariant(cls, isInstantiated(cls), | 741 assert(invariant(cls, isInstantiated(cls), |
745 message: '$cls has not been instantiated.')); | 742 message: '$cls has not been instantiated.')); |
746 Element element = findMatchIn(cls, selector); | 743 Element element = findMatchIn(cls, selector); |
747 if (element == null) return false; | 744 if (element == null) return false; |
748 | 745 |
749 if (element.isAbstract) { | 746 if (element.isAbstract) { |
750 ClassElement enclosingClass = element.enclosingClass; | 747 ClassElement enclosingClass = element.enclosingClass; |
751 return hasConcreteMatch(enclosingClass.superclass, selector); | 748 return hasConcreteMatch(enclosingClass.superclass, selector); |
752 } | 749 } |
753 return selector.appliesUntyped(element); | 750 return selector.appliesUntyped(element); |
754 } | 751 } |
755 | 752 |
756 @override | 753 @override |
757 bool needsNoSuchMethod( | 754 bool needsNoSuchMethod( |
758 ClassElement base, Selector selector, ClassQuery query) { | 755 ClassElement base, Selector selector, ClassQuery query) { |
759 /// Returns `true` if subclasses in the [rootNode] tree needs noSuchMethod | 756 /// Returns `true` if [cls] is an instantiated class that does not have |
760 /// handling. | 757 /// a concrete method matching [selector]. |
761 bool subclassesNeedNoSuchMethod(ClassHierarchyNode rootNode) { | 758 bool needsNoSuchMethod(ClassElement cls) { |
762 if (!rootNode.isInstantiated) { | 759 // We can skip uninstantiated subclasses. |
763 // No subclass needs noSuchMethod handling since they are all | 760 if (!isInstantiated(cls)) { |
764 // uninstantiated. | |
765 return false; | 761 return false; |
766 } | 762 } |
767 ClassElement rootClass = rootNode.cls; | 763 // We can just skip abstract classes because we know no |
768 if (hasConcreteMatch(rootClass, selector)) { | 764 // instance of them will be created at runtime, and |
769 // The root subclass has a concrete implementation so no subclass needs | 765 // therefore there is no instance that will require |
770 // noSuchMethod handling. | 766 // [noSuchMethod] handling. |
771 return false; | 767 return !cls.isAbstract && !hasConcreteMatch(cls, selector); |
772 } else if (rootNode.isDirectlyInstantiated) { | |
773 // The root class need noSuchMethod handling. | |
774 return true; | |
775 } | |
776 IterationStep result = rootNode.forEachSubclass((ClassElement subclass) { | |
777 if (hasConcreteMatch(subclass, selector, stopAtSuperclass: rootClass)) { | |
778 // Found a match - skip all subclasses. | |
779 return IterationStep.SKIP_SUBCLASSES; | |
780 } else { | |
781 // Stop fast - we found a need for noSuchMethod handling. | |
782 return IterationStep.STOP; | |
783 } | |
784 }, ClassHierarchyNode.DIRECTLY_INSTANTIATED, strict: true); | |
785 // We stopped fast so we need noSuchMethod handling. | |
786 return result == IterationStep.STOP; | |
787 } | 768 } |
788 | 769 |
789 ClassSet classSet = getClassSet(base); | 770 bool baseNeedsNoSuchMethod = needsNoSuchMethod(base); |
790 ClassHierarchyNode node = classSet.node; | 771 if (query == ClassQuery.EXACT || baseNeedsNoSuchMethod) { |
791 if (query == ClassQuery.EXACT) { | 772 return baseNeedsNoSuchMethod; |
792 return node.isDirectlyInstantiated && !hasConcreteMatch(base, selector); | 773 } |
793 } else if (query == ClassQuery.SUBCLASS) { | 774 |
794 return subclassesNeedNoSuchMethod(node); | 775 Iterable<ClassElement> subclassesToCheck; |
| 776 if (query == ClassQuery.SUBTYPE) { |
| 777 subclassesToCheck = strictSubtypesOf(base); |
795 } else { | 778 } else { |
796 if (subclassesNeedNoSuchMethod(node)) return true; | 779 assert(query == ClassQuery.SUBCLASS); |
797 for (ClassHierarchyNode subtypeNode in classSet.subtypeNodes) { | 780 subclassesToCheck = strictSubclassesOf(base); |
798 if (subclassesNeedNoSuchMethod(subtypeNode)) return true; | |
799 } | |
800 return false; | |
801 } | 781 } |
| 782 |
| 783 return subclassesToCheck != null && |
| 784 subclassesToCheck.any(needsNoSuchMethod); |
802 } | 785 } |
803 | 786 |
804 final Compiler _compiler; | 787 final Compiler _compiler; |
805 BackendClasses get backendClasses => _backend.backendClasses; | 788 BackendClasses get backendClasses => _backend.backendClasses; |
806 JavaScriptBackend get _backend => _compiler.backend; | 789 JavaScriptBackend get _backend => _compiler.backend; |
807 CommonMasks get commonMasks => _compiler.commonMasks; | 790 CommonMasks get commonMasks => _compiler.commonMasks; |
808 final FunctionSet allFunctions; | 791 final FunctionSet allFunctions; |
809 final Set<Element> functionsCalledInLoop = new Set<Element>(); | 792 final Set<Element> functionsCalledInLoop = new Set<Element>(); |
810 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); | 793 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); |
811 | 794 |
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1160 /// Only the class itself is included. | 1143 /// Only the class itself is included. |
1161 EXACT, | 1144 EXACT, |
1162 | 1145 |
1163 /// The class and all subclasses (transitively) are included. | 1146 /// The class and all subclasses (transitively) are included. |
1164 SUBCLASS, | 1147 SUBCLASS, |
1165 | 1148 |
1166 /// The class and all classes that implement or subclass it (transitively) | 1149 /// The class and all classes that implement or subclass it (transitively) |
1167 /// are included. | 1150 /// are included. |
1168 SUBTYPE, | 1151 SUBTYPE, |
1169 } | 1152 } |
OLD | NEW |