blob: c623bd824bb34c53c0a0b03c53419d2257f93bdf [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library deferred_load;
import 'dart:uri';
import 'dart2jslib.dart'
show Compiler,
CompilerTask,
ConstructedConstant,
MessageKind,
SourceString,
StringConstant;
import 'elements/elements.dart'
show ClassElement,
Element,
LibraryElement,
MetadataAnnotation;
import 'util/util.dart'
show Link;
import 'tree/tree.dart'
show LibraryTag;
class DeferredLoadTask extends CompilerTask {
final Set<LibraryElement> deferredLibraries = new Set<LibraryElement>();
ClassElement cachedDeferredLibraryClass;
DeferredLoadTask(Compiler compiler) : super(compiler);
String get name => 'Lazy';
/// DeferredLibrary from dart:async
ClassElement get deferredLibraryClass {
if (cachedDeferredLibraryClass == null) {
cachedDeferredLibraryClass = findDeferredLibraryClass();
}
return cachedDeferredLibraryClass;
}
ClassElement findDeferredLibraryClass() {
var uri = new Uri.fromComponents(scheme: 'dart', path: 'async');
LibraryElement asyncLibrary =
compiler.libraryLoader.loadLibrary(uri, null, uri);
var element = asyncLibrary.find(const SourceString('DeferredLibrary'));
if (element == null) {
compiler.internalErrorOnElement(
asyncLibrary,
'dart:async library does not contain required class: '
'DeferredLibrary');
}
return element;
}
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".
return deferredLibraries.contains(element.getLibrary());
}
void registerMainApp(LibraryElement mainApp) {
if (mainApp == null) return;
measureElement(mainApp, () {
deferredLibraries.addAll(findDeferredLibraries(mainApp));
});
}
Link<LibraryElement> findDeferredLibraries(LibraryElement library) {
Link<LibraryElement> link = const Link<LibraryElement>();
for (LibraryTag tag in library.tags) {
Link<MetadataAnnotation> metadata = tag.metadata;
if (metadata == null) continue;
for (MetadataAnnotation metadata in tag.metadata) {
metadata.ensureResolved(compiler);
Element element = metadata.value.computeType(compiler).element;
if (element == deferredLibraryClass) {
ConstructedConstant value = metadata.value;
StringConstant nameField = value.fields[0];
SourceString expectedName = nameField.toDartString().source;
LibraryElement deferredLibrary = library.getLibraryFromTag(tag);
link = link.prepend(deferredLibrary);
SourceString actualName =
new SourceString(deferredLibrary.getLibraryOrScriptName());
if (expectedName != actualName) {
compiler.reportErrorCode(
metadata,
MessageKind.DEFERRED_LIBRARY_NAME_MISMATCH,
{ 'expectedName': expectedName.slowToString(),
'actualName': actualName.slowToString()});
}
}
}
}
return link;
}
}