blob: 87a90be9da23170547401e37fd11c7476ff7126a [file] [log] [blame]
// Copyright (c) 2014, 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 kernel.deferred_load_data;
import 'package:kernel/ast.dart' as ir;
import '../common_elements.dart';
import '../compiler.dart' show Compiler;
import '../constants/values.dart';
import '../deferred_load.dart';
import '../elements/entities.dart';
import '../ir/util.dart';
import 'element_map.dart';
class KernelDeferredLoadTask extends DeferredLoadTask {
KernelToElementMap _elementMap;
Map<ir.Library, Set<ir.NamedNode>> _additionalExportsSets =
<ir.Library, Set<ir.NamedNode>>{};
KernelDeferredLoadTask(Compiler compiler, this._elementMap) : super(compiler);
Iterable<ImportEntity> _findImportsTo(ir.NamedNode node, String nodeName,
ir.Library enclosingLibrary, LibraryEntity library) {
return measureSubtask('find-imports', () {
List<ImportEntity> imports = [];
ir.Library source = _elementMap.getLibraryNode(library);
if (!source.dependencies.any((d) => d.isDeferred)) return const [];
for (ir.LibraryDependency dependency in source.dependencies) {
if (dependency.isExport) continue;
if (!_isVisible(dependency.combinators, nodeName)) continue;
if (enclosingLibrary == dependency.targetLibrary ||
additionalExports(dependency.targetLibrary).contains(node)) {
imports.add(_elementMap.getImport(dependency));
}
}
return imports;
});
}
@override
Iterable<ImportEntity> classImportsTo(
ClassEntity element, LibraryEntity library) {
ir.Class node = _elementMap.getClassNode(element);
return _findImportsTo(node, node.name, node.enclosingLibrary, library);
}
@override
Iterable<ImportEntity> typedefImportsTo(
TypedefEntity element, LibraryEntity library) {
ir.Typedef node = _elementMap.getTypedefNode(element);
return _findImportsTo(node, node.name, node.enclosingLibrary, library);
}
@override
Iterable<ImportEntity> memberImportsTo(
Entity element, LibraryEntity library) {
ir.Member node = _elementMap.getMemberNode(element);
return _findImportsTo(
node is ir.Constructor ? node.enclosingClass : node,
node is ir.Constructor ? node.enclosingClass.name : node.name.name,
node.enclosingLibrary,
library);
}
@override
void checkForDeferredErrorCases(LibraryEntity library) {
// Nothing to do. The FE checks for error cases upfront.
}
@override
void collectConstantsFromMetadata(
Entity element, Set<ConstantValue> constants) {
// Nothing to do. Kernel-pipeline doesn't support mirrors, so we don't need
// to track any constants from meta-data.
}
@override
void collectConstantsInBody(MemberEntity element, Dependencies dependencies) {
ir.Member node = _elementMap.getMemberNode(element);
// Fetch the internal node in order to skip annotations on the member.
// TODO(sigmund): replace this pattern when the kernel-ast provides a better
// way to skip annotations (issue 31565).
var visitor = new ConstantCollector(_elementMap, dependencies);
if (node is ir.Field) {
node.initializer?.accept(visitor);
return;
}
if (node is ir.Constructor) {
node.initializers.forEach((i) => i.accept(visitor));
}
node.function?.accept(visitor);
}
Set<ir.NamedNode> additionalExports(ir.Library library) {
return _additionalExportsSets[library] ??= new Set<ir.NamedNode>.from(
library.additionalExports.map((ir.Reference ref) => ref.node));
}
@override
void cleanup() {
_additionalExportsSets = null;
}
}
/// Returns whether [name] would be visible according to the given list of
/// show/hide [combinators].
bool _isVisible(List<ir.Combinator> combinators, String name) {
for (var c in combinators) {
if (c.isShow && !c.names.contains(name)) return false;
if (c.isHide && c.names.contains(name)) return false;
}
return true;
}
class ConstantCollector extends ir.RecursiveVisitor {
final KernelToElementMap elementMap;
final Dependencies dependencies;
ConstantCollector(this.elementMap, this.dependencies);
CommonElements get commonElements => elementMap.commonElements;
void add(ir.Expression node, {bool required: true}) {
ConstantValue constant =
elementMap.getConstantValue(node, requireConstant: required);
if (constant != null) {
dependencies.addConstant(
constant, elementMap.getImport(getDeferredImport(node)));
}
}
@override
void visitIntLiteral(ir.IntLiteral literal) {}
@override
void visitDoubleLiteral(ir.DoubleLiteral literal) {}
@override
void visitBoolLiteral(ir.BoolLiteral literal) {}
@override
void visitStringLiteral(ir.StringLiteral literal) {}
@override
void visitSymbolLiteral(ir.SymbolLiteral literal) => add(literal);
@override
void visitNullLiteral(ir.NullLiteral literal) {}
@override
void visitListLiteral(ir.ListLiteral literal) {
if (literal.isConst) {
add(literal);
} else {
super.visitListLiteral(literal);
}
}
@override
void visitSetLiteral(ir.SetLiteral literal) {
if (literal.isConst) {
add(literal);
} else {
super.visitSetLiteral(literal);
}
}
@override
void visitMapLiteral(ir.MapLiteral literal) {
if (literal.isConst) {
add(literal);
} else {
super.visitMapLiteral(literal);
}
}
@override
void visitConstructorInvocation(ir.ConstructorInvocation node) {
if (node.isConst) {
add(node);
} else {
super.visitConstructorInvocation(node);
}
}
@override
void visitTypeParameter(ir.TypeParameter node) {
// We avoid visiting metadata on the type parameter declaration. The bound
// cannot hold constants so we skip that as well.
}
@override
void visitVariableDeclaration(ir.VariableDeclaration node) {
// We avoid visiting metadata on the parameter declaration by only visiting
// the initializer. The type cannot hold constants so can kan skip that
// as well.
node.initializer?.accept(this);
}
@override
void visitTypeLiteral(ir.TypeLiteral node) {
if (node.type is! ir.TypeParameterType) add(node);
}
@override
void visitInstantiation(ir.Instantiation node) {
// TODO(johnniwinther): The CFE should mark constant instantiations as
// constant.
add(node, required: false);
super.visitInstantiation(node);
}
@override
void visitConstantExpression(ir.ConstantExpression node) {
add(node);
}
}