mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 14:13:09 +00:00
[analyzer] Less duplicated line starts data with multiple contexts
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 <jensj@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
parent
36d6676833
commit
2bbf99351e
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -138,13 +128,15 @@ class Scanner {
|
|||
includeComments: _preserveComments,
|
||||
languageVersionChanged: _languageVersionChanged);
|
||||
|
||||
// fasta pretends there is an additional line at EOF
|
||||
result.lineStarts.removeLast();
|
||||
// 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);
|
||||
}
|
||||
|
||||
// for compatibility, there is already a first entry in lineStarts
|
||||
result.lineStarts.removeAt(0);
|
||||
|
||||
lineStarts.addAll(result.lineStarts);
|
||||
fasta.Token token = result.tokens;
|
||||
|
||||
// The fasta parser handles error tokens produced by the scanner
|
||||
|
|
|
@ -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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue