Use worker input digests for ddk instead of reading the full file bytes.

Also actually compare the SDK summary digest instead of assuming it doesn't change.

Most of this logic is mirroring logic in the bazel_worker.dart file that kernel uses, which eventually we should unify.

Change-Id: If33af0d8de0b0a6a17081dcd852dd036c4b34a82
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107184
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Vijay Menon <vsm@google.com>
Commit-Queue: Jake Macdonald <jakemac@google.com>
diff --git a/pkg/dev_compiler/bin/dartdevc.dart b/pkg/dev_compiler/bin/dartdevc.dart
index db2f7b8..276320d 100755
--- a/pkg/dev_compiler/bin/dartdevc.dart
+++ b/pkg/dev_compiler/bin/dartdevc.dart
@@ -52,7 +52,20 @@
     var args = _startupArgs.merge(request.arguments);
     var output = StringBuffer();
     var context = args.reuseResult ? lastResult : null;
-    lastResult = await runZoned(() => compile(args, previousResult: context),
+
+    /// Build a map of uris to digests.
+    final inputDigests = <Uri, List<int>>{};
+    for (var input in request.inputs) {
+      var uri = Uri.parse(input.path);
+      if (uri.scheme.isEmpty) {
+        uri = Uri.parse('file://${input.path}');
+      }
+      inputDigests[uri] = input.digest;
+    }
+
+    lastResult = await runZoned(
+        () =>
+            compile(args, previousResult: context, inputDigests: inputDigests),
         zoneSpecification:
             ZoneSpecification(print: (self, parent, zone, message) {
       output.writeln(message.toString());
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index 0388456..c30e7a9 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -400,7 +400,7 @@
 /// The result may also contain a [previousResult], which can be passed back in
 /// for batch/worker executions to attempt to existing state.
 Future<CompilerResult> compile(ParsedArguments args,
-    {CompilerResult previousResult}) {
+    {CompilerResult previousResult, Map<Uri, List<int>> inputDigests}) {
   if (previousResult != null && !args.isBatchOrWorker) {
     throw ArgumentError(
         'previousResult requires --batch or --bazel_worker mode/');
@@ -408,7 +408,8 @@
   if (args.isKernel) {
     return kernel_compiler.compile(args.rest,
         compilerState: previousResult?.kernelState,
-        useIncrementalCompiler: args.useIncrementalCompiler);
+        useIncrementalCompiler: args.useIncrementalCompiler,
+        inputDigests: inputDigests);
   } else {
     var result = analyzer_compiler.compile(args.rest,
         compilerState: previousResult?.analyzerState);
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index ca85c12..ecd4d84 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -37,11 +37,13 @@
 /// Returns `true` if the program compiled without any fatal errors.
 Future<CompilerResult> compile(List<String> args,
     {fe.InitializedCompilerState compilerState,
-    bool useIncrementalCompiler = false}) async {
+    bool useIncrementalCompiler = false,
+    Map<Uri, List<int>> inputDigests}) async {
   try {
     return await _compile(args,
         compilerState: compilerState,
-        useIncrementalCompiler: useIncrementalCompiler);
+        useIncrementalCompiler: useIncrementalCompiler,
+        inputDigests: inputDigests);
   } catch (error, stackTrace) {
     print('''
 We're sorry, you've found a bug in our compiler.
@@ -68,7 +70,8 @@
 
 Future<CompilerResult> _compile(List<String> args,
     {fe.InitializedCompilerState compilerState,
-    bool useIncrementalCompiler = false}) async {
+    bool useIncrementalCompiler = false,
+    Map<Uri, List<int>> inputDigests}) async {
   // TODO(jmesserly): refactor options to share code with dartdevc CLI.
   var argParser = ArgParser(allowTrailingOptions: true)
     ..addFlag('help',
@@ -253,6 +256,7 @@
         sourcePathToUri(packageFile),
         sourcePathToUri(librarySpecPath),
         summaryModules.keys.toList(),
+        inputDigests,
         DevCompilerTarget(
             TargetFlags(trackWidgetCreation: trackWidgetCreation)),
         fileSystem: fileSystem,
diff --git a/pkg/front_end/lib/src/api_unstable/ddc.dart b/pkg/front_end/lib/src/api_unstable/ddc.dart
index 4c2076b..a344601 100644
--- a/pkg/front_end/lib/src/api_unstable/ddc.dart
+++ b/pkg/front_end/lib/src/api_unstable/ddc.dart
@@ -131,6 +131,7 @@
     Uri packagesFile,
     Uri librariesSpecificationUri,
     List<Uri> inputSummaries,
+    Map<Uri, List<int>> workerInputDigests,
     Target target,
     {FileSystem fileSystem,
     Map<ExperimentalFlag, bool> experiments}) async {
@@ -143,12 +144,18 @@
 
   Map<Uri, WorkerInputComponent> workerInputCache =
       oldState?.workerInputCache ?? new Map<Uri, WorkerInputComponent>();
+  var sdkDigest = workerInputDigests[sdkSummary];
+  if (sdkDigest == null) {
+    throw new StateError("Expected to get sdk digest at $cachedSdkInput");
+  }
+
   cachedSdkInput = workerInputCache[sdkSummary];
 
   if (oldState == null ||
       oldState.incrementalCompiler == null ||
       oldState.options.compileSdk != compileSdk ||
-      cachedSdkInput == null) {
+      cachedSdkInput == null ||
+      !digestsEqual(cachedSdkInput.digest, sdkDigest)) {
     // No previous state.
     options = new CompilerOptions()
       ..compileSdk = compileSdk
@@ -166,8 +173,8 @@
 
     processedOpts = new ProcessedOptions(options: options);
 
-    cachedSdkInput = new WorkerInputComponent(null /* not compared anyway */,
-        await processedOpts.loadSdkSummary(null));
+    cachedSdkInput = new WorkerInputComponent(
+        sdkDigest, await processedOpts.loadSdkSummary(null));
     workerInputCache[sdkSummary] = cachedSdkInput;
     incrementalCompiler = new IncrementalCompiler.fromComponent(
         new CompilerContext(processedOpts), cachedSdkInput.component);
@@ -207,10 +214,13 @@
   for (int i = 0; i < inputSummaries.length; i++) {
     Uri inputSummary = inputSummaries[i];
     WorkerInputComponent cachedInput = workerInputCache[inputSummary];
+    var digest = workerInputDigests[inputSummary];
+    if (digest == null) {
+      throw new StateError("Expected to get digest for $inputSummary");
+    }
     if (cachedInput == null ||
         cachedInput.component.root != nameRoot ||
-        !digestsEqual(await fileSystem.entityForUri(inputSummary).readAsBytes(),
-            cachedInput.digest)) {
+        !digestsEqual(digest, cachedInput.digest)) {
       loadFromDillIndexes.add(i);
     } else {
       // Need to reset cached components so they are usable again.
@@ -226,11 +236,15 @@
   for (int i = 0; i < loadFromDillIndexes.length; i++) {
     int index = loadFromDillIndexes[i];
     Uri summary = inputSummaries[index];
-    List<int> data = await fileSystem.entityForUri(summary).readAsBytes();
+    List<int> digest = workerInputDigests[summary];
+    if (digest == null) {
+      throw new StateError("Expected to get digest for $summary");
+    }
+    var bytes = await fileSystem.entityForUri(summary).readAsBytes();
     WorkerInputComponent cachedInput = WorkerInputComponent(
-        data,
+        digest,
         await compilerState.processedOpts
-            .loadComponent(data, nameRoot, alwaysCreateNewNamedNodes: true));
+            .loadComponent(bytes, nameRoot, alwaysCreateNewNamedNodes: true));
     workerInputCache[summary] = cachedInput;
     doneInputSummaries[index] = cachedInput.component;
   }