| Index: pkg/front_end/lib/src/incremental/kernel_driver.dart
|
| diff --git a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart b/pkg/front_end/lib/src/incremental/kernel_driver.dart
|
| similarity index 71%
|
| copy from pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| copy to pkg/front_end/lib/src/incremental/kernel_driver.dart
|
| index daff92492b7f5bf6d67378210c91de80962cfde9..8e4c795c484fbb08da33c85f032491d7edf69ec5 100644
|
| --- a/pkg/front_end/lib/src/incremental_kernel_generator_impl.dart
|
| +++ b/pkg/front_end/lib/src/incremental/kernel_driver.dart
|
| @@ -5,10 +5,8 @@
|
| 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';
|
| @@ -23,35 +21,49 @@ 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].
|
| +/// This function is invoked for each newly discovered file, and the returned
|
| +/// [Future] is awaited before reading the file content.
|
| +typedef Future<Null> KernelDriverFileAddedFn(Uri uri);
|
| +
|
| +/// This class computes [KernelResult]s for Dart files.
|
| +///
|
| +/// Let the "current file state" represent a map from file URI to the file
|
| +/// contents most recently read from that file. When the driver needs to
|
| +/// access a file that is not in the current file state yet, it will call
|
| +/// the optional "file added" function, read the file and put it into the
|
| +/// current file state.
|
| ///
|
| -/// TODO(scheglov) Update the documentation.
|
| +/// The client invokes [getKernel] to schedule computing the [KernelResult]
|
| +/// for a Dart file. The driver will eventually use the current file state
|
| +/// of the specified file and all files that it transitively depends on to
|
| +/// compute corresponding kernel files (or read them from the [ByteStore]).
|
| ///
|
| -/// Theory of operation: an instance of [IncrementalResolvedAstGenerator] is
|
| -/// used to obtain resolved ASTs, and these are fed into kernel code generation
|
| -/// logic.
|
| -class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| +/// A call to [invalidate] removes the specified file from the current file
|
| +/// state, so that it will be reread before any following [getKernel] will
|
| +/// return a result.
|
| +class KernelDriver {
|
| /// 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 [FileSystem] which should be used by the front end to access files.
|
| + final FileSystem _fileSystem;
|
| +
|
| /// The byte storage to get and put serialized data.
|
| final ByteStore _byteStore;
|
|
|
| - /// The URI of the program entry point.
|
| - final Uri _entryPoint;
|
| + /// The object that knows how to resolve "package:" and "dart:" URIs.
|
| + final TranslateUri _uriTranslator;
|
|
|
| - /// The function to notify when files become used or unused, or `null`.
|
| - final WatchUsedFilesFn _watchFn;
|
| + /// Is `true` if strong mode analysis should be used.
|
| + final bool _strongMode;
|
| +
|
| + /// The function that is invoked when a new file is about to be added to
|
| + /// the current file state. The [Future] that it returns is awaited before
|
| + /// reading the file contents.
|
| + final KernelDriverFileAddedFn _fileAddedFn;
|
|
|
| /// The salt to mix into all hashes used as keys for serialized data.
|
| List<int> _salt;
|
| @@ -59,9 +71,6 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| /// The current file system state.
|
| FileSystemState _fsState;
|
|
|
| - /// 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>();
|
| @@ -69,38 +78,49 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| /// The object that provides additional information for tests.
|
| final _TestView _testView = new _TestView();
|
|
|
| - IncrementalKernelGeneratorImpl(
|
| - this._options, this._uriTranslator, this._entryPoint,
|
| - {WatchUsedFilesFn watch})
|
| - : _logger = _options.logger,
|
| - _byteStore = _options.byteStore,
|
| - _watchFn = watch {
|
| + KernelDriver(this._logger, this._fileSystem, this._byteStore,
|
| + this._uriTranslator, this._strongMode,
|
| + {KernelDriverFileAddedFn fileAddedFn})
|
| + : _fileAddedFn = fileAddedFn {
|
| _computeSalt();
|
|
|
| Future<Null> onFileAdded(Uri uri) {
|
| - if (_watchFn != null) {
|
| - return _watchFn(uri, true);
|
| + if (_fileAddedFn != null) {
|
| + return _fileAddedFn(uri);
|
| }
|
| return new Future.value();
|
| }
|
|
|
| - _fsState = new FileSystemState(_options.byteStore, _options.fileSystem,
|
| - _uriTranslator, _salt, onFileAdded);
|
| + _fsState = new FileSystemState(
|
| + _byteStore, _fileSystem, _uriTranslator, _salt, onFileAdded);
|
| }
|
|
|
| + /// Return the [FileSystemState] that contains the current file state.
|
| + FileSystemState get fsState => _fsState;
|
| +
|
| /// Return the object that provides additional information for tests.
|
| @visibleForTesting
|
| _TestView get test => _testView;
|
|
|
| - @override
|
| - Future<DeltaProgram> computeDelta() async {
|
| + /// Return the [KernelResult] for the Dart file with the given [uri].
|
| + ///
|
| + /// The [uri] must be absolute and normalized.
|
| + ///
|
| + /// The driver will update the current file state for any file previously
|
| + /// reported using [invalidate].
|
| + ///
|
| + /// If the driver has the cached result for the file with the current file
|
| + /// state, it is returned.
|
| + ///
|
| + /// Otherwise the driver will compute new kernel files and return them.
|
| + Future<KernelResult> getKernel(Uri uri) 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);
|
| + return await _fsState.getFile(uri);
|
| });
|
|
|
| List<LibraryCycle> cycles = _logger.run('Compute library cycles', () {
|
| @@ -113,77 +133,41 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| DillTarget dillTarget = new DillTarget(
|
| new Ticker(isVerbose: false),
|
| _uriTranslator,
|
| - new VmFastaTarget(new TargetFlags(strongMode: _options.strongMode)));
|
| + new VmFastaTarget(new TargetFlags(strongMode: _strongMode)));
|
|
|
| - List<_LibraryCycleResult> results = [];
|
| + List<LibraryCycleResult> results = [];
|
| _testView.compiledCycles.clear();
|
| await _logger.runAsync('Compute results for cycles', () async {
|
| for (LibraryCycle cycle in cycles) {
|
| - _LibraryCycleResult result =
|
| + LibraryCycleResult result =
|
| await _compileCycle(nameRoot, dillTarget, cycle);
|
| results.add(result);
|
| }
|
| });
|
|
|
| - Program program = new Program(nameRoot: nameRoot);
|
| -
|
| - // The set of affected library cycles (have different signatures).
|
| - final affectedLibraryCycles = new Set<LibraryCycle>();
|
| - for (_LibraryCycleResult result in results) {
|
| - for (Library library in result.kernelLibraries) {
|
| - Uri uri = library.importUri;
|
| - if (_latestSignature[uri] != result.signature) {
|
| - _latestSignature[uri] = result.signature;
|
| - affectedLibraryCycles.add(result.cycle);
|
| - }
|
| - }
|
| - }
|
| -
|
| - // The set of affected library cycles (have different signatures),
|
| - // or libraries that import or export affected libraries (so VM might
|
| - // have inlined some code from affected libraries into them).
|
| - final vmRequiredLibraryCycles = new Set<LibraryCycle>();
|
| -
|
| - void gatherVmRequiredLibraryCycles(LibraryCycle cycle) {
|
| - if (vmRequiredLibraryCycles.add(cycle)) {
|
| - cycle.directUsers.forEach(gatherVmRequiredLibraryCycles);
|
| - }
|
| - }
|
| -
|
| - affectedLibraryCycles.forEach(gatherVmRequiredLibraryCycles);
|
| -
|
| - // Add required libraries.
|
| - for (_LibraryCycleResult result in results) {
|
| - if (vmRequiredLibraryCycles.contains(result.cycle)) {
|
| - for (Library library in result.kernelLibraries) {
|
| - program.libraries.add(library);
|
| - library.parent = program;
|
| - }
|
| - }
|
| - }
|
| -
|
| - // Set the main method.
|
| - if (program.libraries.isNotEmpty) {
|
| - for (Library library in results.last.kernelLibraries) {
|
| - if (library.importUri == _entryPoint) {
|
| - program.mainMethod = library.procedures.firstWhere(
|
| - (procedure) => procedure.name.name == 'main',
|
| - orElse: () => null);
|
| - break;
|
| - }
|
| - }
|
| - }
|
| -
|
| - return new DeltaProgram(program);
|
| + return new KernelResult(nameRoot, results);
|
| });
|
| }
|
|
|
| - @override
|
| + /// The file with the given [uri] might have changed - updated, added, or
|
| + /// removed. Or not, we don't know. Or it might have, but then changed back.
|
| + ///
|
| + /// The [uri] must be absolute and normalized file URI.
|
| + ///
|
| + /// Schedules the file contents for the [uri] to be read into the current
|
| + /// file state prior the next invocation of [getKernel] returns the result.
|
| + ///
|
| + /// Invocation of this method will not prevent a [Future] returned from
|
| + /// [getKernel] from completing with a result, but the result is not
|
| + /// guaranteed to be consistent with the new current file state after this
|
| + /// [invalidate] invocation.
|
| void invalidate(Uri uri) {
|
| _invalidatedFiles.add(uri);
|
| }
|
|
|
| - @override
|
| + /// Flush the current file state completely.
|
| + ///
|
| + /// TODO(scheglov) Do we really need this functionality?
|
| void invalidateAll() {
|
| _invalidatedFiles.addAll(_fsState.fileUris);
|
| }
|
| @@ -191,7 +175,7 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| /// 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(
|
| + Future<LibraryCycleResult> _compileCycle(
|
| CanonicalName nameRoot, DillTarget dillTarget, LibraryCycle cycle) async {
|
| return _logger.runAsync('Compile cycle $cycle', () async {
|
| String signature = _getCycleSignature(cycle);
|
| @@ -229,7 +213,7 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
|
|
| await appendNewDillLibraries(program);
|
|
|
| - return new _LibraryCycleResult(cycle, signature, program.libraries);
|
| + return new LibraryCycleResult(cycle, signature, program.libraries);
|
| });
|
| }
|
|
|
| @@ -263,7 +247,7 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| _logger.writeln('Stored ${bytes.length} bytes.');
|
| });
|
|
|
| - return new _LibraryCycleResult(cycle, signature, kernelLibraries);
|
| + return new LibraryCycleResult(cycle, signature, kernelLibraries);
|
| });
|
| }
|
|
|
| @@ -299,8 +283,7 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| void _computeSalt() {
|
| var saltBuilder = new ApiSignature();
|
| saltBuilder.addInt(DATA_VERSION);
|
| - saltBuilder.addBool(_options.strongMode);
|
| - saltBuilder.addString(_entryPoint.toString());
|
| + saltBuilder.addBool(_strongMode);
|
| _salt = saltBuilder.toByteList();
|
| }
|
|
|
| @@ -354,20 +337,20 @@ class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
|
| 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);
|
| - }
|
| - }
|
| });
|
| }
|
| }
|
|
|
| +/// The result of compiling of a single file.
|
| +class KernelResult {
|
| + final CanonicalName nameRoot;
|
| + final List<LibraryCycleResult> results;
|
| +
|
| + KernelResult(this.nameRoot, this.results);
|
| +}
|
| +
|
| /// Compilation result for a library cycle.
|
| -class _LibraryCycleResult {
|
| +class LibraryCycleResult {
|
| final LibraryCycle cycle;
|
|
|
| /// The signature of the result.
|
| @@ -382,7 +365,7 @@ class _LibraryCycleResult {
|
| /// are not included, but but references to those dependencies are included.
|
| final List<Library> kernelLibraries;
|
|
|
| - _LibraryCycleResult(this.cycle, this.signature, this.kernelLibraries);
|
| + LibraryCycleResult(this.cycle, this.signature, this.kernelLibraries);
|
| }
|
|
|
| @visibleForTesting
|
|
|