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