| 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 |