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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
178 /// Returns `true` if [cls] is instantiated. | 178 /// Returns `true` if [cls] is instantiated. |
179 bool isInstantiated(ClassElement cls) { | 179 bool isInstantiated(ClassElement cls) { |
180 return compiler.resolverWorld.isInstantiated(cls); | 180 return compiler.resolverWorld.isInstantiated(cls); |
181 } | 181 } |
182 | 182 |
183 /// Returns an iterable over the directly instantiated classes that extend | 183 /// Returns an iterable over the directly instantiated classes that extend |
184 /// [cls] possibly including [cls] itself, if it is live. | 184 /// [cls] possibly including [cls] itself, if it is live. |
185 Iterable<ClassElement> subclassesOf(ClassElement cls) { | 185 Iterable<ClassElement> subclassesOf(ClassElement cls) { |
186 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 186 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; |
187 if (hierarchy == null) return const <ClassElement>[]; | 187 if (hierarchy == null) return const <ClassElement>[]; |
188 assert(invariant(cls, isInstantiated(cls.declaration), | 188 return hierarchy.subclasses( |
189 message: 'Class $cls has not been instantiated.')); | 189 includeIndirectlyInstantiated: false, |
190 return hierarchy.subclasses(); | 190 includeUninstantiated: false); |
191 } | 191 } |
192 | 192 |
193 /// Returns an iterable over the directly instantiated classes that extend | 193 /// Returns an iterable over the directly instantiated classes that extend |
194 /// [cls] _not_ including [cls] itself. | 194 /// [cls] _not_ including [cls] itself. |
195 Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { | 195 Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { |
196 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 196 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
197 if (subclasses == null) return const <ClassElement>[]; | 197 if (subclasses == null) return const <ClassElement>[]; |
198 assert(invariant(cls, isInstantiated(cls.declaration), | 198 return subclasses.subclasses( |
199 message: 'Class $cls has not been instantiated.')); | 199 strict: true, |
200 return subclasses.strictSubclasses(); | 200 includeIndirectlyInstantiated: false, |
| 201 includeUninstantiated: false); |
201 } | 202 } |
202 | 203 |
203 /// Returns an iterable over the directly instantiated that implement [cls] | 204 /// Returns an iterable over the directly instantiated that implement [cls] |
204 /// _not_ including [cls]. | 205 /// _not_ including [cls]. |
205 Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { | 206 Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { |
206 Set<ClassElement> subtypes = _subtypes[cls.declaration]; | 207 ClassSet classSet = _classSets[cls.declaration]; |
207 return subtypes != null ? subtypes : const <ClassElement>[]; | 208 if (classSet == null) { |
| 209 return const <ClassElement>[]; |
| 210 } else { |
| 211 return classSet.subtypes( |
| 212 strict: true, |
| 213 includeIndirectlyInstantiated: false, |
| 214 includeUninstantiated: false); |
| 215 } |
208 } | 216 } |
209 | 217 |
210 /// Returns `true` if any directly instantiated class other than [cls] extends | 218 /// Returns `true` if any directly instantiated class other than [cls] extends |
211 /// [cls]. | 219 /// [cls]. |
212 bool hasAnyStrictSubclass(ClassElement cls) { | 220 bool hasAnyStrictSubclass(ClassElement cls) { |
213 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 221 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
214 if (subclasses == null) return false; | 222 if (subclasses == null) return false; |
215 assert(invariant(cls, isInstantiated(cls.declaration), | |
216 message: 'Class $cls has not been instantiated.')); | |
217 return subclasses.isIndirectlyInstantiated; | 223 return subclasses.isIndirectlyInstantiated; |
218 } | 224 } |
219 | 225 |
220 /// Returns `true` if any directly instantiated class other than [cls] | 226 /// Returns `true` if any directly instantiated class other than [cls] |
221 /// implements [cls]. | 227 /// implements [cls]. |
222 bool hasAnyStrictSubtype(ClassElement cls) { | 228 bool hasAnyStrictSubtype(ClassElement cls) { |
223 return !strictSubtypesOf(cls).isEmpty; | 229 return !strictSubtypesOf(cls).isEmpty; |
224 } | 230 } |
225 | 231 |
226 /// Returns `true` if all directly instantiated classes that implement [cls] | 232 /// Returns `true` if all directly instantiated classes that implement [cls] |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
331 new Map<ClassElement, List<MixinApplicationElement>>(); | 337 new Map<ClassElement, List<MixinApplicationElement>>(); |
332 Map<ClassElement, List<MixinApplicationElement>> _liveMixinUses; | 338 Map<ClassElement, List<MixinApplicationElement>> _liveMixinUses; |
333 | 339 |
334 final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses = | 340 final Map<ClassElement, Set<ClassElement>> _typesImplementedBySubclasses = |
335 new Map<ClassElement, Set<ClassElement>>(); | 341 new Map<ClassElement, Set<ClassElement>>(); |
336 | 342 |
337 // We keep track of subtype and subclass relationships in four | 343 // We keep track of subtype and subclass relationships in four |
338 // distinct sets to make class hierarchy analysis faster. | 344 // distinct sets to make class hierarchy analysis faster. |
339 final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes = | 345 final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes = |
340 <ClassElement, ClassHierarchyNode>{}; | 346 <ClassElement, ClassHierarchyNode>{}; |
341 final Map<ClassElement, Set<ClassElement>> _subtypes = | 347 final Map<ClassElement, ClassSet> _classSets = |
342 new Map<ClassElement, Set<ClassElement>>(); | 348 <ClassElement, ClassSet>{}; |
343 | 349 |
344 final Set<Element> sideEffectsFreeElements = new Set<Element>(); | 350 final Set<Element> sideEffectsFreeElements = new Set<Element>(); |
345 | 351 |
346 final Set<Element> elementsThatCannotThrow = new Set<Element>(); | 352 final Set<Element> elementsThatCannotThrow = new Set<Element>(); |
347 | 353 |
348 final Set<Element> functionsThatMightBePassedToApply = | 354 final Set<Element> functionsThatMightBePassedToApply = |
349 new Set<FunctionElement>(); | 355 new Set<FunctionElement>(); |
350 | 356 |
351 final Set<Element> alreadyPopulated; | 357 final Set<Element> alreadyPopulated; |
352 | 358 |
(...skipping 11 matching lines...) Expand all Loading... |
364 | 370 |
365 Set<ClassElement> typesImplementedBySubclassesOf(ClassElement cls) { | 371 Set<ClassElement> typesImplementedBySubclassesOf(ClassElement cls) { |
366 return _typesImplementedBySubclasses[cls.declaration]; | 372 return _typesImplementedBySubclasses[cls.declaration]; |
367 } | 373 } |
368 | 374 |
369 World(Compiler compiler) | 375 World(Compiler compiler) |
370 : allFunctions = new FunctionSet(compiler), | 376 : allFunctions = new FunctionSet(compiler), |
371 this.compiler = compiler, | 377 this.compiler = compiler, |
372 alreadyPopulated = compiler.cacheStrategy.newSet(); | 378 alreadyPopulated = compiler.cacheStrategy.newSet(); |
373 | 379 |
374 ClassHierarchyNode classHierarchyNode(ClassElement cls) { | 380 /// Called to add [cls] to the set of known classes. |
375 return _classHierarchyNodes[cls]; | 381 /// |
| 382 /// This ensures that class hierarchy queries can be performed on [cls] and |
| 383 /// classes that extend or implement it. |
| 384 void registerClass(ClassElement cls) { |
| 385 _ensureClassSet(cls); |
| 386 } |
| 387 |
| 388 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies |
| 389 /// of known classes. |
| 390 /// |
| 391 /// This method is only provided for testing. For queries on classes, use the |
| 392 /// methods defined in [ClassWorld]. |
| 393 ClassHierarchyNode getClassHierarchyNode(ClassElement cls) { |
| 394 return _classHierarchyNodes[cls.declaration]; |
| 395 } |
| 396 |
| 397 ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) { |
| 398 cls = cls.declaration; |
| 399 return _classHierarchyNodes.putIfAbsent(cls, () { |
| 400 ClassHierarchyNode node = new ClassHierarchyNode(cls); |
| 401 if (cls.superclass != null) { |
| 402 _ensureClassHierarchyNode(cls.superclass).addDirectSubclass(node); |
| 403 } |
| 404 return node; |
| 405 }); |
| 406 } |
| 407 |
| 408 /// Returns [ClassSet] for [cls] used to model the extends and implements |
| 409 /// relations of known classes. |
| 410 /// |
| 411 /// This method is only provided for testing. For queries on classes, use the |
| 412 /// methods defined in [ClassWorld]. |
| 413 ClassSet getClassSet(ClassElement cls) { |
| 414 return _classSets[cls.declaration]; |
| 415 } |
| 416 |
| 417 ClassSet _ensureClassSet(ClassElement cls) { |
| 418 cls = cls.declaration; |
| 419 return _classSets.putIfAbsent(cls, () { |
| 420 ClassHierarchyNode node = _ensureClassHierarchyNode(cls); |
| 421 ClassSet classSet = new ClassSet(node); |
| 422 |
| 423 for (InterfaceType type in cls.allSupertypes) { |
| 424 // TODO(johnniwinther): Optimization: Avoid adding [cls] to |
| 425 // superclasses. |
| 426 ClassSet subtypeSet = _ensureClassSet(type.element); |
| 427 subtypeSet.addSubtype(node); |
| 428 } |
| 429 return classSet; |
| 430 }); |
376 } | 431 } |
377 | 432 |
378 void populate() { | 433 void populate() { |
379 | 434 /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated` |
380 /// Ensure that a [ClassHierarchyNode] exists for [cls]. Updates the | 435 /// properties of the [ClassHierarchyNode] for [cls]. |
381 /// `isDirectlyInstantiated` and `isIndirectlyInstantiated` property of the | 436 void updateClassHierarchyNodeForClass( |
382 /// node according the provided arguments and returns the node. | |
383 ClassHierarchyNode createClassHierarchyNodeForClass( | |
384 ClassElement cls, | 437 ClassElement cls, |
385 {bool directlyInstantiated: false, | 438 {bool directlyInstantiated: false, |
386 bool indirectlyInstantiated: false}) { | 439 bool indirectlyInstantiated: false}) { |
387 assert(isInstantiated(cls)); | 440 assert(!directlyInstantiated || isInstantiated(cls)); |
388 | 441 ClassHierarchyNode node = getClassHierarchyNode(cls); |
389 ClassHierarchyNode node = _classHierarchyNodes.putIfAbsent(cls, () { | 442 bool changed = false; |
390 ClassHierarchyNode node = new ClassHierarchyNode(cls); | 443 if (directlyInstantiated && !node.isDirectlyInstantiated) { |
391 if (cls.superclass != null) { | |
392 createClassHierarchyNodeForClass(cls.superclass, | |
393 indirectlyInstantiated: | |
394 directlyInstantiated || indirectlyInstantiated) | |
395 .addDirectSubclass(node); | |
396 } | |
397 return node; | |
398 }); | |
399 if (directlyInstantiated) { | |
400 node.isDirectlyInstantiated = true; | 444 node.isDirectlyInstantiated = true; |
| 445 changed = true; |
401 } | 446 } |
402 if (indirectlyInstantiated) { | 447 if (indirectlyInstantiated && !node.isIndirectlyInstantiated) { |
403 node.isIndirectlyInstantiated = true; | 448 node.isIndirectlyInstantiated = true; |
| 449 changed = true; |
404 } | 450 } |
405 return node; | 451 if (changed && cls.superclass != null) { |
| 452 updateClassHierarchyNodeForClass( |
| 453 cls.superclass, indirectlyInstantiated: true); |
| 454 } |
406 } | 455 } |
407 | 456 |
408 void addSubtypes(ClassElement cls) { | 457 void addSubtypes(ClassElement cls) { |
409 if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) { | 458 if (compiler.hasIncrementalSupport && !alreadyPopulated.add(cls)) { |
410 return; | 459 return; |
411 } | 460 } |
412 assert(cls.isDeclaration); | 461 assert(cls.isDeclaration); |
413 if (!cls.isResolved) { | 462 if (!cls.isResolved) { |
414 compiler.internalError(cls, 'Class "${cls.name}" is not resolved.'); | 463 compiler.internalError(cls, 'Class "${cls.name}" is not resolved.'); |
415 } | 464 } |
416 | 465 |
417 createClassHierarchyNodeForClass(cls, directlyInstantiated: true); | 466 updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); |
418 | |
419 for (DartType type in cls.allSupertypes) { | |
420 Set<Element> subtypesOfSupertype = | |
421 _subtypes.putIfAbsent(type.element, () => new Set<ClassElement>()); | |
422 subtypesOfSupertype.add(cls); | |
423 } | |
424 | 467 |
425 // Walk through the superclasses, and record the types | 468 // Walk through the superclasses, and record the types |
426 // implemented by that type on the superclasses. | 469 // implemented by that type on the superclasses. |
427 ClassElement superclass = cls.superclass; | 470 ClassElement superclass = cls.superclass; |
428 while (superclass != null) { | 471 while (superclass != null) { |
429 Set<Element> typesImplementedBySubclassesOfCls = | 472 Set<Element> typesImplementedBySubclassesOfCls = |
430 _typesImplementedBySubclasses.putIfAbsent( | 473 _typesImplementedBySubclasses.putIfAbsent( |
431 superclass, () => new Set<ClassElement>()); | 474 superclass, () => new Set<ClassElement>()); |
432 for (DartType current in cls.allSupertypes) { | 475 for (DartType current in cls.allSupertypes) { |
433 typesImplementedBySubclassesOfCls.add(current.element); | 476 typesImplementedBySubclassesOfCls.add(current.element); |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
583 // function expressions's element. | 626 // function expressions's element. |
584 // TODO(herhut): Generate classes for function expressions earlier. | 627 // TODO(herhut): Generate classes for function expressions earlier. |
585 if (element is SynthesizedCallMethodElementX) { | 628 if (element is SynthesizedCallMethodElementX) { |
586 return getMightBePassedToApply(element.expression); | 629 return getMightBePassedToApply(element.expression); |
587 } | 630 } |
588 return functionsThatMightBePassedToApply.contains(element); | 631 return functionsThatMightBePassedToApply.contains(element); |
589 } | 632 } |
590 | 633 |
591 bool get hasClosedWorldAssumption => !compiler.hasIncrementalSupport; | 634 bool get hasClosedWorldAssumption => !compiler.hasIncrementalSupport; |
592 } | 635 } |
OLD | NEW |