Skip to content

Commit

Permalink
[analyzer] Less duplicated line starts data with multiple contexts
Browse files Browse the repository at this point in the history
When having multiple contexts we have duplicates of some things.
For instance line starts data.
This CL deduplicates some of it, and makes use of `Uint16List` and
`Uint32List` as appropriate (some where regular `List<int>`s before),
reducing the heap usage for analyzing `flutter/flutter` (80+ contexts)
when analyzing with an empty cache with about 165 MB.

Details:

```
_GrowableList (dart:core) (bytes):
Difference at 95.0% confidence
   -451040.00 +/- 0.00
   -0.79% +/- 0.00%

_Uint16List (dart:typed_data) (bytes):
Difference at 95.0% confidence
   6558032.00 +/- 0.00
   696.69% +/- 0.00%

_List (dart:core) (bytes):
Difference at 95.0% confidence
   -70840960.00 +/- 231371.19
   -9.58% +/- 0.03%

_Uint32List (dart:typed_data) (bytes):
Difference at 95.0% confidence
   -103560448.00 +/- 2829564.24
   -23.56% +/- 0.64%

heapUsage:
Difference at 95.0% confidence
   -173020528.00 +/- 7787712.50
   -4.78% +/- 0.21%
```
Change-Id: I49e23dde14a2faa7c8af94515b0ad1c669867c78
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/324501
Commit-Queue: Jens Johansen <[email protected]>
Reviewed-by: Brian Wilkerson <[email protected]>
  • Loading branch information
jensjoha authored and Commit Queue committed Sep 7, 2023
1 parent 36d6676 commit 2bbf993
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 26 deletions.
40 changes: 16 additions & 24 deletions pkg/analyzer/lib/src/dart/scanner/scanner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// 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:_fe_analyzer_shared/src/scanner/errors.dart'
show translateErrorToken;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
Expand All @@ -28,6 +30,8 @@ export 'package:analyzer/src/dart/error/syntactic_errors.dart';
/// have any context, so it always resolves such conflicts by scanning the
/// longest possible token.
class Scanner {
static final Uint8List _lineStartsZero = Uint8List(0);

final Source source;

/// The text to be scanned.
Expand All @@ -47,9 +51,7 @@ class Scanner {

/// The flag specifying whether documentation comments should be parsed.
bool _preserveComments = true;

final List<int> lineStarts = <int>[];

List<int>? _lineStarts;
late final Token firstToken;

Version? _overrideVersion;
Expand All @@ -72,9 +74,7 @@ class Scanner {
}

Scanner._(
this.source, this._contents, this._readerOffset, this._errorListener) {
lineStarts.add(0);
}
this.source, this._contents, this._readerOffset, this._errorListener);

/// The features associated with this scanner.
///
Expand All @@ -86,6 +86,8 @@ class Scanner {
/// Use [configureFeatures] to set the features.
FeatureSet get featureSet => _featureSet;

List<int> get lineStarts => _lineStarts ?? _lineStartsZero;

/// The language version override specified for this compilation unit using a
/// token like '// @dart = 2.7', or `null` if no override is specified.
Version? get overrideVersion => _overrideVersion;
Expand Down Expand Up @@ -116,18 +118,6 @@ class Scanner {
);
}

void setSourceStart(int line, int column) {
int offset = _readerOffset;
if (line < 1 || column < 1 || offset < 0 || (line + column - 2) >= offset) {
return;
}
lineStarts.removeAt(0);
for (int i = 2; i < line; i++) {
lineStarts.add(1);
}
lineStarts.add(offset - column + 1);
}

/// The fasta parser handles error tokens produced by the scanner
/// but the old parser used by angular does not
/// and expects that scanner errors to be reported by this method.
Expand All @@ -138,13 +128,15 @@ class Scanner {
includeComments: _preserveComments,
languageVersionChanged: _languageVersionChanged);

// fasta pretends there is an additional line at EOF
result.lineStarts.removeLast();

// for compatibility, there is already a first entry in lineStarts
result.lineStarts.removeAt(0);
// fasta pretends there is an additional line at EOF so we skip the last one.
if (result.lineStarts.last > 65535) {
Uint32List list = _lineStarts = Uint32List(result.lineStarts.length - 1);
list.setRange(0, result.lineStarts.length - 1, result.lineStarts);
} else {
Uint16List list = _lineStarts = Uint16List(result.lineStarts.length - 1);
list.setRange(0, result.lineStarts.length - 1, result.lineStarts);
}

lineStarts.addAll(result.lineStarts);
fasta.Token token = result.tokens;

// The fasta parser handles error tokens produced by the scanner
Expand Down
10 changes: 9 additions & 1 deletion pkg/analyzer/lib/src/services/available_declarations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';
import 'dart:collection';
import 'dart:typed_data';

import 'package:_fe_analyzer_shared/src/util/dependency_walker.dart' as graph
show DependencyWalker, Node;
Expand Down Expand Up @@ -1923,7 +1924,14 @@ class _File {
void _readFileDeclarationsFromBytes(List<int> bytes) {
var idlFile = idl.AvailableFile.fromBuffer(bytes);

lineStarts = idlFile.lineStarts.toList();
lineStarts = idlFile.lineStarts;
if (lineStarts.last > 65535) {
Uint32List list = lineStarts = Uint32List(lineStarts.length);
list.setRange(0, lineStarts.length, lineStarts);
} else {
Uint16List list = lineStarts = Uint16List(lineStarts.length);
list.setRange(0, lineStarts.length, lineStarts);
}
lineInfo = LineInfo(lineStarts);

isLibrary = idlFile.isLibrary;
Expand Down
19 changes: 18 additions & 1 deletion pkg/analyzer/lib/src/summary2/informative_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1858,7 +1858,8 @@ class _InfoUnit {
return _InfoUnit._(
codeOffset: reader.readUInt30(),
codeLength: reader.readUInt30(),
lineStarts: reader.readUInt30List(),
// Having duplicated line-starts adds up --- deduplicate if possible.
lineStarts: _readUint30ListPossiblyFromCache(cache, reader),
libraryName: _InfoLibraryName(reader),
libraryConstantOffsets: reader.readUInt30List(),
docComment: reader.readStringUtf8(),
Expand Down Expand Up @@ -1929,6 +1930,22 @@ class _InfoUnit {
required this.mixinDeclarations,
required this.topLevelVariable,
});

static Uint32List _readUint30ListPossiblyFromCache(
InfoDeclarationStore cache, SummaryDataReader reader) {
final initialOffset = reader.offset;
final cacheKey = cache.createKey(reader, initialOffset);
final cachedLineStarts =
cache.get<Uint32List>(reader, cacheKey, initialOffset);
if (cachedLineStarts != null) {
return cachedLineStarts;
} else {
// Add to cache.
var lineStarts = reader.readUInt30List();
cache.put(reader, cacheKey, initialOffset, lineStarts);
return lineStarts;
}
}
}

class _OffsetsApplier extends _OffsetsAstVisitor {
Expand Down

0 comments on commit 2bbf993

Please sign in to comment.