Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: dart/sdk/lib/_internal/compiler/implementation/deferred_load.dart

Issue 12525007: Record dependency information to implement first version of dependency (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rebased/merged Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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:uri'; 7 import 'dart:uri';
8 import 'dart:collection';
ngeoffray 2013/03/07 11:21:14 show LinkedHashSet?
ahe 2013/03/11 12:28:01 Done.
8 9
9 import 'dart2jslib.dart' 10 import 'dart2jslib.dart'
10 show Compiler, 11 show Compiler,
11 CompilerTask, 12 CompilerTask,
12 ConstructedConstant, 13 ConstructedConstant,
13 MessageKind, 14 MessageKind,
14 SourceString, 15 SourceString,
15 StringConstant; 16 StringConstant;
16 17
17 import 'elements/elements.dart' 18 import 'elements/elements.dart'
18 show ClassElement, 19 show ClassElement,
19 Element, 20 Element,
21 Elements,
22 FunctionElement,
20 LibraryElement, 23 LibraryElement,
21 MetadataAnnotation; 24 MetadataAnnotation,
25 ScopeContainerElement;
22 26
23 import 'util/util.dart' 27 import 'util/util.dart'
24 show Link; 28 show Link;
25 29
26 import 'tree/tree.dart' 30 import 'tree/tree.dart'
27 show LibraryTag; 31 show LibraryTag,
32 Node,
33 Visitor;
34
35 import 'resolution/resolution.dart'
36 show TreeElements;
28 37
29 class DeferredLoadTask extends CompilerTask { 38 class DeferredLoadTask extends CompilerTask {
30 final Set<LibraryElement> deferredLibraries = new Set<LibraryElement>(); 39 final Set<LibraryElement> deferredLibraries =
40 new LinkedHashSet<LibraryElement>();
41
42 /// Records all elements that are deferred.
43 ///
44 /// Long term, we want to split deferred element into more than one
45 /// file (one for each library that is deferred), and this field
46 /// should become obsolete.
47 final Set<Element> allDeferredElements = new LinkedHashSet<Element>();
31 48
32 ClassElement cachedDeferredLibraryClass; 49 ClassElement cachedDeferredLibraryClass;
33 50
34 DeferredLoadTask(Compiler compiler) : super(compiler); 51 DeferredLoadTask(Compiler compiler) : super(compiler);
35 52
36 String get name => 'Lazy'; 53 String get name => 'Deferred Loading';
37 54
38 /// DeferredLibrary from dart:async 55 /// DeferredLibrary from dart:async
39 ClassElement get deferredLibraryClass { 56 ClassElement get deferredLibraryClass {
40 if (cachedDeferredLibraryClass == null) { 57 if (cachedDeferredLibraryClass == null) {
41 cachedDeferredLibraryClass = findDeferredLibraryClass(); 58 cachedDeferredLibraryClass = findDeferredLibraryClass();
42 } 59 }
43 return cachedDeferredLibraryClass; 60 return cachedDeferredLibraryClass;
44 } 61 }
45 62
46 ClassElement findDeferredLibraryClass() { 63 ClassElement findDeferredLibraryClass() {
47 var uri = new Uri.fromComponents(scheme: 'dart', path: 'async'); 64 var uri = new Uri.fromComponents(scheme: 'dart', path: 'async');
48 LibraryElement asyncLibrary = 65 LibraryElement asyncLibrary =
49 compiler.libraryLoader.loadLibrary(uri, null, uri); 66 compiler.libraryLoader.loadLibrary(uri, null, uri);
50 var element = asyncLibrary.find(const SourceString('DeferredLibrary')); 67 var element = asyncLibrary.find(const SourceString('DeferredLibrary'));
51 if (element == null) { 68 if (element == null) {
52 compiler.internalErrorOnElement( 69 compiler.internalErrorOnElement(
53 asyncLibrary, 70 asyncLibrary,
54 'dart:async library does not contain required class: ' 71 'dart:async library does not contain required class: '
55 'DeferredLibrary'); 72 'DeferredLibrary');
56 } 73 }
57 return element; 74 return element;
58 } 75 }
59 76
60 bool isDeferred(Element element) { 77 bool isDeferred(Element element) {
61 // TODO(ahe): This is really a graph coloring problem. We should 78 element = element.implementation;
62 // make sure that libraries and elements only used by a deferred 79 return allDeferredElements.contains(element);
63 // library are also deferred. 80 }
64 // Also, if something is deferred depends on your 81
65 // perspective. Inside a deferred library, other elements of the 82 bool isExplicitlyDeferred(Element element) {
66 // same library are not deferred. We should add an extra parameter 83 element = element.implementation;
67 // to this method to indicate "from where".
68 return deferredLibraries.contains(element.getLibrary()); 84 return deferredLibraries.contains(element.getLibrary());
69 } 85 }
70 86
71 void registerMainApp(LibraryElement mainApp) { 87 void onResolutionComplete(FunctionElement main) {
72 if (mainApp == null) return; 88 if (main == null) return;
89 LibraryElement mainApp = main.getLibrary();
73 measureElement(mainApp, () { 90 measureElement(mainApp, () {
74 deferredLibraries.addAll(findDeferredLibraries(mainApp)); 91 deferredLibraries.addAll(findDeferredLibraries(mainApp));
92 if (deferredLibraries.isEmpty) return;
93
94 Map<LibraryElement, Set<Element>> deferredElements =
95 new LinkedHashMap<LibraryElement, Set<Element>>();
96 Set<Element> eagerElements = new LinkedHashSet<Element>();
97
98 // Iterate through the local members of the main script. Create
99 // a root-set of elements that must be loaded eagerly
100 // (everything that is directly referred to from the main
101 // script, but not imported from a deferred library), as well as
102 // root-sets for deferred libraries.
103 mainApp.forEachLocalMember((Element e) {
104 for (Element dependency in allElementsResolvedFrom(e)) {
105 if (isExplicitlyDeferred(dependency)) {
106 Set<Element> deferredElementsFromLibrary =
107 deferredElements.putIfAbsent(
108 dependency.getLibrary(),
109 () => new LinkedHashSet<Element>());
110 deferredElementsFromLibrary.add(dependency);
111 } else if (mainApp != dependency.getLibrary()) {
ngeoffray 2013/03/07 11:21:14 Nitpicking, but I would reverse the operators here
ahe 2013/03/11 12:28:01 Done.
112 eagerElements.add(dependency);
113 }
114 }
115 });
116
117 // Also add "global" dependencies to the eager root-set. These
118 // are things that the backend need but cannot associate with a
119 // particular element, for example, startRootIsolate. This set
120 // also contains elements for which we lack precise information.
121 eagerElements.addAll(compiler.globalDependencies.otherDependencies);
122
123 addTransitiveClosureTo(eagerElements);
124
125 for (Set<Element> e in deferredElements.values) {
126 addTransitiveClosureTo(e);
127 e.removeAll(eagerElements);
128 for (Element element in e) {
129 allDeferredElements.add(element);
130 }
131 }
132
133 // TODO(ahe): The following code has no effect yet. I'm
134 // including it as a comment for how to extend this to support
135 // multiple deferred files.
136 Map<Element, List<LibraryElement>> reverseMap =
137 new LinkedHashMap<Element, List<LibraryElement>>();
138
139 deferredElements.forEach((LibraryElement library, Set<Element> map) {
140 for (Element element in map) {
141 List<LibraryElement> libraries =
142 reverseMap.putIfAbsent(element, () => <LibraryElement>[]);
143 libraries.add(library);
144 }
145 });
146
147 // Now compute the output files based on the lists in reverseMap.
148 // TODO(ahe): Do that.
75 }); 149 });
76 } 150 }
77 151
152 /// Returns all elements in the tree map of [element], but not the
153 /// transitive closure.
154 Set<Element> allElementsResolvedFrom(Element element) {
155 element = element.implementation;
156 Set<Element> result = new LinkedHashSet<Element>();
157 if (element.isGenerativeConstructor()) {
158 element = element.getEnclosingClass();
ngeoffray 2013/03/07 11:21:14 This looks magic. Is it to get the fields? Please
ahe 2013/03/11 12:28:01 I've added a comment.
159 }
160 if (element.isClass()) {
161 ClassElement cls = element;
162 cls.forEachLocalMember((Element e) {
163 result.addAll(DependencyCollector.collect(e, compiler));
164 });
165 for (var type in cls.allSupertypes) {
166 result.add(type.element);
167 }
168 result.add(cls);
169 } else if (Elements.isStaticOrTopLevel(element)) {
170 result.addAll(DependencyCollector.collect(element, compiler));
171 }
ngeoffray 2013/03/07 11:21:14 Why can't you end up with a member here? Should yo
ahe 2013/03/11 12:28:01 I can end up with a member, but that is not releva
172 return result;
173 }
174
175 void addTransitiveClosureTo(Set<Element> elements) {
176 Set<Element> workSet = new LinkedHashSet.from(elements);
177 Set<Element> closure = new LinkedHashSet<Element>();
178 while (!workSet.isEmpty) {
179 Element current = workSet.first;
180 workSet.remove(current);
181 if (closure.contains(current)) continue;
182 workSet.addAll(allElementsResolvedFrom(current));
183 closure.add(current);
184 }
185 elements.addAll(closure);
186 }
187
78 Link<LibraryElement> findDeferredLibraries(LibraryElement library) { 188 Link<LibraryElement> findDeferredLibraries(LibraryElement library) {
79 Link<LibraryElement> link = const Link<LibraryElement>(); 189 Link<LibraryElement> link = const Link<LibraryElement>();
80 for (LibraryTag tag in library.tags) { 190 for (LibraryTag tag in library.tags) {
81 Link<MetadataAnnotation> metadata = tag.metadata; 191 Link<MetadataAnnotation> metadata = tag.metadata;
82 if (metadata == null) continue; 192 if (metadata == null) continue;
83 for (MetadataAnnotation metadata in tag.metadata) { 193 for (MetadataAnnotation metadata in tag.metadata) {
84 metadata.ensureResolved(compiler); 194 metadata.ensureResolved(compiler);
85 Element element = metadata.value.computeType(compiler).element; 195 Element element = metadata.value.computeType(compiler).element;
86 if (element == deferredLibraryClass) { 196 if (element == deferredLibraryClass) {
87 ConstructedConstant value = metadata.value; 197 ConstructedConstant value = metadata.value;
88 StringConstant nameField = value.fields[0]; 198 StringConstant nameField = value.fields[0];
89 SourceString expectedName = nameField.toDartString().source; 199 SourceString expectedName = nameField.toDartString().source;
90 LibraryElement deferredLibrary = library.getLibraryFromTag(tag); 200 LibraryElement deferredLibrary = library.getLibraryFromTag(tag);
91 link = link.prepend(deferredLibrary); 201 link = link.prepend(deferredLibrary);
92 SourceString actualName = 202 SourceString actualName =
93 new SourceString(deferredLibrary.getLibraryOrScriptName()); 203 new SourceString(deferredLibrary.getLibraryOrScriptName());
94 if (expectedName != actualName) { 204 if (expectedName != actualName) {
95 compiler.reportErrorCode( 205 compiler.reportErrorCode(
96 metadata, 206 metadata,
97 MessageKind.DEFERRED_LIBRARY_NAME_MISMATCH, 207 MessageKind.DEFERRED_LIBRARY_NAME_MISMATCH,
98 { 'expectedName': expectedName.slowToString(), 208 { 'expectedName': expectedName.slowToString(),
99 'actualName': actualName.slowToString()}); 209 'actualName': actualName.slowToString()});
100 } 210 }
101 } 211 }
102 } 212 }
103 } 213 }
104 return link; 214 return link;
105 } 215 }
106 } 216 }
217
218 class DependencyCollector extends Visitor {
219 final Set<Element> dependencies = new LinkedHashSet<Element>();
220 final TreeElements elements;
221 final Compiler compiler;
222
223 DependencyCollector(this.elements, this.compiler);
224
225 visitNode(Node node) {
226 Element dependency = elements[node];
227 if (dependency != null) {
228 TreeElements elements =
229 compiler.enqueuer.resolution.getCachedElements(dependency);
230 if (elements != null) {
231 dependencies.add(elements.currentElement);
232 }
233 }
234 node.visitChildren(this);
235 }
236
237 static Set<Element> collect(Element element, Compiler compiler) {
238 TreeElements elements =
239 compiler.enqueuer.resolution.getCachedElements(element);
240 if (elements == null) return new LinkedHashSet<Element>();
241 Node node = element.parseNode(compiler);
242 var collector = new DependencyCollector(elements, compiler);
243 node.accept(collector);
244 collector.dependencies.addAll(elements.otherDependencies);
245 return collector.dependencies;
246 }
247 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698