Chromium Code Reviews| 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}) { | |
| 732 // Use the [:implementation] of [cls] in case the found [element] | 733 // Use the [:implementation] of [cls] in case the found [element] |
| 733 // is in the patch class. | 734 // is in the patch class. |
| 734 var result = cls.implementation.lookupByName(selector.memberName); | 735 var result = cls.implementation |
| 736 .lookupByName(selector.memberName, stopAtSuperclass: stopAtSuperclass); | |
| 735 return result; | 737 return result; |
| 736 } | 738 } |
| 737 | 739 |
| 738 /// Returns whether a [selector] call on an instance of [cls] | 740 /// Returns whether a [selector] call on an instance of [cls] |
| 739 /// will hit a method at runtime, and not go through [noSuchMethod]. | 741 /// will hit a method at runtime, and not go through [noSuchMethod]. |
| 740 bool hasConcreteMatch(ClassElement cls, Selector selector) { | 742 bool hasConcreteMatch(ClassElement cls, Selector selector, |
| 743 {ClassElement stopAtSuperclass}) { | |
| 741 assert(invariant(cls, isInstantiated(cls), | 744 assert(invariant(cls, isInstantiated(cls), |
| 742 message: '$cls has not been instantiated.')); | 745 message: '$cls has not been instantiated.')); |
| 743 Element element = findMatchIn(cls, selector); | 746 Element element = findMatchIn(cls, selector); |
| 744 if (element == null) return false; | 747 if (element == null) return false; |
| 745 | 748 |
| 746 if (element.isAbstract) { | 749 if (element.isAbstract) { |
| 747 ClassElement enclosingClass = element.enclosingClass; | 750 ClassElement enclosingClass = element.enclosingClass; |
| 748 return hasConcreteMatch(enclosingClass.superclass, selector); | 751 return hasConcreteMatch(enclosingClass.superclass, selector); |
| 749 } | 752 } |
| 750 return selector.appliesUntyped(element); | 753 return selector.appliesUntyped(element); |
| 751 } | 754 } |
| 752 | 755 |
| 753 @override | 756 @override |
| 754 bool needsNoSuchMethod( | 757 bool needsNoSuchMethod( |
| 755 ClassElement base, Selector selector, ClassQuery query) { | 758 ClassElement base, Selector selector, ClassQuery query) { |
| 756 /// Returns `true` if [cls] is an instantiated class that does not have | 759 /// Returns `true` if subclasses in the [rootNode] tree needs noSuchMethod |
| 757 /// a concrete method matching [selector]. | 760 /// handling. |
| 758 bool needsNoSuchMethod(ClassElement cls) { | 761 bool subclassesNeedNoSuchMethod(ClassHierarchyNode rootNode) { |
| 759 // We can skip uninstantiated subclasses. | 762 if (!rootNode.isInstantiated) { |
| 760 if (!isInstantiated(cls)) { | 763 // No subclass needs noSuchMethod handling since they are all |
| 764 // uninstantiated. | |
| 761 return false; | 765 return false; |
| 762 } | 766 } |
| 763 // We can just skip abstract classes because we know no | 767 ClassElement rootClass = rootNode.cls; |
| 764 // instance of them will be created at runtime, and | 768 if (hasConcreteMatch(rootClass, selector)) { |
| 765 // therefore there is no instance that will require | 769 // The root subclass has a concrete implementation so no subclass needs |
| 766 // [noSuchMethod] handling. | 770 // noSuchMethod handling. |
| 767 return !cls.isAbstract && !hasConcreteMatch(cls, selector); | 771 return false; |
| 772 } else if (rootNode.isDirectlyInstantiated && !rootClass.isAbstract) { | |
| 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; | |
|
Siggi Cherem (dart-lang)
2016/10/17 19:30:34
should we also check that subclass is not abstract
Johnni Winther
2016/10/18 08:13:51
Wasn't needed above either (now that type inferenc
| |
| 783 } | |
| 784 }, ClassHierarchyNode.DIRECTLY_INSTANTIATED, strict: true); | |
| 785 // We stopped fast so we need noSuchMethod handling. | |
| 786 return result == IterationStep.STOP; | |
| 768 } | 787 } |
| 769 | 788 |
| 770 bool baseNeedsNoSuchMethod = needsNoSuchMethod(base); | 789 ClassSet classSet = getClassSet(base); |
| 771 if (query == ClassQuery.EXACT || baseNeedsNoSuchMethod) { | 790 ClassHierarchyNode node = classSet.node; |
| 772 return baseNeedsNoSuchMethod; | 791 if (query == ClassQuery.EXACT) { |
| 792 return node.isDirectlyInstantiated && !hasConcreteMatch(base, selector); | |
| 793 } else if (query == ClassQuery.SUBCLASS) { | |
| 794 return subclassesNeedNoSuchMethod(node); | |
| 795 } else { | |
| 796 if (subclassesNeedNoSuchMethod(node)) return true; | |
| 797 for (ClassHierarchyNode subtypeNode in classSet.subtypeNodes) { | |
|
Siggi Cherem (dart-lang)
2016/10/17 19:30:34
remind me - do subtype nodes include just the imme
Johnni Winther
2016/10/18 08:13:51
It contains the roots for subclass trees that impl
| |
| 798 if (subclassesNeedNoSuchMethod(subtypeNode)) return true; | |
|
Siggi Cherem (dart-lang)
2016/10/17 19:30:34
Q: are we guaranteed that subtypes here can't be s
Johnni Winther
2016/10/18 08:13:51
Yes. The are not subclasses of [base] (then they w
| |
| 799 } | |
| 800 return false; | |
| 773 } | 801 } |
| 774 | |
| 775 Iterable<ClassElement> subclassesToCheck; | |
| 776 if (query == ClassQuery.SUBTYPE) { | |
| 777 subclassesToCheck = strictSubtypesOf(base); | |
| 778 } else { | |
| 779 assert(query == ClassQuery.SUBCLASS); | |
| 780 subclassesToCheck = strictSubclassesOf(base); | |
| 781 } | |
| 782 | |
| 783 return subclassesToCheck != null && | |
| 784 subclassesToCheck.any(needsNoSuchMethod); | |
| 785 } | 802 } |
| 786 | 803 |
| 787 final Compiler _compiler; | 804 final Compiler _compiler; |
| 788 BackendClasses get backendClasses => _backend.backendClasses; | 805 BackendClasses get backendClasses => _backend.backendClasses; |
| 789 JavaScriptBackend get _backend => _compiler.backend; | 806 JavaScriptBackend get _backend => _compiler.backend; |
| 790 CommonMasks get commonMasks => _compiler.commonMasks; | 807 CommonMasks get commonMasks => _compiler.commonMasks; |
| 791 final FunctionSet allFunctions; | 808 final FunctionSet allFunctions; |
| 792 final Set<Element> functionsCalledInLoop = new Set<Element>(); | 809 final Set<Element> functionsCalledInLoop = new Set<Element>(); |
| 793 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); | 810 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); |
| 794 | 811 |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1143 /// Only the class itself is included. | 1160 /// Only the class itself is included. |
| 1144 EXACT, | 1161 EXACT, |
| 1145 | 1162 |
| 1146 /// The class and all subclasses (transitively) are included. | 1163 /// The class and all subclasses (transitively) are included. |
| 1147 SUBCLASS, | 1164 SUBCLASS, |
| 1148 | 1165 |
| 1149 /// The class and all classes that implement or subclass it (transitively) | 1166 /// The class and all classes that implement or subclass it (transitively) |
| 1150 /// are included. | 1167 /// are included. |
| 1151 SUBTYPE, | 1168 SUBTYPE, |
| 1152 } | 1169 } |
| OLD | NEW |