| 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 |