| Index: utils/kernel-service/kernel-service.dart
|
| diff --git a/utils/kernel-service/kernel-service.dart b/utils/kernel-service/kernel-service.dart
|
| index 92cb34eb2da696525bf4b9982f17e9839399e0c0..cd5ae0ca70a75cb02189cff016fa9163875b6de5 100644
|
| --- a/utils/kernel-service/kernel-service.dart
|
| +++ b/utils/kernel-service/kernel-service.dart
|
| @@ -21,12 +21,14 @@
|
| library runtime.tools.kernel_service;
|
|
|
| import 'dart:async' show Future;
|
| +import 'dart:convert' show JSON;
|
| import 'dart:io' show Platform hide FileSystemEntity;
|
| import 'dart:isolate';
|
| import 'dart:typed_data' show Uint8List;
|
|
|
| import 'package:front_end/file_system.dart';
|
| import 'package:front_end/front_end.dart';
|
| +import 'package:front_end/incremental_kernel_generator.dart';
|
| import 'package:front_end/memory_file_system.dart';
|
| import 'package:front_end/physical_file_system.dart';
|
| import 'package:front_end/src/fasta/kernel/utils.dart';
|
| @@ -38,6 +40,119 @@ import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
|
| const bool verbose = const bool.fromEnvironment('DFE_VERBOSE');
|
| const bool strongMode = const bool.fromEnvironment('DFE_STRONG_MODE');
|
|
|
| +abstract class Compiler {
|
| + final FileSystem fileSystem;
|
| + final List<String> errors = new List<String>();
|
| +
|
| + CompilerOptions options;
|
| +
|
| + Compiler(this.fileSystem) {
|
| + Uri packagesUri = (Platform.packageConfig != null)
|
| + ? Uri.parse(Platform.packageConfig)
|
| + : null;
|
| +
|
| + Uri sdkSummary = Uri.base
|
| + .resolveUri(new Uri.file(Platform.resolvedExecutable))
|
| + .resolveUri(new Uri.directory("patched_sdk"))
|
| + // TODO(sigmund): use outline.dill when the mixin transformer is
|
| + // modular.
|
| + .resolve('platform.dill');
|
| +
|
| + if (verbose) {
|
| + print("DFE: Platform.packageConfig: ${Platform.packageConfig}");
|
| + print("DFE: packagesUri: ${packagesUri}");
|
| + print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}");
|
| + print("DFE: sdkSummary: ${sdkSummary}");
|
| + }
|
| +
|
| + options = new CompilerOptions()
|
| + ..strongMode = strongMode
|
| + ..fileSystem = fileSystem
|
| + ..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode))
|
| + ..packagesFileUri = packagesUri
|
| + ..sdkSummary = sdkSummary
|
| + ..verbose = verbose
|
| + ..throwOnErrors = false
|
| + ..reportMessages = true
|
| + ..onError = (CompilationMessage e) {
|
| + if (e.severity == Severity.error) {
|
| + // TODO(sigmund): support emitting code with errors as long as they
|
| + // are handled in the generated code (issue #30194).
|
| + errors.add(e.message);
|
| + }
|
| + };
|
| + }
|
| +
|
| + Future<Program> compile(Uri script);
|
| +}
|
| +
|
| +class IncrementalCompiler extends Compiler {
|
| + IncrementalKernelGenerator generator;
|
| +
|
| + IncrementalCompiler(FileSystem fileSystem) : super(fileSystem);
|
| +
|
| + @override
|
| + Future<Program> compile(Uri script) async {
|
| + if (generator == null) {
|
| + generator = await IncrementalKernelGenerator.newInstance(options, script);
|
| + }
|
| + DeltaProgram deltaProgram = await generator.computeDelta();
|
| + // TODO(aam): Accepting/rejecting should be done based on VM response.
|
| + generator.acceptLastDelta();
|
| + return deltaProgram.newProgram;
|
| + }
|
| +
|
| + void invalidate(Uri uri) {
|
| + generator.invalidate(uri);
|
| + }
|
| +}
|
| +
|
| +class SingleShotCompiler extends Compiler {
|
| + final bool requireMain;
|
| +
|
| + SingleShotCompiler(FileSystem fileSystem, this.requireMain)
|
| + : super(fileSystem);
|
| +
|
| + @override
|
| + Future<Program> compile(Uri script) async {
|
| + return requireMain
|
| + ? kernelForProgram(script, options)
|
| + : kernelForBuildUnit([script], options..chaseDependencies = true);
|
| + }
|
| +}
|
| +
|
| +final Map<int, Compiler> isolateCompilers = new Map<int, Compiler>();
|
| +
|
| +Future<Compiler> lookupOrBuildNewIncrementalCompiler(
|
| + int isolateId, List sourceFiles) async {
|
| + IncrementalCompiler compiler;
|
| + if (isolateCompilers.containsKey(isolateId)) {
|
| + compiler = isolateCompilers[isolateId];
|
| + final HybridFileSystem fileSystem = compiler.fileSystem;
|
| + if (sourceFiles != null) {
|
| + for (int i = 0; i < sourceFiles.length ~/ 2; i++) {
|
| + Uri uri = Uri.parse(sourceFiles[i * 2]);
|
| + fileSystem.memory
|
| + .entityForUri(uri)
|
| + .writeAsBytesSync(sourceFiles[i * 2 + 1]);
|
| + compiler.invalidate(uri);
|
| + }
|
| + }
|
| + } else {
|
| + final FileSystem fileSystem = sourceFiles == null
|
| + ? PhysicalFileSystem.instance
|
| + : _buildFileSystem(sourceFiles);
|
| +
|
| + // TODO(aam): IncrementalCompiler instance created below have to be
|
| + // destroyed when corresponding isolate is shut down. To achieve that kernel
|
| + // isolate needs to receive a message indicating that particular
|
| + // isolate was shut down. Message should be handled here in this script.
|
| + compiler = new IncrementalCompiler(fileSystem);
|
| + isolateCompilers[isolateId] = compiler;
|
| + }
|
| + return compiler;
|
| +}
|
| +
|
| // Process a request from the runtime. See KernelIsolate::CompileToKernel in
|
| // kernel_isolate.cc and Loader::SendKernelRequest in loader.cc.
|
| Future _processLoadRequest(request) async {
|
| @@ -47,66 +162,44 @@ Future _processLoadRequest(request) async {
|
| final SendPort port = request[1];
|
| final String inputFileUri = request[2];
|
| final Uri script = Uri.base.resolve(inputFileUri);
|
| -
|
| - FileSystem fileSystem = PhysicalFileSystem.instance;
|
| - bool requireMain = true;
|
| -
|
| - if (request.length > 3) {
|
| - fileSystem = _buildFileSystem(request[3]);
|
| - requireMain = false;
|
| - }
|
| -
|
| - Uri packagesUri = (Platform.packageConfig != null)
|
| - ? Uri.parse(Platform.packageConfig)
|
| - : null;
|
| -
|
| - Uri sdkSummary = Uri.base
|
| - .resolveUri(new Uri.file(Platform.resolvedExecutable))
|
| - .resolveUri(new Uri.directory("patched_sdk"))
|
| - // TODO(sigmund): use outline.dill when the mixin transformer is modular.
|
| - .resolve('platform.dill');
|
| -
|
| - if (verbose) {
|
| - print("DFE: scriptUri: ${script}");
|
| - print("DFE: Platform.packageConfig: ${Platform.packageConfig}");
|
| - print("DFE: packagesUri: ${packagesUri}");
|
| - print("DFE: Platform.resolvedExecutable: ${Platform.resolvedExecutable}");
|
| - print("DFE: sdkSummary: ${sdkSummary}");
|
| + final bool incremental = request[3];
|
| +
|
| + final List sourceFiles = request.length > 5 ? request[5] : null;
|
| +
|
| + Compiler compiler;
|
| + // TODO(aam): There should be no need to have an option to choose
|
| + // one compiler or another. We should always use an incremental
|
| + // compiler as its functionality is a super set of the other one. We need to
|
| + // watch the performance though.
|
| + if (incremental) {
|
| + final int isolateId = request[4];
|
| + compiler =
|
| + await lookupOrBuildNewIncrementalCompiler(isolateId, sourceFiles);
|
| + } else {
|
| + final FileSystem fileSystem = sourceFiles == null
|
| + ? PhysicalFileSystem.instance
|
| + : _buildFileSystem(sourceFiles);
|
| + compiler = new SingleShotCompiler(
|
| + fileSystem, sourceFiles == null /* requireMain */);
|
| }
|
|
|
| - var errors = <String>[];
|
| - var options = new CompilerOptions()
|
| - ..strongMode = strongMode
|
| - ..fileSystem = fileSystem
|
| - ..target = new VmFastaTarget(new TargetFlags(strongMode: strongMode))
|
| - ..packagesFileUri = packagesUri
|
| - ..sdkSummary = sdkSummary
|
| - ..verbose = verbose
|
| - ..throwOnErrors = false
|
| - ..reportMessages = true
|
| - ..onError = (CompilationMessage e) {
|
| - if (e.severity == Severity.error) {
|
| - // TODO(sigmund): support emitting code with errors as long as they are
|
| - // handled in the generated code (issue #30194).
|
| - errors.add(e.message);
|
| - }
|
| - };
|
| -
|
| CompilationResult result;
|
| try {
|
| - Program program = requireMain
|
| - ? await kernelForProgram(script, options)
|
| - : await kernelForBuildUnit([script], options..chaseDependencies = true);
|
| + if (verbose) {
|
| + print("DFE: scriptUri: ${script}");
|
| + }
|
| +
|
| + Program program = await compiler.compile(script);
|
|
|
| - if (errors.isNotEmpty) {
|
| + if (compiler.errors.isNotEmpty) {
|
| // TODO(sigmund): the compiler prints errors to the console, so we
|
| // shouldn't print those messages again here.
|
| - result = new CompilationResult.errors(errors);
|
| + result = new CompilationResult.errors(compiler.errors);
|
| } else {
|
| // We serialize the program excluding platform.dill because the VM has
|
| // these sources built-in. Everything loaded as a summary in
|
| // [kernelForProgram] is marked `external`, so we can use that bit to
|
| - // decide what to excluce.
|
| + // decide what to exclude.
|
| // TODO(sigmund): remove the following line (Issue #30111)
|
| program.libraries.forEach((e) => e.isExternal = false);
|
| result = new CompilationResult.ok(
|
| @@ -166,7 +259,13 @@ train(String scriptUri) {
|
| throw "Unexpected response: $response";
|
| }
|
| };
|
| - var request = [tag, responsePort.sendPort, scriptUri];
|
| + var request = [
|
| + tag,
|
| + responsePort.sendPort,
|
| + scriptUri,
|
| + 1 /* isolateId chosen randomly */,
|
| + false /* incremental */
|
| + ];
|
| _processLoadRequest(request);
|
| }
|
|
|
|
|