| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 'dart:collection' | |
| 8 show LinkedHashMap, | |
| 9 LinkedHashSet; | |
| 10 | |
| 11 import 'dart2jslib.dart' | 7 import 'dart2jslib.dart' |
| 12 show Compiler, | 8 show Compiler, |
| 13 CompilerTask, | 9 CompilerTask, |
| 14 ConstructedConstant, | 10 ConstructedConstant, |
| 15 MessageKind, | 11 MessageKind, |
| 16 SourceString, | 12 SourceString, |
| 17 StringConstant; | 13 StringConstant; |
| 18 | 14 |
| 19 import 'elements/elements.dart' | 15 import 'elements/elements.dart' |
| 20 show ClassElement, | 16 show ClassElement, |
| 21 Element, | 17 Element, |
| 22 Elements, | 18 Elements, |
| 23 FunctionElement, | 19 FunctionElement, |
| 24 LibraryElement, | 20 LibraryElement, |
| 25 MetadataAnnotation, | 21 MetadataAnnotation, |
| 26 ScopeContainerElement; | 22 ScopeContainerElement; |
| 27 | 23 |
| 28 import 'util/util.dart' | 24 import 'util/util.dart' |
| 29 show Link; | 25 show Link; |
| 30 | 26 |
| 31 import 'tree/tree.dart' | 27 import 'tree/tree.dart' |
| 32 show LibraryTag, | 28 show LibraryTag, |
| 33 Node, | 29 Node, |
| 34 Visitor; | 30 Visitor; |
| 35 | 31 |
| 36 import 'resolution/resolution.dart' | 32 import 'resolution/resolution.dart' |
| 37 show TreeElements; | 33 show TreeElements; |
| 38 | 34 |
| 39 class DeferredLoadTask extends CompilerTask { | 35 class DeferredLoadTask extends CompilerTask { |
| 40 final Set<LibraryElement> deferredLibraries = | 36 final Set<LibraryElement> deferredLibraries = new Set<LibraryElement>(); |
| 41 new LinkedHashSet<LibraryElement>(); | |
| 42 | 37 |
| 43 /// Records all elements that are deferred. | 38 /// Records all elements that are deferred. |
| 44 /// | 39 /// |
| 45 /// Long term, we want to split deferred element into more than one | 40 /// Long term, we want to split deferred element into more than one |
| 46 /// file (one for each library that is deferred), and this field | 41 /// file (one for each library that is deferred), and this field |
| 47 /// should become obsolete. | 42 /// should become obsolete. |
| 48 final Set<Element> allDeferredElements = new LinkedHashSet<Element>(); | 43 final Set<Element> allDeferredElements = new Set<Element>(); |
| 49 | 44 |
| 50 DeferredLoadTask(Compiler compiler) : super(compiler); | 45 DeferredLoadTask(Compiler compiler) : super(compiler); |
| 51 | 46 |
| 52 String get name => 'Deferred Loading'; | 47 String get name => 'Deferred Loading'; |
| 53 | 48 |
| 54 /// DeferredLibrary from dart:async | 49 /// DeferredLibrary from dart:async |
| 55 ClassElement get deferredLibraryClass => compiler.deferredLibraryClass; | 50 ClassElement get deferredLibraryClass => compiler.deferredLibraryClass; |
| 56 | 51 |
| 57 bool get areAnyElementsDeferred => !allDeferredElements.isEmpty; | 52 bool get areAnyElementsDeferred => !allDeferredElements.isEmpty; |
| 58 | 53 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 71 LibraryElement mainApp = main.getLibrary(); | 66 LibraryElement mainApp = main.getLibrary(); |
| 72 measureElement(mainApp, () { | 67 measureElement(mainApp, () { |
| 73 deferredLibraries.addAll(findDeferredLibraries(mainApp).toList()); | 68 deferredLibraries.addAll(findDeferredLibraries(mainApp).toList()); |
| 74 if (deferredLibraries.isEmpty) return; | 69 if (deferredLibraries.isEmpty) return; |
| 75 | 70 |
| 76 // TODO(ahe): Enforce the following invariants on | 71 // TODO(ahe): Enforce the following invariants on |
| 77 // [deferredElements] and [eagerElements]: | 72 // [deferredElements] and [eagerElements]: |
| 78 // 1. Only static or top-level elements are recorded. | 73 // 1. Only static or top-level elements are recorded. |
| 79 // 2. Only implementation is stored. | 74 // 2. Only implementation is stored. |
| 80 Map<LibraryElement, Set<Element>> deferredElements = | 75 Map<LibraryElement, Set<Element>> deferredElements = |
| 81 new LinkedHashMap<LibraryElement, Set<Element>>(); | 76 new Map<LibraryElement, Set<Element>>(); |
| 82 Set<Element> eagerElements = new LinkedHashSet<Element>(); | 77 Set<Element> eagerElements = new Set<Element>(); |
| 83 | 78 |
| 84 // Iterate through live local members of the main script. Create | 79 // Iterate through live local members of the main script. Create |
| 85 // a root-set of elements that must be loaded eagerly | 80 // a root-set of elements that must be loaded eagerly |
| 86 // (everything that is directly referred to from the main | 81 // (everything that is directly referred to from the main |
| 87 // script, but not imported from a deferred library), as well as | 82 // script, but not imported from a deferred library), as well as |
| 88 // root-sets for deferred libraries. | 83 // root-sets for deferred libraries. |
| 89 mainApp.forEachLocalMember((Element e) { | 84 mainApp.forEachLocalMember((Element e) { |
| 90 if (compiler.enqueuer.resolution.isLive(e)) { | 85 if (compiler.enqueuer.resolution.isLive(e)) { |
| 91 for (Element dependency in allElementsResolvedFrom(e)) { | 86 for (Element dependency in allElementsResolvedFrom(e)) { |
| 92 if (isExplicitlyDeferred(dependency)) { | 87 if (isExplicitlyDeferred(dependency)) { |
| 93 Set<Element> deferredElementsFromLibrary = | 88 Set<Element> deferredElementsFromLibrary = |
| 94 deferredElements.putIfAbsent( | 89 deferredElements.putIfAbsent( |
| 95 dependency.getLibrary(), | 90 dependency.getLibrary(), |
| 96 () => new LinkedHashSet<Element>()); | 91 () => new Set<Element>()); |
| 97 deferredElementsFromLibrary.add(dependency); | 92 deferredElementsFromLibrary.add(dependency); |
| 98 } else if (dependency.getLibrary() != mainApp) { | 93 } else if (dependency.getLibrary() != mainApp) { |
| 99 eagerElements.add(dependency.implementation); | 94 eagerElements.add(dependency.implementation); |
| 100 } | 95 } |
| 101 } | 96 } |
| 102 } | 97 } |
| 103 }); | 98 }); |
| 104 | 99 |
| 105 // Also add "global" dependencies to the eager root-set. These | 100 // Also add "global" dependencies to the eager root-set. These |
| 106 // are things that the backend need but cannot associate with a | 101 // are things that the backend need but cannot associate with a |
| 107 // particular element, for example, startRootIsolate. This set | 102 // particular element, for example, startRootIsolate. This set |
| 108 // also contains elements for which we lack precise information. | 103 // also contains elements for which we lack precise information. |
| 109 eagerElements.addAll(compiler.globalDependencies.otherDependencies); | 104 eagerElements.addAll(compiler.globalDependencies.otherDependencies); |
| 110 | 105 |
| 111 addTransitiveClosureTo(eagerElements); | 106 addTransitiveClosureTo(eagerElements); |
| 112 | 107 |
| 113 for (Set<Element> e in deferredElements.values) { | 108 for (Set<Element> e in deferredElements.values) { |
| 114 addTransitiveClosureTo(e); | 109 addTransitiveClosureTo(e); |
| 115 e.removeAll(eagerElements); | 110 e.removeAll(eagerElements); |
| 116 for (Element element in e) { | 111 for (Element element in e) { |
| 117 allDeferredElements.add(element); | 112 allDeferredElements.add(element); |
| 118 } | 113 } |
| 119 } | 114 } |
| 120 | 115 |
| 121 // TODO(ahe): The following code has no effect yet. I'm | 116 // TODO(ahe): The following code has no effect yet. I'm |
| 122 // including it as a comment for how to extend this to support | 117 // including it as a comment for how to extend this to support |
| 123 // multiple deferred files. | 118 // multiple deferred files. |
| 124 Map<Element, List<LibraryElement>> reverseMap = | 119 Map<Element, List<LibraryElement>> reverseMap = |
| 125 new LinkedHashMap<Element, List<LibraryElement>>(); | 120 new Map<Element, List<LibraryElement>>(); |
| 126 | 121 |
| 127 deferredElements.forEach((LibraryElement library, Set<Element> map) { | 122 deferredElements.forEach((LibraryElement library, Set<Element> map) { |
| 128 for (Element element in map) { | 123 for (Element element in map) { |
| 129 List<LibraryElement> libraries = | 124 List<LibraryElement> libraries = |
| 130 reverseMap.putIfAbsent(element, () => <LibraryElement>[]); | 125 reverseMap.putIfAbsent(element, () => <LibraryElement>[]); |
| 131 libraries.add(library); | 126 libraries.add(library); |
| 132 } | 127 } |
| 133 }); | 128 }); |
| 134 | 129 |
| 135 // Now compute the output files based on the lists in reverseMap. | 130 // Now compute the output files based on the lists in reverseMap. |
| 136 // TODO(ahe): Do that. | 131 // TODO(ahe): Do that. |
| 137 }); | 132 }); |
| 138 } | 133 } |
| 139 | 134 |
| 140 /// Returns all elements in the tree map of [element], but not the | 135 /// Returns all elements in the tree map of [element], but not the |
| 141 /// transitive closure. | 136 /// transitive closure. |
| 142 Set<Element> allElementsResolvedFrom(Element element) { | 137 Set<Element> allElementsResolvedFrom(Element element) { |
| 143 element = element.implementation; | 138 element = element.implementation; |
| 144 Set<Element> result = new LinkedHashSet<Element>(); | 139 Set<Element> result = new Set<Element>(); |
| 145 if (element.isGenerativeConstructor()) { | 140 if (element.isGenerativeConstructor()) { |
| 146 // When instantiating a class, we record a reference to the | 141 // When instantiating a class, we record a reference to the |
| 147 // constructor, not the class itself. We must add all the | 142 // constructor, not the class itself. We must add all the |
| 148 // instance members of the constructor's class (see below). | 143 // instance members of the constructor's class (see below). |
| 149 result.addAll( | 144 result.addAll( |
| 150 allElementsResolvedFrom(element.getEnclosingClass().implementation)); | 145 allElementsResolvedFrom(element.getEnclosingClass().implementation)); |
| 151 } | 146 } |
| 152 if (element.isClass()) { | 147 if (element.isClass()) { |
| 153 // If we see a class, add everything its instance members refer | 148 // If we see a class, add everything its instance members refer |
| 154 // to. Static members are not relevant. | 149 // to. Static members are not relevant. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 172 } else if (Elements.isStaticOrTopLevel(element) | 167 } else if (Elements.isStaticOrTopLevel(element) |
| 173 || element.isConstructor()) { | 168 || element.isConstructor()) { |
| 174 result.addAll(DependencyCollector.collect(element, compiler)); | 169 result.addAll(DependencyCollector.collect(element, compiler)); |
| 175 } | 170 } |
| 176 // Other elements, in particular instance members, are ignored as | 171 // Other elements, in particular instance members, are ignored as |
| 177 // they are processed as part of the class. | 172 // they are processed as part of the class. |
| 178 return result; | 173 return result; |
| 179 } | 174 } |
| 180 | 175 |
| 181 void addTransitiveClosureTo(Set<Element> elements) { | 176 void addTransitiveClosureTo(Set<Element> elements) { |
| 182 Set<Element> workSet = new LinkedHashSet.from(elements); | 177 Set<Element> workSet = new Set.from(elements); |
| 183 Set<Element> closure = new LinkedHashSet<Element>(); | 178 Set<Element> closure = new Set<Element>(); |
| 184 while (!workSet.isEmpty) { | 179 while (!workSet.isEmpty) { |
| 185 Element current = workSet.first; | 180 Element current = workSet.first; |
| 186 workSet.remove(current); | 181 workSet.remove(current); |
| 187 if (closure.contains(current)) continue; | 182 if (closure.contains(current)) continue; |
| 188 workSet.addAll(allElementsResolvedFrom(current)); | 183 workSet.addAll(allElementsResolvedFrom(current)); |
| 189 closure.add(current); | 184 closure.add(current); |
| 190 } | 185 } |
| 191 elements.addAll(closure); | 186 elements.addAll(closure); |
| 192 } | 187 } |
| 193 | 188 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 217 'actualName': actualName.slowToString()}); | 212 'actualName': actualName.slowToString()}); |
| 218 } | 213 } |
| 219 } | 214 } |
| 220 } | 215 } |
| 221 } | 216 } |
| 222 return link; | 217 return link; |
| 223 } | 218 } |
| 224 } | 219 } |
| 225 | 220 |
| 226 class DependencyCollector extends Visitor { | 221 class DependencyCollector extends Visitor { |
| 227 final Set<Element> dependencies = new LinkedHashSet<Element>(); | 222 final Set<Element> dependencies = new Set<Element>(); |
| 228 final TreeElements elements; | 223 final TreeElements elements; |
| 229 final Compiler compiler; | 224 final Compiler compiler; |
| 230 | 225 |
| 231 DependencyCollector(this.elements, this.compiler); | 226 DependencyCollector(this.elements, this.compiler); |
| 232 | 227 |
| 233 visitNode(Node node) { | 228 visitNode(Node node) { |
| 234 node.visitChildren(this); | 229 node.visitChildren(this); |
| 235 Element dependency = elements[node]; | 230 Element dependency = elements[node]; |
| 236 if (Elements.isUnresolved(dependency)) return; | 231 if (Elements.isUnresolved(dependency)) return; |
| 237 dependencies.add(dependency.implementation); | 232 dependencies.add(dependency.implementation); |
| 238 } | 233 } |
| 239 | 234 |
| 240 static Set<Element> collect(Element element, Compiler compiler) { | 235 static Set<Element> collect(Element element, Compiler compiler) { |
| 241 TreeElements elements = | 236 TreeElements elements = |
| 242 compiler.enqueuer.resolution.getCachedElements(element); | 237 compiler.enqueuer.resolution.getCachedElements(element); |
| 243 if (elements == null) return new LinkedHashSet<Element>(); | 238 if (elements == null) return new Set<Element>(); |
| 244 Node node = element.parseNode(compiler); | 239 Node node = element.parseNode(compiler); |
| 245 if (node == null) return new LinkedHashSet<Element>(); | 240 if (node == null) return new Set<Element>(); |
| 246 var collector = new DependencyCollector(elements, compiler); | 241 var collector = new DependencyCollector(elements, compiler); |
| 247 node.accept(collector); | 242 node.accept(collector); |
| 248 collector.dependencies.addAll(elements.otherDependencies); | 243 collector.dependencies.addAll(elements.otherDependencies); |
| 249 return collector.dependencies; | 244 return collector.dependencies; |
| 250 } | 245 } |
| 251 } | 246 } |
| OLD | NEW |