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

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

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library deferred_load;
6
7 import 'constants/expressions.dart';
8 import 'constants/values.dart' show
9 ConstantValue,
10 ConstructedConstantValue,
11 DeferredConstantValue,
12 StringConstantValue;
13
14 import 'dart2jslib.dart' show
15 Backend,
16 Compiler,
17 CompilerTask,
18 invariant,
19 MessageKind;
20
21 import 'dart_backend/dart_backend.dart' show
22 DartBackend;
23
24 import 'js_backend/js_backend.dart' show
25 JavaScriptBackend;
26
27 import 'elements/elements.dart' show
28 AstElement,
29 ClassElement,
30 Element,
31 ElementKind,
32 Elements,
33 FunctionElement,
34 LibraryElement,
35 MetadataAnnotation,
36 PrefixElement,
37 ScopeContainerElement,
38 TypedefElement,
39 VoidElement;
40
41 import 'util/util.dart' show
42 Link, makeUnique;
43
44 import 'util/setlet.dart' show
45 Setlet;
46
47 import 'tree/tree.dart' show
48 Import,
49 LibraryTag,
50 LibraryDependency,
51 LiteralDartString,
52 LiteralString,
53 NewExpression,
54 Node;
55
56 import 'tree/tree.dart' as ast;
57
58 import 'resolution/resolution.dart' show
59 AnalyzableElementX,
60 TreeElements;
61
62 /// A "hunk" of the program that will be loaded whenever one of its [imports]
63 /// are loaded.
64 ///
65 /// Elements that are only used in one deferred import, is in an OutputUnit with
66 /// the deferred import as single element in the [imports] set.
67 ///
68 /// Whenever a deferred Element is shared between several deferred imports it is
69 /// in an output unit with those imports in the [imports] Set.
70 ///
71 /// OutputUnits are equal if their [imports] are equal.
72 class OutputUnit {
73 /// The deferred imports that will load this output unit when one of them is
74 /// loaded.
75 final Setlet<Import> imports = new Setlet<Import>();
76
77 /// A unique name representing this [OutputUnit].
78 /// Based on the set of [imports].
79 String name;
80
81 String toString() => "OutputUnit($name)";
82
83 bool operator==(OutputUnit other) {
84 return imports.length == other.imports.length &&
85 imports.containsAll(other.imports);
86 }
87
88 int get hashCode {
89 int sum = 0;
90 for (Import import in imports) {
91 sum = (sum + import.hashCode) & 0x3FFFFFFF; // Stay in 30 bit range.
92 }
93 return sum;
94 }
95 }
96
97 /// For each deferred import, find elements and constants to be loaded when that
98 /// import is loaded. Elements that are used by several deferred imports are in
99 /// shared OutputUnits.
100 class DeferredLoadTask extends CompilerTask {
101 /// The name of this task.
102 String get name => 'Deferred Loading';
103
104 /// DeferredLibrary from dart:async
105 ClassElement get deferredLibraryClass => compiler.deferredLibraryClass;
106
107 /// A synthetic [Import] representing the loading of the main
108 /// program.
109 final Import _fakeMainImport = new Import(null, new LiteralString(null,
110 new LiteralDartString("main")), null, null, null);
111
112 /// The OutputUnit that will be loaded when the program starts.
113 final OutputUnit mainOutputUnit = new OutputUnit();
114
115 /// A set containing (eventually) all output units that will result from the
116 /// program.
117 final Set<OutputUnit> allOutputUnits = new Set<OutputUnit>();
118
119 /// Will be `true` if the program contains deferred libraries.
120 bool isProgramSplit = false;
121
122 /// A mapping from the name of a defer import to all the output units it
123 /// depends on in a list of lists to be loaded in the order they appear.
124 ///
125 /// For example {"lib1": [[lib1_lib2_lib3], [lib1_lib2, lib1_lib3],
126 /// [lib1]]} would mean that in order to load "lib1" first the hunk
127 /// lib1_lib2_lib2 should be loaded, then the hunks lib1_lib2 and lib1_lib3
128 /// can be loaded in parallel. And finally lib1 can be loaded.
129 final Map<String, List<OutputUnit>> hunksToLoad =
130 new Map<String, List<OutputUnit>>();
131 final Map<Import, String> importDeferName = new Map<Import, String>();
132
133 /// A mapping from elements and constants to their output unit. Query this via
134 /// [outputUnitForElement]
135 final Map<Element, OutputUnit> _elementToOutputUnit =
136 new Map<Element, OutputUnit>();
137
138 /// A mapping from constants to their output unit. Query this via
139 /// [outputUnitForConstant]
140 final Map<ConstantValue, OutputUnit> _constantToOutputUnit =
141 new Map<ConstantValue, OutputUnit>();
142
143 /// All the imports with a [DeferredLibrary] annotation, mapped to the
144 /// [LibraryElement] they import.
145 /// The main library is included in this set for convenience.
146 final Map<Import, LibraryElement> _allDeferredImports =
147 new Map<Import, LibraryElement>();
148
149 // For each deferred import we want to know exactly what elements have to
150 // be loaded.
151 Map<Import, Set<Element>> _importedDeferredBy = null;
152 Map<Import, Set<ConstantValue>> _constantsDeferredBy = null;
153
154 Set<Element> _mainElements = new Set<Element>();
155
156 DeferredLoadTask(Compiler compiler) : super(compiler) {
157 mainOutputUnit.imports.add(_fakeMainImport);
158 }
159
160 Backend get backend => compiler.backend;
161
162 /// Returns the [OutputUnit] where [element] belongs.
163 OutputUnit outputUnitForElement(Element element) {
164 if (!isProgramSplit) return mainOutputUnit;
165
166 element = element.implementation;
167 while (!_elementToOutputUnit.containsKey(element)) {
168 // TODO(21051): workaround: it looks like we output annotation constants
169 // for classes that we don't include in the output. This seems to happen
170 // when we have reflection but can see that some classes are not needed.
171 // We still add the annotation but don't run through it below (where we
172 // assign every element to its output unit).
173 if (element.enclosingElement == null) {
174 _elementToOutputUnit[element] = mainOutputUnit;
175 break;
176 }
177 element = element.enclosingElement.implementation;
178 }
179 return _elementToOutputUnit[element];
180 }
181
182 /// Returns the [OutputUnit] where [constant] belongs.
183 OutputUnit outputUnitForConstant(ConstantValue constant) {
184 if (!isProgramSplit) return mainOutputUnit;
185
186 return _constantToOutputUnit[constant];
187 }
188
189 bool isDeferred(Element element) {
190 return outputUnitForElement(element) != mainOutputUnit;
191 }
192
193 /// Returns true if e1 and e2 are in the same output unit.
194 bool inSameOutputUnit(Element e1, Element e2) {
195 return outputUnitForElement(e1) == outputUnitForElement(e2);
196 }
197
198 void registerConstantDeferredUse(DeferredConstantValue constant,
199 PrefixElement prefix) {
200 OutputUnit outputUnit = new OutputUnit();
201 outputUnit.imports.add(prefix.deferredImport);
202 _constantToOutputUnit[constant] = outputUnit;
203 }
204
205 /// Answers whether [element] is explicitly deferred when referred to from
206 /// [library].
207 bool _isExplicitlyDeferred(Element element, LibraryElement library) {
208 Link<Import> imports = _getImports(element, library);
209 // If the element is not imported explicitly, it is implicitly imported
210 // not deferred.
211 if (imports.isEmpty) return false;
212 // An element could potentially be loaded by several imports. If all of them
213 // is explicitly deferred, we say the element is explicitly deferred.
214 // TODO(sigurdm): We might want to give a warning if the imports do not
215 // agree.
216 return imports.every((Import import) => import.isDeferred);
217 }
218
219 /// Returns a [Link] of every [Import] that imports [element] into [library].
220 Link<Import> _getImports(Element element, LibraryElement library) {
221 if (element.isClassMember) {
222 element = element.enclosingClass;
223 }
224 if (element.isAccessor) {
225 element = (element as FunctionElement).abstractField;
226 }
227 return library.getImportsFor(element);
228 }
229
230 /// Finds all elements and constants that [element] depends directly on.
231 /// (not the transitive closure.)
232 ///
233 /// Adds the results to [elements] and [constants].
234 void _collectAllElementsAndConstantsResolvedFrom(
235 Element element,
236 Set<Element> elements,
237 Set<ConstantValue> constants,
238 isMirrorUsage) {
239
240 /// Recursively add the constant and its dependencies to [constants].
241 void addConstants(ConstantValue constant) {
242 if (constants.contains(constant)) return;
243 constants.add(constant);
244 if (constant is ConstructedConstantValue) {
245 elements.add(constant.type.element);
246 }
247 constant.getDependencies().forEach(addConstants);
248 }
249
250 /// Collects all direct dependencies of [element].
251 ///
252 /// The collected dependent elements and constants are are added to
253 /// [elements] and [constants] respectively.
254 void collectDependencies(Element element) {
255 // TODO(johnniwinther): Remove this when [AbstractFieldElement] has been
256 // removed.
257 if (element is! AstElement) return;
258 AstElement astElement = element;
259
260 // TODO(sigurdm): We want to be more specific about this - need a better
261 // way to query "liveness".
262 if (astElement is! TypedefElement &&
263 !compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
264 return;
265 }
266
267 TreeElements treeElements = astElement.resolvedAst.elements;
268
269 assert(treeElements != null);
270
271 for (Element dependency in treeElements.allElements) {
272 if (dependency.isLocal && !dependency.isFunction) continue;
273 if (dependency.isErroneous) continue;
274 if (dependency.isTypeVariable) continue;
275
276 elements.add(dependency);
277 }
278 treeElements.forEachConstantNode((Node node, _) {
279 // Explicitly depend on the backend constants.
280 addConstants(
281 backend.constants.getConstantForNode(node, treeElements).value);
282 });
283 elements.addAll(treeElements.otherDependencies);
284 }
285
286 // TODO(sigurdm): How is metadata on a patch-class handled?
287 for (MetadataAnnotation metadata in element.metadata) {
288 ConstantExpression constant =
289 backend.constants.getConstantForMetadata(metadata);
290 if (constant != null) {
291 addConstants(constant.value);
292 }
293 }
294 if (element.isClass) {
295 // If we see a class, add everything its live instance members refer
296 // to. Static members are not relevant, unless we are processing
297 // extra dependencies due to mirrors.
298 void addLiveInstanceMember(Element element) {
299 if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
300 if (!isMirrorUsage && !element.isInstanceMember) return;
301 collectDependencies(element.implementation);
302 }
303 ClassElement cls = element.declaration;
304 cls.forEachLocalMember(addLiveInstanceMember);
305 if (cls.implementation != cls) {
306 // TODO(ahe): Why doesn't ClassElement.forEachLocalMember do this?
307 cls.implementation.forEachLocalMember(addLiveInstanceMember);
308 }
309 for (var type in cls.implementation.allSupertypes) {
310 elements.add(type.element.implementation);
311 }
312 elements.add(cls.implementation);
313 } else if (Elements.isStaticOrTopLevel(element) ||
314 element.isConstructor) {
315 collectDependencies(element);
316 }
317 if (element.isGenerativeConstructor) {
318 // When instantiating a class, we record a reference to the
319 // constructor, not the class itself. We must add all the
320 // instance members of the constructor's class.
321 ClassElement implementation =
322 element.enclosingClass.implementation;
323 _collectAllElementsAndConstantsResolvedFrom(
324 implementation, elements, constants, isMirrorUsage);
325 }
326
327 // Other elements, in particular instance members, are ignored as
328 // they are processed as part of the class.
329 }
330
331 /// Returns the transitive closure of all libraries that are imported
332 /// from root without DeferredLibrary annotations.
333 Set<LibraryElement> _nonDeferredReachableLibraries(LibraryElement root) {
334 Set<LibraryElement> result = new Set<LibraryElement>();
335
336 void traverseLibrary(LibraryElement library) {
337 if (result.contains(library)) return;
338 result.add(library);
339
340 iterateTags(LibraryElement library) {
341 // TODO(sigurdm): Make helper getLibraryDependencyTags when tags is
342 // changed to be a List instead of a Link.
343 for (LibraryTag tag in library.tags) {
344 if (tag is! LibraryDependency) continue;
345 LibraryDependency libraryDependency = tag;
346 if (!(libraryDependency is Import && libraryDependency.isDeferred)) {
347 LibraryElement importedLibrary = library.getLibraryFromTag(tag);
348 traverseLibrary(importedLibrary);
349 }
350 }
351 }
352
353 iterateTags(library);
354 if (library.isPatched) {
355 iterateTags(library.implementation);
356 }
357 }
358 traverseLibrary(root);
359 result.add(compiler.coreLibrary);
360 return result;
361 }
362
363 /// Recursively traverses the graph of dependencies from [element], mapping
364 /// deferred imports to each dependency it needs in the sets
365 /// [_importedDeferredBy] and [_constantsDeferredBy].
366 void _mapDependencies(Element element, Import import,
367 {isMirrorUsage: false}) {
368 Set<Element> elements = _importedDeferredBy.putIfAbsent(import,
369 () => new Set<Element>());
370 Set<ConstantValue> constants = _constantsDeferredBy.putIfAbsent(import,
371 () => new Set<ConstantValue>());
372
373 // Only process elements once, unless we are doing dependencies due to
374 // mirrors, which are added in additional traversals.
375 if (!isMirrorUsage && elements.contains(element)) return;
376 // Anything used directly by main will be loaded from the start
377 // We do not need to traverse it again.
378 if (import != _fakeMainImport && _mainElements.contains(element)) return;
379
380 // Here we modify [_importedDeferredBy].
381 elements.add(element);
382
383 Set<Element> dependentElements = new Set<Element>();
384
385 // This call can modify [_importedDeferredBy] and [_constantsDeferredBy].
386 _collectAllElementsAndConstantsResolvedFrom(
387 element, dependentElements, constants, isMirrorUsage);
388
389 LibraryElement library = element.library;
390 for (Element dependency in dependentElements) {
391 if (_isExplicitlyDeferred(dependency, library)) {
392 for (Import deferredImport in _getImports(dependency, library)) {
393 _mapDependencies(dependency, deferredImport);
394 };
395 } else {
396 _mapDependencies(dependency, import);
397 }
398 }
399 }
400
401 /// Adds extra dependencies coming from mirror usage.
402 ///
403 /// The elements are added with [_mapDependencies].
404 void _addMirrorElements() {
405 void mapDependenciesIfResolved(Element element, Import deferredImport) {
406 // If an element is the target of a MirrorsUsed annotation but never used
407 // It will not be resolved, and we should not call isNeededForReflection.
408 // TODO(sigurdm): Unresolved elements should just answer false when
409 // asked isNeededForReflection. Instead an internal error is triggered.
410 // So we have to filter them out here.
411 if (element is AnalyzableElementX && !element.hasTreeElements) return;
412 if (compiler.backend.isAccessibleByReflection(element)) {
413 _mapDependencies(element, deferredImport, isMirrorUsage: true);
414 }
415 }
416
417 // For each deferred import we analyze all elements reachable from the
418 // imported library through non-deferred imports.
419 handleLibrary(LibraryElement library, Import deferredImport) {
420 library.implementation.forEachLocalMember((Element element) {
421 mapDependenciesIfResolved(element, deferredImport);
422 });
423
424 for (MetadataAnnotation metadata in library.metadata) {
425 ConstantExpression constant =
426 backend.constants.getConstantForMetadata(metadata);
427 if (constant != null) {
428 _mapDependencies(constant.value.computeType(compiler).element,
429 deferredImport);
430 }
431 }
432 for (LibraryTag tag in library.tags) {
433 for (MetadataAnnotation metadata in tag.metadata) {
434 ConstantExpression constant =
435 backend.constants.getConstantForMetadata(metadata);
436 if (constant != null) {
437 _mapDependencies(constant.value.computeType(compiler).element,
438 deferredImport);
439 }
440 }
441 }
442 }
443
444 for (Import deferredImport in _allDeferredImports.keys) {
445 LibraryElement deferredLibrary = _allDeferredImports[deferredImport];
446 for (LibraryElement library in
447 _nonDeferredReachableLibraries(deferredLibrary)) {
448 handleLibrary(library, deferredImport);
449 }
450 }
451 }
452
453 /// Computes a unique string for the name field for each outputUnit.
454 ///
455 /// Also sets up the [hunksToLoad] mapping.
456 void _assignNamesToOutputUnits(Set<OutputUnit> allOutputUnits) {
457 Set<String> usedImportNames = new Set<String>();
458
459 // Finds the first argument to the [DeferredLibrary] annotation
460 void computeImportDeferName(Import import) {
461 String result;
462 if (import == _fakeMainImport) {
463 result = "main";
464 } else if (import.isDeferred) {
465 result = import.prefix.toString();
466 } else {
467 Link<MetadataAnnotation> metadatas = import.metadata;
468 assert(metadatas != null);
469 for (MetadataAnnotation metadata in metadatas) {
470 metadata.ensureResolved(compiler);
471 Element element =
472 metadata.constant.value.computeType(compiler).element;
473 if (element == deferredLibraryClass) {
474 ConstructedConstantValue constant = metadata.constant.value;
475 StringConstantValue s = constant.fields[0];
476 result = s.primitiveValue.slowToString();
477 break;
478 }
479 }
480 }
481 assert(result != null);
482 importDeferName[import] = makeUnique(result, usedImportNames);;
483 }
484
485 int counter = 1;
486
487 for (Import import in _allDeferredImports.keys) {
488 computeImportDeferName(import);
489 }
490
491 for (OutputUnit outputUnit in allOutputUnits) {
492 if (outputUnit == mainOutputUnit) {
493 outputUnit.name = "main";
494 } else {
495 outputUnit.name = "$counter";
496 ++counter;
497 }
498 }
499
500 List sortedOutputUnits = new List.from(allOutputUnits);
501 // Sort the output units in descending order of the number of imports they
502 // include.
503
504 // The loading of the output units mut be ordered because a superclass needs
505 // to be initialized before its subclass.
506 // But a class can only depend on another class in an output unit shared by
507 // a strict superset of the imports:
508 // By contradiction: Assume a class C in output unit shared by imports in
509 // the set S1 = (lib1,.., lib_n) depends on a class D in an output unit
510 // shared by S2 such that S2 not a superset of S1. Let lib_s be a library in
511 // S1 not in S2. lib_s must depend on C, and then in turn on D therefore D
512 // is not in the right output unit.
513 sortedOutputUnits.sort((a, b) => b.imports.length - a.imports.length);
514
515 // For each deferred import we find out which outputUnits to load.
516 for (Import import in _allDeferredImports.keys) {
517 if (import == _fakeMainImport) continue;
518 hunksToLoad[importDeferName[import]] = new List<OutputUnit>();
519 for (OutputUnit outputUnit in sortedOutputUnits) {
520 if (outputUnit == mainOutputUnit) continue;
521 if (outputUnit.imports.contains(import)) {
522 hunksToLoad[importDeferName[import]].add(outputUnit);
523 }
524 }
525 }
526 }
527
528 void onResolutionComplete(FunctionElement main) {
529 if (!isProgramSplit) {
530 allOutputUnits.add(mainOutputUnit);
531 return;
532 }
533 if (main == null) return;
534 LibraryElement mainLibrary = main.library;
535 _importedDeferredBy = new Map<Import, Set<Element>>();
536 _constantsDeferredBy = new Map<Import, Set<ConstantValue>>();
537 _importedDeferredBy[_fakeMainImport] = _mainElements;
538
539 measureElement(mainLibrary, () {
540
541 // Starting from main, traverse the program and find all dependencies.
542 _mapDependencies(compiler.mainFunction, _fakeMainImport);
543
544 // Also add "global" dependencies to the main OutputUnit. These are
545 // things that the backend need but cannot associate with a particular
546 // element, for example, startRootIsolate. This set also contains
547 // elements for which we lack precise information.
548 for (Element element in compiler.globalDependencies.otherDependencies) {
549 _mapDependencies(element, _fakeMainImport);
550 }
551
552 // Now check to see if we have to add more elements due to mirrors.
553 if (compiler.mirrorsLibrary != null) {
554 _addMirrorElements();
555 }
556
557 // Build the OutputUnits using these two maps.
558 Map<Element, OutputUnit> elementToOutputUnitBuilder =
559 new Map<Element, OutputUnit>();
560 Map<ConstantValue, OutputUnit> constantToOutputUnitBuilder =
561 new Map<ConstantValue, OutputUnit>();
562
563 // Reverse the mappings. For each element record an OutputUnit collecting
564 // all deferred imports mapped to this element. Same for constants.
565 for (Import import in _importedDeferredBy.keys) {
566 for (Element element in _importedDeferredBy[import]) {
567 // Only one file should be loaded when the program starts, so make
568 // sure that only one OutputUnit is created for [fakeMainImport].
569 if (import == _fakeMainImport) {
570 elementToOutputUnitBuilder[element] = mainOutputUnit;
571 } else {
572 elementToOutputUnitBuilder
573 .putIfAbsent(element, () => new OutputUnit())
574 .imports.add(import);
575 }
576 }
577 for (ConstantValue constant in _constantsDeferredBy[import]) {
578 // Only one file should be loaded when the program starts, so make
579 // sure that only one OutputUnit is created for [fakeMainImport].
580 if (import == _fakeMainImport) {
581 constantToOutputUnitBuilder[constant] = mainOutputUnit;
582 } else {
583 constantToOutputUnitBuilder
584 .putIfAbsent(constant, () => new OutputUnit())
585 .imports.add(import);
586 }
587 }
588 }
589
590 // Release maps;
591 _importedDeferredBy = null;
592 _constantsDeferredBy = null;
593
594 // Find all the output units elements/constants have been mapped to, and
595 // canonicalize them.
596 elementToOutputUnitBuilder.forEach(
597 (Element element, OutputUnit outputUnit) {
598 OutputUnit representative = allOutputUnits.lookup(outputUnit);
599 if (representative == null) {
600 representative = outputUnit;
601 allOutputUnits.add(representative);
602 }
603 _elementToOutputUnit[element] = representative;
604 });
605 constantToOutputUnitBuilder.forEach(
606 (ConstantValue constant, OutputUnit outputUnit) {
607 OutputUnit representative = allOutputUnits.lookup(outputUnit);
608 if (representative == null) {
609 representative = outputUnit;
610 allOutputUnits.add(representative);
611 }
612 _constantToOutputUnit[constant] = representative;
613 });
614
615 // Generate a unique name for each OutputUnit.
616 _assignNamesToOutputUnits(allOutputUnits);
617 });
618 }
619
620 void ensureMetadataResolved(Compiler compiler) {
621 if (compiler.mainApp == null) return;
622 _allDeferredImports[_fakeMainImport] = compiler.mainApp;
623 var lastDeferred;
624 // When detecting duplicate prefixes of deferred libraries there are 4
625 // cases of duplicate prefixes:
626 // 1.
627 // import "lib.dart" deferred as a;
628 // import "lib2.dart" deferred as a;
629 // 2.
630 // import "lib.dart" deferred as a;
631 // import "lib2.dart" as a;
632 // 3.
633 // import "lib.dart" as a;
634 // import "lib2.dart" deferred as a;
635 // 4.
636 // import "lib.dart" as a;
637 // import "lib2.dart" as a;
638 // We must be able to signal error for case 1, 2, 3, but accept case 4.
639
640 // The prefixes that have been used by any imports in this library.
641 Setlet<String> usedPrefixes = new Setlet<String>();
642 // The last deferred import we saw with a given prefix (if any).
643 Map<String, Import> prefixDeferredImport = new Map<String, Import>();
644 for (LibraryElement library in compiler.libraryLoader.libraries) {
645 compiler.withCurrentElement(library, () {
646 prefixDeferredImport.clear();
647 usedPrefixes.clear();
648 // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
649 // instead of a Link.
650 for (LibraryTag tag in library.tags) {
651 if (tag is! Import) continue;
652 Import import = tag;
653
654 /// Give an error if the old annotation-based syntax has been used.
655 Link<MetadataAnnotation> metadataList = import.metadata;
656 if (metadataList != null) {
657 for (MetadataAnnotation metadata in metadataList) {
658 metadata.ensureResolved(compiler);
659 Element element =
660 metadata.constant.value.computeType(compiler).element;
661 if (element == deferredLibraryClass) {
662 compiler.reportFatalError(
663 import, MessageKind.DEFERRED_OLD_SYNTAX);
664 }
665 }
666 }
667
668 String prefix = (import.prefix != null)
669 ? import.prefix.toString()
670 : null;
671 // The last import we saw with the same prefix.
672 Import previousDeferredImport = prefixDeferredImport[prefix];
673 if (import.isDeferred) {
674 _allDeferredImports[import] = library.getLibraryFromTag(import);
675
676 if (prefix == null) {
677 compiler.reportError(import,
678 MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
679 } else {
680 prefixDeferredImport[prefix] = import;
681 }
682 isProgramSplit = true;
683 lastDeferred = import;
684 }
685 if (prefix != null) {
686 if (previousDeferredImport != null ||
687 (import.isDeferred && usedPrefixes.contains(prefix))) {
688 Import failingImport = (previousDeferredImport != null)
689 ? previousDeferredImport
690 : import;
691 compiler.reportError(failingImport.prefix,
692 MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
693 }
694 usedPrefixes.add(prefix);
695 }
696 }
697 });
698 }
699 Backend backend = compiler.backend;
700 if (isProgramSplit && backend is JavaScriptBackend) {
701 backend.registerCheckDeferredIsLoaded(compiler.globalDependencies);
702 }
703 if (isProgramSplit && backend is DartBackend) {
704 // TODO(sigurdm): Implement deferred loading for dart2dart.
705 compiler.reportWarning(
706 lastDeferred,
707 MessageKind.DEFERRED_LIBRARY_DART_2_DART);
708 isProgramSplit = false;
709 }
710 }
711
712 /// If [send] is a static send with a deferred element, returns the
713 /// [PrefixElement] that the first prefix of the send resolves to.
714 /// Otherwise returns null.
715 ///
716 /// Precondition: send must be static.
717 ///
718 /// Example:
719 ///
720 /// import "a.dart" deferred as a;
721 ///
722 /// main() {
723 /// print(a.loadLibrary.toString());
724 /// a.loadLibrary().then((_) {
725 /// a.run();
726 /// a.foo.method();
727 /// });
728 /// }
729 ///
730 /// Returns null for a.loadLibrary() (the special
731 /// function loadLibrary is not deferred). And returns the PrefixElement for
732 /// a.run() and a.foo.
733 /// a.loadLibrary.toString() and a.foo.method() are dynamic sends - and
734 /// this functions should not be called on them.
735 PrefixElement deferredPrefixElement(ast.Send send, TreeElements elements) {
736 Element element = elements[send];
737 // The DeferredLoaderGetter is not deferred, therefore we do not return the
738 // prefix.
739 if (element != null && element.isDeferredLoaderGetter) return null;
740
741 ast.Node firstNode(ast.Node node) {
742 if (node is! ast.Send) {
743 return node;
744 } else {
745 ast.Send send = node;
746 ast.Node receiver = send.receiver;
747 ast.Node receiverFirst = firstNode(receiver);
748 if (receiverFirst != null) {
749 return receiverFirst;
750 } else {
751 return firstNode(send.selector);
752 }
753 }
754 }
755 ast.Node first = firstNode(send);
756 ast.Node identifier = first.asIdentifier();
757 if (identifier == null) return null;
758 Element maybePrefix = elements[identifier];
759 if (maybePrefix != null && maybePrefix.isPrefix) {
760 PrefixElement prefixElement = maybePrefix;
761 if (prefixElement.isDeferred) {
762 return prefixElement;
763 }
764 }
765 return null;
766 }
767 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698