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

Unified Diff: pkg/analyzer/lib/src/summary/pub_summary.dart

Issue 2375383004: Don't use actual dependency walker in pub summaries. (Closed)
Patch Set: Extract _ContextLinker for computing linked bundles of a context. Created 4 years, 3 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/summary/pub_summary.dart
diff --git a/pkg/analyzer/lib/src/summary/pub_summary.dart b/pkg/analyzer/lib/src/summary/pub_summary.dart
index 0113564b25f583e216346968e291730261545cfb..171c2ff12da4986e4a97479d5eac4bae4ab2d30a 100644
--- a/pkg/analyzer/lib/src/summary/pub_summary.dart
+++ b/pkg/analyzer/lib/src/summary/pub_summary.dart
@@ -33,12 +33,6 @@ import 'package:meta/meta.dart';
import 'package:path/path.dart' as pathos;
/**
- * Return the raw string value of the variable with the given [name],
- * or `null` of the variable is not defined.
- */
-typedef String _GetDeclaredVariable(String name);
-
-/**
* Unlinked and linked information about a [PubPackage].
*/
class LinkedPubPackage {
@@ -180,94 +174,7 @@ class PubSummaryManager {
* referencing the same packages.
*/
List<LinkedPubPackage> getLinkedBundles(AnalysisContext context) {
-// Stopwatch timer = new Stopwatch()..start();
-
- _GetDeclaredVariable getDeclaredVariable = context.declaredVariables.get;
- SourceFactory sourceFactory = context.sourceFactory;
- _ListedPackages listedPackages = new _ListedPackages(sourceFactory);
-
- PackageBundle sdkBundle = sourceFactory.dartSdk.getLinkedBundle();
- if (sdkBundle == null) {
- return const <LinkedPubPackage>[];
- }
-
- bool strong = context.analysisOptions.strongMode;
- Map<PubPackage, PackageBundle> unlinkedBundles =
- getUnlinkedBundles(context);
-
- // TODO(scheglov) remove debug output after optimizing
-// print('LOADED ${unlinkedBundles.length} unlinked bundles'
-// ' in ${timer.elapsedMilliseconds} ms');
-// timer..reset();
-
- // If no unlinked bundles, there is nothing we can try to link.
- if (unlinkedBundles.isEmpty) {
- return const <LinkedPubPackage>[];
- }
-
- // Create graph nodes for packages.
- List<_LinkNode> nodes = <_LinkNode>[];
- Map<String, _LinkNode> packageToNode = <String, _LinkNode>{};
- unlinkedBundles.forEach((package, unlinked) {
- _LinkNode node = new _LinkNode(sdkBundle, getDeclaredVariable,
- listedPackages, package, unlinked, packageToNode);
- nodes.add(node);
- packageToNode[package.name] = node;
- });
-
- // Compute transitive dependencies, mark some nodes as failed.
- for (_LinkNode node in nodes) {
- node.computeTransitiveDependencies();
- }
-
- // Attempt to read existing linked bundles.
- for (_LinkNode node in nodes) {
- _readLinked(node, strong);
- }
-
- // Link new bundles, if allowed.
- if (allowLinking) {
- // Fill the store with bundles.
- // Append the linked SDK bundle.
- // Append unlinked and (if read from a cache) linked package bundles.
- SummaryDataStore store = new SummaryDataStore(const <String>[]);
- store.addBundle(null, sdkBundle);
- for (_LinkNode node in nodes) {
- store.addBundle(null, node.unlinked);
- if (node.linked != null) {
- store.addBundle(null, node.linked);
- }
- }
-
- // Link each package node.
- for (_LinkNode node in nodes) {
- if (!node.isEvaluated) {
- new _LinkWalker(getDeclaredVariable, listedPackages, store, strong)
- .walk(node);
- }
- }
-
- // Write newly linked bundles.
- for (_LinkNode node in nodes) {
- _writeLinked(node, strong);
- }
- }
-
- // Create successfully linked packages.
- List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[];
- for (_LinkNode node in nodes) {
- if (node.linked != null) {
- linkedPackages.add(new LinkedPubPackage(
- node.package, node.unlinked, node.linked, node.linkedHash));
- }
- }
-
- // TODO(scheglov) remove debug output after optimizing
-// print('LINKED ${linkedPackages.length} bundles'
-// ' in ${timer.elapsedMilliseconds} ms');
-
- // Done.
- return linkedPackages;
+ return new _ContextLinker(this, context).getLinkedBundles();
}
/**
@@ -381,17 +288,6 @@ class PubSummaryManager {
}
/**
- * Return the name of the file for a linked bundle, in strong or spec mode.
- */
- String _getLinkedName(String hash, bool strong) {
- if (strong) {
- return 'linked_$hash.ds';
- } else {
- return 'linked_spec_$hash.ds';
- }
- }
-
- /**
* Return the name of the file for an unlinked bundle, in strong or spec mode.
*/
String _getUnlinkedName(bool strong) {
@@ -511,35 +407,6 @@ class PubSummaryManager {
}
/**
- * Attempt to find the linked bundle that corresponds to the given [node]
- * with all its transitive dependencies and put it into [_LinkNode.linked].
- */
- void _readLinked(_LinkNode node, bool strong) {
- String hash = node.linkedHash;
- if (hash != null) {
- String fileName = _getLinkedName(hash, strong);
- File file = node.package.folder.getChildAssumingFile(fileName);
- // Try to find in the cache.
- PackageBundle linked = linkedBundleMap[file.path];
- if (linked != null) {
- node.linked = linked;
- return;
- }
- // Try to read from the file system.
- if (file.exists) {
- try {
- List<int> bytes = file.readAsBytesSync();
- linked = new PackageBundle.fromBuffer(bytes);
- linkedBundleMap[file.path] = linked;
- node.linked = linked;
- } on FileSystemException {
- // Ignore file system exceptions.
- }
- }
- }
- }
-
- /**
* Schedule delayed computation of the next package unlinked bundle from the
* set of [packagesToComputeUnlinked]. We delay each computation because we
* want operations in analysis server to proceed, and computing bundles of
@@ -570,20 +437,6 @@ class PubSummaryManager {
}
/**
- * If a new linked bundle was linked for the given [node], write the bundle
- * into the memory cache and the file system.
- */
- void _writeLinked(_LinkNode node, bool strong) {
- String hash = node.linkedHash;
- if (hash != null && node.linkedNewBytes != null) {
- String fileName = _getLinkedName(hash, strong);
- File file = node.package.folder.getChildAssumingFile(fileName);
- linkedBundleMap[file.path] = node.linked;
- _writeAtomic(node.package.folder, fileName, node.linkedNewBytes);
- }
- }
-
- /**
* If the given [uri] has the `package` scheme, return the name of the
* package that contains the referenced resource. Otherwise return `null`.
*
@@ -617,33 +470,270 @@ class PubSummaryManager {
}
}
+class _ContextLinker {
+ final PubSummaryManager manager;
+ final AnalysisContext context;
+
+ final strong;
+ final _ListedPackages listedPackages;
+ final PackageBundle sdkBundle;
+
+ final List<_LinkNode> nodes = <_LinkNode>[];
+ final Map<String, _LinkNode> packageToNode = <String, _LinkNode>{};
+
+ _ContextLinker(this.manager, AnalysisContext context)
+ : context = context,
+ strong = context.analysisOptions.strongMode,
+ listedPackages = new _ListedPackages(context.sourceFactory),
+ sdkBundle = context.sourceFactory.dartSdk.getLinkedBundle();
+
+ /**
+ * Return the list of linked [LinkedPubPackage]s that can be provided at this
+ * time for a subset of the packages used by the [context].
+ */
+ List<LinkedPubPackage> getLinkedBundles() {
+// Stopwatch timer = new Stopwatch()..start();
+
+ if (sdkBundle == null) {
+ return const <LinkedPubPackage>[];
+ }
+
+ Map<PubPackage, PackageBundle> unlinkedBundles =
+ manager.getUnlinkedBundles(context);
+
+ // TODO(scheglov) remove debug output after optimizing
+// print('LOADED ${unlinkedBundles.length} unlinked bundles'
+// ' in ${timer.elapsedMilliseconds} ms');
+// timer..reset();
+
+ // If no unlinked bundles, there is nothing we can try to link.
+ if (unlinkedBundles.isEmpty) {
+ return const <LinkedPubPackage>[];
+ }
+
+ // Create nodes for packages.
+ unlinkedBundles.forEach((package, unlinked) {
+ _LinkNode node = new _LinkNode(this, package, unlinked);
+ nodes.add(node);
+ packageToNode[package.name] = node;
+ });
+
+ // Compute transitive dependencies, mark some nodes as failed.
+ for (_LinkNode node in nodes) {
+ node.computeTransitiveDependencies();
+ }
+
+ // Attempt to read existing linked bundles.
+ for (_LinkNode node in nodes) {
+ _readLinked(node);
+ }
+
+ // Link new packages, if allowed.
+ if (manager.allowLinking) {
+ _link();
+ }
+
+ // Create successfully linked packages.
+ List<LinkedPubPackage> linkedPackages = <LinkedPubPackage>[];
+ for (_LinkNode node in nodes) {
+ if (node.linked != null) {
+ linkedPackages.add(new LinkedPubPackage(
+ node.package, node.unlinked, node.linked, node.linkedHash));
+ }
+ }
+
+ // TODO(scheglov) remove debug output after optimizing
+// print('LINKED ${linkedPackages.length} bundles'
+// ' in ${timer.elapsedMilliseconds} ms');
+
+ // Done.
+ return linkedPackages;
+ }
+
+ String _getDeclaredVariable(String name) {
+ return context.declaredVariables.get(name);
+ }
+
+ /**
+ * Return the name of the file for a linked bundle, in strong or spec mode.
+ */
+ String _getLinkedName(String hash) {
+ if (strong) {
+ return 'linked_$hash.ds';
+ } else {
+ return 'linked_spec_$hash.ds';
+ }
+ }
+
+ void _link() {
+ // Fill the store with bundles.
+ // Append the linked SDK bundle.
+ // Append unlinked and (if read from a cache) linked package bundles.
+ SummaryDataStore store = new SummaryDataStore(const <String>[]);
+ store.addBundle(null, sdkBundle);
+ for (_LinkNode node in nodes) {
+ store.addBundle(null, node.unlinked);
+ if (node.linked != null) {
+ store.addBundle(null, node.linked);
+ }
+ }
+
+ // Prepare URIs to link.
+ Map<String, _LinkNode> uriToNode = <String, _LinkNode>{};
+ for (_LinkNode node in nodes) {
+ if (!node.isReady) {
+ for (String uri in node.unlinked.unlinkedUnitUris) {
+ uriToNode[uri] = node;
+ }
+ }
+ }
+ Set<String> libraryUris = uriToNode.keys.toSet();
+
+ // Perform linking.
+ Map<String, LinkedLibraryBuilder> linkedLibraries =
+ link(libraryUris, (String uri) {
+ return store.linkedMap[uri];
+ }, (String uri) {
+ return store.unlinkedMap[uri];
+ }, _getDeclaredVariable, strong);
+
+ // Assemble newly linked bundles.
+ for (_LinkNode node in nodes) {
+ if (!node.isReady) {
+ PackageBundleAssembler assembler = new PackageBundleAssembler();
+ linkedLibraries.forEach((uri, linkedLibrary) {
+ if (identical(uriToNode[uri], node)) {
+ assembler.addLinkedLibrary(uri, linkedLibrary);
+ }
+ });
+ List<int> bytes = assembler.assemble().toBuffer();
+ node.linkedNewBytes = bytes;
+ node.linked = new PackageBundle.fromBuffer(bytes);
+ }
+ }
+
+ // Write newly linked bundles.
+ for (_LinkNode node in nodes) {
+ _writeLinked(node);
+ }
+ }
+
+ /**
+ * Attempt to find the linked bundle that corresponds to the given [node]
+ * with all its transitive dependencies and put it into [_LinkNode.linked].
+ */
+ void _readLinked(_LinkNode node) {
+ String hash = node.linkedHash;
+ if (hash != null) {
+ String fileName = _getLinkedName(hash);
+ File file = node.package.folder.getChildAssumingFile(fileName);
+ // Try to find in the cache.
+ PackageBundle linked = manager.linkedBundleMap[file.path];
+ if (linked != null) {
+ node.linked = linked;
+ return;
+ }
+ // Try to read from the file system.
+ if (file.exists) {
+ try {
+ List<int> bytes = file.readAsBytesSync();
+ linked = new PackageBundle.fromBuffer(bytes);
+ manager.linkedBundleMap[file.path] = linked;
+ node.linked = linked;
+ } on FileSystemException {
+ // Ignore file system exceptions.
+ }
+ }
+ }
+ }
+
+ /**
+ * If a new linked bundle was linked for the given [node], write the bundle
+ * into the memory cache and the file system.
+ */
+ void _writeLinked(_LinkNode node) {
+ String hash = node.linkedHash;
+ if (hash != null && node.linkedNewBytes != null) {
+ String fileName = _getLinkedName(hash);
+ File file = node.package.folder.getChildAssumingFile(fileName);
+ manager.linkedBundleMap[file.path] = node.linked;
+ manager._writeAtomic(node.package.folder, fileName, node.linkedNewBytes);
+ }
+ }
+}
+
/**
- * Specialization of [Node] for linking packages in proper dependency order.
+ * Information about a package to link.
*/
-class _LinkNode extends Node<_LinkNode> {
- final PackageBundle sdkBundle;
- final _GetDeclaredVariable getDeclaredVariable;
- final _ListedPackages listedPackages;
+class _LinkNode {
+ final _ContextLinker linker;
final PubPackage package;
final PackageBundle unlinked;
- final Map<String, _LinkNode> packageToNode;
bool failed = false;
Set<_LinkNode> transitiveDependencies;
+
+ List<_LinkNode> _dependencies;
String _linkedHash;
List<int> linkedNewBytes;
PackageBundle linked;
- _LinkNode(this.sdkBundle, this.getDeclaredVariable, this.listedPackages,
- this.package, this.unlinked, this.packageToNode);
+ _LinkNode(this.linker, this.package, this.unlinked);
- @override
- bool get isEvaluated => linked != null || failed;
+ /**
+ * Retrieve the dependencies of this node.
+ */
+ List<_LinkNode> get dependencies {
+ if (_dependencies == null) {
+ Set<_LinkNode> dependencies = new Set<_LinkNode>();
+
+ void appendDependency(String uriStr) {
+ Uri uri = FastUri.parse(uriStr);
+ if (!uri.hasScheme) {
+ // A relative path in this package, skip it.
+ } else if (uri.scheme == 'dart') {
+ // Dependency on the SDK is implicit and always added.
+ // The SDK linked bundle is precomputed before linking packages.
+ } else if (uriStr.startsWith('package:')) {
+ String package = PubSummaryManager.getPackageName(uriStr);
+ _LinkNode packageNode = linker.packageToNode[package];
+ if (packageNode == null && linker.listedPackages.isListed(uriStr)) {
+ failed = true;
+ }
+ if (packageNode != null) {
+ dependencies.add(packageNode);
+ }
+ } else {
+ failed = true;
+ }
+ }
+
+ for (UnlinkedUnit unit in unlinked.unlinkedUnits) {
+ for (UnlinkedImport import in unit.imports) {
+ if (!import.isImplicit) {
+ appendDependency(import.uri);
+ }
+ }
+ for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
+ appendDependency(export.uri);
+ }
+ }
+
+ _dependencies = dependencies.toList();
+ }
+ return _dependencies;
+ }
+
+ /**
+ * Return `true` is the node is ready - has the linked bundle or failed (does
+ * not have all required dependencies).
+ */
+ bool get isReady => linked != null || failed;
/**
* Return the hash string that corresponds to this linked bundle in the
- * context of its [sdkBundle] and transitive dependencies. Return `null` if
+ * context of its SDK bundle and transitive dependencies. Return `null` if
* the hash computation fails, because for example the full transitive
* dependencies cannot computed.
*/
@@ -652,56 +742,45 @@ class _LinkNode extends Node<_LinkNode> {
ApiSignature signature = new ApiSignature();
// Add all unlinked API signatures.
List<String> signatures = <String>[];
- signatures.add(sdkBundle.apiSignature);
+ signatures.add(linker.sdkBundle.apiSignature);
transitiveDependencies
.map((node) => node.unlinked.apiSignature)
.forEach(signatures.add);
signatures.sort();
signatures.forEach(signature.addString);
// Combine into a single hash.
- _appendDeclaredVariables(signature);
+ appendDeclaredVariables(signature);
_linkedHash = signature.toHex();
}
return _linkedHash;
}
- @override
- List<_LinkNode> computeDependencies() {
- Set<_LinkNode> dependencies = new Set<_LinkNode>();
-
- void appendDependency(String uriStr) {
- Uri uri = FastUri.parse(uriStr);
- if (!uri.hasScheme) {
- // A relative path in this package, skip it.
- } else if (uri.scheme == 'dart') {
- // Dependency on the SDK is implicit and always added.
- // The SDK linked bundle is precomputed before linking packages.
- } else if (uriStr.startsWith('package:')) {
- String package = PubSummaryManager.getPackageName(uriStr);
- _LinkNode packageNode = packageToNode[package];
- if (packageNode == null && listedPackages.isListed(uriStr)) {
- failed = true;
+ /**
+ * Append names and values of all referenced declared variables (even the
+ * ones without actually declared values) to the given [signature].
+ */
+ void appendDeclaredVariables(ApiSignature signature) {
+ Set<String> nameSet = new Set<String>();
+ for (_LinkNode node in transitiveDependencies) {
+ for (UnlinkedUnit unit in node.unlinked.unlinkedUnits) {
+ for (UnlinkedImport import in unit.imports) {
+ for (UnlinkedConfiguration configuration in import.configurations) {
+ nameSet.add(configuration.name);
+ }
}
- if (packageNode != null) {
- dependencies.add(packageNode);
+ for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
+ for (UnlinkedConfiguration configuration in export.configurations) {
+ nameSet.add(configuration.name);
+ }
}
- } else {
- failed = true;
}
}
-
- for (UnlinkedUnit unit in unlinked.unlinkedUnits) {
- for (UnlinkedImport import in unit.imports) {
- if (!import.isImplicit) {
- appendDependency(import.uri);
- }
- }
- for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
- appendDependency(export.uri);
- }
+ List<String> sortedNameList = nameSet.toList()..sort();
+ signature.addInt(sortedNameList.length);
+ for (String name in sortedNameList) {
+ signature.addString(name);
+ signature.addString(linker._getDeclaredVariable(name) ?? '');
}
-
- return dependencies.toList();
}
/**
@@ -729,83 +808,6 @@ class _LinkNode extends Node<_LinkNode> {
@override
String toString() => package.toString();
-
- /**
- * Append names and values of all referenced declared variables (even the
- * ones without actually declared values) to the given [signature].
- */
- void _appendDeclaredVariables(ApiSignature signature) {
- Set<String> nameSet = new Set<String>();
- for (_LinkNode node in transitiveDependencies) {
- for (UnlinkedUnit unit in node.unlinked.unlinkedUnits) {
- for (UnlinkedImport import in unit.imports) {
- for (UnlinkedConfiguration configuration in import.configurations) {
- nameSet.add(configuration.name);
- }
- }
- for (UnlinkedExportPublic export in unit.publicNamespace.exports) {
- for (UnlinkedConfiguration configuration in export.configurations) {
- nameSet.add(configuration.name);
- }
- }
- }
- }
- List<String> sortedNameList = nameSet.toList()..sort();
- signature.addInt(sortedNameList.length);
- for (String name in sortedNameList) {
- signature.addString(name);
- signature.addString(getDeclaredVariable(name) ?? '');
- }
- }
-}
-
-/**
- * Specialization of [DependencyWalker] for linking packages.
- */
-class _LinkWalker extends DependencyWalker<_LinkNode> {
- final _GetDeclaredVariable getDeclaredVariable;
- final _ListedPackages listedPackages;
- final SummaryDataStore store;
- final bool strong;
-
- _LinkWalker(
- this.getDeclaredVariable, this.listedPackages, this.store, this.strong);
-
- @override
- void evaluate(_LinkNode node) {
- evaluateScc([node]);
- }
-
- @override
- void evaluateScc(List<_LinkNode> scc) {
- Map<String, _LinkNode> uriToNode = <String, _LinkNode>{};
- for (_LinkNode node in scc) {
- for (String uri in node.unlinked.unlinkedUnitUris) {
- uriToNode[uri] = node;
- }
- }
- Set<String> libraryUris = uriToNode.keys.toSet();
- // Perform linking.
- Map<String, LinkedLibraryBuilder> linkedLibraries =
- link(libraryUris, (String uri) {
- return store.linkedMap[uri];
- }, (String uri) {
- return store.unlinkedMap[uri];
- }, getDeclaredVariable, strong);
- // Assemble linked bundles and put them into the store.
- for (_LinkNode node in scc) {
- PackageBundleAssembler assembler = new PackageBundleAssembler();
- linkedLibraries.forEach((uri, linkedLibrary) {
- if (identical(uriToNode[uri], node)) {
- assembler.addLinkedLibrary(uri, linkedLibrary);
- }
- });
- List<int> bytes = assembler.assemble().toBuffer();
- node.linkedNewBytes = bytes;
- node.linked = new PackageBundle.fromBuffer(bytes);
- store.addBundle(null, node.linked);
- }
- }
}
/**
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698