| 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 'cache_strategy.dart'; | |
| 8 import 'closure.dart' show ClosureClassElement, SynthesizedCallMethodElementX; | 7 import 'closure.dart' show ClosureClassElement, SynthesizedCallMethodElementX; |
| 9 import 'common/backend_api.dart' show BackendClasses; | 8 import 'common/backend_api.dart' show BackendClasses; |
| 10 import 'common.dart'; | 9 import 'common.dart'; |
| 11 import 'constants/constant_system.dart'; | 10 import 'constants/constant_system.dart'; |
| 12 import 'core_types.dart' show CoreTypes, CoreClasses, CommonElements; | 11 import 'core_types.dart' show CoreTypes, CoreClasses, CommonElements; |
| 13 import 'dart_types.dart'; | 12 import 'dart_types.dart'; |
| 14 import 'elements/elements.dart' | 13 import 'elements/elements.dart' |
| 15 show | 14 show |
| 16 ClassElement, | 15 ClassElement, |
| 17 Element, | 16 Element, |
| 18 FunctionElement, | 17 FunctionElement, |
| 19 MixinApplicationElement, | 18 MixinApplicationElement, |
| 20 TypedefElement, | 19 TypedefElement, |
| 21 FieldElement; | 20 FieldElement; |
| 22 import 'js_backend/backend.dart' show JavaScriptBackend; | 21 import 'js_backend/backend.dart' show JavaScriptBackend; |
| 23 import 'ordered_typeset.dart'; | 22 import 'ordered_typeset.dart'; |
| 24 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; | 23 import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; |
| 25 import 'universe/class_set.dart'; | 24 import 'universe/class_set.dart'; |
| 26 import 'universe/function_set.dart' show FunctionSet, FunctionSetBuilder; | 25 import 'universe/function_set.dart' show FunctionSet, FunctionSetBuilder; |
| 27 import 'universe/selector.dart' show Selector; | 26 import 'universe/selector.dart' show Selector; |
| 28 import 'universe/side_effects.dart' show SideEffects; | 27 import 'universe/side_effects.dart' show SideEffects; |
| 29 import 'universe/world_builder.dart' | 28 import 'universe/world_builder.dart' show ResolutionWorldBuilder; |
| 30 show InstantiationInfo, ResolutionWorldBuilder; | |
| 31 import 'util/util.dart' show Link; | 29 import 'util/util.dart' show Link; |
| 32 | 30 |
| 33 /// Common superinterface for [OpenWorld] and [ClosedWorld]. | 31 /// Common superinterface for [OpenWorld] and [ClosedWorld]. |
| 34 abstract class World {} | 32 abstract class World {} |
| 35 | 33 |
| 36 /// The [ClosedWorld] represents the information known about a program when | 34 /// The [ClosedWorld] represents the information known about a program when |
| 37 /// compiling with closed-world semantics. | 35 /// compiling with closed-world semantics. |
| 38 /// | 36 /// |
| 39 /// Given the entrypoint of an application, we can track what's reachable from | 37 /// Given the entrypoint of an application, we can track what's reachable from |
| 40 /// it, what functions are called, what classes are allocated, which native | 38 /// it, what functions are called, what classes are allocated, which native |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 | 341 |
| 344 void registerUsedElement(Element element); | 342 void registerUsedElement(Element element); |
| 345 void registerTypedef(TypedefElement typedef); | 343 void registerTypedef(TypedefElement typedef); |
| 346 | 344 |
| 347 ClosedWorld closeWorld(DiagnosticReporter reporter); | 345 ClosedWorld closeWorld(DiagnosticReporter reporter); |
| 348 | 346 |
| 349 /// Returns an iterable over all mixin applications that mixin [cls]. | 347 /// Returns an iterable over all mixin applications that mixin [cls]. |
| 350 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls); | 348 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls); |
| 351 } | 349 } |
| 352 | 350 |
| 353 class WorldImpl implements OpenWorld { | |
| 354 bool _closed = false; | |
| 355 ClosedWorld _closedWorldCache; | |
| 356 | |
| 357 final JavaScriptBackend _backend; | |
| 358 FunctionSetBuilder _allFunctions; | |
| 359 | |
| 360 final Set<TypedefElement> _allTypedefs = new Set<TypedefElement>(); | |
| 361 | |
| 362 final Map<ClassElement, Set<MixinApplicationElement>> _mixinUses = | |
| 363 new Map<ClassElement, Set<MixinApplicationElement>>(); | |
| 364 | |
| 365 // We keep track of subtype and subclass relationships in four | |
| 366 // distinct sets to make class hierarchy analysis faster. | |
| 367 final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes = | |
| 368 <ClassElement, ClassHierarchyNode>{}; | |
| 369 final Map<ClassElement, ClassSet> _classSets = <ClassElement, ClassSet>{}; | |
| 370 | |
| 371 final Map<ClassElement, Map<ClassElement, bool>> _subtypeCoveredByCache = | |
| 372 <ClassElement, Map<ClassElement, bool>>{}; | |
| 373 | |
| 374 final Set<Element> alreadyPopulated; | |
| 375 | |
| 376 final CommonElements commonElements; | |
| 377 | |
| 378 final CoreTypes coreTypes; | |
| 379 | |
| 380 final CacheStrategy cacheStrategy; | |
| 381 | |
| 382 final ResolutionWorldBuilder resolverWorld; | |
| 383 | |
| 384 bool get isClosed => _closed; | |
| 385 | |
| 386 WorldImpl(this.resolverWorld, this._backend, this.commonElements, | |
| 387 this.coreTypes, CacheStrategy cacheStrategy) | |
| 388 : this.cacheStrategy = cacheStrategy, | |
| 389 alreadyPopulated = cacheStrategy.newSet() { | |
| 390 _allFunctions = new FunctionSetBuilder(); | |
| 391 } | |
| 392 | |
| 393 /// Returns an iterable over all mixin applications that mixin [cls]. | |
| 394 Iterable<MixinApplicationElement> allMixinUsesOf(ClassElement cls) { | |
| 395 Iterable<MixinApplicationElement> uses = _mixinUses[cls]; | |
| 396 return uses != null ? uses : const <MixinApplicationElement>[]; | |
| 397 } | |
| 398 | |
| 399 /// Called to add [cls] to the set of known classes. | |
| 400 /// | |
| 401 /// This ensures that class hierarchy queries can be performed on [cls] and | |
| 402 /// classes that extend or implement it. | |
| 403 void registerClass(ClassElement cls) => _registerClass(cls); | |
| 404 | |
| 405 void _registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) { | |
| 406 _ensureClassSet(cls); | |
| 407 if (isDirectlyInstantiated) { | |
| 408 _updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 void registerTypedef(TypedefElement typdef) { | |
| 413 _allTypedefs.add(typdef); | |
| 414 } | |
| 415 | |
| 416 ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) { | |
| 417 cls = cls.declaration; | |
| 418 return _classHierarchyNodes.putIfAbsent(cls, () { | |
| 419 ClassHierarchyNode parentNode; | |
| 420 if (cls.superclass != null) { | |
| 421 parentNode = _ensureClassHierarchyNode(cls.superclass); | |
| 422 } | |
| 423 return new ClassHierarchyNode(parentNode, cls); | |
| 424 }); | |
| 425 } | |
| 426 | |
| 427 ClassSet _ensureClassSet(ClassElement cls) { | |
| 428 cls = cls.declaration; | |
| 429 return _classSets.putIfAbsent(cls, () { | |
| 430 ClassHierarchyNode node = _ensureClassHierarchyNode(cls); | |
| 431 ClassSet classSet = new ClassSet(node); | |
| 432 | |
| 433 for (InterfaceType type in cls.allSupertypes) { | |
| 434 // TODO(johnniwinther): Optimization: Avoid adding [cls] to | |
| 435 // superclasses. | |
| 436 ClassSet subtypeSet = _ensureClassSet(type.element); | |
| 437 subtypeSet.addSubtype(node); | |
| 438 } | |
| 439 if (cls.isMixinApplication) { | |
| 440 // TODO(johnniwinther): Store this in the [ClassSet]. | |
| 441 MixinApplicationElement mixinApplication = cls; | |
| 442 if (mixinApplication.mixin != null) { | |
| 443 // If [mixinApplication] is malformed [mixin] is `null`. | |
| 444 registerMixinUse(mixinApplication, mixinApplication.mixin); | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 return classSet; | |
| 449 }); | |
| 450 } | |
| 451 | |
| 452 void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) { | |
| 453 // Ensure that classes implicitly implementing `Function` are in its | |
| 454 // subtype set. | |
| 455 ClassElement cls = node.cls; | |
| 456 if (cls != commonElements.functionClass && | |
| 457 cls.implementsFunction(commonElements)) { | |
| 458 ClassSet subtypeSet = _ensureClassSet(commonElements.functionClass); | |
| 459 subtypeSet.addSubtype(node); | |
| 460 } | |
| 461 if (!node.isInstantiated && node.parentNode != null) { | |
| 462 _updateSuperClassHierarchyNodeForClass(node.parentNode); | |
| 463 } | |
| 464 } | |
| 465 | |
| 466 void _updateClassHierarchyNodeForClass(ClassElement cls, | |
| 467 {bool directlyInstantiated: false, bool abstractlyInstantiated: false}) { | |
| 468 ClassHierarchyNode node = _ensureClassHierarchyNode(cls); | |
| 469 _updateSuperClassHierarchyNodeForClass(node); | |
| 470 if (directlyInstantiated) { | |
| 471 node.isDirectlyInstantiated = true; | |
| 472 } | |
| 473 if (abstractlyInstantiated) { | |
| 474 node.isAbstractlyInstantiated = true; | |
| 475 } | |
| 476 } | |
| 477 | |
| 478 ClosedWorld closeWorld(DiagnosticReporter reporter) { | |
| 479 Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses = | |
| 480 new Map<ClassElement, Set<ClassElement>>(); | |
| 481 | |
| 482 /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated` | |
| 483 /// properties of the [ClassHierarchyNode] for [cls]. | |
| 484 | |
| 485 void addSubtypes(ClassElement cls, InstantiationInfo info) { | |
| 486 if (!info.hasInstantiation) { | |
| 487 return; | |
| 488 } | |
| 489 if (cacheStrategy.hasIncrementalSupport && !alreadyPopulated.add(cls)) { | |
| 490 return; | |
| 491 } | |
| 492 assert(cls.isDeclaration); | |
| 493 if (!cls.isResolved) { | |
| 494 reporter.internalError(cls, 'Class "${cls.name}" is not resolved.'); | |
| 495 } | |
| 496 | |
| 497 _updateClassHierarchyNodeForClass(cls, | |
| 498 directlyInstantiated: info.isDirectlyInstantiated, | |
| 499 abstractlyInstantiated: info.isAbstractlyInstantiated); | |
| 500 | |
| 501 // Walk through the superclasses, and record the types | |
| 502 // implemented by that type on the superclasses. | |
| 503 ClassElement superclass = cls.superclass; | |
| 504 while (superclass != null) { | |
| 505 Set<Element> typesImplementedBySubclassesOfCls = | |
| 506 typesImplementedBySubclasses.putIfAbsent( | |
| 507 superclass, () => new Set<ClassElement>()); | |
| 508 for (DartType current in cls.allSupertypes) { | |
| 509 typesImplementedBySubclassesOfCls.add(current.element); | |
| 510 } | |
| 511 superclass = superclass.superclass; | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 // Use the [:seenClasses:] set to include non-instantiated | |
| 516 // classes: if the superclass of these classes require RTI, then | |
| 517 // they also need RTI, so that a constructor passes the type | |
| 518 // variables to the super constructor. | |
| 519 resolverWorld.forEachInstantiatedClass(addSubtypes); | |
| 520 | |
| 521 _closed = true; | |
| 522 return _closedWorldCache = new ClosedWorldImpl( | |
| 523 backend: _backend, | |
| 524 commonElements: commonElements, | |
| 525 coreTypes: coreTypes, | |
| 526 resolverWorld: resolverWorld, | |
| 527 functionSetBuilder: _allFunctions, | |
| 528 allTypedefs: _allTypedefs, | |
| 529 mixinUses: _mixinUses, | |
| 530 typesImplementedBySubclasses: typesImplementedBySubclasses, | |
| 531 classHierarchyNodes: _classHierarchyNodes, | |
| 532 classSets: _classSets); | |
| 533 } | |
| 534 | |
| 535 void registerMixinUse( | |
| 536 MixinApplicationElement mixinApplication, ClassElement mixin) { | |
| 537 // TODO(johnniwinther): Add map restricted to live classes. | |
| 538 // We don't support patch classes as mixin. | |
| 539 assert(mixin.isDeclaration); | |
| 540 Set<MixinApplicationElement> users = | |
| 541 _mixinUses.putIfAbsent(mixin, () => new Set<MixinApplicationElement>()); | |
| 542 users.add(mixinApplication); | |
| 543 } | |
| 544 | |
| 545 void registerUsedElement(Element element) { | |
| 546 if (element.isInstanceMember && !element.isAbstract) { | |
| 547 _allFunctions.add(element); | |
| 548 } | |
| 549 } | |
| 550 | |
| 551 ClosedWorld get closedWorldCache { | |
| 552 assert(isClosed); | |
| 553 return _closedWorldCache; | |
| 554 } | |
| 555 } | |
| 556 | |
| 557 /// Enum values defining subset of classes included in queries. | 351 /// Enum values defining subset of classes included in queries. |
| 558 enum ClassQuery { | 352 enum ClassQuery { |
| 559 /// Only the class itself is included. | 353 /// Only the class itself is included. |
| 560 EXACT, | 354 EXACT, |
| 561 | 355 |
| 562 /// The class and all subclasses (transitively) are included. | 356 /// The class and all subclasses (transitively) are included. |
| 563 SUBCLASS, | 357 SUBCLASS, |
| 564 | 358 |
| 565 /// The class and all classes that implement or subclass it (transitively) | 359 /// The class and all classes that implement or subclass it (transitively) |
| 566 /// are included. | 360 /// are included. |
| (...skipping 751 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1318 return getMightBePassedToApply(element.expression); | 1112 return getMightBePassedToApply(element.expression); |
| 1319 } | 1113 } |
| 1320 return functionsThatMightBePassedToApply.contains(element); | 1114 return functionsThatMightBePassedToApply.contains(element); |
| 1321 } | 1115 } |
| 1322 | 1116 |
| 1323 @override | 1117 @override |
| 1324 bool getCurrentlyKnownMightBePassedToApply(Element element) { | 1118 bool getCurrentlyKnownMightBePassedToApply(Element element) { |
| 1325 return getMightBePassedToApply(element); | 1119 return getMightBePassedToApply(element); |
| 1326 } | 1120 } |
| 1327 } | 1121 } |
| OLD | NEW |