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 |