Add support for SDK outline in KernelDriver.

I had to weaken file system createDirectory() to avoid conflicts when
we re-create SDK, and attempt to re-recreate its directory.

R=ahe@google.com, paulberry@google.com, sigmund@google.com
BUG=

Review-Url: https://codereview.chromium.org/2993093003 .
This commit is contained in:
Konstantin Shcheglov 2017-08-07 10:46:41 -07:00
parent ae4cbb50af
commit c28419bce0
6 changed files with 164 additions and 72 deletions

View file

@ -63,15 +63,11 @@ class MemoryFileSystemEntity implements FileSystemEntity {
/// Create a directory for this file system entry.
///
/// If the entry already exists, either as a file, or as a directory,
/// this is an error.
/// If the entry is an existing file, this is an error.
void createDirectory() {
if (_fileSystem._files[uri] != null) {
throw new FileSystemException(uri, 'Entry $uri is a file.');
}
if (_fileSystem._directories.contains(uri)) {
throw new FileSystemException(uri, 'Directory $uri already exists.');
}
_fileSystem._directories.add(uri);
}

View file

@ -281,6 +281,10 @@ class FileSystemState {
/// contain `file:*` URIs as keys.
final Map<Uri, FileState> _fileUriToFile = {};
/// The set of absolute URIs with the `dart` scheme that should be skipped.
/// We do this when we use SDK outline instead of compiling SDK sources.
final Set<Uri> skipSdkLibraries = new Set<Uri>();
FileSystemState(this._byteStore, this.fileSystem, this.uriTranslator,
this._salt, this._newFileFn);
@ -333,6 +337,11 @@ class FileSystemState {
///
/// The returned file has the last known state since it was last refreshed.
Future<FileState> getFile(Uri absoluteUri) async {
// We don't need to process SDK libraries if we have SDK outline.
if (skipSdkLibraries.contains(absoluteUri)) {
return null;
}
// Resolve the absolute URI into the absolute file URI.
Uri fileUri;
if (absoluteUri.isScheme('file')) {

View file

@ -51,6 +51,10 @@ class KernelDriver {
/// Options used by the kernel compiler.
final ProcessedOptions _options;
/// The optional SDK outline as a serialized program.
/// If provided, the driver will not attempt to read SDK files.
final List<int> _sdkOutlineBytes;
/// The logger to report compilation progress.
final PerformanceLog _logger;
@ -68,6 +72,10 @@ class KernelDriver {
/// reading the file contents.
final KernelDriverFileAddedFn _fileAddedFn;
/// The optional SDK outline loaded from [_sdkOutlineBytes].
/// Might be `null` if the bytes are not provided, or if not loaded yet.
Program _sdkOutline;
/// The salt to mix into all hashes used as keys for serialized data.
List<int> _salt;
@ -82,10 +90,11 @@ class KernelDriver {
final _TestView _testView = new _TestView();
KernelDriver(this._options, this._uriTranslator,
{KernelDriverFileAddedFn fileAddedFn})
{List<int> sdkOutlineBytes, KernelDriverFileAddedFn fileAddedFn})
: _logger = _options.logger,
_fileSystem = _options.fileSystem,
_byteStore = _options.byteStore,
_sdkOutlineBytes = sdkOutlineBytes,
_fileAddedFn = fileAddedFn {
_computeSalt();
@ -122,6 +131,10 @@ class KernelDriver {
return await runWithFrontEndContext('Compute delta', () async {
await _refreshInvalidatedFiles();
// Load the SDK outline before building the graph, so that the file
// system state is configured to skip SDK libraries.
await _loadSdkOutline();
// Ensure that the graph starting at the entry point is ready.
FileState entryLibrary =
await _logger.runAsync('Build graph of files', () async {
@ -138,6 +151,12 @@ class KernelDriver {
DillTarget dillTarget = new DillTarget(
new Ticker(isVerbose: false), _uriTranslator, _options.target);
// If there is SDK outline, load it.
if (_sdkOutline != null) {
dillTarget.loader.appendLibraries(_sdkOutline);
await dillTarget.buildOutlines();
}
List<LibraryCycleResult> results = [];
_testView.compiledCycles.clear();
await _logger.runAsync('Compute results for cycles', () async {
@ -297,6 +316,9 @@ class KernelDriver {
var saltBuilder = new ApiSignature();
saltBuilder.addInt(DATA_VERSION);
saltBuilder.addBool(_options.strongMode);
if (_sdkOutlineBytes != null) {
saltBuilder.addBytes(_sdkOutlineBytes);
}
_salt = saltBuilder.toByteList();
}
@ -335,6 +357,23 @@ class KernelDriver {
return signatureBuilder.toHex();
}
/// Load the SDK outline if its bytes are provided, and configure the file
/// system state to skip SDK library files.
Future<Null> _loadSdkOutline() async {
if (_sdkOutlineBytes != null) {
if (_sdkOutline == null) {
await _logger.runAsync('Load SDK outline from bytes.', () async {
_sdkOutline = new Program();
new BinaryBuilder(_sdkOutlineBytes).readProgram(_sdkOutline);
// Configure the file system state to skip the outline libraries.
for (var outlineLibrary in _sdkOutline.libraries) {
_fsState.skipSdkLibraries.add(outlineLibrary.importUri);
}
});
}
}
}
/// Refresh all the invalidated files and update dependencies.
Future<Null> _refreshInvalidatedFiles() async {
await _logger.runAsync('Refresh invalidated files', () async {

View file

@ -44,7 +44,8 @@ class FileTest extends _BaseTestNative {
test_createDirectory_exists_asDirectory() async {
file.createDirectory();
expect(() => file.createDirectory(), _throwsFileSystemException);
file.createDirectory();
expect(await file.exists(), true);
}
test_createDirectory_exists_asFile() async {

View file

@ -12,6 +12,7 @@ import 'package:front_end/src/fasta/kernel/utils.dart';
import 'package:front_end/src/fasta/uri_translator_impl.dart';
import 'package:front_end/src/incremental/byte_store.dart';
import 'package:front_end/src/incremental/kernel_driver.dart';
import 'package:front_end/summary_generator.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart';
import 'package:kernel/target/targets.dart';
@ -286,6 +287,34 @@ static field (core::String) → core::int f;
expect(result.types.hierarchy, isNotNull);
}
test_compile_useSdkOutline() async {
List<int> sdkOutlineBytes = await _computeSdkOutlineBytes();
// Configure the driver to use the SDK outline.
_createDriver(sdkOutlineBytes: sdkOutlineBytes);
writeFile('/test/.packages', 'test:lib/');
String aPath = '/test/lib/a.dart';
Uri aUri = writeFile(aPath, r'''
import 'dart:async';
var a = 1;
Future<String> b;
''');
KernelResult result = await driver.getKernel(aUri);
// The result does not include SDK libraries.
_assertLibraryUris(result,
includes: [aUri],
excludes: [Uri.parse('dart:core'), Uri.parse('dart:core')]);
// The types of top-level variables are resolved.
var library = _getLibrary(result, aUri);
expect(library.fields[0].type.toString(), 'dart.core::int');
expect(library.fields[1].type.toString(),
'dart.async::Future<dart.core::String>');
}
test_limitedStore_exportDependencies() async {
writeFile('/test/.packages', 'test:lib/');
String aPath = '/test/lib/a.dart';
@ -647,20 +676,35 @@ import 'b.dart';
}
}
Future<List<int>> _computeSdkOutlineBytes() async {
var options = new CompilerOptions()
..fileSystem = fileSystem
..sdkRoot = Uri.parse('file:///sdk/')
..compileSdk = true
..chaseDependencies = true
..strongMode = true
..target = new NoneTarget(new TargetFlags(strongMode: true));
var inputs = [Uri.parse('dart:core')];
return summaryFor(inputs, options);
}
/// Create new [KernelDriver] instance and put it into the [driver] field.
void _createDriver(
{Map<String, Uri> packages, KernelDriverFileAddedFn fileAddedFn}) {
{List<int> sdkOutlineBytes,
Map<String, Uri> packages,
KernelDriverFileAddedFn fileAddedFn}) {
var uriTranslator = new UriTranslatorImpl(
createSdkFiles(fileSystem), new MapPackages(packages));
driver = new KernelDriver(
new ProcessedOptions(new CompilerOptions()
..logger = new PerformanceLog(null)
..fileSystem = fileSystem
..byteStore = new MemoryByteStore()
..strongMode = true
..target = new NoneTarget(new TargetFlags(strongMode: true))),
uriTranslator,
fileAddedFn: fileAddedFn);
var options = new CompilerOptions()
..logger = new PerformanceLog(null)
..fileSystem = fileSystem
..byteStore = new MemoryByteStore()
..strongMode = true
..target = new NoneTarget(new TargetFlags(strongMode: true));
driver = new KernelDriver(new ProcessedOptions(options), uriTranslator,
sdkOutlineBytes: sdkOutlineBytes, fileAddedFn: fileAddedFn);
}
Library _getLibrary(KernelResult result, Uri uri) {

View file

@ -5,22 +5,45 @@
import 'package:front_end/memory_file_system.dart';
import 'package:front_end/src/base/libraries_specification.dart';
/// Create SDK libraries which are used by Fasta to perform kernel generation.
/// The root of the SDK is `file:///sdk`, it will contain a libraries
/// specification file at `lib/libraries.json`.
///
/// Returns the [TargetLibrariesSpecification] whose contents are in
/// libraries.json.
TargetLibrariesSpecification createSdkFiles(MemoryFileSystem fileSystem) {
Map<String, LibraryInfo> dartLibraries = {};
void addSdkLibrary(String name, String contents) {
String path = '$name/$name.dart';
Uri uri = Uri.parse('file:///sdk/lib/$path');
fileSystem.entityForUri(uri).writeAsStringSync(contents);
dartLibraries[name] = new LibraryInfo(name, uri, const []);
}
final _ASYNC = r'''
library dart.async;
addSdkLibrary('core', r'''
class Future<T> {
factory Future(computation()) => null;
factory Future.delayed(Duration duration, [T computation()]) => null;
factory Future.microtask(FutureOr<T> computation()) => null;
factory Future.value([value]) => null;
static Future<List<T>> wait<T>(Iterable<Future<T>> futures) => null;
Future<R> then<R>(FutureOr<R> onValue(T value)) => null;
Future<T> whenComplete(action());
}
class FutureOr<T> {}
class Stream<T> {}
abstract class StreamIterator<T> {}
abstract class Completer<T> {
factory Completer() => null;
factory Completer.sync() => null;
Future<T> get future;
void complete([FutureOr<T> value]);
void completeError(Object error, [StackTrace stackTrace]);
bool get isCompleted;
}
class _StreamIterator<T> implements StreamIterator<T> {}
class _AsyncStarStreamController {}
Object _asyncStackTraceHelper(Function async_op) { }
Function _asyncThenWrapperHelper(continuation) {}
Function _asyncErrorWrapperHelper(continuation) {}
Future _awaitHelper(
object, Function thenCallback, Function errorCallback, var awaiter) {}
''';
final _CORE = r'''
library dart.core;
import 'dart:_internal';
import 'dart:async';
@ -203,45 +226,27 @@ external bool identical(Object a, Object b);
void print(Object o) {}
abstract class _SyncIterable implements Iterable {}
''');
''';
addSdkLibrary('async', r'''
library dart.async;
/// Create SDK libraries which are used by Fasta to perform kernel generation.
/// The root of the SDK is `file:///sdk`, it will contain a libraries
/// specification file at `lib/libraries.json`.
///
/// Returns the [TargetLibrariesSpecification] whose contents are in
/// libraries.json.
TargetLibrariesSpecification createSdkFiles(MemoryFileSystem fileSystem) {
Map<String, LibraryInfo> dartLibraries = {};
void addSdkLibrary(String name, String contents) {
String path = '$name/$name.dart';
Uri uri = Uri.parse('file:///sdk/lib/$path');
fileSystem.entityForUri(uri).writeAsStringSync(contents);
dartLibraries[name] = new LibraryInfo(name, uri, const []);
}
class Future<T> {
factory Future(computation()) => null;
factory Future.delayed(Duration duration, [T computation()]) => null;
factory Future.microtask(FutureOr<T> computation()) => null;
factory Future.value([value]) => null;
fileSystem.entityForUri(Uri.parse('file:///sdk/')).createDirectory();
static Future<List<T>> wait<T>(Iterable<Future<T>> futures) => null;
Future<R> then<R>(FutureOr<R> onValue(T value)) => null;
Future<T> whenComplete(action());
}
class FutureOr<T> {}
class Stream<T> {}
abstract class StreamIterator<T> {}
abstract class Completer<T> {
factory Completer() => null;
factory Completer.sync() => null;
Future<T> get future;
void complete([FutureOr<T> value]);
void completeError(Object error, [StackTrace stackTrace]);
bool get isCompleted;
}
class _StreamIterator<T> implements StreamIterator<T> {}
class _AsyncStarStreamController {}
Object _asyncStackTraceHelper(Function async_op) { }
Function _asyncThenWrapperHelper(continuation) {}
Function _asyncErrorWrapperHelper(continuation) {}
Future _awaitHelper(
object, Function thenCallback, Function errorCallback, var awaiter) {}
''');
addSdkLibrary('core', _CORE);
addSdkLibrary('async', _ASYNC);
addSdkLibrary('collection', 'library dart.collection;');
addSdkLibrary('convert', 'library dart.convert;');
@ -256,7 +261,6 @@ external double sin(num radians);
addSdkLibrary('nativewrappers', 'library dart.nativewrappers;');
addSdkLibrary('profiler', 'library dart.profiler;');
addSdkLibrary('typed_data', 'library dart.typed_data;');
addSdkLibrary('vmservice_io', 'library dart.vmservice_io;');
addSdkLibrary('_builtin', 'library dart._builtin;');
addSdkLibrary('_internal', '''
library dart._internal;
@ -266,10 +270,9 @@ class ExternalName {
const ExternalName(this.name);
}
''');
addSdkLibrary('_vmservice', 'library dart._vmservice;');
var targetSpec = new TargetLibrariesSpecification('vm', dartLibraries);
var spec = new LibrariesSpecification({'vm': targetSpec});
var targetSpec = new TargetLibrariesSpecification(null, dartLibraries);
var spec = new LibrariesSpecification({'none': targetSpec, 'vm': targetSpec});
Uri uri = Uri.parse('file:///sdk/lib/libraries.json');
fileSystem.entityForUri(uri).writeAsStringSync(spec.toJsonString(uri));