[standalone] Record dependencies in DFE and include them in snapshot depfiles.
Bug: https://github.com/dart-lang/sdk/issues/33390
Change-Id: Ib1ce6078ccff1b8727c26a8ff7b24e9fb99fd086
Reviewed-on: https://dart-review.googlesource.com/60020
Reviewed-by: Zach Anderson <zra@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 8bd4fe4..20ed01c 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -21,6 +21,7 @@
library runtime.tools.kernel_service;
import 'dart:async' show Future, ZoneSpecification, runZoned;
+import 'dart:convert' show utf8;
import 'dart:io' show Platform, stderr hide FileSystemEntity;
import 'dart:isolate';
import 'dart:typed_data' show Uint8List;
@@ -38,7 +39,7 @@
import 'package:kernel/target/vm.dart' show VmTarget;
import 'package:vm/incremental_compiler.dart';
-const bool verbose = const bool.fromEnvironment('DFE_VERBOSE');
+final bool verbose = new bool.fromEnvironment('DFE_VERBOSE');
const String platformKernelFile = 'virtual_platform_kernel.dill';
// NOTE: Any changes to these tags need to be reflected in kernel_isolate.cc
@@ -51,11 +52,13 @@
// 3 - APP JIT snapshot training run for kernel_service.
// 4 - Compile an individual expression in some context (for debugging
// purposes).
+// 5 - List program dependencies (for creating depfiles)
const int kCompileTag = 0;
const int kUpdateSourcesTag = 1;
const int kAcceptTag = 2;
const int kTrainTag = 3;
const int kCompileExpressionTag = 4;
+const int kListDependenciesTag = 5;
bool allowDartInternalImport = false;
@@ -182,8 +185,10 @@
}
}
+// TODO(33428): This state is leaked on isolate shutdown.
final Map<int, IncrementalCompilerWrapper> isolateCompilers =
new Map<int, IncrementalCompilerWrapper>();
+final Map<int, List<Uri>> isolateDependencies = new Map<int, List<Uri>>();
IncrementalCompilerWrapper lookupIncrementalCompiler(int isolateId) {
return isolateCompilers[isolateId];
@@ -294,6 +299,54 @@
port.send(result.toResponse());
}
+void _recordDependencies(
+ int isolateId, Component component, String packageConfig) {
+ final dependencies = isolateDependencies[isolateId] ??= new List<Uri>();
+
+ for (var lib in component.libraries) {
+ if (lib.importUri.scheme == "dart") continue;
+
+ dependencies.add(lib.fileUri);
+ for (var part in lib.parts) {
+ final fileUri = lib.fileUri.resolve(part.partUri);
+ if (fileUri.scheme != "" && fileUri.scheme != "file") {
+ // E.g. part 'package:foo/foo.dart';
+ // Maybe the front end should resolve this?
+ continue;
+ }
+ dependencies.add(fileUri);
+ }
+ }
+
+ if (packageConfig != null) {
+ dependencies.add(Uri.parse(packageConfig));
+ }
+}
+
+String _escapeDependency(Uri uri) {
+ return uri.toFilePath().replaceAll("\\", "\\\\").replaceAll(" ", "\\ ");
+}
+
+List<int> _serializeDependencies(List<Uri> uris) {
+ return utf8.encode(uris.map(_escapeDependency).join(" "));
+}
+
+Future _processListDependenciesRequest(request) async {
+ final SendPort port = request[1];
+ final int isolateId = request[6];
+
+ final List<Uri> dependencies = isolateDependencies[isolateId] ?? <Uri>[];
+
+ CompilationResult result;
+ try {
+ result = new CompilationResult.ok(_serializeDependencies(dependencies));
+ } catch (error, stack) {
+ result = new CompilationResult.crash(error, stack);
+ }
+
+ port.send(result.toResponse());
+}
+
Future _processLoadRequest(request) async {
if (verbose) print("DFE: request: $request");
@@ -304,6 +357,11 @@
return;
}
+ if (tag == kListDependenciesTag) {
+ await _processListDependenciesRequest(request);
+ return;
+ }
+
final SendPort port = request[1];
final String inputFileUri = request[2];
final Uri script =
@@ -387,6 +445,7 @@
}
Component component = await compiler.compile(script);
+ _recordDependencies(isolateId, component, packageConfig);
if (compiler.errors.isNotEmpty) {
result = new CompilationResult.errors(compiler.errors,
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 67d681b..4bddd36a 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -1528,12 +1528,19 @@
if (app_script_name != NULL) {
dfe.ReadScript(app_script_name, &kernel_buffer, &kernel_buffer_size);
}
- if (kernel_buffer != NULL && !SnapshotKindAllowedFromKernel()) {
- // TODO(sivachandra): Add check for the kernel program format (incremental
- // vs batch).
- Log::PrintErr(
- "Can only generate core or aot snapshots from a kernel file.\n");
- return kErrorExitCode;
+ if (kernel_buffer != NULL) {
+ if (!SnapshotKindAllowedFromKernel()) {
+ // TODO(sivachandra): Add check for the kernel program format (incremental
+ // vs batch).
+ Log::PrintErr(
+ "Can only generate core or aot snapshots from a kernel file.\n");
+ return kErrorExitCode;
+ }
+ if ((dependencies_filename != NULL) || print_dependencies ||
+ dependencies_only) {
+ Log::PrintErr("Depfiles are not supported in Dart 2.\n");
+ return kErrorExitCode;
+ }
}
if (!Platform::Initialize()) {
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 01e11b7..b3c71de 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -193,6 +193,17 @@
success &= file->Print("%s ", dep);
free(dep);
}
+ if (Options::preview_dart_2()) {
+ Dart_KernelCompilationResult result = Dart_KernelListDependencies();
+ if (result.status != Dart_KernelCompilationStatus_Ok) {
+ ErrorExit(
+ kErrorExitCode,
+ "Error: Failed to fetch dependencies from kernel service: %s\n\n",
+ result.error);
+ }
+ success &= file->WriteFully(result.kernel, result.kernel_size);
+ free(result.kernel);
+ }
success &= file->Print("\n");
if (!success) {
ErrorExit(kErrorExitCode, "Error: Unable to write snapshot depfile: %s\n\n",
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index b5bdd1a..8fc3f17 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3199,6 +3199,8 @@
*
*/
+// TODO(33433): Remove kernel service from the embedding API.
+
typedef enum {
Dart_KernelCompilationStatus_Unknown = -1,
Dart_KernelCompilationStatus_Ok = 0,
@@ -3237,6 +3239,8 @@
bool incremental_compile,
const char* package_config);
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies();
+
#define DART_KERNEL_ISOLATE_NAME "kernel-service"
/*
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 201b5b9..b51735f 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5905,7 +5905,6 @@
#if defined(DART_PRECOMPILED_RUNTIME)
result.status = Dart_KernelCompilationStatus_Unknown;
result.error = strdup("Dart_CompileToKernel is unsupported.");
- return result;
#else
result = KernelIsolate::CompileToKernel(script_uri, platform_kernel,
platform_kernel_size, 0, NULL,
@@ -5918,8 +5917,8 @@
" compilation results.");
}
}
- return result;
#endif
+ return result;
}
DART_EXPORT Dart_KernelCompilationResult
@@ -5934,7 +5933,6 @@
#if defined(DART_PRECOMPILED_RUNTIME)
result.status = Dart_KernelCompilationStatus_Unknown;
result.error = strdup("Dart_CompileSourcesToKernel is unsupported.");
- return result;
#else
result = KernelIsolate::CompileToKernel(
script_uri, platform_kernel, platform_kernel_size, source_files_count,
@@ -5947,9 +5945,19 @@
" compilation results.");
}
}
- return result;
-
#endif
+ return result;
+}
+
+DART_EXPORT Dart_KernelCompilationResult Dart_KernelListDependencies() {
+ Dart_KernelCompilationResult result;
+#if defined(DART_PRECOMPILED_RUNTIME)
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Dart_KernelListDependencies is unsupported.");
+#else
+ result = KernelIsolate::ListDependencies();
+#endif
+ return result;
}
// --- Service support ---
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index f0b47d5..64b6982 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -53,6 +53,7 @@
const int KernelIsolate::kAcceptTag = 2;
const int KernelIsolate::kTrainTag = 3;
const int KernelIsolate::kCompileExpressionTag = 4;
+const int KernelIsolate::kListDependenciesTag = 5;
Dart_IsolateCreateCallback KernelIsolate::create_callback_ = NULL;
Monitor* KernelIsolate::monitor_ = new Monitor();
@@ -716,6 +717,20 @@
incremental_compile, package_config);
}
+Dart_KernelCompilationResult KernelIsolate::ListDependencies() {
+ Dart_Port kernel_port = WaitForKernelPort();
+ if (kernel_port == ILLEGAL_PORT) {
+ Dart_KernelCompilationResult result;
+ result.status = Dart_KernelCompilationStatus_Unknown;
+ result.error = strdup("Error while initializing Kernel isolate");
+ return result;
+ }
+
+ KernelCompilationRequest request;
+ return request.SendAndWaitForResponse(kListDependenciesTag, kernel_port, NULL,
+ NULL, 0, 0, NULL, false, NULL);
+}
+
Dart_KernelCompilationResult KernelIsolate::AcceptCompilation() {
// This must be the main script to be loaded. Wait for Kernel isolate
// to finish initialization.
diff --git a/runtime/vm/kernel_isolate.h b/runtime/vm/kernel_isolate.h
index 2e45b52..d888630 100644
--- a/runtime/vm/kernel_isolate.h
+++ b/runtime/vm/kernel_isolate.h
@@ -16,6 +16,8 @@
namespace dart {
+// TODO(33433): The kernel service does not belong in the VM.
+
class KernelIsolate : public AllStatic {
public:
static const char* kName;
@@ -24,6 +26,7 @@
static const int kAcceptTag;
static const int kTrainTag;
static const int kCompileExpressionTag;
+ static const int kListDependenciesTag;
static void Run();
@@ -56,6 +59,8 @@
const char* klass,
bool is_static);
+ static Dart_KernelCompilationResult ListDependencies();
+
protected:
static Monitor* monitor_;
static Dart_IsolateCreateCallback create_callback_;