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 | 7 import 'closure.dart' show |
8 SynthesizedCallMethodElementX; | 8 SynthesizedCallMethodElementX; |
9 import 'common/backend_api.dart' show | 9 import 'common/backend_api.dart' show |
10 Backend; | 10 Backend; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 | 59 |
60 /// The [ClassElement] for the [double] class defined in 'dart:core'. | 60 /// The [ClassElement] for the [double] class defined in 'dart:core'. |
61 ClassElement get doubleClass; | 61 ClassElement get doubleClass; |
62 | 62 |
63 /// The [ClassElement] for the [String] class defined in 'dart:core'. | 63 /// The [ClassElement] for the [String] class defined in 'dart:core'. |
64 ClassElement get stringClass; | 64 ClassElement get stringClass; |
65 | 65 |
66 /// Returns `true` if [cls] is instantiated. | 66 /// Returns `true` if [cls] is instantiated. |
67 bool isInstantiated(ClassElement cls); | 67 bool isInstantiated(ClassElement cls); |
68 | 68 |
69 /// Returns `true` if [cls] is implemented by an instantiated class. | |
70 bool isImplemented(ClassElement cls); | |
71 | |
72 /// Returns `true` if the class world is closed. | 69 /// Returns `true` if the class world is closed. |
73 bool get isClosed; | 70 bool get isClosed; |
74 | 71 |
75 /// Return `true` if [x] is a subclass of [y]. | 72 /// Return `true` if [x] is a subclass of [y]. |
76 bool isSubclassOf(ClassElement x, ClassElement y); | 73 bool isSubclassOf(ClassElement x, ClassElement y); |
77 | 74 |
78 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an | 75 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an |
79 /// instance of [y]. | 76 /// instance of [y]. |
80 bool isSubtypeOf(ClassElement x, ClassElement y); | 77 bool isSubtypeOf(ClassElement x, ClassElement y); |
81 | 78 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 /// Returns `true` if any live class that mixes in [mixin] is also a subclass | 116 /// Returns `true` if any live class that mixes in [mixin] is also a subclass |
120 /// of [superclass]. | 117 /// of [superclass]. |
121 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin); | 118 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin); |
122 | 119 |
123 /// Returns `true` if any subclass of [superclass] implements [type]. | 120 /// Returns `true` if any subclass of [superclass] implements [type]. |
124 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type); | 121 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type); |
125 | 122 |
126 /// Returns `true` if closed-world assumptions can be made, that is, | 123 /// Returns `true` if closed-world assumptions can be made, that is, |
127 /// incremental compilation isn't enabled. | 124 /// incremental compilation isn't enabled. |
128 bool get hasClosedWorldAssumption; | 125 bool get hasClosedWorldAssumption; |
129 | |
130 /// Returns a string representation of the closed world. | |
131 String dump(); | |
132 } | 126 } |
133 | 127 |
134 class World implements ClassWorld { | 128 class World implements ClassWorld { |
135 ClassElement get objectClass => compiler.objectClass; | 129 ClassElement get objectClass => compiler.objectClass; |
136 ClassElement get functionClass => compiler.functionClass; | 130 ClassElement get functionClass => compiler.functionClass; |
137 ClassElement get boolClass => compiler.boolClass; | 131 ClassElement get boolClass => compiler.boolClass; |
138 ClassElement get numClass => compiler.numClass; | 132 ClassElement get numClass => compiler.numClass; |
139 ClassElement get intClass => compiler.intClass; | 133 ClassElement get intClass => compiler.intClass; |
140 ClassElement get doubleClass => compiler.doubleClass; | 134 ClassElement get doubleClass => compiler.doubleClass; |
141 ClassElement get stringClass => compiler.stringClass; | 135 ClassElement get stringClass => compiler.stringClass; |
142 ClassElement get nullClass => compiler.nullClass; | 136 ClassElement get nullClass => compiler.nullClass; |
143 | 137 |
144 /// Cache of [ti.FlatTypeMask]s grouped by the 8 possible values of the | 138 /// Cache of [ti.FlatTypeMask]s grouped by the 8 possible values of the |
145 /// [ti.FlatTypeMask.flags] property. | 139 /// [ti.FlatTypeMask.flags] property. |
146 List<Map<ClassElement, ti.TypeMask>> canonicalizedTypeMasks = | 140 List<Map<ClassElement, ti.TypeMask>> canonicalizedTypeMasks = |
147 new List<Map<ClassElement, ti.TypeMask>>.filled(8, null); | 141 new List<Map<ClassElement, ti.TypeMask>>.filled(8, null); |
148 | 142 |
149 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { | 143 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { |
150 return | 144 return |
151 invariant(cls, cls.isDeclaration, | 145 invariant(cls, cls.isDeclaration, |
152 message: '$cls must be the declaration.') && | 146 message: '$cls must be the declaration.') && |
153 invariant(cls, cls.isResolved, | 147 invariant(cls, cls.isResolved, |
154 message: '$cls must be resolved.')/* && | 148 message: '$cls must be resolved.') && |
155 // TODO(johnniwinther): Reinsert this or similar invariant. | |
156 (!mustBeInstantiated || | 149 (!mustBeInstantiated || |
157 invariant(cls, isInstantiated(cls), | 150 invariant(cls, isInstantiated(cls), |
158 message: '$cls is not instantiated.'))*/; | 151 message: '$cls is not instantiated.')); |
159 } | 152 } |
160 | 153 |
161 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an | 154 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an |
162 /// instance of [y]. | 155 /// instance of [y]. |
163 bool isSubtypeOf(ClassElement x, ClassElement y) { | 156 bool isSubtypeOf(ClassElement x, ClassElement y) { |
164 assert(checkInvariants(x)); | 157 assert(checkInvariants(x)); |
165 assert(checkInvariants(y, mustBeInstantiated: false)); | 158 assert(checkInvariants(y, mustBeInstantiated: false)); |
166 | 159 |
167 if (y == objectClass) return true; | 160 if (y == objectClass) return true; |
168 if (x == objectClass) return false; | 161 if (x == objectClass) return false; |
169 if (x.asInstanceOf(y) != null) return true; | 162 if (x.asInstanceOf(y) != null) return true; |
170 if (y != functionClass) return false; | 163 if (y != functionClass) return false; |
171 return x.callType != null; | 164 return x.callType != null; |
172 } | 165 } |
173 | 166 |
174 /// Return `true` if [x] is a (non-strict) subclass of [y]. | 167 /// Return `true` if [x] is a (non-strict) subclass of [y]. |
175 bool isSubclassOf(ClassElement x, ClassElement y) { | 168 bool isSubclassOf(ClassElement x, ClassElement y) { |
176 assert(checkInvariants(x)); | 169 assert(checkInvariants(x)); |
177 assert(checkInvariants(y)); | 170 assert(checkInvariants(y)); |
178 | 171 |
179 if (y == objectClass) return true; | 172 if (y == objectClass) return true; |
180 if (x == objectClass) return false; | 173 if (x == objectClass) return false; |
181 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { | 174 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { |
182 if (x == y) return true; | 175 if (x == y) return true; |
183 x = x.superclass; | 176 x = x.superclass; |
184 } | 177 } |
185 return false; | 178 return false; |
186 } | 179 } |
187 | 180 |
188 /// Returns `true` if [cls] is instantiated either directly or through a | 181 /// Returns `true` if [cls] is instantiated. |
189 /// subclass. | |
190 bool isInstantiated(ClassElement cls) { | 182 bool isInstantiated(ClassElement cls) { |
191 return compiler.resolverWorld.isInstantiated(cls); | 183 return compiler.resolverWorld.isInstantiated(cls); |
192 } | 184 } |
193 | 185 |
194 /// Returns `true` if [cls] is implemented by an instantiated class. | |
195 bool isImplemented(ClassElement cls) { | |
196 return compiler.resolverWorld.isImplemented(cls); | |
197 } | |
198 | |
199 /// Returns an iterable over the directly instantiated classes that extend | 186 /// Returns an iterable over the directly instantiated classes that extend |
200 /// [cls] possibly including [cls] itself, if it is live. | 187 /// [cls] possibly including [cls] itself, if it is live. |
201 Iterable<ClassElement> subclassesOf(ClassElement cls) { | 188 Iterable<ClassElement> subclassesOf(ClassElement cls) { |
202 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 189 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; |
203 if (hierarchy == null) return const <ClassElement>[]; | 190 if (hierarchy == null) return const <ClassElement>[]; |
204 return hierarchy.subclasses( | 191 return hierarchy.subclasses( |
205 includeIndirectlyInstantiated: false, | 192 includeIndirectlyInstantiated: false, |
206 includeUninstantiated: false); | 193 includeUninstantiated: false); |
207 } | 194 } |
208 | 195 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 Iterable<MixinApplicationElement> uses = _mixinUses[cls]; | 301 Iterable<MixinApplicationElement> uses = _mixinUses[cls]; |
315 return uses != null ? uses : const <MixinApplicationElement>[]; | 302 return uses != null ? uses : const <MixinApplicationElement>[]; |
316 } | 303 } |
317 | 304 |
318 /// Returns an iterable over the live mixin applications that mixin [cls]. | 305 /// Returns an iterable over the live mixin applications that mixin [cls]. |
319 Iterable<MixinApplicationElement> mixinUsesOf(ClassElement cls) { | 306 Iterable<MixinApplicationElement> mixinUsesOf(ClassElement cls) { |
320 assert(isClosed); | 307 assert(isClosed); |
321 if (_liveMixinUses == null) { | 308 if (_liveMixinUses == null) { |
322 _liveMixinUses = new Map<ClassElement, List<MixinApplicationElement>>(); | 309 _liveMixinUses = new Map<ClassElement, List<MixinApplicationElement>>(); |
323 for (ClassElement mixin in _mixinUses.keys) { | 310 for (ClassElement mixin in _mixinUses.keys) { |
324 List<MixinApplicationElement> uses = <MixinApplicationElement>[]; | 311 Iterable<MixinApplicationElement> uses = |
325 | 312 _mixinUses[mixin].where(isInstantiated); |
326 void addLiveUse(MixinApplicationElement mixinApplication) { | 313 if (uses.isNotEmpty) _liveMixinUses[mixin] = uses.toList(); |
327 if (isInstantiated(mixinApplication)) { | |
328 uses.add(mixinApplication); | |
329 } else if (mixinApplication.isNamedMixinApplication) { | |
330 List<MixinApplicationElement> next = _mixinUses[mixinApplication]; | |
331 if (next != null) { | |
332 next.forEach(addLiveUse); | |
333 } | |
334 } | |
335 } | |
336 | |
337 _mixinUses[mixin].forEach(addLiveUse); | |
338 if (uses.isNotEmpty) { | |
339 _liveMixinUses[mixin] = uses; | |
340 } | |
341 } | 314 } |
342 } | 315 } |
343 Iterable<MixinApplicationElement> uses = _liveMixinUses[cls]; | 316 Iterable<MixinApplicationElement> uses = _liveMixinUses[cls]; |
344 return uses != null ? uses : const <MixinApplicationElement>[]; | 317 return uses != null ? uses : const <MixinApplicationElement>[]; |
345 } | 318 } |
346 | 319 |
347 /// Returns `true` if [cls] is mixed into a live class. | 320 /// Returns `true` if [cls] is mixed into a live class. |
348 bool isUsedAsMixin(ClassElement cls) { | 321 bool isUsedAsMixin(ClassElement cls) { |
349 return !mixinUsesOf(cls).isEmpty; | 322 return !mixinUsesOf(cls).isEmpty; |
350 } | 323 } |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
519 } | 492 } |
520 } | 493 } |
521 | 494 |
522 // Use the [:seenClasses:] set to include non-instantiated | 495 // Use the [:seenClasses:] set to include non-instantiated |
523 // classes: if the superclass of these classes require RTI, then | 496 // classes: if the superclass of these classes require RTI, then |
524 // they also need RTI, so that a constructor passes the type | 497 // they also need RTI, so that a constructor passes the type |
525 // variables to the super constructor. | 498 // variables to the super constructor. |
526 compiler.resolverWorld.directlyInstantiatedClasses.forEach(addSubtypes); | 499 compiler.resolverWorld.directlyInstantiatedClasses.forEach(addSubtypes); |
527 } | 500 } |
528 | 501 |
529 @override | |
530 String dump() { | |
531 StringBuffer sb = new StringBuffer(); | |
532 sb.write("Instantiated classes in the closed world:\n"); | |
533 getClassHierarchyNode(compiler.objectClass) | |
534 .printOn(sb, ' ', instantiatedOnly: true); | |
535 return sb.toString(); | |
536 } | |
537 | |
538 void registerMixinUse(MixinApplicationElement mixinApplication, | 502 void registerMixinUse(MixinApplicationElement mixinApplication, |
539 ClassElement mixin) { | 503 ClassElement mixin) { |
540 // TODO(johnniwinther): Add map restricted to live classes. | 504 // TODO(johnniwinther): Add map restricted to live classes. |
541 // We don't support patch classes as mixin. | 505 // We don't support patch classes as mixin. |
542 assert(mixin.isDeclaration); | 506 assert(mixin.isDeclaration); |
543 List<MixinApplicationElement> users = | 507 List<MixinApplicationElement> users = |
544 _mixinUses.putIfAbsent(mixin, () => | 508 _mixinUses.putIfAbsent(mixin, () => |
545 new List<MixinApplicationElement>()); | 509 new List<MixinApplicationElement>()); |
546 users.add(mixinApplication); | 510 users.add(mixinApplication); |
547 } | 511 } |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 // function expressions's element. | 639 // function expressions's element. |
676 // TODO(herhut): Generate classes for function expressions earlier. | 640 // TODO(herhut): Generate classes for function expressions earlier. |
677 if (element is SynthesizedCallMethodElementX) { | 641 if (element is SynthesizedCallMethodElementX) { |
678 return getMightBePassedToApply(element.expression); | 642 return getMightBePassedToApply(element.expression); |
679 } | 643 } |
680 return functionsThatMightBePassedToApply.contains(element); | 644 return functionsThatMightBePassedToApply.contains(element); |
681 } | 645 } |
682 | 646 |
683 bool get hasClosedWorldAssumption => !compiler.hasIncrementalSupport; | 647 bool get hasClosedWorldAssumption => !compiler.hasIncrementalSupport; |
684 } | 648 } |
OLD | NEW |