OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 deferred_load; | 5 library deferred_load; |
6 | 6 |
7 import 'constants/expressions.dart'; | 7 import 'constants/expressions.dart'; |
8 import 'constants/values.dart' show | 8 import 'constants/values.dart' show |
9 ConstantValue, | 9 ConstantValue, |
10 ConstructedConstantValue, | 10 ConstructedConstantValue, |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 break; | 187 break; |
188 } | 188 } |
189 element = element.enclosingElement.implementation; | 189 element = element.enclosingElement.implementation; |
190 } | 190 } |
191 return _elementToOutputUnit[element]; | 191 return _elementToOutputUnit[element]; |
192 } | 192 } |
193 | 193 |
194 /// Returns the [OutputUnit] where [constant] belongs. | 194 /// Returns the [OutputUnit] where [constant] belongs. |
195 OutputUnit outputUnitForConstant(ConstantValue constant) { | 195 OutputUnit outputUnitForConstant(ConstantValue constant) { |
196 if (!isProgramSplit) return mainOutputUnit; | 196 if (!isProgramSplit) return mainOutputUnit; |
197 | |
198 return _constantToOutputUnit[constant]; | 197 return _constantToOutputUnit[constant]; |
199 } | 198 } |
200 | 199 |
201 bool isDeferred(Element element) { | 200 bool isDeferred(Element element) { |
202 return outputUnitForElement(element) != mainOutputUnit; | 201 return outputUnitForElement(element) != mainOutputUnit; |
203 } | 202 } |
204 | 203 |
205 /// Returns true if e1 and e2 are in the same output unit. | 204 /// Returns true if e1 and e2 are in the same output unit. |
206 bool inSameOutputUnit(Element e1, Element e2) { | 205 bool inSameOutputUnit(Element e1, Element e2) { |
207 return outputUnitForElement(e1) == outputUnitForElement(e2); | 206 return outputUnitForElement(e1) == outputUnitForElement(e2); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
242 /// Finds all elements and constants that [element] depends directly on. | 241 /// Finds all elements and constants that [element] depends directly on. |
243 /// (not the transitive closure.) | 242 /// (not the transitive closure.) |
244 /// | 243 /// |
245 /// Adds the results to [elements] and [constants]. | 244 /// Adds the results to [elements] and [constants]. |
246 void _collectAllElementsAndConstantsResolvedFrom( | 245 void _collectAllElementsAndConstantsResolvedFrom( |
247 Element element, | 246 Element element, |
248 Set<Element> elements, | 247 Set<Element> elements, |
249 Set<ConstantValue> constants, | 248 Set<ConstantValue> constants, |
250 isMirrorUsage) { | 249 isMirrorUsage) { |
251 | 250 |
252 /// Recursively add the constant and its dependencies to [constants]. | |
253 void addConstants(ConstantValue constant) { | |
254 if (constants.contains(constant)) return; | |
255 constants.add(constant); | |
256 if (constant is ConstructedConstantValue) { | |
257 elements.add(constant.type.element); | |
258 } | |
259 constant.getDependencies().forEach(addConstants); | |
260 } | |
261 | |
262 /// Collects all direct dependencies of [element]. | 251 /// Collects all direct dependencies of [element]. |
263 /// | 252 /// |
264 /// The collected dependent elements and constants are are added to | 253 /// The collected dependent elements and constants are are added to |
265 /// [elements] and [constants] respectively. | 254 /// [elements] and [constants] respectively. |
266 void collectDependencies(Element element) { | 255 void collectDependencies(Element element) { |
267 // TODO(johnniwinther): Remove this when [AbstractFieldElement] has been | 256 // TODO(johnniwinther): Remove this when [AbstractFieldElement] has been |
268 // removed. | 257 // removed. |
269 if (element is! AstElement) return; | 258 if (element is! AstElement) return; |
270 AstElement astElement = element; | 259 AstElement astElement = element; |
271 | 260 |
(...skipping 10 matching lines...) Expand all Loading... |
282 | 271 |
283 for (Element dependency in treeElements.allElements) { | 272 for (Element dependency in treeElements.allElements) { |
284 if (dependency.isLocal && !dependency.isFunction) continue; | 273 if (dependency.isLocal && !dependency.isFunction) continue; |
285 if (dependency.isErroneous) continue; | 274 if (dependency.isErroneous) continue; |
286 if (dependency.isTypeVariable) continue; | 275 if (dependency.isTypeVariable) continue; |
287 | 276 |
288 elements.add(dependency); | 277 elements.add(dependency); |
289 } | 278 } |
290 treeElements.forEachConstantNode((Node node, _) { | 279 treeElements.forEachConstantNode((Node node, _) { |
291 // Explicitly depend on the backend constants. | 280 // Explicitly depend on the backend constants. |
292 addConstants( | 281 constants.add( |
293 backend.constants.getConstantForNode(node, treeElements).value); | 282 backend.constants.getConstantForNode(node, treeElements).value); |
294 }); | 283 }); |
295 elements.addAll(treeElements.otherDependencies); | 284 elements.addAll(treeElements.otherDependencies); |
296 } | 285 } |
297 | 286 |
298 // TODO(sigurdm): How is metadata on a patch-class handled? | 287 // TODO(sigurdm): How is metadata on a patch-class handled? |
299 for (MetadataAnnotation metadata in element.metadata) { | 288 for (MetadataAnnotation metadata in element.metadata) { |
300 ConstantExpression constant = | 289 ConstantExpression constant = |
301 backend.constants.getConstantForMetadata(metadata); | 290 backend.constants.getConstantForMetadata(metadata); |
302 if (constant != null) { | 291 if (constant != null) { |
303 addConstants(constant.value); | 292 constants.add(constant.value); |
304 } | 293 } |
305 } | 294 } |
306 | 295 |
307 collectTypeDependencies(DartType type) { | 296 collectTypeDependencies(DartType type) { |
308 if (type is FunctionType) { | 297 if (type is FunctionType) { |
309 for (DartType argumentType in type.parameterTypes) { | 298 for (DartType argumentType in type.parameterTypes) { |
310 collectTypeDependencies(argumentType); | 299 collectTypeDependencies(argumentType); |
311 } | 300 } |
312 for (DartType argumentType in type.optionalParameterTypes) { | 301 for (DartType argumentType in type.optionalParameterTypes) { |
313 collectTypeDependencies(argumentType); | 302 collectTypeDependencies(argumentType); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 iterateTags(library); | 383 iterateTags(library); |
395 if (library.isPatched) { | 384 if (library.isPatched) { |
396 iterateTags(library.implementation); | 385 iterateTags(library.implementation); |
397 } | 386 } |
398 } | 387 } |
399 traverseLibrary(root); | 388 traverseLibrary(root); |
400 result.add(compiler.coreLibrary); | 389 result.add(compiler.coreLibrary); |
401 return result; | 390 return result; |
402 } | 391 } |
403 | 392 |
404 /// Recursively traverses the graph of dependencies from [element], mapping | 393 /// Add all dependencies of [constant] to the mapping of [import]. |
405 /// deferred imports to each dependency it needs in the sets | 394 void _mapConstantDependencies(ConstantValue constant, Import import) { |
406 /// [_importedDeferredBy] and [_constantsDeferredBy]. | 395 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import, |
407 void _mapDependencies(Element element, Import import, | 396 () => new Set<ConstantValue>()); |
408 {isMirrorUsage: false}) { | 397 if (constants.contains(constant)) return; |
| 398 constants.add(constant); |
| 399 if (constant is ConstructedConstantValue) { |
| 400 _mapDependencies(element: constant.type.element, import: import); |
| 401 } |
| 402 constant.getDependencies().forEach((ConstantValue dependency) { |
| 403 _mapConstantDependencies(dependency, import); |
| 404 }); |
| 405 } |
| 406 |
| 407 /// Recursively traverses the graph of dependencies from one of [element] |
| 408 /// or [constant], mapping deferred imports to each dependency it needs in the |
| 409 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. |
| 410 /// Only one of [element] and [constant] should be given. |
| 411 void _mapDependencies({Element element, |
| 412 Import import, |
| 413 isMirrorUsage: false}) { |
| 414 |
409 Set<Element> elements = _importedDeferredBy.putIfAbsent(import, | 415 Set<Element> elements = _importedDeferredBy.putIfAbsent(import, |
410 () => new Set<Element>()); | 416 () => new Set<Element>()); |
411 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import, | |
412 () => new Set<ConstantValue>()); | |
413 | 417 |
414 // Only process elements once, unless we are doing dependencies due to | |
415 // mirrors, which are added in additional traversals. | |
416 if (!isMirrorUsage && elements.contains(element)) return; | |
417 // Anything used directly by main will be loaded from the start | |
418 // We do not need to traverse it again. | |
419 if (import != _fakeMainImport && _mainElements.contains(element)) return; | |
420 | |
421 // Here we modify [_importedDeferredBy]. | |
422 elements.add(element); | |
423 | 418 |
424 Set<Element> dependentElements = new Set<Element>(); | 419 Set<Element> dependentElements = new Set<Element>(); |
| 420 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); |
425 | 421 |
426 // This call can modify [_importedDeferredBy] and [_constantsDeferredBy]. | 422 LibraryElement library; |
427 _collectAllElementsAndConstantsResolvedFrom( | |
428 element, dependentElements, constants, isMirrorUsage); | |
429 | 423 |
430 LibraryElement library = element.library; | 424 if (element != null) { |
| 425 // Only process elements once, unless we are doing dependencies due to |
| 426 // mirrors, which are added in additional traversals. |
| 427 if (!isMirrorUsage && elements.contains(element)) return; |
| 428 // Anything used directly by main will be loaded from the start |
| 429 // We do not need to traverse it again. |
| 430 if (import != _fakeMainImport && _mainElements.contains(element)) return; |
| 431 elements.add(element); |
| 432 |
| 433 |
| 434 // This call can modify [dependentElements] and [dependentConstants]. |
| 435 _collectAllElementsAndConstantsResolvedFrom( |
| 436 element, dependentElements, dependentConstants, isMirrorUsage); |
| 437 |
| 438 library = element.library; |
| 439 } |
| 440 |
431 for (Element dependency in dependentElements) { | 441 for (Element dependency in dependentElements) { |
432 if (_isExplicitlyDeferred(dependency, library)) { | 442 if (_isExplicitlyDeferred(dependency, library)) { |
433 for (Import deferredImport in _getImports(dependency, library)) { | 443 for (Import deferredImport in _getImports(dependency, library)) { |
434 _mapDependencies(dependency, deferredImport); | 444 _mapDependencies(element: dependency, import: deferredImport); |
435 }; | 445 } |
436 } else { | 446 } else { |
437 _mapDependencies(dependency, import); | 447 _mapDependencies(element: dependency, import: import); |
| 448 } |
| 449 } |
| 450 |
| 451 for (ConstantValue dependency in dependentConstants) { |
| 452 if (dependency is DeferredConstantValue) { |
| 453 _mapConstantDependencies(dependency, |
| 454 dependency.prefix.deferredImport); |
| 455 } else { |
| 456 _mapConstantDependencies(dependency, import); |
438 } | 457 } |
439 } | 458 } |
440 } | 459 } |
441 | 460 |
442 /// Adds extra dependencies coming from mirror usage. | 461 /// Adds extra dependencies coming from mirror usage. |
443 /// | 462 /// |
444 /// The elements are added with [_mapDependencies]. | 463 /// The elements are added with [_mapDependencies]. |
445 void _addMirrorElements() { | 464 void _addMirrorElements() { |
446 void mapDependenciesIfResolved(Element element, Import deferredImport) { | 465 void mapDependenciesIfResolved(Element element, Import deferredImport) { |
447 // If an element is the target of a MirrorsUsed annotation but never used | 466 // If an element is the target of a MirrorsUsed annotation but never used |
448 // It will not be resolved, and we should not call isNeededForReflection. | 467 // It will not be resolved, and we should not call isNeededForReflection. |
449 // TODO(sigurdm): Unresolved elements should just answer false when | 468 // TODO(sigurdm): Unresolved elements should just answer false when |
450 // asked isNeededForReflection. Instead an internal error is triggered. | 469 // asked isNeededForReflection. Instead an internal error is triggered. |
451 // So we have to filter them out here. | 470 // So we have to filter them out here. |
452 if (element is AnalyzableElementX && !element.hasTreeElements) return; | 471 if (element is AnalyzableElementX && !element.hasTreeElements) return; |
453 if (compiler.backend.isAccessibleByReflection(element)) { | 472 if (compiler.backend.isAccessibleByReflection(element)) { |
454 _mapDependencies(element, deferredImport, isMirrorUsage: true); | 473 _mapDependencies(element: element, import: deferredImport, |
| 474 isMirrorUsage: true); |
455 } | 475 } |
456 } | 476 } |
457 | 477 |
458 // For each deferred import we analyze all elements reachable from the | 478 // For each deferred import we analyze all elements reachable from the |
459 // imported library through non-deferred imports. | 479 // imported library through non-deferred imports. |
460 handleLibrary(LibraryElement library, Import deferredImport) { | 480 handleLibrary(LibraryElement library, Import deferredImport) { |
461 library.implementation.forEachLocalMember((Element element) { | 481 library.implementation.forEachLocalMember((Element element) { |
462 mapDependenciesIfResolved(element, deferredImport); | 482 mapDependenciesIfResolved(element, deferredImport); |
463 }); | 483 }); |
464 | 484 |
465 for (MetadataAnnotation metadata in library.metadata) { | 485 for (MetadataAnnotation metadata in library.metadata) { |
466 ConstantExpression constant = | 486 ConstantExpression constant = |
467 backend.constants.getConstantForMetadata(metadata); | 487 backend.constants.getConstantForMetadata(metadata); |
468 if (constant != null) { | 488 if (constant != null) { |
469 _mapDependencies(constant.value.getType(compiler.coreTypes).element, | 489 _mapConstantDependencies(constant.value, |
470 deferredImport); | 490 deferredImport); |
471 } | 491 } |
472 } | 492 } |
473 for (LibraryTag tag in library.tags) { | 493 for (LibraryTag tag in library.tags) { |
474 for (MetadataAnnotation metadata in tag.metadata) { | 494 for (MetadataAnnotation metadata in tag.metadata) { |
475 ConstantExpression constant = | 495 ConstantExpression constant = |
476 backend.constants.getConstantForMetadata(metadata); | 496 backend.constants.getConstantForMetadata(metadata); |
477 if (constant != null) { | 497 if (constant != null) { |
478 _mapDependencies(constant.value.getType(compiler.coreTypes).element, | 498 _mapConstantDependencies(constant.value, |
479 deferredImport); | 499 deferredImport); |
480 } | 500 } |
481 } | 501 } |
482 } | 502 } |
483 } | 503 } |
484 | 504 |
485 for (Import deferredImport in _allDeferredImports.keys) { | 505 for (Import deferredImport in _allDeferredImports.keys) { |
486 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; | 506 LibraryElement deferredLibrary = _allDeferredImports[deferredImport]; |
487 for (LibraryElement library in | 507 for (LibraryElement library in |
488 _nonDeferredReachableLibraries(deferredLibrary)) { | 508 _nonDeferredReachableLibraries(deferredLibrary)) { |
489 handleLibrary(library, deferredImport); | 509 handleLibrary(library, deferredImport); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 } | 593 } |
574 if (main == null) return; | 594 if (main == null) return; |
575 LibraryElement mainLibrary = main.library; | 595 LibraryElement mainLibrary = main.library; |
576 _importedDeferredBy = new Map<Import, Set<Element>>(); | 596 _importedDeferredBy = new Map<Import, Set<Element>>(); |
577 _constantsDeferredBy = new Map<Import, Set<ConstantValue>>(); | 597 _constantsDeferredBy = new Map<Import, Set<ConstantValue>>(); |
578 _importedDeferredBy[_fakeMainImport] = _mainElements; | 598 _importedDeferredBy[_fakeMainImport] = _mainElements; |
579 | 599 |
580 measureElement(mainLibrary, () { | 600 measureElement(mainLibrary, () { |
581 | 601 |
582 // Starting from main, traverse the program and find all dependencies. | 602 // Starting from main, traverse the program and find all dependencies. |
583 _mapDependencies(compiler.mainFunction, _fakeMainImport); | 603 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); |
584 | 604 |
585 // Also add "global" dependencies to the main OutputUnit. These are | 605 // Also add "global" dependencies to the main OutputUnit. These are |
586 // things that the backend need but cannot associate with a particular | 606 // things that the backend need but cannot associate with a particular |
587 // element, for example, startRootIsolate. This set also contains | 607 // element, for example, startRootIsolate. This set also contains |
588 // elements for which we lack precise information. | 608 // elements for which we lack precise information. |
589 for (Element element in compiler.globalDependencies.otherDependencies) { | 609 for (Element element in compiler.globalDependencies.otherDependencies) { |
590 _mapDependencies(element, _fakeMainImport); | 610 _mapDependencies(element: element, import: _fakeMainImport); |
591 } | 611 } |
592 | 612 |
593 // Now check to see if we have to add more elements due to mirrors. | 613 // Now check to see if we have to add more elements due to mirrors. |
594 if (compiler.mirrorsLibrary != null) { | 614 if (compiler.mirrorsLibrary != null) { |
595 _addMirrorElements(); | 615 _addMirrorElements(); |
596 } | 616 } |
597 | 617 |
598 // Build the OutputUnits using these two maps. | 618 // Build the OutputUnits using these two maps. |
599 Map<Element, OutputUnit> elementToOutputUnitBuilder = | 619 Map<Element, OutputUnit> elementToOutputUnitBuilder = |
600 new Map<Element, OutputUnit>(); | 620 new Map<Element, OutputUnit>(); |
601 Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder = | 621 Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder = |
602 new Map<ConstantValue, OutputUnit>(); | 622 new Map<ConstantValue, OutputUnit>(); |
603 | 623 |
604 // Reverse the mappings. For each element record an OutputUnit collecting | 624 // Reverse the mappings. For each element record an OutputUnit collecting |
605 // all deferred imports mapped to this element. Same for constants. | 625 // all deferred imports mapped to this element. Same for constants. |
606 for (Import import in _importedDeferredBy.keys) { | 626 for (Import import in _importedDeferredBy.keys) { |
607 for (Element element in _importedDeferredBy[import]) { | 627 for (Element element in _importedDeferredBy[import]) { |
608 // Only one file should be loaded when the program starts, so make | 628 // Only one file should be loaded when the program starts, so make |
609 // sure that only one OutputUnit is created for [fakeMainImport]. | 629 // sure that only one OutputUnit is created for [fakeMainImport]. |
610 if (import == _fakeMainImport) { | 630 if (import == _fakeMainImport) { |
611 elementToOutputUnitBuilder[element] = mainOutputUnit; | 631 elementToOutputUnitBuilder[element] = mainOutputUnit; |
612 } else { | 632 } else { |
613 elementToOutputUnitBuilder | 633 elementToOutputUnitBuilder |
614 .putIfAbsent(element, () => new OutputUnit()) | 634 .putIfAbsent(element, () => new OutputUnit()) |
615 .imports.add(import); | 635 .imports.add(import); |
616 } | 636 } |
617 } | 637 } |
| 638 } |
| 639 for (Import import in _constantsDeferredBy.keys) { |
618 for (ConstantValue constant in _constantsDeferredBy[import]) { | 640 for (ConstantValue constant in _constantsDeferredBy[import]) { |
619 // Only one file should be loaded when the program starts, so make | 641 // Only one file should be loaded when the program starts, so make |
620 // sure that only one OutputUnit is created for [fakeMainImport]. | 642 // sure that only one OutputUnit is created for [fakeMainImport]. |
621 if (import == _fakeMainImport) { | 643 if (import == _fakeMainImport) { |
622 constantToOutputUnitBuilder[constant] = mainOutputUnit; | 644 constantToOutputUnitBuilder[constant] = mainOutputUnit; |
623 } else { | 645 } else { |
624 constantToOutputUnitBuilder | 646 constantToOutputUnitBuilder |
625 .putIfAbsent(constant, () => new OutputUnit()) | 647 .putIfAbsent(constant, () => new OutputUnit()) |
626 .imports.add(import); | 648 .imports.add(import); |
627 } | 649 } |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 _importingLibrary = importingLibrary; | 882 _importingLibrary = importingLibrary; |
861 | 883 |
862 String get importingLibraryName { | 884 String get importingLibraryName { |
863 String libraryName = _importingLibrary.getLibraryName(); | 885 String libraryName = _importingLibrary.getLibraryName(); |
864 return libraryName == "" | 886 return libraryName == "" |
865 ? "<unnamed>" | 887 ? "<unnamed>" |
866 : libraryName; | 888 : libraryName; |
867 } | 889 } |
868 | 890 |
869 } | 891 } |
OLD | NEW |