| 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 'common/tasks.dart' show CompilerTask; | 7 import 'common/tasks.dart' show CompilerTask; |
| 8 import 'common.dart'; | 8 import 'common.dart'; |
| 9 import 'compiler.dart' show Compiler; | 9 import 'compiler.dart' show Compiler; |
| 10 import 'constants/expressions.dart' show ConstantExpression; | 10 import 'constants/expressions.dart' show ConstantExpression; |
| (...skipping 509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 constants.add(constant); | 520 constants.add(constant); |
| 521 if (constant is ConstructedConstantValue) { | 521 if (constant is ConstructedConstantValue) { |
| 522 ClassElement cls = constant.type.element; | 522 ClassElement cls = constant.type.element; |
| 523 _mapDependencies(element: cls, import: import); | 523 _mapDependencies(element: cls, import: import); |
| 524 } | 524 } |
| 525 constant.getDependencies().forEach((ConstantValue dependency) { | 525 constant.getDependencies().forEach((ConstantValue dependency) { |
| 526 _mapConstantDependencies(dependency, import); | 526 _mapConstantDependencies(dependency, import); |
| 527 }); | 527 }); |
| 528 } | 528 } |
| 529 | 529 |
| 530 /// Recursively traverses the graph of dependencies from one of [element] | 530 /// Recursively traverses the graph of dependencies from [element], mapping |
| 531 /// or [constant], mapping deferred imports to each dependency it needs in the | 531 /// deferred imports to each dependency it needs in the sets |
| 532 /// sets [_importedDeferredBy] and [_constantsDeferredBy]. | 532 /// [_importedDeferredBy] and [_constantsDeferredBy]. |
| 533 /// Only one of [element] and [constant] should be given. | |
| 534 void _mapDependencies( | 533 void _mapDependencies( |
| 535 {Element element, _DeferredImport import, isMirrorUsage: false}) { | 534 {Element element, _DeferredImport import, isMirrorUsage: false}) { |
| 536 Set<Element> elements = | 535 Set<Element> elements = _importedDeferredBy[import] ??= new Set<Element>(); |
| 537 _importedDeferredBy.putIfAbsent(import, () => new Set<Element>()); | |
| 538 | 536 |
| 539 Set<Element> dependentElements = new Set<Element>(); | 537 Set<Element> dependentElements = new Set<Element>(); |
| 540 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); | 538 Set<ConstantValue> dependentConstants = new Set<ConstantValue>(); |
| 541 | 539 |
| 542 LibraryElement library; | 540 LibraryElement library; |
| 543 | 541 |
| 544 if (element != null) { | 542 if (element != null) { |
| 545 // Only process elements once, unless we are doing dependencies due to | 543 // Only process elements once, unless we are doing dependencies due to |
| 546 // mirrors, which are added in additional traversals. | 544 // mirrors, which are added in additional traversals. |
| 547 if (!isMirrorUsage && elements.contains(element)) return; | 545 if (!isMirrorUsage && elements.contains(element)) return; |
| 548 // Anything used directly by main will be loaded from the start | 546 // Anything used directly by main will be loaded from the start |
| 549 // We do not need to traverse it again. | 547 // We do not need to traverse it again. |
| 550 if (import != _fakeMainImport && _mainElements.contains(element)) return; | 548 if (import != _fakeMainImport && _mainElements.contains(element)) return; |
| 549 // This adds [element] to [_mainElements]. Since [_mainElements] is |
| 550 // aliased with `_importedDeferredBy[_fakeMainImport]]`, |
| 551 elements.add(element); | 551 elements.add(element); |
| 552 | 552 |
| 553 // This call can modify [dependentElements] and [dependentConstants]. | 553 // This call can modify [dependentElements] and [dependentConstants]. |
| 554 _collectAllElementsAndConstantsResolvedFrom( | 554 _collectAllElementsAndConstantsResolvedFrom( |
| 555 element, dependentElements, dependentConstants, isMirrorUsage); | 555 element, dependentElements, dependentConstants, isMirrorUsage); |
| 556 | 556 |
| 557 library = element.library; | 557 library = element.library; |
| 558 } | 558 } |
| 559 | 559 |
| 560 for (Element dependency in dependentElements) { | 560 for (Element dependency in dependentElements) { |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 allOutputUnits.add(mainOutputUnit); | 708 allOutputUnits.add(mainOutputUnit); |
| 709 return; | 709 return; |
| 710 } | 710 } |
| 711 if (main == null) return; | 711 if (main == null) return; |
| 712 MethodElement mainMethod = main; | 712 MethodElement mainMethod = main; |
| 713 LibraryElement mainLibrary = mainMethod.library; | 713 LibraryElement mainLibrary = mainMethod.library; |
| 714 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); | 714 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); |
| 715 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); | 715 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); |
| 716 _importedDeferredBy[_fakeMainImport] = _mainElements; | 716 _importedDeferredBy[_fakeMainImport] = _mainElements; |
| 717 | 717 |
| 718 reporter.withCurrentElement( | 718 work() { |
| 719 mainLibrary, | 719 // Starting from main, traverse the program and find all dependencies. |
| 720 () => measure(() { | 720 _mapDependencies(element: mainMethod, import: _fakeMainImport); |
| 721 // Starting from main, traverse the program and find all | |
| 722 // dependencies. | |
| 723 _mapDependencies(element: mainMethod, import: _fakeMainImport); | |
| 724 | 721 |
| 725 // Also add "global" dependencies to the main OutputUnit. These | 722 // Also add "global" dependencies to the main OutputUnit. These are |
| 726 // are things that the backend needs but cannot associate with a | 723 // things that the backend needs but cannot associate with a particular |
| 727 // particular element, for example, startRootIsolate. This set | 724 // element, for example, startRootIsolate. This set also contains |
| 728 // also contains elements for which we lack precise information. | 725 // elements for which we lack precise information. |
| 729 for (MethodElement element | 726 for (MethodElement element |
| 730 in closedWorld.backendUsage.globalFunctionDependencies) { | 727 in closedWorld.backendUsage.globalFunctionDependencies) { |
| 731 _mapDependencies( | 728 _mapDependencies( |
| 732 element: element.implementation, import: _fakeMainImport); | 729 element: element.implementation, import: _fakeMainImport); |
| 733 } | 730 } |
| 734 for (ClassElement element | 731 for (ClassElement element |
| 735 in closedWorld.backendUsage.globalClassDependencies) { | 732 in closedWorld.backendUsage.globalClassDependencies) { |
| 736 _mapDependencies( | 733 _mapDependencies( |
| 737 element: element.implementation, import: _fakeMainImport); | 734 element: element.implementation, import: _fakeMainImport); |
| 738 } | 735 } |
| 739 | 736 |
| 740 // Now check to see if we have to add more elements due to | 737 // Now check to see if we have to add more elements due to mirrors. |
| 741 // mirrors. | 738 if (closedWorld.backendUsage.isMirrorsUsed) { |
| 742 if (closedWorld.backendUsage.isMirrorsUsed) { | 739 _addMirrorElements(); |
| 743 _addMirrorElements(); | 740 } |
| 744 } | |
| 745 | 741 |
| 746 // Build the OutputUnits using these two maps. | 742 // Build the OutputUnits using these two maps. |
| 747 Map<Element, OutputUnit> elementToOutputUnitBuilder = | 743 Map<Element, OutputUnit> elementToOutputUnitBuilder = |
| 748 new Map<Element, OutputUnit>(); | 744 new Map<Element, OutputUnit>(); |
| 749 Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder = | 745 Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder = |
| 750 new Map<ConstantValue, OutputUnit>(); | 746 new Map<ConstantValue, OutputUnit>(); |
| 751 | 747 |
| 752 // Add all constants that may have been registered during | 748 // Add all constants that may have been registered during resolution with |
| 753 // resolution with [registerConstantDeferredUse]. | 749 // [registerConstantDeferredUse]. |
| 754 constantToOutputUnitBuilder.addAll(_constantToOutputUnit); | 750 constantToOutputUnitBuilder.addAll(_constantToOutputUnit); |
| 755 _constantToOutputUnit.clear(); | 751 _constantToOutputUnit.clear(); |
| 756 | 752 |
| 757 // Reverse the mappings. For each element record an OutputUnit | 753 // Reverse the mappings. For each element record an OutputUnit collecting |
| 758 // collecting all deferred imports mapped to this element. Same | 754 // all deferred imports mapped to this element. Same for constants. |
| 759 // for constants. | 755 for (_DeferredImport import in _importedDeferredBy.keys) { |
| 760 for (_DeferredImport import in _importedDeferredBy.keys) { | 756 for (Element element in _importedDeferredBy[import]) { |
| 761 for (Element element in _importedDeferredBy[import]) { | 757 // Only one file should be loaded when the program starts, so make |
| 762 // Only one file should be loaded when the program starts, so | 758 // sure that only one OutputUnit is created for [fakeMainImport]. |
| 763 // make sure that only one OutputUnit is created for | 759 if (import == _fakeMainImport) { |
| 764 // [fakeMainImport]. | 760 elementToOutputUnitBuilder[element] = mainOutputUnit; |
| 765 if (import == _fakeMainImport) { | 761 } else { |
| 766 elementToOutputUnitBuilder[element] = mainOutputUnit; | 762 elementToOutputUnitBuilder |
| 767 } else { | 763 .putIfAbsent(element, () => new OutputUnit()) |
| 768 elementToOutputUnitBuilder | 764 .imports |
| 769 .putIfAbsent(element, () => new OutputUnit()) | 765 .add(import); |
| 770 .imports | 766 } |
| 771 .add(import); | 767 } |
| 772 } | 768 } |
| 773 } | 769 for (_DeferredImport import in _constantsDeferredBy.keys) { |
| 774 } | 770 for (ConstantValue constant in _constantsDeferredBy[import]) { |
| 775 for (_DeferredImport import in _constantsDeferredBy.keys) { | 771 // Only one file should be loaded when the program starts, so make |
| 776 for (ConstantValue constant in _constantsDeferredBy[import]) { | 772 // sure that only one OutputUnit is created for [fakeMainImport]. |
| 777 // Only one file should be loaded when the program starts, so | 773 if (import == _fakeMainImport) { |
| 778 // make sure that only one OutputUnit is created for | 774 constantToOutputUnitBuilder[constant] = mainOutputUnit; |
| 779 // [fakeMainImport]. | 775 } else { |
| 780 if (import == _fakeMainImport) { | 776 constantToOutputUnitBuilder |
| 781 constantToOutputUnitBuilder[constant] = mainOutputUnit; | 777 .putIfAbsent(constant, () => new OutputUnit()) |
| 782 } else { | 778 .imports |
| 783 constantToOutputUnitBuilder | 779 .add(import); |
| 784 .putIfAbsent(constant, () => new OutputUnit()) | 780 } |
| 785 .imports | 781 } |
| 786 .add(import); | 782 } |
| 787 } | |
| 788 } | |
| 789 } | |
| 790 | 783 |
| 791 // Release maps; | 784 // Release maps; |
| 792 _importedDeferredBy = null; | 785 _importedDeferredBy = null; |
| 793 _constantsDeferredBy = null; | 786 _constantsDeferredBy = null; |
| 794 | 787 |
| 795 // Find all the output units elements/constants have been mapped | 788 // Find all the output units elements/constants have been mapped |
| 796 // to, and canonicalize them. | 789 // to, and canonicalize them. |
| 797 elementToOutputUnitBuilder | 790 elementToOutputUnitBuilder |
| 798 .forEach((Element element, OutputUnit outputUnit) { | 791 .forEach((Element element, OutputUnit outputUnit) { |
| 799 _elementToOutputUnit[element] = _getCanonicalUnit(outputUnit); | 792 _elementToOutputUnit[element] = _getCanonicalUnit(outputUnit); |
| 800 }); | 793 }); |
| 801 constantToOutputUnitBuilder | 794 constantToOutputUnitBuilder |
| 802 .forEach((ConstantValue constant, OutputUnit outputUnit) { | 795 .forEach((ConstantValue constant, OutputUnit outputUnit) { |
| 803 _constantToOutputUnit[constant] = _getCanonicalUnit(outputUnit); | 796 _constantToOutputUnit[constant] = _getCanonicalUnit(outputUnit); |
| 804 }); | 797 }); |
| 805 | 798 |
| 806 // Generate a unique name for each OutputUnit. | 799 // Generate a unique name for each OutputUnit. |
| 807 _assignNamesToOutputUnits(allOutputUnits); | 800 _assignNamesToOutputUnits(allOutputUnits); |
| 808 })); | 801 } |
| 802 |
| 803 reporter.withCurrentElement(mainLibrary, () => measure(work)); |
| 804 |
| 809 // Notify the impact strategy impacts are no longer needed for deferred | 805 // Notify the impact strategy impacts are no longer needed for deferred |
| 810 // load. | 806 // load. |
| 811 compiler.impactStrategy.onImpactUsed(IMPACT_USE); | 807 compiler.impactStrategy.onImpactUsed(IMPACT_USE); |
| 812 } | 808 } |
| 813 | 809 |
| 814 void beforeResolution(LibraryEntity mainLibrary) { | 810 void beforeResolution(LibraryEntity mainLibrary) { |
| 815 if (mainLibrary == null) return; | 811 if (mainLibrary == null) return; |
| 816 // TODO(johnniwinther): Support deferred load for kernel based elements. | 812 // TODO(johnniwinther): Support deferred load for kernel based elements. |
| 817 if (compiler.options.useKernel) return; | 813 if (compiler.options.useKernel) return; |
| 818 _allDeferredImports[_fakeMainImport] = mainLibrary; | 814 _allDeferredImports[_fakeMainImport] = mainLibrary; |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 | 1118 |
| 1123 bool operator ==(other) { | 1119 bool operator ==(other) { |
| 1124 if (other is! _DeclaredDeferredImport) return false; | 1120 if (other is! _DeclaredDeferredImport) return false; |
| 1125 return declaration == other.declaration; | 1121 return declaration == other.declaration; |
| 1126 } | 1122 } |
| 1127 | 1123 |
| 1128 int get hashCode => declaration.hashCode * 17; | 1124 int get hashCode => declaration.hashCode * 17; |
| 1129 | 1125 |
| 1130 String toString() => '$declaration'; | 1126 String toString() => '$declaration'; |
| 1131 } | 1127 } |
| OLD | NEW |