[analyzer] Deduplicate _Info* instances

When having several contexts we'll end up having many copies of the same
_Info* instances. This CL deduplicates it.
TL;DR: On flutter/flutter (82 contexts) this, when run from a clean
cache, reduces the memory usage by 600-800 MB (~15%).

Details:

All numbers from runs made from analyzer source with a clean cache on
flutter/flutter (82 contexts), memory usage after a forced GC:

Runtime:
No difference proven at 95.0% confidence

Current memory (GB):
Difference at 95.0% confidence
        -0.683333 +/- 0.0627592
        -13.3987% +/- 1.23057%
        (Student's t, pooled s = 0.0276887)

Peak memory (GB):
Difference at 95.0% confidence
        -0.643333 +/- 0.0746028
        -12.5243% +/- 1.45236%
        (Student's t, pooled s = 0.032914)

Heap (used) (GB):
Difference at 95.0% confidence
        -0.77 +/- 0
        -17.5799% +/- 0%
        (Student's t, pooled s = 0)

Heap (capacity) (GB):
Difference at 95.0% confidence
        -0.69 +/- 0.05552
        -15.2993% +/- 1.23104%
        (Student's t, pooled s = 0.0244949)

_List (MB):
Difference at 95.0% confidence
        -59.2333 +/- 0.0925333
        -6.91547% +/- 0.0108032%
        (Student's t, pooled s = 0.0408248)

_Uint32List (MB):
Difference at 95.0% confidence
        -105.433 +/- 1.06715
        -17.3382% +/- 0.175489%
        (Student's t, pooled s = 0.470815)

_OneByteString (MB):
Difference at 95.0% confidence
        -403.667 +/- 2.37542
        -58.1206% +/- 0.342017%
        (Student's t, pooled s = 1.04801)

Raw data:

NOW:

Runtime (ms): 151855
current memory	4.46GB
peak memory	4.54GB
heap 3.61GB of 3.86GB
797.3 MB 6067774 _List
503.1 MB 2574937 _Uint32List
291.7 MB 2233396 _OneByteString
233.0 MB 338029 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901830 _Map

Runtime (ms): 152410
current memory	4.40GB
peak memory	4.49GB
heap 3.61GB of 3.80GB
797.3 MB 6067637 _List
503.0 MB 2574976 _Uint32List
290.7 MB 2232326 _OneByteString
226.8 MB 339447 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901830 _Map

Runtime (ms): 153205
current memory	4.39GB
peak memory	4.45GB
heap 3.61GB of 3.80GB
797.3 MB 6067638 _List
501.9 MB 2556644 _Uint32List
290.2 MB 2235718 _OneByteString
226.7 MB 338584 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901830 _Map




BEFORE:

Runtime (ms): 159178
current memory	5.09GB
peak memory	5.15GB
heap 4.38GB of 4.51GB
856.6 MB 7366027 _List
696.0 MB 3780593 _OneByteString
608.1 MB 5239817 _Uint32List
226.9 MB 341102 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901829 _Map

Runtime (ms): 153913
current memory	5.11GB
peak memory	5.13GB
heap 4.38GB of 4.51GB
856.5 MB 7366249 _List
693.8 MB 3730773 _OneByteString
608.1 MB 5239925 _Uint32List
233.0 MB 338205 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901829 _Map

Runtime (ms): 157729
current memory	5.10GB
peak memory	5.13GB
heap 4.38GB of 4.51GB
856.5 MB 7366221 _List
693.8 MB 3730773 _OneByteString
608.1 MB 5239924 _Uint32List
233.0 MB 337860 _Uint8List
158.7 MB 3466691 Reference
116.1 MB 1901829 _Map

Change-Id: I5697ff0efd40c9325f7f15d8092655b80b4876ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/318940
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 406059d..722fd3e 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -54,6 +54,7 @@
 import 'package:analyzer/src/dart/analysis/file_byte_store.dart'
     show EvictingFileByteStore;
 import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
 import 'package:analyzer/src/dart/analysis/status.dart' as analysis;
@@ -114,6 +115,8 @@
 
   final UnlinkedUnitStore unlinkedUnitStore = UnlinkedUnitStoreImpl();
 
+  final InfoDeclarationStore infoDeclarationStore = InfoDeclarationStoreImpl();
+
   late analysis.AnalysisDriverScheduler analysisDriverScheduler;
 
   DeclarationsTracker? declarationsTracker;
@@ -273,6 +276,7 @@
       byteStore,
       fileContentCache,
       unlinkedUnitStore,
+      infoDeclarationStore,
       analysisPerformanceLogger,
       analysisDriverScheduler,
       instrumentationService,
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 69355e3..4186704 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -18,6 +18,7 @@
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
 import 'package:analyzer/src/generated/sdk.dart';
@@ -174,6 +175,9 @@
   /// The cache of already deserialized unlinked units.
   final UnlinkedUnitStore _unlinkedUnitStore;
 
+  /// The cache of already deserialized data from a SummaryDataReader.
+  final InfoDeclarationStore _infoDeclarationStore;
+
   /// The logger used to create analysis contexts.
   final PerformanceLog _performanceLog;
 
@@ -256,6 +260,7 @@
       this._byteStore,
       this._fileContentCache,
       this._unlinkedUnitStore,
+      this._infoDeclarationStore,
       this._performanceLog,
       this._scheduler,
       this._instrumentationService,
@@ -562,6 +567,7 @@
           packagesFile: packagesFile,
           fileContentCache: _fileContentCache,
           unlinkedUnitStore: _unlinkedUnitStore,
+          infoDeclarationStore: _infoDeclarationStore,
           updateAnalysisOptions2: ({
             required analysisOptions,
             required contextRoot,
diff --git a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
index 866f8d3..f24ba3a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/analysis_context_collection.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
@@ -60,6 +61,7 @@
     AnalysisDriverScheduler? scheduler,
     FileContentCache? fileContentCache,
     UnlinkedUnitStore? unlinkedUnitStore,
+    InfoDeclarationStore? infoDeclarationStore,
     @Deprecated('Use updateAnalysisOptions2, which must be a function that '
         'accepts a second parameter')
     void Function(AnalysisOptionsImpl)? updateAnalysisOptions,
@@ -111,6 +113,7 @@
         updateAnalysisOptions2: updateAnalysisOptions2,
         fileContentCache: fileContentCache,
         unlinkedUnitStore: unlinkedUnitStore ?? UnlinkedUnitStoreImpl(),
+        infoDeclarationStore: infoDeclarationStore,
         macroKernelBuilder: macroKernelBuilder,
         macroExecutor: macroExecutor,
         ownedFiles: ownedFiles,
diff --git a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
index 91b4a3c..3ec3c2f 100644
--- a/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/context_builder.dart
@@ -23,6 +23,7 @@
         OwnedFiles;
 import 'package:analyzer/src/dart/analysis/driver_based_analysis_context.dart';
 import 'package:analyzer/src/dart/analysis/file_content_cache.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart'
     show PerformanceLog;
 import 'package:analyzer/src/dart/analysis/unlinked_unit_store.dart';
@@ -73,6 +74,7 @@
     })? updateAnalysisOptions2,
     FileContentCache? fileContentCache,
     UnlinkedUnitStore? unlinkedUnitStore,
+    InfoDeclarationStore? infoDeclarationStore,
     MacroKernelBuilder? macroKernelBuilder,
     macro.MultiMacroExecutor? macroExecutor,
     OwnedFiles? ownedFiles,
@@ -149,6 +151,7 @@
       retainDataForTesting: retainDataForTesting,
       fileContentCache: fileContentCache,
       unlinkedUnitStore: unlinkedUnitStore,
+      infoDeclarationStore: infoDeclarationStore,
       macroKernelBuilder: macroKernelBuilder,
       macroExecutor: macroExecutor,
       declaredVariables: declaredVariables,
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index b6ef6cc..f27dd3a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -22,6 +22,7 @@
 import 'package:analyzer/src/dart/analysis/file_state.dart';
 import 'package:analyzer/src/dart/analysis/file_tracker.dart';
 import 'package:analyzer/src/dart/analysis/index.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
 import 'package:analyzer/src/dart/analysis/library_context.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
@@ -108,6 +109,11 @@
   /// It can be shared with other [AnalysisDriver]s.
   final ByteStore _byteStore;
 
+  /// The cache of deserialized data read from SummaryDataReader.
+  ///
+  /// It can be shared with other [AnalysisDriver]s.
+  final InfoDeclarationStore _infoDeclarationStore;
+
   /// The optional store with externally provided unlinked and corresponding
   /// linked summaries. These summaries are always added to the store for any
   /// file analysis.
@@ -281,6 +287,7 @@
     this.analysisContext,
     FileContentCache? fileContentCache,
     UnlinkedUnitStore? unlinkedUnitStore,
+    InfoDeclarationStore? infoDeclarationStore,
     this.enableIndex = false,
     SummaryDataStore? externalSummaries,
     DeclaredVariables? declaredVariables,
@@ -292,6 +299,8 @@
         _fileContentCache =
             fileContentCache ?? FileContentCache.ephemeral(resourceProvider),
         _unlinkedUnitStore = unlinkedUnitStore ?? UnlinkedUnitStoreImpl(),
+        _infoDeclarationStore =
+            infoDeclarationStore ?? NoOpInfoDeclarationStore(),
         _analysisOptions = analysisOptions,
         _logger = logger,
         _packages = packages,
@@ -349,6 +358,7 @@
       analysisSession: AnalysisSessionImpl(this),
       logger: _logger,
       byteStore: _byteStore,
+      infoDeclarationStore: _infoDeclarationStore,
       analysisOptions: _analysisOptions,
       declaredVariables: declaredVariables,
       sourceFactory: _sourceFactory,
diff --git a/pkg/analyzer/lib/src/dart/analysis/info_declaration_store.dart b/pkg/analyzer/lib/src/dart/analysis/info_declaration_store.dart
new file mode 100644
index 0000000..157dadf
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/analysis/info_declaration_store.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:typed_data';
+
+import 'package:analyzer/src/summary2/data_reader.dart';
+
+abstract class InfoDeclarationStore {
+  String createKey(SummaryDataReader reader, int initialOffset);
+  E? get<E>(SummaryDataReader reader, String key, int initialOffset);
+  void put(
+      SummaryDataReader reader, String key, int initialOffset, Object value);
+}
+
+class InfoDeclarationStoreImpl implements InfoDeclarationStore {
+  final Map<String, _InfoDeclarationStoreData> map = {};
+  late final Finalizer _finalizer;
+
+  InfoDeclarationStoreImpl() {
+    _finalizer = Finalizer((key) {
+      map.remove(key);
+    });
+  }
+
+  @override
+  String createKey(SummaryDataReader reader, int initialOffset) {
+    return "${identityHashCode(reader.bytes)}|$initialOffset";
+  }
+
+  @override
+  E? get<E>(SummaryDataReader reader, String key, int initialOffset) {
+    final lookup = map[key];
+    if (lookup != null) {
+      if (identical(lookup.bytes.target, reader.bytes) &&
+          lookup.offset == initialOffset) {
+        final result = lookup.result.target;
+        if (result is E) {
+          reader.offset = lookup.endOffset;
+          return result;
+        }
+      } else {
+        map.remove(key);
+      }
+    }
+    return null;
+  }
+
+  @override
+  void put(
+      SummaryDataReader reader, String key, int initialOffset, Object value) {
+    // Assuming that the bytes will live longer than the result.
+    _finalizer.attach(value, key);
+    map[key] = _InfoDeclarationStoreData(WeakReference(reader.bytes),
+        initialOffset, reader.offset, WeakReference(value));
+  }
+}
+
+class NoOpInfoDeclarationStore implements InfoDeclarationStore {
+  const NoOpInfoDeclarationStore();
+
+  @override
+  String createKey(SummaryDataReader reader, int initialOffset) {
+    return "";
+  }
+
+  @override
+  E? get<E>(SummaryDataReader reader, String key, int initialOffset) {
+    return null;
+  }
+
+  @override
+  void put(
+      SummaryDataReader reader, String key, int initialOffset, Object value) {}
+}
+
+class _InfoDeclarationStoreData {
+  final WeakReference<Uint8List> bytes;
+  final int offset;
+  final int endOffset;
+  final WeakReference<Object> result;
+
+  _InfoDeclarationStoreData(
+      this.bytes, this.offset, this.endOffset, this.result);
+}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_context.dart b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
index e6736b9..245153b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_context.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_context.dart
@@ -14,6 +14,7 @@
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/library_graph.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/session.dart';
@@ -40,6 +41,7 @@
   final LibraryContextTestData? testData;
   final PerformanceLog logger;
   final ByteStore byteStore;
+  final InfoDeclarationStore infoDeclarationStore;
   final FileSystemState fileSystemState;
   final MacroKernelBuilder? macroKernelBuilder;
   final macro.MultiMacroExecutor? macroExecutor;
@@ -55,6 +57,7 @@
     required AnalysisSessionImpl analysisSession,
     required this.logger,
     required this.byteStore,
+    required this.infoDeclarationStore,
     required this.fileSystemState,
     required AnalysisOptionsImpl analysisOptions,
     required DeclaredVariables declaredVariables,
@@ -81,6 +84,7 @@
             elementFactory: elementFactory,
             resolutionBytes: bundle.resolutionBytes,
             unitsInformativeBytes: {},
+            infoDeclarationStore: infoDeclarationStore,
           ),
         );
       }
@@ -207,6 +211,7 @@
             elementFactory: elementFactory,
             unitsInformativeBytes: unitsInformativeBytes,
             resolutionBytes: linkedBytes,
+            infoDeclarationStore: infoDeclarationStore,
           ),
         );
       }
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index bfb6041..f0242de 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -20,6 +20,7 @@
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
 import 'package:analyzer/src/dart/analysis/file_state.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/library_analyzer.dart';
 import 'package:analyzer/src/dart/analysis/library_context.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
@@ -766,6 +767,7 @@
       libraryContext = LibraryContext(
         declaredVariables: contextObjects!.declaredVariables,
         byteStore: byteStore,
+        infoDeclarationStore: const NoOpInfoDeclarationStore(),
         analysisOptions: contextObjects!.analysisOptions,
         analysisSession: contextObjects!.analysisSession,
         logger: logger,
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 19206bf..42c07e1 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/analysis/experiments.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
@@ -36,6 +37,7 @@
 class BundleReader {
   final SummaryDataReader _reader;
   final Map<Uri, Uint8List> _unitsInformativeBytes;
+  final InfoDeclarationStore _infoDeclarationStore;
 
   final Map<Uri, LibraryReader> libraryMap = {};
 
@@ -43,8 +45,10 @@
     required LinkedElementFactory elementFactory,
     required Uint8List resolutionBytes,
     Map<Uri, Uint8List> unitsInformativeBytes = const {},
+    required InfoDeclarationStore infoDeclarationStore,
   })  : _reader = SummaryDataReader(resolutionBytes),
-        _unitsInformativeBytes = unitsInformativeBytes {
+        _unitsInformativeBytes = unitsInformativeBytes,
+        _infoDeclarationStore = infoDeclarationStore {
     _reader.offset = _reader.bytes.length - 4 * 4;
     var baseResolutionOffset = _reader.readUInt32();
     var librariesOffset = _reader.readUInt32();
@@ -79,6 +83,7 @@
         reference: reference,
         offset: libraryHeader.offset,
         classMembersLengths: libraryHeader.classMembersLengths,
+        infoDeclarationStore: _infoDeclarationStore,
       );
     }
   }
@@ -513,6 +518,7 @@
   final _ReferenceReader _referenceReader;
   final Reference _reference;
   final int _offset;
+  final InfoDeclarationStore _deserializedDataStore;
 
   final Uint32List _classMembersLengths;
   int _classMembersLengthsIndex = 0;
@@ -526,6 +532,7 @@
     required Reference reference,
     required int offset,
     required Uint32List classMembersLengths,
+    required InfoDeclarationStore infoDeclarationStore,
   })  : _elementFactory = elementFactory,
         _reader = reader,
         _unitsInformativeBytes = unitsInformativeBytes,
@@ -533,7 +540,8 @@
         _referenceReader = referenceReader,
         _reference = reference,
         _offset = offset,
-        _classMembersLengths = classMembersLengths;
+        _classMembersLengths = classMembersLengths,
+        _deserializedDataStore = infoDeclarationStore;
 
   LibraryElementImpl readElement({required Source librarySource}) {
     var analysisContext = _elementFactory.analysisContext;
@@ -590,7 +598,8 @@
 
     _declareDartCoreDynamicNever();
 
-    InformativeDataApplier(_elementFactory, _unitsInformativeBytes)
+    InformativeDataApplier(
+            _elementFactory, _unitsInformativeBytes, _deserializedDataStore)
         .applyTo(libraryElement);
 
     _readPropertyAccessorAugmentations(accessorAugmentationsOffset);
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index d907f12..3d3c311 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -57,10 +58,12 @@
 class InformativeDataApplier {
   final LinkedElementFactory _elementFactory;
   final Map<Uri, Uint8List> _unitsInformativeBytes2;
+  final InfoDeclarationStore _infoDeclarationStore;
 
   InformativeDataApplier(
     this._elementFactory,
     this._unitsInformativeBytes2,
+    this._infoDeclarationStore,
   );
 
   void applyTo(LibraryElementImpl libraryElement) {
@@ -77,7 +80,7 @@
       var unitInfoBytes = _unitsInformativeBytes2[unitUri];
       if (unitInfoBytes != null) {
         var unitReader = SummaryDataReader(unitInfoBytes);
-        var unitInfo = _InfoUnit(unitReader);
+        var unitInfo = _InfoUnit(_infoDeclarationStore, unitReader);
 
         final enclosing = unitElement.enclosingElement;
         if (enclosing is LibraryElementImpl) {
@@ -750,9 +753,19 @@
   final List<_InfoMethodDeclaration> methods;
   final Uint32List constantOffsets;
 
-  factory _InfoClassDeclaration(SummaryDataReader reader,
+  factory _InfoClassDeclaration(
+      InfoDeclarationStore cache, SummaryDataReader reader,
       {int nameOffsetDelta = 0}) {
-    return _InfoClassDeclaration._(
+    // TODO(jensj/scheglov): Possibly we could just save the bytes and the
+    // offset and then only read it when/if needed.
+    // See https://dart-review.googlesource.com/c/sdk/+/318940.
+    final initialOffset = reader.offset;
+    String cacheKey = cache.createKey(reader, initialOffset);
+    final cached =
+        cache.get<_InfoClassDeclaration>(reader, cacheKey, initialOffset);
+    if (cached != null) return cached;
+
+    final result = _InfoClassDeclaration._(
       codeOffset: reader.readUInt30(),
       codeLength: reader.readUInt30(),
       nameOffset: reader.readUInt30() - nameOffsetDelta,
@@ -774,6 +787,9 @@
       ),
       constantOffsets: reader.readUInt30List(),
     );
+
+    cache.put(reader, cacheKey, initialOffset, result);
+    return result;
   }
 
   _InfoClassDeclaration._({
@@ -1838,7 +1854,7 @@
   final List<_InfoClassDeclaration> mixinDeclarations;
   final List<_InfoTopLevelVariable> topLevelVariable;
 
-  factory _InfoUnit(SummaryDataReader reader) {
+  factory _InfoUnit(InfoDeclarationStore cache, SummaryDataReader reader) {
     return _InfoUnit._(
       codeOffset: reader.readUInt30(),
       codeLength: reader.readUInt30(),
@@ -1856,16 +1872,16 @@
         () => _InfoPart(reader),
       ),
       classDeclarations: reader.readTypedList(
-        () => _InfoClassDeclaration(reader),
+        () => _InfoClassDeclaration(cache, reader),
       ),
       classTypeAliases: reader.readTypedList(
         () => _InfoClassTypeAlias(reader),
       ),
       enums: reader.readTypedList(
-        () => _InfoClassDeclaration(reader),
+        () => _InfoClassDeclaration(cache, reader),
       ),
       extensions: reader.readTypedList(
-        () => _InfoClassDeclaration(reader, nameOffsetDelta: 1),
+        () => _InfoClassDeclaration(cache, reader, nameOffsetDelta: 1),
       ),
       extensionTypes: reader.readTypedList(
         () => _InfoExtensionTypeDeclaration(reader),
@@ -1883,7 +1899,7 @@
         () => _InfoGenericTypeAlias(reader),
       ),
       mixinDeclarations: reader.readTypedList(
-        () => _InfoClassDeclaration(reader),
+        () => _InfoClassDeclaration(cache, reader),
       ),
       topLevelVariable: reader.readTypedList(
         () => _InfoTopLevelVariable(reader),
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
index 7498837..f350880 100644
--- a/pkg/analyzer/test/src/dart/analysis/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/src/context/packages.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
 import 'package:analyzer/src/dart/sdk/sdk.dart';
@@ -24,6 +25,7 @@
 class BaseAnalysisDriverTest with ResourceProviderMixin {
   late final DartSdk sdk;
   final ByteStore byteStore = MemoryByteStore();
+  final InfoDeclarationStore infoDeclarationStore = InfoDeclarationStoreImpl();
 
   final StringBuffer logBuffer = StringBuffer();
   late final PerformanceLog logger;
@@ -62,6 +64,7 @@
       logger: logger,
       resourceProvider: resourceProvider,
       byteStore: byteStore,
+      infoDeclarationStore: infoDeclarationStore,
       sourceFactory: SourceFactory([
         DartUriResolver(sdk),
         generatedUriResolver,
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index d32ea60..008080e 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -11,6 +11,7 @@
 import 'package:analyzer/src/context/packages.dart';
 import 'package:analyzer/src/dart/analysis/byte_store.dart';
 import 'package:analyzer/src/dart/analysis/driver.dart';
+import 'package:analyzer/src/dart/analysis/info_declaration_store.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/status.dart';
 import 'package:analyzer/src/dart/ast/extensions.dart';
@@ -310,6 +311,7 @@
 @reflectiveTest
 class AnalysisDriverSchedulerTest with ResourceProviderMixin {
   final ByteStore byteStore = MemoryByteStore();
+  final InfoDeclarationStore infoDeclarationStore = InfoDeclarationStoreImpl();
 
   final StringBuffer logBuffer = StringBuffer();
   late final PerformanceLog logger;
@@ -327,6 +329,7 @@
       logger: logger,
       resourceProvider: resourceProvider,
       byteStore: byteStore,
+      infoDeclarationStore: infoDeclarationStore,
       sourceFactory: SourceFactory(
         [DartUriResolver(sdk), ResourceUriResolver(resourceProvider)],
       ),