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

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

Powered by Google App Engine
This is Rietveld 408576698