dartdevc and bazel worker can use incremental compiler

This allows dartdevc and the bazel worker to user
the incremental compiler with kernel.
Use --reuse-compiler-result --use-incremental-compiler to run in this mode.

Change-Id: I9189ce5f1a51320d9d96e071f8c95c80fe6fca84
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95386
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Jenny Messerly <jmesserly@google.com>
This commit is contained in:
Jens Johansen 2019-03-29 12:07:42 +00:00 committed by commit-bot@chromium.org
parent a506c708f2
commit b7f69e24a2
6 changed files with 475 additions and 53 deletions

View file

@ -399,7 +399,8 @@ Future<CompilerResult> compile(ParsedArguments args,
}
if (args.isKernel) {
return kernel_compiler.compile(args.rest,
compilerState: previousResult?.kernelState);
compilerState: previousResult?.kernelState,
useIncrementalCompiler: args.useIncrementalCompiler);
} else {
var result = analyzer_compiler.compile(args.rest,
compilerState: previousResult?.analyzerState);
@ -492,11 +493,17 @@ class ParsedArguments {
/// e.g. in a debugger REPL.
final bool reuseResult;
/// Whether to use the incremental compiler for compiling.
///
/// Note that this only makes sense when also reusing results.
final bool useIncrementalCompiler;
ParsedArguments._(this.rest,
{this.isBatch = false,
this.isWorker = false,
this.isKernel = false,
this.reuseResult = false});
this.reuseResult = false,
this.useIncrementalCompiler = false});
/// Preprocess arguments to determine whether DDK is used in batch mode or as a
/// persistent worker.
@ -515,6 +522,7 @@ class ParsedArguments {
bool isBatch = false;
bool isKernel = false;
bool reuseResult = false;
bool useIncrementalCompiler = false;
var len = args.length;
for (int i = 0; i < len; i++) {
var arg = args[i];
@ -533,6 +541,8 @@ class ParsedArguments {
isKernel = true;
} else if (arg == '--reuse-compiler-result') {
reuseResult = true;
} else if (arg == '--use-incremental-compiler') {
useIncrementalCompiler = true;
} else {
newArgs.add(arg);
}
@ -541,7 +551,8 @@ class ParsedArguments {
isWorker: isWorker,
isBatch: isBatch,
isKernel: isKernel,
reuseResult: reuseResult);
reuseResult: reuseResult,
useIncrementalCompiler: useIncrementalCompiler);
}
/// Whether the compiler is running in [isBatch] or [isWorker] mode.
@ -567,7 +578,9 @@ class ParsedArguments {
isWorker: isWorker,
isBatch: isBatch,
isKernel: isKernel || newArgs.isKernel,
reuseResult: reuseResult);
reuseResult: reuseResult || newArgs.reuseResult,
useIncrementalCompiler:
useIncrementalCompiler || newArgs.useIncrementalCompiler);
}
}

View file

@ -35,9 +35,12 @@ const _binaryName = 'dartdevc -k';
///
/// Returns `true` if the program compiled without any fatal errors.
Future<CompilerResult> compile(List<String> args,
{fe.InitializedCompilerState compilerState}) async {
{fe.InitializedCompilerState compilerState,
bool useIncrementalCompiler: false}) async {
try {
return await _compile(args, compilerState: compilerState);
return await _compile(args,
compilerState: compilerState,
useIncrementalCompiler: useIncrementalCompiler);
} catch (error, stackTrace) {
print('''
We're sorry, you've found a bug in our compiler.
@ -63,7 +66,8 @@ String _usageMessage(ArgParser ddcArgParser) =>
'${ddcArgParser.usage}';
Future<CompilerResult> _compile(List<String> args,
{fe.InitializedCompilerState compilerState}) async {
{fe.InitializedCompilerState compilerState,
bool useIncrementalCompiler: false}) async {
// TODO(jmesserly): refactor options to share code with dartdevc CLI.
var argParser = ArgParser(allowTrailingOptions: true)
..addFlag('help',
@ -194,15 +198,37 @@ Future<CompilerResult> _compile(List<String> args,
}
var oldCompilerState = compilerState;
compilerState = await fe.initializeCompiler(
oldCompilerState,
sourcePathToUri(sdkSummaryPath),
sourcePathToUri(packageFile),
sourcePathToUri(librarySpecPath),
summaryModules.keys.toList(),
DevCompilerTarget(),
fileSystem: fileSystem,
experiments: experiments);
List<Component> doneInputSummaries;
fe.IncrementalCompiler incrementalCompiler;
fe.WorkerInputComponent cachedSdkInput;
if (useAnalyzer || !useIncrementalCompiler) {
compilerState = await fe.initializeCompiler(
oldCompilerState,
sourcePathToUri(sdkSummaryPath),
sourcePathToUri(packageFile),
sourcePathToUri(librarySpecPath),
summaryModules.keys.toList(),
DevCompilerTarget(),
fileSystem: fileSystem,
experiments: experiments);
} else {
doneInputSummaries = new List<Component>(summaryModules.length);
compilerState = await fe.initializeIncrementalCompiler(
oldCompilerState,
doneInputSummaries,
sourcePathToUri(sdkSummaryPath),
sourcePathToUri(packageFile),
sourcePathToUri(librarySpecPath),
summaryModules.keys.toList(),
DevCompilerTarget(),
fileSystem: fileSystem,
experiments: experiments);
incrementalCompiler = compilerState.incrementalCompiler;
cachedSdkInput =
compilerState.workerInputCache[sourcePathToUri(sdkSummaryPath)];
}
List<Uri> inputSummaries = compilerState.options.inputSummaries;
var output = argResults['out'] as String;
// TODO(jmesserly): is there a cleaner way to do this?
@ -219,8 +245,26 @@ Future<CompilerResult> _compile(List<String> args,
converter.dispose();
}
fe.DdcResult result =
await fe.compile(compilerState, inputs, diagnosticMessageHandler);
var hierarchy;
fe.DdcResult result;
if (useAnalyzer || !useIncrementalCompiler) {
result = await fe.compile(compilerState, inputs, diagnosticMessageHandler);
} else {
Component incrementalComponent = await incrementalCompiler.computeDelta(
entryPoints: inputs, fullComponent: true);
hierarchy = incrementalCompiler.userCode.loader.hierarchy;
result = new fe.DdcResult(incrementalComponent, doneInputSummaries);
// Workaround for DDC relying on isExternal being set to true.
for (var lib in cachedSdkInput.component.libraries) {
lib.isExternal = true;
}
for (Component c in doneInputSummaries) {
for (Library lib in c.libraries) {
lib.isExternal = true;
}
}
}
if (result == null || !succeeded) {
return CompilerResult(1, kernelState: compilerState);
}
@ -256,8 +300,10 @@ Future<CompilerResult> _compile(List<String> args,
kernel.Printer(sb, showExternal: false).writeComponentFile(component);
outFiles.add(File(output + '.txt').writeAsString(sb.toString()));
}
var target = compilerState.options.target as DevCompilerTarget;
var hierarchy = target.hierarchy;
if (hierarchy == null) {
var target = compilerState.options.target as DevCompilerTarget;
hierarchy = target.hierarchy;
}
// TODO(jmesserly): remove this hack once Flutter SDK has a `dartdevc` with
// support for the widget inspector.
@ -268,8 +314,8 @@ Future<CompilerResult> _compile(List<String> args,
var compiler =
ProgramCompiler(component, hierarchy, options, declaredVariables);
var jsModule = compiler.emitModule(component, result.inputSummaries,
compilerState.options.inputSummaries, summaryModules);
var jsModule = compiler.emitModule(
component, result.inputSummaries, inputSummaries, summaryModules);
// TODO(jmesserly): support for multiple output formats?
//

View file

@ -7,6 +7,8 @@
import 'dart:async' show Future;
import 'package:kernel/kernel.dart' show Component, CanonicalName;
import 'package:kernel/target/targets.dart' show Target;
import '../api_prototype/compiler_options.dart' show CompilerOptions;
@ -17,11 +19,16 @@ import '../api_prototype/file_system.dart' show FileSystem;
import '../base/processed_options.dart' show ProcessedOptions;
import '../fasta/compiler_context.dart' show CompilerContext;
import '../fasta/incremental_compiler.dart' show IncrementalCompiler;
import '../fasta/kernel/utils.dart' show serializeComponent;
import '../kernel_generator_impl.dart' show generateKernel;
import 'compiler_state.dart' show InitializedCompilerState;
import 'compiler_state.dart'
show InitializedCompilerState, WorkerInputComponent, digestsEqual;
export '../api_prototype/diagnostic_message.dart' show DiagnosticMessage;
@ -30,10 +37,138 @@ export '../api_prototype/standard_file_system.dart' show StandardFileSystem;
export '../api_prototype/terminal_color_support.dart'
show printDiagnosticMessage;
export '../fasta/kernel/utils.dart' show serializeComponent;
export '../fasta/severity.dart' show Severity;
export 'compiler_state.dart' show InitializedCompilerState;
/// Initializes the compiler for a modular build.
///
/// Re-uses cached components from [_workerInputCache], and reloads them
/// as necessary based on [workerInputDigests].
Future<InitializedCompilerState> initializeIncrementalCompiler(
InitializedCompilerState oldState,
Uri sdkSummary,
Uri packagesFile,
Uri librariesSpecificationUri,
List<Uri> summaryInputs,
Map<Uri, List<int>> workerInputDigests,
Target target,
FileSystem fileSystem,
bool outlineOnly) async {
List<int> sdkDigest = workerInputDigests[sdkSummary];
IncrementalCompiler incrementalCompiler;
CompilerOptions options;
ProcessedOptions processedOpts;
WorkerInputComponent cachedSdkInput;
Map<Uri, WorkerInputComponent> workerInputCache =
oldState?.workerInputCache ?? new Map<Uri, WorkerInputComponent>();
bool startOver = false;
if (oldState == null ||
oldState.incrementalCompiler == null ||
oldState.incrementalCompiler.outlineOnly != outlineOnly) {
// No previous state.
startOver = true;
} else {
// We do have a previous state.
cachedSdkInput = workerInputCache[sdkSummary];
if (cachedSdkInput == null ||
!digestsEqual(cachedSdkInput.digest, workerInputDigests[sdkSummary])) {
// The sdk is out of date.
startOver = true;
}
}
if (startOver) {
// The sdk was either not cached or it has changed.
options = new CompilerOptions()
..sdkSummary = sdkSummary
..packagesFileUri = packagesFile
..librariesSpecificationUri = librariesSpecificationUri
..target = target
..fileSystem = fileSystem
..omitPlatform = true;
processedOpts = new ProcessedOptions(options: options);
cachedSdkInput = WorkerInputComponent(
sdkDigest, await processedOpts.loadSdkSummary(null));
workerInputCache[sdkSummary] = cachedSdkInput;
incrementalCompiler = new IncrementalCompiler.fromComponent(
new CompilerContext(processedOpts),
cachedSdkInput.component,
outlineOnly);
} else {
options = oldState.options;
processedOpts = oldState.processedOpts;
var sdkComponent = cachedSdkInput.component;
// Reset the state of the component.
for (var lib in sdkComponent.libraries) {
lib.isExternal = cachedSdkInput.externalLibs.contains(lib.importUri);
}
sdkComponent.adoptChildren();
for (WorkerInputComponent cachedInput in workerInputCache.values) {
cachedInput.component.adoptChildren();
}
sdkComponent.unbindCanonicalNames();
sdkComponent.computeCanonicalNames();
// Reuse the incremental compiler, but reset as needed.
incrementalCompiler = oldState.incrementalCompiler;
incrementalCompiler.invalidateAllSources();
options.packagesFileUri = packagesFile;
options.fileSystem = fileSystem;
}
// Then read all the input summary components.
// The nameRoot from the sdk was either just created or just unbound.
// If just unbound, only the sdk stuff is bound. Either way, don't clear it
// again and bind as much as possible before loading new stuff!
CanonicalName nameRoot = cachedSdkInput.component.root;
final inputSummaries = <Component>[];
List<Uri> loadFromDill = new List<Uri>();
for (Uri summary in summaryInputs) {
var cachedInput = workerInputCache[summary];
var summaryDigest = workerInputDigests[summary];
if (cachedInput == null ||
cachedInput.component.root != nameRoot ||
!digestsEqual(cachedInput.digest, summaryDigest)) {
loadFromDill.add(summary);
} else {
// Need to reset cached components so they are usable again.
var component = cachedInput.component;
for (var lib in component.libraries) {
lib.isExternal = cachedInput.externalLibs.contains(lib.importUri);
}
// We don't unbind as the root was unbound already. We do have to compute
// the canonical names though, to rebind everything in the component.
component.adoptChildren();
component.computeCanonicalNames();
inputSummaries.add(component);
}
}
for (int i = 0; i < loadFromDill.length; i++) {
Uri summary = loadFromDill[i];
var summaryDigest = workerInputDigests[summary];
WorkerInputComponent cachedInput = WorkerInputComponent(
summaryDigest,
await processedOpts.loadComponent(
await fileSystem.entityForUri(summary).readAsBytes(), nameRoot));
workerInputCache[summary] = cachedInput;
inputSummaries.add(cachedInput.component);
}
incrementalCompiler.setModulesToLoadOnNextComputeDelta(inputSummaries);
return new InitializedCompilerState(options, processedOpts,
workerInputCache: workerInputCache,
incrementalCompiler: incrementalCompiler);
}
Future<InitializedCompilerState> initializeCompiler(
InitializedCompilerState oldState,
Uri sdkSummary,

View file

@ -6,9 +6,41 @@ import '../api_prototype/compiler_options.dart' show CompilerOptions;
import '../base/processed_options.dart' show ProcessedOptions;
import 'package:front_end/src/fasta/incremental_compiler.dart'
show IncrementalCompiler;
import 'package:kernel/kernel.dart' show Component;
class InitializedCompilerState {
final CompilerOptions options;
final ProcessedOptions processedOpts;
final Map<Uri, WorkerInputComponent> workerInputCache;
final IncrementalCompiler incrementalCompiler;
InitializedCompilerState(this.options, this.processedOpts);
InitializedCompilerState(this.options, this.processedOpts,
{this.workerInputCache, this.incrementalCompiler});
}
/// A cached [Component] for a summary input file.
///
/// Tracks the originally marked "external" libs so that they can be restored,
/// since the kernel generator mutates the state.
class WorkerInputComponent {
final List<int> digest;
final Component component;
final Set<Uri> externalLibs;
WorkerInputComponent(this.digest, this.component)
: externalLibs = component.libraries
.where((lib) => lib.isExternal)
.map((lib) => lib.importUri)
.toSet();
}
bool digestsEqual(List<int> a, List<int> b) {
if (a == null || b == null) return false;
if (a.length != b.length) return false;
for (int i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return true;
}

View file

@ -4,7 +4,7 @@
import 'dart:async' show Future;
import 'package:kernel/kernel.dart' show Component;
import 'package:kernel/kernel.dart' show Component, CanonicalName;
import 'package:kernel/target/targets.dart' show Target;
@ -20,9 +20,14 @@ import '../api_prototype/standard_file_system.dart' show StandardFileSystem;
import '../base/processed_options.dart' show ProcessedOptions;
import '../fasta/compiler_context.dart' show CompilerContext;
import '../fasta/incremental_compiler.dart' show IncrementalCompiler;
import '../kernel_generator_impl.dart' show generateKernel;
import 'compiler_state.dart' show InitializedCompilerState;
import 'compiler_state.dart'
show InitializedCompilerState, WorkerInputComponent, digestsEqual;
export '../api_prototype/compiler_options.dart' show CompilerOptions;
@ -40,6 +45,12 @@ export '../api_prototype/standard_file_system.dart' show StandardFileSystem;
export '../api_prototype/terminal_color_support.dart'
show printDiagnosticMessage;
export '../base/processed_options.dart' show ProcessedOptions;
export '../fasta/compiler_context.dart' show CompilerContext;
export '../fasta/incremental_compiler.dart' show IncrementalCompiler;
export '../fasta/kernel/redirecting_factory_body.dart'
show RedirectingFactoryBody;
@ -48,7 +59,8 @@ export '../fasta/severity.dart' show Severity;
export '../fasta/type_inference/type_schema_environment.dart'
show TypeSchemaEnvironment;
export 'compiler_state.dart' show InitializedCompilerState;
export 'compiler_state.dart'
show InitializedCompilerState, WorkerInputComponent, digestsEqual;
class DdcResult {
final Component component;
@ -119,6 +131,119 @@ Future<InitializedCompilerState> initializeCompiler(
return new InitializedCompilerState(options, processedOpts);
}
Future<InitializedCompilerState> initializeIncrementalCompiler(
InitializedCompilerState oldState,
List<Component> doneInputSummaries,
Uri sdkSummary,
Uri packagesFile,
Uri librariesSpecificationUri,
List<Uri> inputSummaries,
Target target,
{FileSystem fileSystem,
Map<ExperimentalFlag, bool> experiments}) async {
inputSummaries.sort((a, b) => a.toString().compareTo(b.toString()));
IncrementalCompiler incrementalCompiler;
WorkerInputComponent cachedSdkInput;
CompilerOptions options;
ProcessedOptions processedOpts;
Map<Uri, WorkerInputComponent> workerInputCache =
oldState?.workerInputCache ?? new Map<Uri, WorkerInputComponent>();
cachedSdkInput = workerInputCache[sdkSummary];
if (oldState == null ||
oldState.incrementalCompiler == null ||
cachedSdkInput == null) {
// No previous state.
options = new CompilerOptions()
..sdkSummary = sdkSummary
..packagesFileUri = packagesFile
..inputSummaries = inputSummaries
..librariesSpecificationUri = librariesSpecificationUri
..target = target
..fileSystem = fileSystem ?? StandardFileSystem.instance;
if (experiments != null) options.experimentalFlags = experiments;
processedOpts = new ProcessedOptions(options: options);
cachedSdkInput = new WorkerInputComponent(null /* not compared anyway */,
await processedOpts.loadSdkSummary(null));
workerInputCache[sdkSummary] = cachedSdkInput;
incrementalCompiler = new IncrementalCompiler.fromComponent(
new CompilerContext(processedOpts), cachedSdkInput.component);
} else {
options = oldState.options;
options.inputSummaries = inputSummaries;
processedOpts = oldState.processedOpts;
for (var lib in cachedSdkInput.component.libraries) {
lib.isExternal = false;
}
for (WorkerInputComponent cachedInput in workerInputCache.values) {
cachedInput.component.adoptChildren();
}
cachedSdkInput.component.unbindCanonicalNames();
cachedSdkInput.component.computeCanonicalNames();
// Reuse the incremental compiler, but reset as needed.
incrementalCompiler = oldState.incrementalCompiler;
incrementalCompiler.invalidateAllSources();
options.packagesFileUri = packagesFile;
options.fileSystem = fileSystem;
}
InitializedCompilerState compilerState = new InitializedCompilerState(
options, processedOpts,
workerInputCache: workerInputCache,
incrementalCompiler: incrementalCompiler);
CanonicalName nameRoot = cachedSdkInput.component.root;
List<int> loadFromDillIndexes = new List<int>();
// Notice that the ordering of the input summaries matter, so we need to
// keep them in order.
if (doneInputSummaries.length != inputSummaries.length) {
throw new ArgumentError("Invalid length.");
}
for (int i = 0; i < inputSummaries.length; i++) {
Uri inputSummary = inputSummaries[i];
WorkerInputComponent cachedInput = workerInputCache[inputSummary];
if (cachedInput == null ||
cachedInput.component.root != nameRoot ||
!digestsEqual(await fileSystem.entityForUri(inputSummary).readAsBytes(),
cachedInput.digest)) {
loadFromDillIndexes.add(i);
} else {
// Need to reset cached components so they are usable again.
var component = cachedInput.component;
for (var lib in component.libraries) {
lib.isExternal = cachedInput.externalLibs.contains(lib.importUri);
}
// We don't unbind as the root was unbound already. We do have to
// compute the canonical names though, to rebind everything in the
// component.
component.computeCanonicalNames();
doneInputSummaries[i] = component;
}
}
for (int i = 0; i < loadFromDillIndexes.length; i++) {
int index = loadFromDillIndexes[i];
Uri summary = inputSummaries[index];
List<int> data = await fileSystem.entityForUri(summary).readAsBytes();
WorkerInputComponent cachedInput = WorkerInputComponent(
data, await compilerState.processedOpts.loadComponent(data, nameRoot));
workerInputCache[summary] = cachedInput;
doneInputSummaries[index] = cachedInput.component;
}
incrementalCompiler.setModulesToLoadOnNextComputeDelta(doneInputSummaries);
return new InitializedCompilerState(options, processedOpts,
workerInputCache: workerInputCache,
incrementalCompiler: incrementalCompiler);
}
Future<DdcResult> compile(InitializedCompilerState compilerState,
List<Uri> inputs, DiagnosticMessageHandler diagnosticMessageHandler) async {
CompilerOptions options = compilerState.options;

View file

@ -32,8 +32,8 @@ main(List<String> args) async {
}
await new KernelWorker().run();
} else {
var succeeded = await computeKernel(args);
if (!succeeded) {
var result = await computeKernel(args);
if (!result.succeeded) {
exitCode = 15;
}
}
@ -41,13 +41,25 @@ main(List<String> args) async {
/// A bazel worker loop that can compute full or summary kernel files.
class KernelWorker extends AsyncWorkerLoop {
fe.InitializedCompilerState previousState;
Future<WorkResponse> performRequest(WorkRequest request) async {
var outputBuffer = new StringBuffer();
var response = new WorkResponse()..exitCode = 0;
try {
var succeeded = await computeKernel(request.arguments,
isWorker: true, outputBuffer: outputBuffer);
if (!succeeded) {
fe.InitializedCompilerState previousStateToPass;
if (request.arguments.contains("--reuse-compiler-result")) {
previousStateToPass = previousState;
} else {
previousState = null;
}
var result = await computeKernel(request.arguments,
isWorker: true,
outputBuffer: outputBuffer,
inputs: request.inputs,
previousState: previousStateToPass);
previousState = result.previousState;
if (!result.succeeded) {
response.exitCode = 15;
}
} catch (e, s) {
@ -105,7 +117,16 @@ final summaryArgsParser = new ArgParser()
..addOption('libraries-file')
..addOption('packages-file')
..addMultiOption('source')
..addOption('output');
..addOption('output')
..addFlag('reuse-compiler-result', defaultsTo: false)
..addFlag('use-incremental-compiler', defaultsTo: false);
class ComputeKernelResult {
final bool succeeded;
final fe.InitializedCompilerState previousState;
ComputeKernelResult(this.succeeded, this.previousState);
}
/// Computes a kernel file based on [args].
///
@ -115,8 +136,11 @@ final summaryArgsParser = new ArgParser()
/// instead of printed to the console.
///
/// Returns whether or not the summary was successfully output.
Future<bool> computeKernel(List<String> args,
{bool isWorker: false, StringBuffer outputBuffer}) async {
Future<ComputeKernelResult> computeKernel(List<String> args,
{bool isWorker: false,
StringBuffer outputBuffer,
Iterable<Input> inputs,
fe.InitializedCompilerState previousState}) async {
dynamic out = outputBuffer ?? stderr;
bool succeeded = true;
var parsedArgs = summaryArgsParser.parse(args);
@ -124,7 +148,7 @@ Future<bool> computeKernel(List<String> args,
if (parsedArgs['help']) {
out.writeln(summaryArgsParser.usage);
if (!isWorker) exit(0);
return false;
return new ComputeKernelResult(false, previousState);
}
// Bazel creates an overlay file system where some files may be located in the
@ -177,28 +201,75 @@ Future<bool> computeKernel(List<String> args,
var librariesSpec = parsedArgs['libraries-file'] == null
? null
: Uri.base.resolve(parsedArgs['libraries-file']);
var state = await fe.initializeCompiler(
// TODO(sigmund): pass an old state once we can make use of it.
null,
Uri.base.resolve(parsedArgs['dart-sdk-summary']),
librariesSpec,
Uri.base.resolve(parsedArgs['packages-file']),
(parsedArgs['input-summary'] as List<String>)
.map(Uri.base.resolve)
.toList(),
(parsedArgs['input-linked'] as List<String>)
.map(Uri.base.resolve)
.toList(),
target,
fileSystem);
List<Uri> linkedInputs = (parsedArgs['input-linked'] as List<String>)
.map(Uri.base.resolve)
.toList();
List<Uri> summaryInputs = (parsedArgs['input-summary'] as List<String>)
.map(Uri.base.resolve)
.toList();
fe.InitializedCompilerState state;
bool usingIncrementalCompiler = false;
if (parsedArgs['use-incremental-compiler'] && linkedInputs.isEmpty) {
usingIncrementalCompiler = true;
/// Build a map of uris to digests.
final inputDigests = <Uri, List<int>>{};
for (var input in inputs) {
var uri = Uri.parse(input.path);
if (uri.scheme.isEmpty) {
uri = Uri.parse('file://${input.path}');
}
inputDigests[uri] = input.digest;
}
state = await fe.initializeIncrementalCompiler(
previousState,
Uri.base.resolve(parsedArgs['dart-sdk-summary']),
Uri.base.resolve(parsedArgs['packages-file']),
librariesSpec,
summaryInputs,
inputDigests,
target,
fileSystem,
summaryOnly);
} else {
state = await fe.initializeCompiler(
// TODO(sigmund): pass an old state once we can make use of it.
null,
Uri.base.resolve(parsedArgs['dart-sdk-summary']),
librariesSpec,
Uri.base.resolve(parsedArgs['packages-file']),
summaryInputs,
linkedInputs,
target,
fileSystem);
}
void onDiagnostic(fe.DiagnosticMessage message) {
fe.printDiagnosticMessage(message, out.writeln);
succeeded = false;
}
var kernel =
await fe.compile(state, sources, onDiagnostic, summaryOnly: summaryOnly);
List<int> kernel;
if (usingIncrementalCompiler) {
state.options.onDiagnostic = onDiagnostic;
Component incrementalComponent = await state.incrementalCompiler
.computeDelta(entryPoints: sources, fullComponent: true);
if (summaryOnly) {
incrementalComponent.uriToSource.clear();
incrementalComponent.problemsAsJson = null;
incrementalComponent.mainMethod = null;
target.performOutlineTransformations(incrementalComponent);
}
kernel = fe.serializeComponent(incrementalComponent);
} else {
kernel = await fe.compile(state, sources, onDiagnostic,
summaryOnly: summaryOnly);
}
if (kernel != null) {
var outputFile = new File(parsedArgs['output']);
@ -208,7 +279,7 @@ Future<bool> computeKernel(List<String> args,
assert(!succeeded);
}
return succeeded;
return new ComputeKernelResult(succeeded, state);
}
/// Extends the DevCompilerTarget to transform outlines to meet the requirements