Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(213)

Side by Side Diff: pkg/compiler/lib/src/world.dart

Issue 2420073002: Decouple TypeMask from ClassElement (Closed)
Patch Set: Updated cf. comments. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 /// Returns `true` if [cls] is either directly or indirectly instantiated. 48 /// Returns `true` if [cls] is either directly or indirectly instantiated.
49 bool isInstantiated(ClassElement cls); 49 bool isInstantiated(ClassElement cls);
50 50
51 /// Returns `true` if [cls] is directly instantiated. 51 /// Returns `true` if [cls] is directly instantiated.
52 bool isDirectlyInstantiated(ClassElement cls); 52 bool isDirectlyInstantiated(ClassElement cls);
53 53
54 /// Returns `true` if [cls] is indirectly instantiated, that is through a 54 /// Returns `true` if [cls] is indirectly instantiated, that is through a
55 /// subclass. 55 /// subclass.
56 bool isIndirectlyInstantiated(ClassElement cls); 56 bool isIndirectlyInstantiated(ClassElement cls);
57 57
58 /// Returns `true` if [cls] is abstract and thus can only be instantiated
59 /// through subclasses.
60 bool isAbstract(ClassElement cls);
61
58 /// Returns `true` if [cls] is implemented by an instantiated class. 62 /// Returns `true` if [cls] is implemented by an instantiated class.
59 bool isImplemented(ClassElement cls); 63 bool isImplemented(ClassElement cls);
60 64
61 /// Return `true` if [x] is a subclass of [y]. 65 /// Return `true` if [x] is a subclass of [y].
62 bool isSubclassOf(ClassElement x, ClassElement y); 66 bool isSubclassOf(ClassElement x, ClassElement y);
63 67
64 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an 68 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
65 /// instance of [y]. 69 /// instance of [y].
66 bool isSubtypeOf(ClassElement x, ClassElement y); 70 bool isSubtypeOf(ClassElement x, ClassElement y);
67 71
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
149 /// Returns `true` if [cls] or any superclass mixes in [mixin]. 153 /// Returns `true` if [cls] or any superclass mixes in [mixin].
150 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin); 154 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin);
151 155
152 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass 156 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass
153 /// of a mixin application of [y]. 157 /// of a mixin application of [y].
154 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y); 158 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y);
155 159
156 /// Returns `true` if any subclass of [superclass] implements [type]. 160 /// Returns `true` if any subclass of [superclass] implements [type].
157 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type); 161 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type);
158 162
163 /// Returns `true` if a call of [selector] on [cls] and/or subclasses/subtypes
164 /// need noSuchMethod handling.
165 ///
166 /// If the receiver is guaranteed to have a member that matches what we're
167 /// looking for, there's no need to introduce a noSuchMethod handler. It will
168 /// never be called.
169 ///
170 /// As an example, consider this class hierarchy:
171 ///
172 /// A <-- noSuchMethod
173 /// / \
174 /// C B <-- foo
175 ///
176 /// If we know we're calling foo on an object of type B we don't have to worry
177 /// about the noSuchMethod method in A because objects of type B implement
178 /// foo. On the other hand, if we end up calling foo on something of type C we
179 /// have to add a handler for it.
180 ///
181 /// If the holders of all user-defined noSuchMethod implementations that might
182 /// be applicable to the receiver type have a matching member for the current
183 /// name and selector, we avoid introducing a noSuchMethod handler.
184 ///
185 /// As an example, consider this class hierarchy:
186 ///
187 /// A <-- foo
188 /// / \
189 /// noSuchMethod --> B C <-- bar
190 /// | |
191 /// C D <-- noSuchMethod
192 ///
193 /// When calling foo on an object of type A, we know that the implementations
194 /// of noSuchMethod are in the classes B and D that also (indirectly)
195 /// implement foo, so we do not need a handler for it.
196 ///
197 /// If we're calling bar on an object of type D, we don't need the handler
198 /// either because all objects of type D implement bar through inheritance.
199 ///
200 /// If we're calling bar on an object of type A we do need the handler because
201 /// we may have to call B.noSuchMethod since B does not implement bar.
202 bool needsNoSuchMethod(ClassElement cls, Selector selector, ClassQuery query);
203
204 /// Returns whether [element] will be the one used at runtime when being
205 /// invoked on an instance of [cls]. [selector] is used to ensure library
206 /// privacy is taken into account.
207 bool hasElementIn(ClassElement cls, Selector selector, Element element);
208
159 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies 209 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies
160 /// of known classes. 210 /// of known classes.
161 /// 211 ///
162 /// This method is only provided for testing. For queries on classes, use the 212 /// This method is only provided for testing. For queries on classes, use the
163 /// methods defined in [ClosedWorld]. 213 /// methods defined in [ClosedWorld].
164 ClassHierarchyNode getClassHierarchyNode(ClassElement cls); 214 ClassHierarchyNode getClassHierarchyNode(ClassElement cls);
165 215
166 /// Returns [ClassSet] for [cls] used to model the extends and implements 216 /// Returns [ClassSet] for [cls] used to model the extends and implements
167 /// relations of known classes. 217 /// relations of known classes.
168 /// 218 ///
169 /// This method is only provided for testing. For queries on classes, use the 219 /// This method is only provided for testing. For queries on classes, use the
170 /// methods defined in [ClosedWorld]. 220 /// methods defined in [ClosedWorld].
171 ClassSet getClassSet(ClassElement cls); 221 ClassSet getClassSet(ClassElement cls);
172 222
173 // TODO(johnniwinther): Find a better strategy for caching these. 223 /// Return the cached mask for [base] with the given flags, or
174 @deprecated 224 /// calls [createMask] to create the mask and cache it.
175 List<Map<ClassElement, TypeMask>> get canonicalizedTypeMasks; 225 // TODO(johnniwinther): Find a better strategy for caching these?
226 TypeMask getCachedMask(ClassElement base, int flags, TypeMask createMask());
176 227
177 /// Returns the [FunctionSet] containing all live functions in the closed 228 /// Returns the [FunctionSet] containing all live functions in the closed
178 /// world. 229 /// world.
179 FunctionSet get allFunctions; 230 FunctionSet get allFunctions;
180 231
181 /// Returns `true` if the field [element] is known to be effectively final. 232 /// Returns `true` if the field [element] is known to be effectively final.
182 bool fieldNeverChanges(Element element); 233 bool fieldNeverChanges(Element element);
183 234
184 /// Extends the receiver type [mask] for calling [selector] to take live 235 /// Extends the receiver type [mask] for calling [selector] to take live
185 /// `noSuchMethod` handlers into account. 236 /// `noSuchMethod` handlers into account.
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 318
268 ClosedWorld closeWorld(); 319 ClosedWorld closeWorld();
269 320
270 /// Returns an iterable over all mixin applications that mixin [cls]. 321 /// Returns an iterable over all mixin applications that mixin [cls].
271 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls); 322 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls);
272 } 323 }
273 324
274 class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld { 325 class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
275 bool _closed = false; 326 bool _closed = false;
276 327
328 TypeMask getCachedMask(ClassElement base, int flags, TypeMask createMask()) {
329 Map<ClassElement, TypeMask> cachedMasks =
330 _canonicalizedTypeMasks[flags] ??= <ClassElement, TypeMask>{};
331 return cachedMasks.putIfAbsent(base, createMask);
332 }
333
277 /// Cache of [FlatTypeMask]s grouped by the 8 possible values of the 334 /// Cache of [FlatTypeMask]s grouped by the 8 possible values of the
278 /// `FlatTypeMask.flags` property. 335 /// `FlatTypeMask.flags` property.
279 List<Map<ClassElement, TypeMask>> canonicalizedTypeMasks = 336 final List<Map<ClassElement, TypeMask>> _canonicalizedTypeMasks =
280 new List<Map<ClassElement, TypeMask>>.filled(8, null); 337 new List<Map<ClassElement, TypeMask>>.filled(8, null);
281 338
282 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { 339 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) {
283 return invariant(cls, cls.isDeclaration, 340 return invariant(cls, cls.isDeclaration,
284 message: '$cls must be the declaration.') && 341 message: '$cls must be the declaration.') &&
285 invariant(cls, cls.isResolved, 342 invariant(cls, cls.isResolved,
286 message: 343 message:
287 '$cls must be resolved.') /* && 344 '$cls must be resolved.') /* &&
288 // TODO(johnniwinther): Reinsert this or similar invariant. 345 // TODO(johnniwinther): Reinsert this or similar invariant.
289 (!mustBeInstantiated || 346 (!mustBeInstantiated ||
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 return node != null && node.isDirectlyInstantiated; 392 return node != null && node.isDirectlyInstantiated;
336 } 393 }
337 394
338 @override 395 @override
339 bool isIndirectlyInstantiated(ClassElement cls) { 396 bool isIndirectlyInstantiated(ClassElement cls) {
340 assert(isClosed); 397 assert(isClosed);
341 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; 398 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration];
342 return node != null && node.isIndirectlyInstantiated; 399 return node != null && node.isIndirectlyInstantiated;
343 } 400 }
344 401
402 @override
403 bool isAbstract(ClassElement cls) => cls.isAbstract;
404
345 /// Returns `true` if [cls] is implemented by an instantiated class. 405 /// Returns `true` if [cls] is implemented by an instantiated class.
346 bool isImplemented(ClassElement cls) { 406 bool isImplemented(ClassElement cls) {
347 assert(isClosed); 407 assert(isClosed);
348 return _compiler.resolverWorld.isImplemented(cls); 408 return _compiler.resolverWorld.isImplemented(cls);
349 } 409 }
350 410
351 /// Returns an iterable over the directly instantiated classes that extend 411 /// Returns an iterable over the directly instantiated classes that extend
352 /// [cls] possibly including [cls] itself, if it is live. 412 /// [cls] possibly including [cls] itself, if it is live.
353 Iterable<ClassElement> subclassesOf(ClassElement cls) { 413 Iterable<ClassElement> subclassesOf(ClassElement cls) {
354 assert(isClosed); 414 assert(isClosed);
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 /// Returns `true` if any live class that mixes in [mixin] is also a subclass 675 /// Returns `true` if any live class that mixes in [mixin] is also a subclass
616 /// of [superclass]. 676 /// of [superclass].
617 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin) { 677 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin) {
618 assert(isClosed); 678 assert(isClosed);
619 return mixinUsesOf(mixin).any((each) => each.isSubclassOf(superclass)); 679 return mixinUsesOf(mixin).any((each) => each.isSubclassOf(superclass));
620 } 680 }
621 681
622 /// Returns `true` if [cls] or any superclass mixes in [mixin]. 682 /// Returns `true` if [cls] or any superclass mixes in [mixin].
623 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin) { 683 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin) {
624 assert(isClosed); 684 assert(isClosed);
685 assert(cls.isDeclaration);
686 assert(mixin.isDeclaration);
625 if (isUsedAsMixin(mixin)) { 687 if (isUsedAsMixin(mixin)) {
626 ClassElement current = cls.declaration; 688 ClassElement current = cls;
627 mixin = mixin.declaration;
628 while (current != null) { 689 while (current != null) {
629 current = current.declaration;
630 if (current.isMixinApplication) { 690 if (current.isMixinApplication) {
631 MixinApplicationElement application = current; 691 MixinApplicationElement application = current;
632 if (application.mixin.declaration == mixin) return true; 692 if (application.mixin == mixin) return true;
633 } 693 }
634 current = current.superclass; 694 current = current.superclass;
635 } 695 }
636 } 696 }
637 return false; 697 return false;
638 } 698 }
639 699
640 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass 700 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass
641 /// of a mixin application of [y]. 701 /// of a mixin application of [y].
642 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y) { 702 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y) {
643 assert(isClosed); 703 assert(isClosed);
644 x = x.declaration; 704 assert(x.isDeclaration);
645 y = y.declaration; 705 assert(y.isDeclaration);
646 Map<ClassElement, bool> secondMap = 706 Map<ClassElement, bool> secondMap =
647 _subtypeCoveredByCache[x] ??= <ClassElement, bool>{}; 707 _subtypeCoveredByCache[x] ??= <ClassElement, bool>{};
648 return secondMap[y] ??= subtypesOf(x).every((ClassElement cls) => 708 return secondMap[y] ??= subtypesOf(x).every((ClassElement cls) =>
649 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y)); 709 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y));
650 } 710 }
651 711
652 /// Returns `true` if any subclass of [superclass] implements [type]. 712 /// Returns `true` if any subclass of [superclass] implements [type].
653 bool hasAnySubclassThatImplements( 713 bool hasAnySubclassThatImplements(
654 ClassElement superclass, ClassElement type) { 714 ClassElement superclass, ClassElement type) {
655 assert(isClosed); 715 assert(isClosed);
656 Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass); 716 Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass);
657 if (subclasses == null) return false; 717 if (subclasses == null) return false;
658 return subclasses.contains(type); 718 return subclasses.contains(type);
659 } 719 }
660 720
721 @override
722 bool hasElementIn(ClassElement cls, Selector selector, Element element) {
723 // Use [:implementation:] of [element]
724 // because our function set only stores declarations.
725 Element result = findMatchIn(cls, selector);
726 return result == null
727 ? false
728 : result.implementation == element.implementation;
729 }
730
731 Element findMatchIn(ClassElement cls, Selector selector) {
732 // Use the [:implementation] of [cls] in case the found [element]
733 // is in the patch class.
734 var result = cls.implementation.lookupByName(selector.memberName);
735 return result;
736 }
737
738 /// Returns whether a [selector] call on an instance of [cls]
739 /// will hit a method at runtime, and not go through [noSuchMethod].
740 bool hasConcreteMatch(ClassElement cls, Selector selector) {
741 assert(invariant(cls, isInstantiated(cls),
742 message: '$cls has not been instantiated.'));
743 Element element = findMatchIn(cls, selector);
744 if (element == null) return false;
745
746 if (element.isAbstract) {
747 ClassElement enclosingClass = element.enclosingClass;
748 return hasConcreteMatch(enclosingClass.superclass, selector);
749 }
750 return selector.appliesUntyped(element);
751 }
752
753 @override
754 bool needsNoSuchMethod(
755 ClassElement base, Selector selector, ClassQuery query) {
756 /// Returns `true` if [cls] is an instantiated class that does not have
757 /// a concrete method matching [selector].
758 bool needsNoSuchMethod(ClassElement cls) {
759 // We can skip uninstantiated subclasses.
760 if (!isInstantiated(cls)) {
761 return false;
762 }
763 // We can just skip abstract classes because we know no
764 // instance of them will be created at runtime, and
765 // therefore there is no instance that will require
766 // [noSuchMethod] handling.
767 return !cls.isAbstract && !hasConcreteMatch(cls, selector);
768 }
769
770 bool baseNeedsNoSuchMethod = needsNoSuchMethod(base);
771 if (query == ClassQuery.EXACT || baseNeedsNoSuchMethod) {
772 return baseNeedsNoSuchMethod;
773 }
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 }
786
661 final Compiler _compiler; 787 final Compiler _compiler;
662 BackendClasses get backendClasses => _backend.backendClasses; 788 BackendClasses get backendClasses => _backend.backendClasses;
663 JavaScriptBackend get _backend => _compiler.backend; 789 JavaScriptBackend get _backend => _compiler.backend;
664 CommonMasks get commonMasks => _compiler.commonMasks; 790 CommonMasks get commonMasks => _compiler.commonMasks;
665 final FunctionSet allFunctions; 791 final FunctionSet allFunctions;
666 final Set<Element> functionsCalledInLoop = new Set<Element>(); 792 final Set<Element> functionsCalledInLoop = new Set<Element>();
667 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); 793 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>();
668 794
669 final Set<TypedefElement> _allTypedefs = new Set<TypedefElement>(); 795 final Set<TypedefElement> _allTypedefs = new Set<TypedefElement>();
670 796
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 return getMightBePassedToApply(element.expression); 1130 return getMightBePassedToApply(element.expression);
1005 } 1131 }
1006 return functionsThatMightBePassedToApply.contains(element); 1132 return functionsThatMightBePassedToApply.contains(element);
1007 } 1133 }
1008 1134
1009 @override 1135 @override
1010 bool getCurrentlyKnownMightBePassedToApply(Element element) { 1136 bool getCurrentlyKnownMightBePassedToApply(Element element) {
1011 return getMightBePassedToApply(element); 1137 return getMightBePassedToApply(element);
1012 } 1138 }
1013 } 1139 }
1140
1141 /// Enum values defining subset of classes included in queries.
1142 enum ClassQuery {
1143 /// Only the class itself is included.
1144 EXACT,
1145
1146 /// The class and all subclasses (transitively) are included.
1147 SUBCLASS,
1148
1149 /// The class and all classes that implement or subclass it (transitively)
1150 /// are included.
1151 SUBTYPE,
1152 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/types/union_type_mask.dart ('k') | tests/compiler/dart2js/needs_no_such_method_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698