| // Copyright 2019 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| import 'package:kernel/ast.dart'; | |
| import 'package:kernel/util/graph.dart'; | |
| import 'package:front_end/src/api_unstable/vm.dart' show FileSystem; | |
| /// Compute the strongly connected components for JavaScript compilation. | |
| /// | |
| /// Implements a Path-based strong component algorithm. | |
| /// See https://en.wikipedia.org/wiki/Path-based_strong_component_algorithm | |
| /// | |
| /// The file URI for each library is used as an identifier for the module | |
| /// name. [moduleAssignment] will be populated with a mapping of library URI to | |
| /// module name, while [modules] will be populated with a mapping of module | |
| /// name to library set. | |
| /// | |
| /// JavaScript import semantics do not permit circular imports in the same | |
| /// manner that Dart does. When compiling a set of libraries with circular | |
| /// imports, these must be combined into a single JavaScript module. | |
| /// | |
| /// On incremental updates, we completely recompute the strongly connected | |
| /// components, but only for the partial component produced. | |
| class StrongComponents { | |
| StrongComponents( | |
| this.component, | |
| this.loadedLibraries, | |
| this.mainUri, [ | |
| this.fileSystem, | |
| ]); | |
| /// The Component that is being compiled. | |
| /// | |
| /// On incremental compiles, this will only contain the invalidated | |
| /// lbraries. | |
| final Component component; | |
| /// The libraries loaded from a dill file that should not be processed. | |
| final Set<Library> loadedLibraries; | |
| /// The main URI for thiis application. | |
| final Uri mainUri; | |
| /// The filesystem instance for resolving files. | |
| final FileSystem fileSystem; | |
| /// The set of libraries for each module URI. | |
| /// | |
| /// This is populated after calling [computeModules] once. | |
| final Map<Uri, List<Library>> modules = <Uri, List<Library>>{}; | |
| /// The module URI for each library file URI. | |
| /// | |
| /// This is populated after calling [computeModules] once. | |
| final Map<Uri, Uri> moduleAssignment = <Uri, Uri>{}; | |
| /// Compute the strongly connected components for the current program. | |
| /// | |
| /// Throws an [Exception] if [mainUri] cannot be located in the given | |
| /// component. | |
| Future<void> computeModules() async { | |
| assert(modules.isEmpty); | |
| if (component.libraries.isEmpty) { | |
| return; | |
| } | |
| // If we don't have a file uri, just use the first library in the | |
| // component. | |
| Library entrypoint = component.libraries.firstWhere( | |
| (Library library) => | |
| library.fileUri == mainUri || library.importUri == mainUri, | |
| orElse: () => null); | |
| if (entrypoint == null) { | |
| throw Exception('Could not find entrypoint ${mainUri} in Component.'); | |
| } | |
| final List<List<Library>> results = | |
| computeStrongComponents(_LibraryGraph(entrypoint, loadedLibraries)); | |
| for (List<Library> component in results) { | |
| assert(component.length > 0); | |
| final Uri moduleUri = component | |
| .firstWhere((lib) => lib.importUri == mainUri, | |
| orElse: () => component.first) | |
| .importUri; | |
| modules[moduleUri] = component; | |
| for (Library componentLibrary in component) { | |
| moduleAssignment[componentLibrary.importUri] = moduleUri; | |
| } | |
| } | |
| } | |
| } | |
| class _LibraryGraph implements Graph<Library> { | |
| _LibraryGraph(this.library, this.loadedLibraries); | |
| final Library library; | |
| final Set<Library> loadedLibraries; | |
| @override | |
| Iterable<Library> neighborsOf(Library vertex) { | |
| return <Library>[ | |
| for (LibraryDependency dependency in vertex.dependencies) | |
| if (!loadedLibraries.contains(dependency.targetLibrary) && | |
| dependency.targetLibrary.importUri.scheme != 'dart') | |
| dependency.targetLibrary | |
| ]; | |
| } | |
| @override | |
| Iterable<Library> get vertices => <Library>[library]; | |
| } |