Store unlinked data with unlinked salt.

Before this change we used the whole AnalysisOptions.signature as salt.
This means that if two packages have different set of lints, they have
different options signatures, and so we have to parse and compute
unlinked data for SDK and all shared packages separately. But unlinked
data depends only on very small set of options, practically only on
parser options.

This improves performance on workspaces with many modules and empty
cache:

Before:
<= --- Analyzing in 36122 ms.
<= Computed implemented in: 50138 ms.

<= --- Analyzing in 47905 ms.
<= Computed implemented in: 55339 ms.

<= --- Analyzing in 45141 ms.
<= Computed implemented in: 60169 ms.


After:
<= --- Analyzing in 27957 ms.
<= Computed implemented in: 11645 ms.

<= --- Analyzing in 21378 ms.
<= Computed implemented in: 9439 ms.

<= --- Analyzing in 21719 ms.
<= Computed implemented in: 10546 ms.


Here "computed implemented" is computing subtypes of classes in the
open file - it required unlinked data for all files in all available
packages.


It also helps for full cache:
  analysis: 6300 vs. 5700 ms.
  implemented: 5700 vs. 3700 ms.



R=brianwilkerson@google.com, paulberry@google.com

Change-Id: I10dbc6d062617466ad5f35ae77bd1e58a6bb606c
Reviewed-on: https://dart-review.googlesource.com/75128
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Reviewed-by: Paul Berry <paulberry@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/test/src/plugin/plugin_watcher_test.dart b/pkg/analysis_server/test/src/plugin/plugin_watcher_test.dart
index 6029159..fde7e3f 100644
--- a/pkg/analysis_server/test/src/plugin/plugin_watcher_test.dart
+++ b/pkg/analysis_server/test/src/plugin/plugin_watcher_test.dart
@@ -142,6 +142,7 @@
         resourceProvider,
         sourceFactory,
         new AnalysisOptionsImpl(),
+        new Uint32List(0),
         new Uint32List(0));
     currentSession = new AnalysisSessionImpl(this);
   }
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index c032de3..4295352 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -32,6 +32,7 @@
         AnalysisContext,
         AnalysisEngine,
         AnalysisOptions,
+        AnalysisOptionsImpl,
         PerformanceStatistics;
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -92,7 +93,7 @@
   /**
    * The version of data format, should be incremented on every format change.
    */
-  static const int DATA_VERSION = 66;
+  static const int DATA_VERSION = 67;
 
   /**
    * The number of exception contexts allowed to write. Once this field is
@@ -139,7 +140,7 @@
   /**
    * The analysis options to analyze with.
    */
-  AnalysisOptions _analysisOptions;
+  AnalysisOptionsImpl _analysisOptions;
 
   /**
    * The optional SDK bundle, used when the client cannot read SDK files.
@@ -163,9 +164,16 @@
   final ContextRoot contextRoot;
 
   /**
-   * The salt to mix into all hashes used as keys for serialized data.
+   * The salt to mix into all hashes used as keys for unlinked data.
    */
-  final Uint32List _salt = new Uint32List(1 + AnalysisOptions.signatureLength);
+  final Uint32List _unlinkedSalt =
+      new Uint32List(1 + AnalysisOptionsImpl.unlinkedSignatureLength);
+
+  /**
+   * The salt to mix into all hashes used as keys for linked data.
+   */
+  final Uint32List _linkedSalt =
+      new Uint32List(1 + AnalysisOptions.signatureLength);
 
   /**
    * The set of priority files, that should be analyzed sooner.
@@ -841,7 +849,7 @@
     _throwIfNotAbsolutePath(path);
     var file = fsState.getFileForPath(path);
     ApiSignature signature = new ApiSignature();
-    signature.addUint32List(_salt);
+    signature.addUint32List(_linkedSalt);
     signature.addString(file.transitiveSignature);
     return signature;
   }
@@ -1338,8 +1346,15 @@
    */
   void _createFileTracker() {
     _fillSalt();
-    _fsState = new FileSystemState(_logger, _byteStore, _contentOverlay,
-        _resourceProvider, sourceFactory, analysisOptions, _salt,
+    _fsState = new FileSystemState(
+        _logger,
+        _byteStore,
+        _contentOverlay,
+        _resourceProvider,
+        sourceFactory,
+        analysisOptions,
+        _unlinkedSalt,
+        _linkedSalt,
         externalSummaries: _externalSummaries,
         parseExceptionHandler: _storeExceptionContextDuringParsing);
     _fileTracker = new FileTracker(_logger, _fsState, _changeHook);
@@ -1380,15 +1395,14 @@
   }
 
   /**
-   * Fill [_salt] with data.
+   * Fill [_unlinkedSalt] and [_linkedSalt] with data.
    */
   void _fillSalt() {
-    _salt[0] = DATA_VERSION;
-    List<int> crossContextOptions = _analysisOptions.signature;
-    assert(crossContextOptions.length == AnalysisOptions.signatureLength);
-    for (int i = 0; i < crossContextOptions.length; i++) {
-      _salt[i + 1] = crossContextOptions[i];
-    }
+    _unlinkedSalt[0] = DATA_VERSION;
+    _unlinkedSalt.setAll(1, _analysisOptions.unlinkedSignature);
+
+    _linkedSalt[0] = DATA_VERSION;
+    _linkedSalt.setAll(1, _analysisOptions.signature);
   }
 
   /**
@@ -1458,7 +1472,7 @@
    */
   String _getResolvedUnitSignature(FileState library, FileState file) {
     ApiSignature signature = new ApiSignature();
-    signature.addUint32List(_salt);
+    signature.addUint32List(_linkedSalt);
     signature.addString(library.transitiveSignature);
     signature.addString(file.contentHash);
     return signature.toHex();
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 8264349..6fc964a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -356,7 +356,7 @@
   String get transitiveSignature {
     if (_transitiveSignature == null) {
       ApiSignature signature = new ApiSignature();
-      signature.addUint32List(_fsState._salt);
+      signature.addUint32List(_fsState._linkedSalt);
       signature.addInt(transitiveFiles.length);
       transitiveFiles
           .map((file) => file.apiSignature)
@@ -424,7 +424,7 @@
     String unlinkedKey;
     {
       var signature = new ApiSignature();
-      signature.addUint32List(_fsState._salt);
+      signature.addUint32List(_fsState._unlinkedSalt);
       signature.addString(_contentHash);
 
       var signatureHex = signature.toHex();
@@ -707,7 +707,8 @@
   final FileContentOverlay _contentOverlay;
   final SourceFactory _sourceFactory;
   final AnalysisOptions _analysisOptions;
-  final Uint32List _salt;
+  final Uint32List _unlinkedSalt;
+  final Uint32List _linkedSalt;
 
   /**
    * The optional store with externally provided unlinked and corresponding
@@ -789,7 +790,8 @@
     this._resourceProvider,
     this._sourceFactory,
     this._analysisOptions,
-    this._salt, {
+    this._unlinkedSalt,
+    this._linkedSalt, {
     this.externalSummaries,
     this.parseExceptionHandler,
   }) {
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 20824a9..75b6951 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1136,7 +1136,7 @@
  */
 abstract class AnalysisOptions {
   /**
-   * The length of the list returned by [encodeCrossContextOptions].
+   * The length of the list returned by [signature].
    */
   static const int signatureLength = 4;
 
@@ -1377,6 +1377,11 @@
   static const List<String> NONNULLABLE_TYPES = const <String>[];
 
   /**
+   * The length of the list returned by [unlinkedSignature].
+   */
+  static const int unlinkedSignatureLength = 4;
+
+  /**
    * A predicate indicating whether analysis is to parse and analyze function
    * bodies.
    */
@@ -1384,6 +1389,11 @@
       _analyzeAllFunctionBodies;
 
   /**
+   * The cached [unlinkedSignature].
+   */
+  Uint32List _unlinkedSignature;
+
+  /**
    * The cached [signature].
    */
   Uint32List _signature;
@@ -1705,6 +1715,26 @@
       "The strongMode field is deprecated, and shouldn't be assigned to")
   set strongMode(bool value) {}
 
+  /**
+   * Return the opaque signature of the options that affect unlinked data.
+   *
+   * The length of the list is guaranteed to equal [unlinkedSignatureLength].
+   */
+  Uint32List get unlinkedSignature {
+    if (_unlinkedSignature == null) {
+      ApiSignature buffer = new ApiSignature();
+
+      // Append boolean flags.
+      buffer.addBool(enableLazyAssignmentOperators);
+      buffer.addBool(useFastaParser);
+
+      // Hash and convert to Uint32List.
+      List<int> bytes = buffer.toByteList();
+      _unlinkedSignature = new Uint8List.fromList(bytes).buffer.asUint32List();
+    }
+    return _unlinkedSignature;
+  }
+
   @override
   void resetToDefaults() {
     declarationCasts = true;
diff --git a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
index f83688a..0379c6b 100644
--- a/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/file_state_test.dart
@@ -58,8 +58,15 @@
       new ResourceUriResolver(provider)
     ], null, provider);
     AnalysisOptions analysisOptions = new AnalysisOptionsImpl();
-    fileSystemState = new FileSystemState(logger, byteStore, contentOverlay,
-        provider, sourceFactory, analysisOptions, new Uint32List(0));
+    fileSystemState = new FileSystemState(
+        logger,
+        byteStore,
+        contentOverlay,
+        provider,
+        sourceFactory,
+        analysisOptions,
+        new Uint32List(0),
+        new Uint32List(0));
   }
 
   test_definedClassMemberNames() {
diff --git a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
index 0686064..ad20641 100644
--- a/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/unlinked_api_signature_test.dart
@@ -72,6 +72,7 @@
         resourceProvider,
         sourceFactory,
         new AnalysisOptionsImpl(),
+        new Uint32List(0),
         new Uint32List(0));
   }
 
diff --git a/pkg/analyzer_cli/lib/src/build_mode.dart b/pkg/analyzer_cli/lib/src/build_mode.dart
index 729ce0d..051a098 100644
--- a/pkg/analyzer_cli/lib/src/build_mode.dart
+++ b/pkg/analyzer_cli/lib/src/build_mode.dart
@@ -425,7 +425,7 @@
         new FileContentOverlay(),
         null,
         sourceFactory,
-        analysisOptions,
+        analysisOptions as AnalysisOptionsImpl,
         externalSummaries: summaryDataStore);
     analysisDriver.declaredVariables =
         new DeclaredVariables.fromMap(options.definedVariables);