mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
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:
parent
a506c708f2
commit
b7f69e24a2
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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?
|
||||
//
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue