Index: dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart |
diff --git a/dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart b/dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart |
index c623bd824bb34c53c0a0b03c53419d2257f93bdf..024f9d49af24ef7c6c282c0c8f38abda18185166 100644 |
--- a/dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart |
+++ b/dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart |
@@ -5,6 +5,7 @@ |
library deferred_load; |
import 'dart:uri'; |
+import 'dart:collection'; |
import 'dart2jslib.dart' |
show Compiler, |
@@ -17,17 +18,26 @@ import 'dart2jslib.dart' |
import 'elements/elements.dart' |
show ClassElement, |
Element, |
+ Elements, |
+ FunctionElement, |
LibraryElement, |
- MetadataAnnotation; |
+ MetadataAnnotation, |
+ ScopeContainerElement; |
import 'util/util.dart' |
show Link; |
import 'tree/tree.dart' |
- show LibraryTag; |
+ show LibraryTag, |
+ Node, |
+ Visitor; |
+ |
+import 'resolution/resolution.dart' |
+ show TreeElements; |
class DeferredLoadTask extends CompilerTask { |
final Set<LibraryElement> deferredLibraries = new Set<LibraryElement>(); |
+ final Set<Element> deferredElements = new LinkedHashSet<Element>(); |
kasperl
2013/03/06 10:26:51
Is there a reason this needs to be linked when the
ahe
2013/03/06 16:01:41
Done.
|
ClassElement cachedDeferredLibraryClass; |
@@ -58,23 +68,105 @@ class DeferredLoadTask extends CompilerTask { |
} |
bool isDeferred(Element element) { |
- // TODO(ahe): This is really a graph coloring problem. We should |
- // make sure that libraries and elements only used by a deferred |
- // library are also deferred. |
- // Also, if something is deferred depends on your |
- // perspective. Inside a deferred library, other elements of the |
- // same library are not deferred. We should add an extra parameter |
- // to this method to indicate "from where". |
+ element = element.implementation; |
+ return deferredElements.contains(element); |
+ } |
+ |
+ bool isExplicitlyDeferred(Element element) { |
+ element = element.implementation; |
return deferredLibraries.contains(element.getLibrary()); |
} |
- void registerMainApp(LibraryElement mainApp) { |
- if (mainApp == null) return; |
+ void onResolutionComplete(FunctionElement main) { |
+ if (main == null) return; |
+ LibraryElement mainApp = main.getLibrary(); |
measureElement(mainApp, () { |
deferredLibraries.addAll(findDeferredLibraries(mainApp)); |
+ if (deferredLibraries.isEmpty) return; |
+ |
+ Map<LibraryElement, Set<Element>> deferredElements = |
kasperl
2013/03/06 10:26:51
Not sure the shadowing (field/local) here helps th
ahe
2013/03/06 16:01:41
Done.
|
+ new LinkedHashMap<LibraryElement, Set<Element>>(); |
+ Set<Element> eagerElements = new LinkedHashSet<Element>(); |
+ |
+ mainApp.forEachLocalMember((Element e) { |
kasperl
2013/03/06 10:26:51
Maybe add a comment here that briefly outlines wha
ahe
2013/03/06 16:01:41
Done.
|
+ for (Element dependency in allElementsResolvedFrom(e)) { |
+ if (isExplicitlyDeferred(dependency)) { |
+ deferredElements.putIfAbsent(dependency.getLibrary(), |
kasperl
2013/03/06 10:26:51
I think this would be easier to read if you pulled
ahe
2013/03/06 16:01:41
Done.
|
+ () => new LinkedHashSet<Element>()) |
+ .add(dependency); |
+ } else if (mainApp != dependency.getLibrary()) { |
+ eagerElements.add(dependency); |
+ } |
+ } |
+ }); |
+ |
+ eagerElements.addAll(compiler.globalDependencies.backendDependencies); |
+ |
+ computeTransitiveClosure(eagerElements); |
+ |
+ for (Set<Element> e in deferredElements.values) { |
+ computeTransitiveClosure(e); |
+ e.removeAll(eagerElements); |
+ for (Element element in e) { |
+ this.deferredElements.add(element); |
+ } |
+ } |
+ |
kasperl
2013/03/06 10:26:51
Too many newlines.
ahe
2013/03/06 16:01:41
Done.
|
+ |
+ // Pseudo code to be implemented: |
kasperl
2013/03/06 10:26:51
Not sure I understand how to review this based on
ahe
2013/03/06 16:01:41
I updated the comment to be a TODO. Hope it is cle
|
+ Map<Element, List<LibraryElement>> reverseMap = |
+ new LinkedHashMap<Element, List<LibraryElement>>(); |
+ |
+ deferredElements.forEach((LibraryElement lib, Set<Element> map) { |
+ for (Element e in map) { |
+ reverseMap.putIfAbsent(e, |
kasperl
2013/03/06 10:26:51
You an extra local here too?
ahe
2013/03/06 16:01:41
Done.
|
+ () => <LibraryElement>[]).add(lib); |
+ } |
+ }); |
+ |
+ // Now compute the output files based on the lists in reverseMap. |
kasperl
2013/03/06 10:26:51
Change to a TODO or add the code?
ahe
2013/03/06 16:01:41
Done.
|
+ |
}); |
} |
+ /// Returns all elements in the tree map of [element], but not the |
+ /// transitive closure. |
+ Set<Element> allElementsResolvedFrom(Element element) { |
+ element = element.implementation; |
+ // TODO(ahe): This doesn't work. I need to record classes and |
kasperl
2013/03/06 10:26:51
Hmm. The code seems to deal with classes, statics,
ahe
2013/03/06 16:01:41
This was an old note to myself I forgot to remove.
|
+ // top-level functions, but I only record constructors. |
+ Set<Element> result = new LinkedHashSet<Element>(); |
+ if (element.isGenerativeConstructor()) { |
+ element = element.getEnclosingClass(); |
+ } |
+ if (element.isClass()) { |
+ ClassElement cls = element; |
+ cls.forEachLocalMember((Element e) { |
+ result.addAll(DependencyCollector.collect(e, compiler)); |
+ }); |
+ for (var type in cls.allSupertypes) { |
+ result.add(type.element); |
+ } |
+ result.add(cls); |
+ } else if (Elements.isStaticOrTopLevel(element)) { |
+ result.addAll(DependencyCollector.collect(element, compiler)); |
+ } |
+ return result; |
+ } |
+ |
+ void computeTransitiveClosure(Set<Element> elements) { |
kasperl
2013/03/06 10:26:51
The method names makes it sound like you'll be ret
ahe
2013/03/06 16:01:41
Done.
|
+ Set<Element> workSet = new LinkedHashSet.from(elements); |
+ Set<Element> closure = new LinkedHashSet<Element>(); |
+ while (!workSet.isEmpty) { |
+ Element current = workSet.first; |
+ workSet.remove(current); |
+ if (closure.contains(current)) continue; |
+ workSet.addAll(allElementsResolvedFrom(current)); |
+ closure.add(current); |
+ } |
+ elements.addAll(closure); |
+ } |
+ |
Link<LibraryElement> findDeferredLibraries(LibraryElement library) { |
Link<LibraryElement> link = const Link<LibraryElement>(); |
for (LibraryTag tag in library.tags) { |
@@ -104,3 +196,34 @@ class DeferredLoadTask extends CompilerTask { |
return link; |
} |
} |
+ |
+class DependencyCollector extends Visitor { |
+ final Set<Element> dependencies = new LinkedHashSet<Element>(); |
+ final TreeElements elements; |
+ final Compiler compiler; |
+ |
+ DependencyCollector(this.elements, this.compiler); |
+ |
+ visitNode(Node node) { |
+ Element dependency = elements[node]; |
+ if (dependency != null) { |
+ TreeElements elements = |
+ compiler.enqueuer.resolution.getCachedElements(dependency); |
+ if (elements != null) { |
+ dependencies.add(elements.currentElement); |
+ } |
+ } |
+ node.visitChildren(this); |
+ } |
+ |
+ static Set<Element> collect(Element element, Compiler compiler) { |
+ TreeElements elements = |
+ compiler.enqueuer.resolution.getCachedElements(element); |
+ if (elements == null) return new LinkedHashSet<Element>(); |
+ Node node = element.parseNode(compiler); |
+ var collector = new DependencyCollector(elements, compiler); |
+ node.accept(collector); |
+ collector.dependencies.addAll(elements.backendDependencies); |
+ return collector.dependencies; |
+ } |
+} |