Skip to content

Commit 17abf40

Browse files
scheglovCommit Queue
authored andcommitted
Fine. Write URIs and lookup names as string refs in manifests
Switch serialization of heavily repeated strings (URIs, `LookupName`s, and select identifiers) from inline UTF-8 blobs to string references backed by a per-blob string table. Readers now initialize the table from the end of the buffer, and writers emit it once at the end. This cuts duplication in library/requirements/diagnostics bundles and improves both size and speed when analyzing the analyzer: - size: 112 MB → 62 MB (~45% smaller) - time: 450 ms → 310 ms (~31% faster) Key changes - Use `writeStringReference` / `readStringReference` for: - URIs (`writeUri`/`readUri`); parse via `uriCache.parse`. - `LookupName`, `BaseName`, and various manifest/type strings (e.g., token buffers, member/top-level names, record field names, named parameter names). - Add `writeStringTableAtEnd()` in all writers that produce persisted blobs, and `initializeStringTableFromEnd()` in matching readers: - `LinkedBundleProvider` (get/put paths) - `LibraryDiagnosticsBundle` (toBytes/fromBytes) - Manifest and requirements assert-serialization paths - Bump `AnalysisDriver.DATA_VERSION` to 561 to invalidate old caches. Why this works - Manifests and requirements repeat the same URIs and names across many entries. Interning them through a string table removes redundancy and reduces I/O. - `uriCache.parse` avoids repeated `Uri` allocations and speeds up lookup. Trade-offs - Writers must call `writeStringTableAtEnd()` exactly once after all payload writes and before `takeBytes()`. - Readers that consume string references must initialize the table before any reference reads. Change-Id: I2346e02fa34e0f421b6f15ccd485a0d19b00062d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/451126 Reviewed-by: Paul Berry <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 7271e10 commit 17abf40

File tree

11 files changed

+34
-20
lines changed

11 files changed

+34
-20
lines changed

pkg/analyzer/lib/src/binary/binary_reader.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dart:typed_data';
88
import 'package:_fe_analyzer_shared/src/scanner/string_canonicalizer.dart';
99
import 'package:analyzer/src/binary/binary_writer.dart';
1010
import 'package:analyzer/src/binary/string_table.dart';
11+
import 'package:analyzer/src/utilities/uri_cache.dart';
1112

1213
/// Reader for binary formats.
1314
class BinaryReader {
@@ -261,8 +262,8 @@ class BinaryReader {
261262
}
262263

263264
Uri readUri() {
264-
var uriStr = readStringUtf8();
265-
return Uri.parse(uriStr);
265+
var uriStr = readStringReference();
266+
return uriCache.parse(uriStr);
266267
}
267268

268269
List<Uri> readUriList() {

pkg/analyzer/lib/src/binary/binary_writer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ class BinaryWriter {
297297

298298
void writeUri(Uri uri) {
299299
var uriStr = uri.toString();
300-
writeStringUtf8(uriStr);
300+
writeStringReference(uriStr);
301301
}
302302

303303
void writeUriList(List<Uri> uriList) {

pkg/analyzer/lib/src/dart/analysis/driver.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ testFineAfterLibraryAnalyzerHook;
106106
// TODO(scheglov): Clean up the list of implicitly analyzed files.
107107
class AnalysisDriver {
108108
/// The version of data format, should be incremented on every format change.
109-
static const int DATA_VERSION = 560;
109+
static const int DATA_VERSION = 561;
110110

111111
/// The number of exception contexts allowed to write. Once this field is
112112
/// zero, we stop writing any new exception contexts in this process.

pkg/analyzer/lib/src/dart/analysis/library_context.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ class LinkedBundleProvider {
552552

553553
performance.getDataInt('bytesLength').add(bytes.length);
554554
var reader = BinaryReader(bytes);
555+
reader.initializeStringTableFromEnd();
555556
var nonTransitiveApiSignature = reader.readStringUtf8();
556557
var libraryManifests = reader.readMap(
557558
readKey: () => reader.readUri(),
@@ -593,7 +594,9 @@ class LinkedBundleProvider {
593594
entry.requirements.write(writer);
594595
writer.writeUint8List(entry.linkedBytes);
595596

597+
writer.writeStringTableAtEnd();
596598
var bytes = writer.takeBytes();
599+
597600
byteStore.putGet(key, bytes);
598601
performance.getDataInt('bytes').add(bytes.length);
599602

pkg/analyzer/lib/src/dart/analysis/library_diagnostics.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class LibraryDiagnosticsBundle {
3333

3434
factory LibraryDiagnosticsBundle.fromBytes(Uint8List bytes) {
3535
var reader = BinaryReader(bytes);
36+
reader.initializeStringTableFromEnd();
3637
return LibraryDiagnosticsBundle(
3738
requirements: RequirementsManifest.read(reader),
3839
serializedFileResults: reader.readMap(
@@ -58,6 +59,7 @@ class LibraryDiagnosticsBundle {
5859
writeKey: (uri) => writer.writeUri(uri),
5960
writeValue: (bytes) => writer.writeUint8List(bytes),
6061
);
62+
writer.writeStringTableAtEnd();
6163
return writer.takeBytes();
6264
}
6365
}

pkg/analyzer/lib/src/fine/library_manifest.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -798,13 +798,17 @@ class LibraryManifestBuilder {
798798
Uint8List manifestAsBytes(LibraryManifest manifest) {
799799
var writer = BinaryWriter();
800800
manifest.write(writer);
801+
writer.writeStringTableAtEnd();
801802
return writer.takeBytes();
802803
}
803804

804805
newManifests.forEach((uri, manifest) {
805806
var bytes = manifestAsBytes(manifest);
806807

807-
var readManifest = LibraryManifest.read(BinaryReader(bytes));
808+
var reader = BinaryReader(bytes);
809+
reader.initializeStringTableFromEnd();
810+
811+
var readManifest = LibraryManifest.read(reader);
808812
var readBytes = manifestAsBytes(readManifest);
809813

810814
if (!const ListEquality<int>().equals(bytes, readBytes)) {

pkg/analyzer/lib/src/fine/lookup_name.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import 'package:analyzer/src/utilities/extensions/string.dart';
1111
/// In contrast to [LookupName] there is no `=` at the end.
1212
extension type BaseName(String _it) {
1313
factory BaseName.read(BinaryReader reader) {
14-
var str = reader.readStringUtf8();
14+
var str = reader.readStringReference();
1515
return BaseName(str);
1616
}
1717

1818
/// Returns the underlying [String] value, explicitly.
1919
String get asString => _it;
2020

2121
void write(BinaryWriter writer) {
22-
writer.writeStringUtf8(_it);
22+
writer.writeStringReference(_it);
2323
}
2424

2525
static int compare(BaseName left, BaseName right) {
@@ -32,7 +32,7 @@ extension type BaseName(String _it) {
3232
/// Specifically, for setters there is `=` at the end.
3333
extension type LookupName(String _it) {
3434
factory LookupName.read(BinaryReader reader) {
35-
var str = reader.readStringUtf8();
35+
var str = reader.readStringReference();
3636
return LookupName(str);
3737
}
3838

@@ -109,7 +109,7 @@ extension type LookupName(String _it) {
109109
}
110110

111111
void write(BinaryWriter writer) {
112-
writer.writeStringUtf8(_it);
112+
writer.writeStringReference(_it);
113113
}
114114

115115
static int compare(LookupName left, LookupName right) {

pkg/analyzer/lib/src/fine/manifest_ast.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ class ManifestNode {
118118
factory ManifestNode.read(BinaryReader reader) {
119119
return ManifestNode._(
120120
isValid: reader.readBool(),
121-
tokenBuffer: reader.readStringUtf8(),
121+
tokenBuffer: reader.readStringReference(),
122122
tokenLengthList: reader.readUint30List(),
123123
elements: ManifestElement.readList(reader),
124124
elementIndexList: reader.readUint30List(),
@@ -195,7 +195,7 @@ class ManifestNode {
195195

196196
void write(BinaryWriter writer) {
197197
writer.writeBool(isValid);
198-
writer.writeStringUtf8(tokenBuffer);
198+
writer.writeStringReference(tokenBuffer);
199199
writer.writeUint30List(tokenLengthList);
200200
writer.writeList(elements, (e) => e.write(writer));
201201
writer.writeUint30List(elementIndexList);

pkg/analyzer/lib/src/fine/manifest_context.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ final class ManifestElement {
117117
return ManifestElement(
118118
libraryUri: reader.readUri(),
119119
kind: reader.readEnum(ManifestElementKind.values),
120-
topLevelName: reader.readStringUtf8(),
121-
memberName: reader.readOptionalStringUtf8(),
120+
topLevelName: reader.readStringReference(),
121+
memberName: reader.readOptionalStringReference(),
122122
id: reader.readOptionalObject(() => ManifestItemId.read(reader)),
123123
);
124124
}
@@ -173,8 +173,8 @@ final class ManifestElement {
173173
void write(BinaryWriter writer) {
174174
writer.writeUri(libraryUri);
175175
writer.writeEnum(kind);
176-
writer.writeStringUtf8(topLevelName);
177-
writer.writeOptionalStringUtf8(memberName);
176+
writer.writeStringReference(topLevelName);
177+
writer.writeOptionalStringReference(memberName);
178178
id.writeOptional(writer);
179179
}
180180

pkg/analyzer/lib/src/fine/manifest_type.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class ManifestFunctionNamedFormalParameter
102102
isSuperFormal: reader.readBool(),
103103
type: ManifestType.read(reader),
104104
defaultValue: ManifestNode.readOptional(reader),
105-
name: reader.readStringUtf8(),
105+
name: reader.readStringReference(),
106106
);
107107
}
108108

@@ -127,7 +127,7 @@ class ManifestFunctionNamedFormalParameter
127127
@override
128128
void write(BinaryWriter writer) {
129129
super.write(writer);
130-
writer.writeStringUtf8(name);
130+
writer.writeStringReference(name);
131131
}
132132
}
133133

@@ -513,7 +513,7 @@ class ManifestRecordTypeNamedField {
513513

514514
factory ManifestRecordTypeNamedField.read(BinaryReader reader) {
515515
return ManifestRecordTypeNamedField._(
516-
name: reader.readStringUtf8(),
516+
name: reader.readStringReference(),
517517
type: ManifestType.read(reader),
518518
);
519519
}
@@ -525,7 +525,7 @@ class ManifestRecordTypeNamedField {
525525
}
526526

527527
void write(BinaryWriter writer) {
528-
writer.writeStringUtf8(name);
528+
writer.writeStringReference(name);
529529
type.write(writer);
530530
}
531531
}

0 commit comments

Comments
 (0)