| 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.dart'; | 7 import 'common.dart'; |
| 8 import 'common/backend_api.dart' show | 8 import 'common/backend_api.dart' show |
| 9 Backend; | 9 Backend; |
| 10 import 'common/tasks.dart' show | 10 import 'common/tasks.dart' show |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 /// OutputUnits are equal if their [imports] are equal. | 71 /// OutputUnits are equal if their [imports] are equal. |
| 72 class OutputUnit { | 72 class OutputUnit { |
| 73 /// The deferred imports that will load this output unit when one of them is | 73 /// The deferred imports that will load this output unit when one of them is |
| 74 /// loaded. | 74 /// loaded. |
| 75 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); | 75 final Setlet<_DeferredImport> imports = new Setlet<_DeferredImport>(); |
| 76 | 76 |
| 77 /// `true` if this output unit is for the main output file. | 77 /// `true` if this output unit is for the main output file. |
| 78 final bool isMainOutput; | 78 final bool isMainOutput; |
| 79 | 79 |
| 80 /// A unique name representing this [OutputUnit]. | 80 /// A unique name representing this [OutputUnit]. |
| 81 /// Based on the set of [imports]. | |
| 82 String name; | 81 String name; |
| 83 | 82 |
| 84 OutputUnit({this.isMainOutput: false}); | 83 OutputUnit({this.isMainOutput: false}); |
| 85 | 84 |
| 86 String toString() => "OutputUnit($name)"; | 85 String toString() => "OutputUnit($name)"; |
| 87 | 86 |
| 88 bool operator==(OutputUnit other) { | 87 bool operator==(OutputUnit other) { |
| 89 return imports.length == other.imports.length && | 88 return imports.length == other.imports.length && |
| 90 imports.containsAll(other.imports); | 89 imports.containsAll(other.imports); |
| 91 } | 90 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 | 124 |
| 126 /// A mapping from the name of a defer import to all the output units it | 125 /// A mapping from the name of a defer import to all the output units it |
| 127 /// depends on in a list of lists to be loaded in the order they appear. | 126 /// depends on in a list of lists to be loaded in the order they appear. |
| 128 /// | 127 /// |
| 129 /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3], | 128 /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3], |
| 130 /// [lib1]]} would mean that in order to load "lib1" first the hunk | 129 /// [lib1]]} would mean that in order to load "lib1" first the hunk |
| 131 /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3 | 130 /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3 |
| 132 /// can be loaded in parallel. And finally lib1 can be loaded. | 131 /// can be loaded in parallel. And finally lib1 can be loaded. |
| 133 final Map<String, List<OutputUnit>> hunksToLoad = | 132 final Map<String, List<OutputUnit>> hunksToLoad = |
| 134 new Map<String, List<OutputUnit>>(); | 133 new Map<String, List<OutputUnit>>(); |
| 135 final Map<_DeferredImport, String> _importDeferName = | 134 |
| 135 /// A cache of the result of calling `computeImportDeferName` on the keys of |
| 136 /// this map. |
| 137 final Map<_DeferredImport, String> importDeferName = |
| 136 <_DeferredImport, String>{}; | 138 <_DeferredImport, String>{}; |
| 137 | 139 |
| 138 /// A mapping from elements and constants to their output unit. Query this via | 140 /// A mapping from elements and constants to their output unit. Query this via |
| 139 /// [outputUnitForElement] | 141 /// [outputUnitForElement] |
| 140 final Map<Element, OutputUnit> _elementToOutputUnit = | 142 final Map<Element, OutputUnit> _elementToOutputUnit = |
| 141 new Map<Element, OutputUnit>(); | 143 new Map<Element, OutputUnit>(); |
| 142 | 144 |
| 143 /// A mapping from constants to their output unit. Query this via | 145 /// A mapping from constants to their output unit. Query this via |
| 144 /// [outputUnitForConstant] | 146 /// [outputUnitForConstant] |
| 145 final Map<ConstantValue, OutputUnit> _constantToOutputUnit = | 147 final Map<ConstantValue, OutputUnit> _constantToOutputUnit = |
| 146 new Map<ConstantValue, OutputUnit>(); | 148 new Map<ConstantValue, OutputUnit>(); |
| 147 | 149 |
| 148 /// All the imports with a [DeferredLibrary] annotation, mapped to the | 150 /// All the imports with a [DeferredLibrary] annotation, mapped to the |
| 149 /// [LibraryElement] they import. | 151 /// [LibraryElement] they import. |
| 150 /// The main library is included in this set for convenience. | 152 /// The main library is included in this set for convenience. |
| 151 final Map<_DeferredImport, LibraryElement> _allDeferredImports = | 153 final Map<_DeferredImport, LibraryElement> _allDeferredImports = |
| 152 new Map<_DeferredImport, LibraryElement>(); | 154 new Map<_DeferredImport, LibraryElement>(); |
| 153 | 155 |
| 154 /// Because the token-stream is forgotten later in the program, we cache a | 156 /// Because the token-stream is forgotten later in the program, we cache a |
| 155 /// description of each deferred import. | 157 /// description of each deferred import. |
| 156 final Map<_DeferredImport, ImportDescription>_deferredImportDescriptions = | 158 final Map<_DeferredImport, ImportDescription> _deferredImportDescriptions = |
| 157 <_DeferredImport, ImportDescription>{}; | 159 <_DeferredImport, ImportDescription>{}; |
| 158 | 160 |
| 159 // For each deferred import we want to know exactly what elements have to | 161 // For each deferred import we want to know exactly what elements have to |
| 160 // be loaded. | 162 // be loaded. |
| 161 Map<_DeferredImport, Set<Element>> _importedDeferredBy = null; | 163 Map<_DeferredImport, Set<Element>> _importedDeferredBy = null; |
| 162 Map<_DeferredImport, Set<ConstantValue>> _constantsDeferredBy = null; | 164 Map<_DeferredImport, Set<ConstantValue>> _constantsDeferredBy = null; |
| 163 | 165 |
| 164 Set<Element> _mainElements = new Set<Element>(); | 166 Set<Element> _mainElements = new Set<Element>(); |
| 165 | 167 |
| 166 DeferredLoadTask(Compiler compiler) : super(compiler) { | 168 DeferredLoadTask(Compiler compiler) : super(compiler) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 195 return _constantToOutputUnit[constant]; | 197 return _constantToOutputUnit[constant]; |
| 196 } | 198 } |
| 197 | 199 |
| 198 bool isDeferred(Element element) { | 200 bool isDeferred(Element element) { |
| 199 return outputUnitForElement(element) != mainOutputUnit; | 201 return outputUnitForElement(element) != mainOutputUnit; |
| 200 } | 202 } |
| 201 | 203 |
| 202 /// Returns the unique name for the deferred import of [prefix]. | 204 /// Returns the unique name for the deferred import of [prefix]. |
| 203 String getImportDeferName(Spannable node, PrefixElement prefix) { | 205 String getImportDeferName(Spannable node, PrefixElement prefix) { |
| 204 String name = | 206 String name = |
| 205 _importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)]; | 207 importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)]; |
| 206 if (name == null) { | 208 if (name == null) { |
| 207 reporter.internalError(node, "No deferred name for $prefix."); | 209 reporter.internalError(node, "No deferred name for $prefix."); |
| 208 } | 210 } |
| 209 return name; | 211 return name; |
| 210 } | 212 } |
| 211 | 213 |
| 212 /// Returns `true` if element [to] is reachable from element [from] without | 214 /// Returns `true` if element [to] is reachable from element [from] without |
| 213 /// crossing a deferred import. | 215 /// crossing a deferred import. |
| 214 /// | 216 /// |
| 215 /// For example, if we have two deferred libraries `A` and `B` that both | 217 /// For example, if we have two deferred libraries `A` and `B` that both |
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 564 | 566 |
| 565 /// Computes a unique string for the name field for each outputUnit. | 567 /// Computes a unique string for the name field for each outputUnit. |
| 566 /// | 568 /// |
| 567 /// Also sets up the [hunksToLoad] mapping. | 569 /// Also sets up the [hunksToLoad] mapping. |
| 568 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { | 570 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) { |
| 569 Set<String> usedImportNames = new Set<String>(); | 571 Set<String> usedImportNames = new Set<String>(); |
| 570 | 572 |
| 571 void computeImportDeferName(_DeferredImport import) { | 573 void computeImportDeferName(_DeferredImport import) { |
| 572 String result = import.computeImportDeferName(compiler); | 574 String result = import.computeImportDeferName(compiler); |
| 573 assert(result != null); | 575 assert(result != null); |
| 574 _importDeferName[import] = makeUnique(result, usedImportNames); | 576 importDeferName[import] = makeUnique(result, usedImportNames); |
| 575 } | 577 } |
| 576 | 578 |
| 577 int counter = 1; | 579 int counter = 1; |
| 578 | 580 |
| 579 for (_DeferredImport import in _allDeferredImports.keys) { | 581 for (_DeferredImport import in _allDeferredImports.keys) { |
| 580 computeImportDeferName(import); | 582 computeImportDeferName(import); |
| 581 } | 583 } |
| 582 | 584 |
| 583 for (OutputUnit outputUnit in allOutputUnits) { | 585 for (OutputUnit outputUnit in allOutputUnits) { |
| 584 if (outputUnit == mainOutputUnit) { | 586 if (outputUnit == mainOutputUnit) { |
| 585 outputUnit.name = "main"; | 587 outputUnit.name = "main"; |
| 586 } else { | 588 } else { |
| 587 outputUnit.name = "$counter"; | 589 outputUnit.name = "$counter"; |
| 588 ++counter; | 590 ++counter; |
| 589 } | 591 } |
| 590 } | 592 } |
| 591 | 593 |
| 592 List sortedOutputUnits = new List.from(allOutputUnits); | 594 List sortedOutputUnits = new List.from(allOutputUnits); |
| 593 // Sort the output units in descending order of the number of imports they | 595 // Sort the output units in descending order of the number of imports they |
| 594 // include. | 596 // include. |
| 595 | 597 |
| 596 // The loading of the output units mut be ordered because a superclass needs | 598 // The loading of the output units must be ordered because a superclass |
| 597 // to be initialized before its subclass. | 599 // needs to be initialized before its subclass. |
| 598 // But a class can only depend on another class in an output unit shared by | 600 // But a class can only depend on another class in an output unit shared by |
| 599 // a strict superset of the imports: | 601 // a strict superset of the imports: |
| 600 // By contradiction: Assume a class C in output unit shared by imports in | 602 // By contradiction: Assume a class C in output unit shared by imports in |
| 601 // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit | 603 // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit |
| 602 // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in | 604 // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in |
| 603 // S1 not in S2. lib_s must depend on C, and then in turn on D therefore D | 605 // S1 not in S2. lib_s must depend on C, and then in turn on D. Therefore D |
| 604 // is not in the right output unit. | 606 // is not in the right output unit. |
| 605 sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length); | 607 sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length); |
| 606 | 608 |
| 607 // For each deferred import we find out which outputUnits to load. | 609 // For each deferred import we find out which outputUnits to load. |
| 608 for (_DeferredImport import in _allDeferredImports.keys) { | 610 for (_DeferredImport import in _allDeferredImports.keys) { |
| 609 if (import == _fakeMainImport) continue; | 611 if (import == _fakeMainImport) continue; |
| 610 hunksToLoad[_importDeferName[import]] = new List<OutputUnit>(); | 612 hunksToLoad[importDeferName[import]] = new List<OutputUnit>(); |
| 611 for (OutputUnit outputUnit in sortedOutputUnits) { | 613 for (OutputUnit outputUnit in sortedOutputUnits) { |
| 612 if (outputUnit == mainOutputUnit) continue; | 614 if (outputUnit == mainOutputUnit) continue; |
| 613 if (outputUnit.imports.contains(import)) { | 615 if (outputUnit.imports.contains(import)) { |
| 614 hunksToLoad[_importDeferName[import]].add(outputUnit); | 616 hunksToLoad[importDeferName[import]].add(outputUnit); |
| 615 } | 617 } |
| 616 } | 618 } |
| 617 } | 619 } |
| 618 } | 620 } |
| 619 | 621 |
| 620 void onResolutionComplete(FunctionElement main) { | 622 void onResolutionComplete(FunctionElement main) { |
| 621 if (!isProgramSplit) { | 623 if (!isProgramSplit) { |
| 622 allOutputUnits.add(mainOutputUnit); | 624 allOutputUnits.add(mainOutputUnit); |
| 623 return; | 625 return; |
| 624 } | 626 } |
| 625 if (main == null) return; | 627 if (main == null) return; |
| 626 LibraryElement mainLibrary = main.library; | 628 LibraryElement mainLibrary = main.library; |
| 627 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); | 629 _importedDeferredBy = new Map<_DeferredImport, Set<Element>>(); |
| 628 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); | 630 _constantsDeferredBy = new Map<_DeferredImport, Set<ConstantValue>>(); |
| 629 _importedDeferredBy[_fakeMainImport] = _mainElements; | 631 _importedDeferredBy[_fakeMainImport] = _mainElements; |
| 630 | 632 |
| 631 measureElement(mainLibrary, () { | 633 measureElement(mainLibrary, () { |
| 632 | 634 |
| 633 // Starting from main, traverse the program and find all dependencies. | 635 // Starting from main, traverse the program and find all dependencies. |
| 634 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); | 636 _mapDependencies(element: compiler.mainFunction, import: _fakeMainImport); |
| 635 | 637 |
| 636 // Also add "global" dependencies to the main OutputUnit. These are | 638 // Also add "global" dependencies to the main OutputUnit. These are |
| 637 // things that the backend need but cannot associate with a particular | 639 // things that the backend needs but cannot associate with a particular |
| 638 // element, for example, startRootIsolate. This set also contains | 640 // element, for example, startRootIsolate. This set also contains |
| 639 // elements for which we lack precise information. | 641 // elements for which we lack precise information. |
| 640 for (Element element in compiler.globalDependencies.otherDependencies) { | 642 for (Element element in compiler.globalDependencies.otherDependencies) { |
| 641 _mapDependencies(element: element, import: _fakeMainImport); | 643 _mapDependencies(element: element, import: _fakeMainImport); |
| 642 } | 644 } |
| 643 | 645 |
| 644 // Now check to see if we have to add more elements due to mirrors. | 646 // Now check to see if we have to add more elements due to mirrors. |
| 645 if (compiler.mirrorsLibrary != null) { | 647 if (compiler.mirrorsLibrary != null) { |
| 646 _addMirrorElements(); | 648 _addMirrorElements(); |
| 647 } | 649 } |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 857 return null; | 859 return null; |
| 858 } | 860 } |
| 859 | 861 |
| 860 /// Returns a json-style map for describing what files that are loaded by a | 862 /// Returns a json-style map for describing what files that are loaded by a |
| 861 /// given deferred import. | 863 /// given deferred import. |
| 862 /// The mapping is structured as: | 864 /// The mapping is structured as: |
| 863 /// library uri -> {"name": library name, "files": (prefix -> list of files)} | 865 /// library uri -> {"name": library name, "files": (prefix -> list of files)} |
| 864 /// Where | 866 /// Where |
| 865 /// | 867 /// |
| 866 /// - <library uri> is the relative uri of the library making a deferred | 868 /// - <library uri> is the relative uri of the library making a deferred |
| 867 /// import | 869 /// import. |
| 868 /// - <library name> is the name of the libary, and "<unnamed>" if it is | 870 /// - <library name> is the name of the library, and "<unnamed>" if it is |
| 869 /// unnamed. | 871 /// unnamed. |
| 870 /// - <prefix> is the `as` prefix used for a given deferred import. | 872 /// - <prefix> is the `as` prefix used for a given deferred import. |
| 871 /// - <list of files> is a list of the filenames the must be loaded when that | 873 /// - <list of files> is a list of the filenames the must be loaded when that |
| 872 /// import is loaded. | 874 /// import is loaded. |
| 873 Map<String, Map<String, dynamic>> computeDeferredMap() { | 875 Map<String, Map<String, dynamic>> computeDeferredMap() { |
| 874 JavaScriptBackend backend = compiler.backend; | 876 JavaScriptBackend backend = compiler.backend; |
| 875 Map<String, Map<String, dynamic>> mapping = | 877 Map<String, Map<String, dynamic>> mapping = |
| 876 new Map<String, Map<String, dynamic>>(); | 878 new Map<String, Map<String, dynamic>>(); |
| 877 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { | 879 _deferredImportDescriptions.keys.forEach((_DeferredImport import) { |
| 878 List<OutputUnit> outputUnits = hunksToLoad[_importDeferName[import]]; | 880 List<OutputUnit> outputUnits = hunksToLoad[importDeferName[import]]; |
| 879 ImportDescription description = _deferredImportDescriptions[import]; | 881 ImportDescription description = _deferredImportDescriptions[import]; |
| 880 Map<String, dynamic> libraryMap = | 882 Map<String, dynamic> libraryMap = |
| 881 mapping.putIfAbsent(description.importingUri, | 883 mapping.putIfAbsent(description.importingUri, |
| 882 () => <String, dynamic>{"name": description.importingLibraryName, | 884 () => <String, dynamic>{"name": description.importingLibraryName, |
| 883 "imports": <String, List<String>>{}}); | 885 "imports": <String, List<String>>{}}); |
| 884 | 886 |
| 885 libraryMap["imports"][description.prefix] = outputUnits.map( | 887 libraryMap["imports"][importDeferName[import]] = outputUnits.map( |
| 886 (OutputUnit outputUnit) { | 888 (OutputUnit outputUnit) { |
| 887 return backend.deferredPartFileName(outputUnit.name); | 889 return backend.deferredPartFileName(outputUnit.name); |
| 888 }).toList(); | 890 }).toList(); |
| 889 }); | 891 }); |
| 890 return mapping; | 892 return mapping; |
| 891 } | 893 } |
| 892 | 894 |
| 893 /// Creates a textual representation of the output unit content. | 895 /// Creates a textual representation of the output unit content. |
| 894 String dump() { | 896 String dump() { |
| 895 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; | 897 Map<OutputUnit, List<String>> elementMap = <OutputUnit, List<String>>{}; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 996 return result; | 998 return result; |
| 997 } | 999 } |
| 998 | 1000 |
| 999 bool operator ==(other) { | 1001 bool operator ==(other) { |
| 1000 if (other is! _DeclaredDeferredImport) return false; | 1002 if (other is! _DeclaredDeferredImport) return false; |
| 1001 return declaration == other.declaration; | 1003 return declaration == other.declaration; |
| 1002 } | 1004 } |
| 1003 | 1005 |
| 1004 int get hashCode => declaration.hashCode * 17; | 1006 int get hashCode => declaration.hashCode * 17; |
| 1005 } | 1007 } |
| OLD | NEW |