| Index: pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| diff --git a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart b/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| index daff92492b7f5bf6d67378210c91de80962cfde9..e73b95c6267260370fe4be21a7248e1e7062d736 100644
|
| --- a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| +++ b/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| @@ -4,23 +4,13 @@
|
|
|
| import 'dart:async';
|
|
|
| -import 'package:front_end/file_system.dart';
|
| import 'package:front_end/incremental_kernel_generator.dart';
|
| -import 'package:front_end/src/base/api_signature.dart';
|
| import 'package:front_end/src/base/performace_logger.dart';
|
| import 'package:front_end/src/base/processed_options.dart';
|
| -import 'package:front_end/src/fasta/dill/dill_library_builder.dart';
|
| -import 'package:front_end/src/fasta/dill/dill_target.dart';
|
| -import 'package:front_end/src/fasta/kernel/kernel_target.dart';
|
| -import 'package:front_end/src/fasta/kernel/utils.dart';
|
| -import 'package:front_end/src/fasta/ticker.dart';
|
| import 'package:front_end/src/fasta/translate_uri.dart';
|
| -import 'package:front_end/src/incremental/byte_store.dart';
|
| import 'package:front_end/src/incremental/file_state.dart';
|
| -import 'package:kernel/binary/ast_from_binary.dart';
|
| +import 'package:front_end/src/incremental/kernel_driver.dart';
|
| import 'package:kernel/kernel.dart' hide Source;
|
| -import 'package:kernel/target/targets.dart' show TargetFlags;
|
| -import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
|
| import 'package:meta/meta.dart';
|
|
|
| /// Implementation of [IncrementalKernelGenerator].
|
| @@ -34,48 +24,30 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| /// The version of data format, should be incremented on every format change.
|
| static const int DATA_VERSION = 1;
|
|
|
| - /// The compiler options, such as the [FileSystem], the SDK dill location,
|
| - /// etc.
|
| - final ProcessedOptions _options;
|
| -
|
| - /// The object that knows how to resolve "package:" and "dart:" URIs.
|
| - final TranslateUri _uriTranslator;
|
| -
|
| /// The logger to report compilation progress.
|
| final PerformanceLog _logger;
|
|
|
| - /// The byte storage to get and put serialized data.
|
| - final ByteStore _byteStore;
|
| -
|
| /// The URI of the program entry point.
|
| final Uri _entryPoint;
|
|
|
| /// The function to notify when files become used or unused, or `null`.
|
| final WatchUsedFilesFn _watchFn;
|
|
|
| - /// The salt to mix into all hashes used as keys for serialized data.
|
| - List<int> _salt;
|
| -
|
| - /// The current file system state.
|
| - FileSystemState _fsState;
|
| + /// TODO(scheglov) document
|
| + KernelDriver _driver;
|
|
|
| /// Latest compilation signatures produced by [computeDelta] for libraries.
|
| final Map<Uri, String> _latestSignature = {};
|
|
|
| - /// The set of absolute file URIs that were reported through [invalidate]
|
| - /// and not checked for actual changes yet.
|
| - final Set<Uri> _invalidatedFiles = new Set<Uri>();
|
| -
|
| /// The object that provides additional information for tests.
|
| - final _TestView _testView = new _TestView();
|
| + _TestView _testView;
|
|
|
| IncrementalKernelGeneratorImpl(
|
| - this._options, this._uriTranslator, this._entryPoint,
|
| + ProcessedOptions options, TranslateUri uriTranslator, this._entryPoint,
|
| {WatchUsedFilesFn watch})
|
| - : _logger = _options.logger,
|
| - _byteStore = _options.byteStore,
|
| + : _logger = options.logger,
|
| _watchFn = watch {
|
| - _computeSalt();
|
| + _testView = new _TestView(this);
|
|
|
| Future<Null> onFileAdded(Uri uri) {
|
| if (_watchFn != null) {
|
| @@ -84,8 +56,9 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| return new Future.value();
|
| }
|
|
|
| - _fsState = new FileSystemState(_options.byteStore, _options.fileSystem,
|
| - _uriTranslator, _salt, onFileAdded);
|
| + _driver = new KernelDriver(_logger, options.fileSystem, options.byteStore,
|
| + uriTranslator, options.strongMode,
|
| + fileAddedFn: onFileAdded);
|
| }
|
|
|
| /// Return the object that provides additional information for tests.
|
| @@ -95,41 +68,15 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| @override
|
| Future<DeltaProgram> computeDelta() async {
|
| return await _logger.runAsync('Compute delta', () async {
|
| - await _refreshInvalidatedFiles();
|
| -
|
| - // Ensure that the graph starting at the entry point is ready.
|
| - FileState entryLibrary =
|
| - await _logger.runAsync('Build graph of files', () async {
|
| - return await _fsState.getFile(_entryPoint);
|
| - });
|
| -
|
| - List<LibraryCycle> cycles = _logger.run('Compute library cycles', () {
|
| - List<LibraryCycle> cycles = entryLibrary.topologicalOrder;
|
| - _logger.writeln('Computed ${cycles.length} cycles.');
|
| - return cycles;
|
| - });
|
| -
|
| - CanonicalName nameRoot = new CanonicalName.root();
|
| - DillTarget dillTarget = new DillTarget(
|
| - new Ticker(isVerbose: false),
|
| - _uriTranslator,
|
| - new VmFastaTarget(new TargetFlags(strongMode: _options.strongMode)));
|
| + KernelResult kernelResult = await _driver.getKernel(_entryPoint);
|
| + List<LibraryCycleResult> results = kernelResult.results;
|
|
|
| - List<_LibraryCycleResult> results = [];
|
| - _testView.compiledCycles.clear();
|
| - await _logger.runAsync('Compute results for cycles', () async {
|
| - for (LibraryCycle cycle in cycles) {
|
| - _LibraryCycleResult result =
|
| - await _compileCycle(nameRoot, dillTarget, cycle);
|
| - results.add(result);
|
| - }
|
| - });
|
| -
|
| - Program program = new Program(nameRoot: nameRoot);
|
| + // The file graph might have changed, perform GC.
|
| + await _gc();
|
|
|
| // The set of affected library cycles (have different signatures).
|
| final affectedLibraryCycles = new Set<LibraryCycle>();
|
| - for (_LibraryCycleResult result in results) {
|
| + for (LibraryCycleResult result in results) {
|
| for (Library library in result.kernelLibraries) {
|
| Uri uri = library.importUri;
|
| if (_latestSignature[uri] != result.signature) {
|
| @@ -153,7 +100,8 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| affectedLibraryCycles.forEach(gatherVmRequiredLibraryCycles);
|
|
|
| // Add required libraries.
|
| - for (_LibraryCycleResult result in results) {
|
| + Program program = new Program(nameRoot: kernelResult.nameRoot);
|
| + for (LibraryCycleResult result in results) {
|
| if (vmRequiredLibraryCycles.contains(result.cycle)) {
|
| for (Library library in result.kernelLibraries) {
|
| program.libraries.add(library);
|
| @@ -180,214 +128,31 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
|
|
| @override
|
| void invalidate(Uri uri) {
|
| - _invalidatedFiles.add(uri);
|
| + _driver.invalidate(uri);
|
| }
|
|
|
| @override
|
| void invalidateAll() {
|
| - _invalidatedFiles.addAll(_fsState.fileUris);
|
| + _driver.invalidateAll();
|
| }
|
|
|
| - /// Ensure that [dillTarget] includes the [cycle] libraries. It already
|
| - /// contains all the libraries that sorted before the given [cycle] in
|
| - /// topological order. Return the result with the cycle libraries.
|
| - Future<_LibraryCycleResult> _compileCycle(
|
| - CanonicalName nameRoot, DillTarget dillTarget, LibraryCycle cycle) async {
|
| - return _logger.runAsync('Compile cycle $cycle', () async {
|
| - String signature = _getCycleSignature(cycle);
|
| -
|
| - _logger.writeln('Signature: $signature.');
|
| - var kernelKey = '$signature.kernel';
|
| -
|
| - // We need kernel libraries for these URIs.
|
| - var libraryUris = new Set<Uri>();
|
| - var libraryUriToFile = <Uri, FileState>{};
|
| - for (FileState library in cycle.libraries) {
|
| - Uri uri = library.uri;
|
| - libraryUris.add(uri);
|
| - libraryUriToFile[uri] = library;
|
| - }
|
| -
|
| - Future<Null> appendNewDillLibraries(Program program) async {
|
| - List<DillLibraryBuilder> libraryBuilders = dillTarget.loader
|
| - .appendLibraries(program, (uri) => libraryUris.contains(uri));
|
| -
|
| - // Compute local scopes.
|
| - await dillTarget.buildOutlines();
|
| -
|
| - // Compute export scopes.
|
| - _computeExportScopes(dillTarget, libraryUriToFile, libraryBuilders);
|
| - }
|
| -
|
| - // Check if there is already a bundle with these libraries.
|
| - List<int> bytes = _byteStore.get(kernelKey);
|
| - if (bytes != null) {
|
| - return _logger.runAsync('Read serialized libraries', () async {
|
| - var program = new Program(nameRoot: nameRoot);
|
| - var reader = new BinaryBuilder(bytes);
|
| - reader.readProgram(program);
|
| -
|
| - await appendNewDillLibraries(program);
|
| -
|
| - return new _LibraryCycleResult(cycle, signature, program.libraries);
|
| - });
|
| - }
|
| -
|
| - // Create KernelTarget and configure it for compiling the cycle URIs.
|
| - KernelTarget kernelTarget =
|
| - new KernelTarget(_fsState.fileSystemView, dillTarget, _uriTranslator);
|
| - for (FileState library in cycle.libraries) {
|
| - kernelTarget.read(library.uri);
|
| - }
|
| -
|
| - // Compile the cycle libraries into a new full program.
|
| - Program program = await _logger
|
| - .runAsync('Compile ${cycle.libraries.length} libraries', () async {
|
| - await kernelTarget.buildOutlines(nameRoot: nameRoot);
|
| - return await kernelTarget.buildProgram();
|
| - });
|
| - _testView.compiledCycles.add(cycle);
|
| -
|
| - // Add newly compiled libraries into DILL.
|
| - await appendNewDillLibraries(program);
|
| -
|
| - List<Library> kernelLibraries = program.libraries
|
| - .where((library) => libraryUris.contains(library.importUri))
|
| - .toList();
|
| -
|
| - _logger.run('Serialize ${kernelLibraries.length} libraries', () {
|
| - program.uriToSource.clear();
|
| - List<int> bytes =
|
| - serializeProgram(program, filter: kernelLibraries.contains);
|
| - _byteStore.put(kernelKey, bytes);
|
| - _logger.writeln('Stored ${bytes.length} bytes.');
|
| - });
|
| -
|
| - return new _LibraryCycleResult(cycle, signature, kernelLibraries);
|
| - });
|
| - }
|
| -
|
| - /// Compute exports scopes for a new strongly connected cycle of [libraries].
|
| - /// The [dillTarget] can be used to access libraries from previous cycles.
|
| - /// TODO(scheglov) Remove/replace this when Kernel has export scopes.
|
| - void _computeExportScopes(DillTarget dillTarget,
|
| - Map<Uri, FileState> uriToFile, List<DillLibraryBuilder> libraries) {
|
| - bool wasChanged = false;
|
| - do {
|
| - wasChanged = false;
|
| - for (DillLibraryBuilder library in libraries) {
|
| - FileState file = uriToFile[library.uri];
|
| - for (NamespaceExport export in file.exports) {
|
| - DillLibraryBuilder exportedLibrary =
|
| - dillTarget.loader.read(export.library.uri, -1, accessor: library);
|
| - if (exportedLibrary != null) {
|
| - exportedLibrary.exports.forEach((name, member) {
|
| - if (export.isExposed(name) &&
|
| - library.addToExportScope(name, member)) {
|
| - wasChanged = true;
|
| - }
|
| - });
|
| - } else {
|
| - // TODO(scheglov) How to handle this?
|
| - }
|
| - }
|
| - }
|
| - } while (wasChanged);
|
| - }
|
| -
|
| - /// Compute salt and put into [_salt].
|
| - void _computeSalt() {
|
| - var saltBuilder = new ApiSignature();
|
| - saltBuilder.addInt(DATA_VERSION);
|
| - saltBuilder.addBool(_options.strongMode);
|
| - saltBuilder.addString(_entryPoint.toString());
|
| - _salt = saltBuilder.toByteList();
|
| - }
|
| -
|
| - String _getCycleSignature(LibraryCycle cycle) {
|
| - bool hasMixinApplication =
|
| - cycle.libraries.any((library) => library.hasMixinApplicationLibrary);
|
| - var signatureBuilder = new ApiSignature();
|
| - signatureBuilder.addBytes(_salt);
|
| - Set<FileState> transitiveFiles = cycle.libraries
|
| - .map((library) => library.transitiveFiles)
|
| - .expand((files) => files)
|
| - .toSet();
|
| - signatureBuilder.addInt(transitiveFiles.length);
|
| -
|
| - // Append API signatures of transitive files.
|
| - for (var file in transitiveFiles) {
|
| - signatureBuilder.addBytes(file.uriBytes);
|
| - // TODO(scheglov): Stop using content hashes here, when Kernel stops
|
| - // copying methods of mixed-in classes.
|
| - // https://github.com/dart-lang/sdk/issues/29881
|
| - if (hasMixinApplication) {
|
| - signatureBuilder.addBytes(file.contentHash);
|
| - } else {
|
| - signatureBuilder.addBytes(file.apiSignature);
|
| - }
|
| - }
|
| -
|
| - // Append content hashes of the cycle files.
|
| - for (var library in cycle.libraries) {
|
| - signatureBuilder.addBytes(library.contentHash);
|
| - for (var part in library.partFiles) {
|
| - signatureBuilder.addBytes(part.contentHash);
|
| + /// TODO(scheglov) document
|
| + Future<Null> _gc() async {
|
| + var removedFiles = _driver.fsState.gc(_entryPoint);
|
| + if (removedFiles.isNotEmpty && _watchFn != null) {
|
| + for (var removedFile in removedFiles) {
|
| + await _watchFn(removedFile.fileUri, false);
|
| }
|
| }
|
| -
|
| - return signatureBuilder.toHex();
|
| - }
|
| -
|
| - /// Refresh all the invalidated files and update dependencies.
|
| - Future<Null> _refreshInvalidatedFiles() async {
|
| - await _logger.runAsync('Refresh invalidated files', () async {
|
| - // Create a copy to avoid concurrent modifications.
|
| - var invalidatedFiles = _invalidatedFiles.toList();
|
| - _invalidatedFiles.clear();
|
| -
|
| - // Refresh the files.
|
| - for (var fileUri in invalidatedFiles) {
|
| - var file = _fsState.getFileByFileUri(fileUri);
|
| - if (file != null) {
|
| - _logger.writeln('Refresh $fileUri');
|
| - await file.refresh();
|
| - }
|
| - }
|
| -
|
| - // The file graph might have changed, perform GC.
|
| - var removedFiles = _fsState.gc(_entryPoint);
|
| - if (removedFiles.isNotEmpty && _watchFn != null) {
|
| - for (var removedFile in removedFiles) {
|
| - await _watchFn(removedFile.fileUri, false);
|
| - }
|
| - }
|
| - });
|
| }
|
| }
|
|
|
| -/// Compilation result for a library cycle.
|
| -class _LibraryCycleResult {
|
| - final LibraryCycle cycle;
|
| -
|
| - /// The signature of the result.
|
| - ///
|
| - /// It is based on the full content of the libraries in the [cycle], and
|
| - /// either API signatures of the transitive dependencies (usually), or
|
| - /// the full content of them (in the [cycle] has a library with a mixin
|
| - /// application).
|
| - final String signature;
|
| -
|
| - /// Kernel libraries for libraries in the [cycle]. Bodies of dependencies
|
| - /// are not included, but but references to those dependencies are included.
|
| - final List<Library> kernelLibraries;
|
| -
|
| - _LibraryCycleResult(this.cycle, this.signature, this.kernelLibraries);
|
| -}
|
| -
|
| @visibleForTesting
|
| class _TestView {
|
| - /// The list of [LibraryCycle]s compiled for the last delta.
|
| - /// It does not include libraries which were read from the cache.
|
| - final List<LibraryCycle> compiledCycles = [];
|
| + final IncrementalKernelGeneratorImpl _generator;
|
| +
|
| + _TestView(this._generator);
|
| +
|
| + /// The [KernelDriver] that is used to actually compile.
|
| + KernelDriver get driver => _generator._driver;
|
| }
|
|
|