23cde7f4b8
TEST=reformatting only Change-Id: I310e2568661e919a2c8354e01e19d18f7109f54c Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/399261 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
195 lines
5.4 KiB
Dart
195 lines
5.4 KiB
Dart
// Copyright (c) 2020, 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 vm.transformations.deferred_loading;
|
|
|
|
import 'package:kernel/ast.dart';
|
|
import 'package:kernel/core_types.dart' show CoreTypes;
|
|
import 'package:kernel/target/targets.dart' show Target;
|
|
|
|
import '../dominators.dart';
|
|
import '../metadata/loading_units.dart';
|
|
import 'pragma.dart';
|
|
|
|
class _LoadingUnitBuilder {
|
|
late int id;
|
|
final _LibraryVertex root;
|
|
final List<Library> members = <Library>[];
|
|
final List<_LoadingUnitBuilder> children = <_LoadingUnitBuilder>[];
|
|
|
|
_LoadingUnitBuilder(this.root);
|
|
|
|
_LoadingUnitBuilder? get parent => root.dominator?.loadingUnit;
|
|
int get parentId => parent == null ? 0 : parent!.id;
|
|
|
|
LoadingUnit asLoadingUnit() {
|
|
return new LoadingUnit(
|
|
id,
|
|
parentId,
|
|
members.map((l) => l.importUri.toString()).toList(),
|
|
);
|
|
}
|
|
|
|
String toString() =>
|
|
"_LoadingUnitBuilder(id=$id, parent=${parentId}, size=${members.length})";
|
|
}
|
|
|
|
class _LibraryVertex extends Vertex<_LibraryVertex> {
|
|
final Library library;
|
|
bool isLoadingRoot = true;
|
|
_LoadingUnitBuilder? loadingUnit;
|
|
_LibraryVertex(this.library);
|
|
|
|
String toString() => "_LibraryVertex(${library.importUri})";
|
|
}
|
|
|
|
class HasEntryPointVisitor extends RecursiveVisitor {
|
|
final PragmaAnnotationParser parser;
|
|
bool _hasEntryPoint = false;
|
|
|
|
HasEntryPointVisitor(this.parser);
|
|
|
|
visitAnnotations(List<Expression> annotations) {
|
|
for (var ann in annotations) {
|
|
ParsedPragma? pragma = parser.parsePragma(ann);
|
|
if (pragma is ParsedEntryPointPragma) {
|
|
_hasEntryPoint = true;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
visitClass(Class klass) {
|
|
visitAnnotations(klass.annotations);
|
|
klass.visitChildren(this);
|
|
}
|
|
|
|
@override
|
|
defaultMember(Member node) {
|
|
visitAnnotations(node.annotations);
|
|
}
|
|
|
|
bool hasEntryPoint(Library lib) {
|
|
_hasEntryPoint = false;
|
|
visitLibrary(lib);
|
|
return _hasEntryPoint;
|
|
}
|
|
}
|
|
|
|
List<LoadingUnit> computeLoadingUnits(
|
|
Component component,
|
|
HasEntryPointVisitor visitor,
|
|
) {
|
|
// 1. Build the dominator tree for the library import graph.
|
|
final map = <Library, _LibraryVertex>{};
|
|
for (final lib in component.libraries) {
|
|
map[lib] = new _LibraryVertex(lib);
|
|
}
|
|
for (final vertex in map.values) {
|
|
for (final dep in vertex.library.dependencies) {
|
|
final target = map[dep.targetLibrary]!;
|
|
vertex.successors.add(target);
|
|
}
|
|
}
|
|
final root = map[component.mainMethod!.enclosingLibrary]!;
|
|
|
|
// Fake imports from root library to every core library or library containing
|
|
// an entry point pragma so that they end up in the same loading unit
|
|
// attributed to the user's root library.
|
|
for (final vertex in map.values) {
|
|
if (vertex == root) {
|
|
continue;
|
|
}
|
|
if (vertex.library.importUri.isScheme("dart") ||
|
|
visitor.hasEntryPoint(vertex.library)) {
|
|
root.successors.add(vertex);
|
|
vertex.isLoadingRoot = false;
|
|
}
|
|
}
|
|
|
|
computeDominators(root);
|
|
|
|
// 2. Find loading unit roots.
|
|
for (var importer in map.values) {
|
|
if ((importer != root) && (importer.dominator == null)) {
|
|
continue; // Unreachable library.
|
|
}
|
|
for (var dep in importer.library.dependencies) {
|
|
if (dep.isDeferred) {
|
|
continue;
|
|
}
|
|
var importee = map[dep.targetLibrary]!;
|
|
if (importer.isDominatedBy(importee)) {
|
|
continue;
|
|
}
|
|
importee.isLoadingRoot = false;
|
|
}
|
|
}
|
|
assert(root.isLoadingRoot);
|
|
|
|
final List<_LoadingUnitBuilder> loadingUnits = <_LoadingUnitBuilder>[];
|
|
for (var vertex in map.values) {
|
|
if (vertex.isLoadingRoot) {
|
|
var unit = new _LoadingUnitBuilder(vertex);
|
|
vertex.loadingUnit = unit;
|
|
unit.members.add(vertex.library);
|
|
loadingUnits.add(unit);
|
|
}
|
|
}
|
|
|
|
// 3. Attribute every library to the dominating loading unit.
|
|
for (var vertex in map.values) {
|
|
if (vertex.isLoadingRoot) {
|
|
continue; // Already processed.
|
|
}
|
|
var dom = vertex.dominator;
|
|
if (dom == null) {
|
|
continue; // Unreachable library.
|
|
}
|
|
while (dom!.loadingUnit == null) {
|
|
dom = dom.dominator;
|
|
}
|
|
vertex.loadingUnit = dom.loadingUnit;
|
|
vertex.loadingUnit!.members.add(vertex.library);
|
|
}
|
|
|
|
// 4. Sort loading units so parents are before children. Normally this order
|
|
// would already exist as a side effect of loading sources in import order,
|
|
// but this isn't guaranteed when combining separately produced kernel files.
|
|
for (var unit in loadingUnits) {
|
|
var parent = unit.parent;
|
|
if (parent != null) {
|
|
parent.children.add(unit);
|
|
}
|
|
}
|
|
var index = 0;
|
|
loadingUnits.clear();
|
|
loadingUnits.add(root.loadingUnit!);
|
|
while (index < loadingUnits.length) {
|
|
var unit = loadingUnits[index];
|
|
unit.id = ++index;
|
|
loadingUnits.addAll(unit.children);
|
|
}
|
|
|
|
return loadingUnits.map((u) => u.asLoadingUnit()).toList();
|
|
}
|
|
|
|
Component transformComponent(
|
|
Component component,
|
|
CoreTypes coreTypes,
|
|
Target target,
|
|
) {
|
|
final parser = ConstantPragmaAnnotationParser(coreTypes, target);
|
|
final visitor = HasEntryPointVisitor(parser);
|
|
final metadata = new LoadingUnitsMetadata(
|
|
computeLoadingUnits(component, visitor),
|
|
);
|
|
final repo = new LoadingUnitsMetadataRepository();
|
|
component.addMetadataRepository(repo);
|
|
repo.mapping[component] = metadata;
|
|
|
|
return component;
|
|
}
|