12c4e22a4d
Handles ExtensionType in inference of MapLiteral, inference of ObjectPattern, and exhaustiveness. TEST=tests/extension_type/* Change-Id: I3284da2c69d875e192cf3f004ee1156e1aedd98b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/333160 Reviewed-by: Ömer Ağacan <omersa@google.com> Reviewed-by: Chloe Stefantsova <cstefantsova@google.com> Commit-Queue: Johnni Winther <johnniwinther@google.com>
4482 lines
150 KiB
Dart
4482 lines
150 KiB
Dart
// Copyright (c) 2016, 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.
|
|
|
|
library kernel.ast_from_binary;
|
|
|
|
import 'dart:developer';
|
|
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import '../ast.dart';
|
|
import '../transformations/flags.dart';
|
|
import 'tag.dart';
|
|
|
|
const int $_ = 95;
|
|
|
|
class ParseError {
|
|
final String? filename;
|
|
final int byteIndex;
|
|
final String message;
|
|
final String path;
|
|
|
|
ParseError(this.message,
|
|
{required this.filename, required this.byteIndex, required this.path});
|
|
|
|
@override
|
|
String toString() => '$filename:$byteIndex: $message at $path';
|
|
}
|
|
|
|
class InvalidKernelVersionError {
|
|
final String? filename;
|
|
final int version;
|
|
|
|
InvalidKernelVersionError(this.filename, this.version);
|
|
|
|
@override
|
|
String toString() {
|
|
StringBuffer sb = new StringBuffer();
|
|
sb.write('Unexpected Kernel Format Version ${version} '
|
|
'(expected ${Tag.BinaryFormatVersion})');
|
|
if (filename != null) {
|
|
sb.write(' when reading $filename.');
|
|
}
|
|
return '$sb';
|
|
}
|
|
}
|
|
|
|
class InvalidKernelSdkVersionError {
|
|
final String version;
|
|
|
|
InvalidKernelSdkVersionError(this.version);
|
|
|
|
@override
|
|
String toString() {
|
|
return 'Unexpected Kernel SDK Version ${version} '
|
|
'(expected ${expectedSdkHash}).';
|
|
}
|
|
}
|
|
|
|
class CompilationModeError {
|
|
final String message;
|
|
|
|
CompilationModeError(this.message);
|
|
|
|
@override
|
|
String toString() => "CompilationModeError[$message]";
|
|
}
|
|
|
|
class _ComponentIndex {
|
|
static const int numberOfFixedFields = 12;
|
|
|
|
final int binaryOffsetForSourceTable;
|
|
final int binaryOffsetForCanonicalNames;
|
|
final int binaryOffsetForMetadataPayloads;
|
|
final int binaryOffsetForMetadataMappings;
|
|
final int binaryOffsetForStringTable;
|
|
final int binaryOffsetForConstantTable;
|
|
final int binaryOffsetForConstantTableIndex;
|
|
final int binaryOffsetForStartOfComponentIndex;
|
|
final int mainMethodReference;
|
|
final NonNullableByDefaultCompiledMode compiledMode;
|
|
final List<int> libraryOffsets;
|
|
final int libraryCount;
|
|
final int componentFileSizeInBytes;
|
|
|
|
_ComponentIndex(
|
|
{required this.binaryOffsetForSourceTable,
|
|
required this.binaryOffsetForCanonicalNames,
|
|
required this.binaryOffsetForMetadataPayloads,
|
|
required this.binaryOffsetForMetadataMappings,
|
|
required this.binaryOffsetForStringTable,
|
|
required this.binaryOffsetForConstantTable,
|
|
required this.binaryOffsetForConstantTableIndex,
|
|
required this.binaryOffsetForStartOfComponentIndex,
|
|
required this.mainMethodReference,
|
|
required this.compiledMode,
|
|
required this.libraryOffsets,
|
|
required this.libraryCount,
|
|
required this.componentFileSizeInBytes});
|
|
}
|
|
|
|
class SubComponentView {
|
|
final List<Library> libraries;
|
|
final int componentStartOffset;
|
|
final int componentFileSize;
|
|
|
|
SubComponentView(
|
|
this.libraries, this.componentStartOffset, this.componentFileSize);
|
|
}
|
|
|
|
/// [StringInterner] allows Strings created from the binary to be shared with
|
|
/// other components.
|
|
///
|
|
/// The [StringInterner] is an optional parameter to [BinaryBuilder], so sharing
|
|
/// should not be required for correctness, and an implementation of
|
|
/// [StringInterner] method may be partial (sometimes not finding an existing
|
|
/// object) or trivial (returning the argument).
|
|
abstract class StringInterner {
|
|
/// Returns a string with the same contents as [string].
|
|
String internString(String string);
|
|
}
|
|
|
|
/// Helper used to trigger the read of a late variable in asserts.
|
|
bool _lateIsInitialized(dynamic value) {
|
|
return true;
|
|
}
|
|
|
|
class BinaryBuilder {
|
|
final List<VariableDeclaration> variableStack = <VariableDeclaration>[];
|
|
final List<LabeledStatement> labelStack = <LabeledStatement>[];
|
|
int labelStackBase = 0;
|
|
int switchCaseStackBase = 0;
|
|
final List<SwitchCase> switchCaseStack = <SwitchCase>[];
|
|
final List< /* TypeParameter | StructuralParameter */ Object>
|
|
typeParameterStack = <Object>[];
|
|
final String? filename;
|
|
final List<int> _bytes;
|
|
int _byteOffset = 0;
|
|
List<String> _stringTable = const [];
|
|
late Map<int, Name?> _nameCache;
|
|
List<Uri> _sourceUriTable = const [];
|
|
List<Constant> _constantTable = const <Constant>[];
|
|
late List<CanonicalName> _linkTable;
|
|
late Map<int, DartType?> _cachedSimpleInterfaceTypes;
|
|
List<FunctionType?> _voidFunctionFunctionTypesCache = [
|
|
null,
|
|
null,
|
|
null,
|
|
null
|
|
];
|
|
int _transformerFlags = 0;
|
|
Library? _currentLibrary;
|
|
int _componentStartOffset = 0;
|
|
NonNullableByDefaultCompiledMode? compilationMode;
|
|
|
|
// If something goes wrong, this list should indicate what library,
|
|
// class, and member was being built.
|
|
List<String> debugPath = <String>[];
|
|
|
|
final bool alwaysCreateNewNamedNodes;
|
|
|
|
/// If binary contains metadata section with payloads referencing other nodes
|
|
/// such Kernel binary can't be read lazily because metadata cross references
|
|
/// will not be resolved correctly.
|
|
bool _disableLazyReading = false;
|
|
|
|
/// If binary contains metadata section with payloads referencing other nodes
|
|
/// such Kernel binary can't be read lazily because metadata cross references
|
|
/// will not be resolved correctly.
|
|
bool _disableLazyClassReading = false;
|
|
|
|
/// [stringInterner] (optional) may be used to allow components to share
|
|
/// instances of [String] that have the same contents.
|
|
final StringInterner? stringInterner;
|
|
|
|
/// When creating lists that *might* be growable, use this boolean as the
|
|
/// setting to pass to `growable` so the dill can be loaded in a more compact
|
|
/// manner if the caller knows that the growability isn't needed.
|
|
final bool useGrowableLists;
|
|
|
|
/// Note that [disableLazyClassReading] is incompatible
|
|
/// with checkCanonicalNames on readComponent.
|
|
BinaryBuilder(this._bytes,
|
|
{this.filename,
|
|
bool disableLazyReading = false,
|
|
bool disableLazyClassReading = false,
|
|
bool? alwaysCreateNewNamedNodes,
|
|
this.stringInterner,
|
|
this.useGrowableLists = true})
|
|
: _disableLazyReading = disableLazyReading,
|
|
_disableLazyClassReading = disableLazyReading ||
|
|
disableLazyClassReading ||
|
|
// Disable lazy class reading when forcing the creation of new named
|
|
// nodes as it is a logical "relink" to the new version (overwriting
|
|
// the old one) - which doesn't play well with lazy loading class
|
|
// content as old loaded references will then potentially still
|
|
// point to the old content until the new class has been lazy
|
|
// loaded.
|
|
(alwaysCreateNewNamedNodes == true),
|
|
this.alwaysCreateNewNamedNodes = alwaysCreateNewNamedNodes ?? false;
|
|
|
|
Never fail(String message) {
|
|
throw ParseError(message,
|
|
byteIndex: _byteOffset, filename: filename, path: debugPath.join('::'));
|
|
}
|
|
|
|
int get byteOffset => _byteOffset;
|
|
|
|
int readByte() => _bytes[_byteOffset++];
|
|
int peekByte() => _bytes[_byteOffset];
|
|
|
|
int readUInt30() {
|
|
int byte = readByte();
|
|
if (byte & 0x80 == 0) {
|
|
// 0xxxxxxx
|
|
return byte;
|
|
} else if (byte & 0x40 == 0) {
|
|
// 10xxxxxx
|
|
return ((byte & 0x3F) << 8) | readByte();
|
|
} else {
|
|
// 11xxxxxx
|
|
return ((byte & 0x3F) << 24) |
|
|
(readByte() << 16) |
|
|
(readByte() << 8) |
|
|
readByte();
|
|
}
|
|
}
|
|
|
|
int readUint32() {
|
|
return (readByte() << 24) |
|
|
(readByte() << 16) |
|
|
(readByte() << 8) |
|
|
readByte();
|
|
}
|
|
|
|
final Float64List _doubleBuffer = new Float64List(1);
|
|
Uint8List? _doubleBufferUint8;
|
|
|
|
double readDouble() {
|
|
Uint8List doubleBufferUint8 =
|
|
_doubleBufferUint8 ??= _doubleBuffer.buffer.asUint8List();
|
|
doubleBufferUint8[0] = readByte();
|
|
doubleBufferUint8[1] = readByte();
|
|
doubleBufferUint8[2] = readByte();
|
|
doubleBufferUint8[3] = readByte();
|
|
doubleBufferUint8[4] = readByte();
|
|
doubleBufferUint8[5] = readByte();
|
|
doubleBufferUint8[6] = readByte();
|
|
doubleBufferUint8[7] = readByte();
|
|
return _doubleBuffer[0];
|
|
}
|
|
|
|
Uint8List readBytes(int length) {
|
|
Uint8List bytes = new Uint8List(length);
|
|
bytes.setRange(0, bytes.length, _bytes, _byteOffset);
|
|
_byteOffset += bytes.length;
|
|
return bytes;
|
|
}
|
|
|
|
Uint8List readByteList() {
|
|
return readBytes(readUInt30());
|
|
}
|
|
|
|
Uint8List readOrViewByteList() {
|
|
int length = readUInt30();
|
|
List<int> source = _bytes;
|
|
if (source is Uint8List) {
|
|
Uint8List view =
|
|
source.buffer.asUint8List(source.offsetInBytes + _byteOffset, length);
|
|
_byteOffset += length;
|
|
return view;
|
|
}
|
|
return readBytes(length);
|
|
}
|
|
|
|
String readString() {
|
|
return readStringEntry(readUInt30());
|
|
}
|
|
|
|
String readStringEntry(int numBytes) {
|
|
String string = _readStringEntry(numBytes);
|
|
if (stringInterner == null) return string;
|
|
return stringInterner!.internString(string);
|
|
}
|
|
|
|
String _readStringEntry(int numBytes) {
|
|
int start = _byteOffset;
|
|
int end = start + numBytes;
|
|
_byteOffset = end;
|
|
for (int i = start; i < end; i++) {
|
|
if (_bytes[i] > 127) {
|
|
return _decodeWtf8(start, end);
|
|
}
|
|
}
|
|
return new String.fromCharCodes(_bytes, start, end);
|
|
}
|
|
|
|
String _decodeWtf8(int start, int end) {
|
|
// WTF-8 decoder that trusts its input, meaning that the correctness of
|
|
// the code depends on the bytes from start to end being valid and
|
|
// complete WTF-8. Instead of masking off the control bits from every
|
|
// byte, it simply xor's the byte values together at their appropriate
|
|
// bit shifts, and then xor's out all of the control bits at once.
|
|
Uint16List charCodes = new Uint16List(end - start);
|
|
int i = start;
|
|
int j = 0;
|
|
while (i < end) {
|
|
int byte = _bytes[i++];
|
|
if (byte < 0x80) {
|
|
// ASCII.
|
|
charCodes[j++] = byte;
|
|
} else if (byte < 0xE0) {
|
|
// Two-byte sequence (11-bit unicode value).
|
|
int byte2 = _bytes[i++];
|
|
int value = (byte << 6) ^ byte2 ^ 0x3080;
|
|
assert(value >= 0x80 && value < 0x800);
|
|
charCodes[j++] = value;
|
|
} else if (byte < 0xF0) {
|
|
// Three-byte sequence (16-bit unicode value).
|
|
int byte2 = _bytes[i++];
|
|
int byte3 = _bytes[i++];
|
|
int value = (byte << 12) ^ (byte2 << 6) ^ byte3 ^ 0xE2080;
|
|
assert(value >= 0x800 && value < 0x10000);
|
|
charCodes[j++] = value;
|
|
} else {
|
|
// Four-byte sequence (non-BMP unicode value).
|
|
int byte2 = _bytes[i++];
|
|
int byte3 = _bytes[i++];
|
|
int byte4 = _bytes[i++];
|
|
int value =
|
|
(byte << 18) ^ (byte2 << 12) ^ (byte3 << 6) ^ byte4 ^ 0x3C82080;
|
|
assert(value >= 0x10000 && value < 0x110000);
|
|
charCodes[j++] = 0xD7C0 + (value >> 10);
|
|
charCodes[j++] = 0xDC00 + (value & 0x3FF);
|
|
}
|
|
}
|
|
assert(i == end);
|
|
return new String.fromCharCodes(charCodes, 0, j);
|
|
}
|
|
|
|
/// Read metadataMappings section from the binary.
|
|
void _readMetadataMappings(
|
|
Component component, int binaryOffsetForMetadataPayloads) {
|
|
// Default reader ignores metadata section entirely.
|
|
}
|
|
|
|
/// Reads metadata for the given [node].
|
|
T _associateMetadata<T extends Node>(T node, int nodeOffset) {
|
|
// Default reader ignores metadata section entirely.
|
|
return node;
|
|
}
|
|
|
|
void readStringTable() {
|
|
// Read the table of end offsets.
|
|
int length = readUInt30();
|
|
List<int> endOffsets =
|
|
new List<int>.generate(length, (_) => readUInt30(), growable: false);
|
|
// Read the WTF-8 encoded strings.
|
|
int startOffset = 0;
|
|
|
|
// Reset name cache here to make any index into it always
|
|
// be about the corresponding string table entry.
|
|
_nameCache = {};
|
|
_stringTable = new List<String>.generate(length, (int index) {
|
|
String result = readStringEntry(endOffsets[index] - startOffset);
|
|
startOffset = endOffsets[index];
|
|
return result;
|
|
}, growable: false);
|
|
}
|
|
|
|
void readConstantTable() {
|
|
final int length = readUInt30();
|
|
// Because of "back-references" (e.g. the 10th constant referencing the 3rd
|
|
// constant) we can't use List.generate.
|
|
_constantTable =
|
|
new List<Constant>.filled(length, dummyConstant, growable: false);
|
|
for (int i = 0; i < length; i++) {
|
|
_constantTable[i] = readConstantTableEntry();
|
|
}
|
|
}
|
|
|
|
Constant readConstantTableEntry() {
|
|
final int constantTag = readByte();
|
|
switch (constantTag) {
|
|
case ConstantTag.NullConstant:
|
|
return _readNullConstant();
|
|
case ConstantTag.BoolConstant:
|
|
return _readBoolConstant();
|
|
case ConstantTag.IntConstant:
|
|
return _readIntConstant();
|
|
case ConstantTag.DoubleConstant:
|
|
return _readDoubleConstant();
|
|
case ConstantTag.StringConstant:
|
|
return _readStringConstant();
|
|
case ConstantTag.SymbolConstant:
|
|
return _readSymbolConstant();
|
|
case ConstantTag.MapConstant:
|
|
return _readMapConstant();
|
|
case ConstantTag.ListConstant:
|
|
return _readListConstant();
|
|
case ConstantTag.SetConstant:
|
|
return _readSetConstant();
|
|
case ConstantTag.RecordConstant:
|
|
return _readRecordConstant();
|
|
case ConstantTag.InstanceConstant:
|
|
return _readInstanceConstant();
|
|
case ConstantTag.InstantiationConstant:
|
|
return _readInstantiationConstant();
|
|
case ConstantTag.TypedefTearOffConstant:
|
|
return _readTypedefTearOffConstant();
|
|
case ConstantTag.StaticTearOffConstant:
|
|
return _readStaticTearOffConstant();
|
|
case ConstantTag.ConstructorTearOffConstant:
|
|
return _readConstructorTearOffConstant();
|
|
case ConstantTag.RedirectingFactoryTearOffConstant:
|
|
return _readRedirectingFactoryTearOffConstant();
|
|
case ConstantTag.TypeLiteralConstant:
|
|
return _readTypeLiteralConstant();
|
|
case ConstantTag.UnevaluatedConstant:
|
|
return _readUnevaluatedConstant();
|
|
}
|
|
|
|
throw fail('unexpected constant tag: $constantTag');
|
|
}
|
|
|
|
Constant _readNullConstant() {
|
|
return new NullConstant();
|
|
}
|
|
|
|
Constant _readBoolConstant() {
|
|
return new BoolConstant(readByte() == 1);
|
|
}
|
|
|
|
Constant _readIntConstant() {
|
|
return new IntConstant((readExpression() as IntLiteral).value);
|
|
}
|
|
|
|
Constant _readDoubleConstant() {
|
|
return new DoubleConstant(readDouble());
|
|
}
|
|
|
|
Constant _readStringConstant() {
|
|
return new StringConstant(readStringReference());
|
|
}
|
|
|
|
Constant _readSymbolConstant() {
|
|
Reference? libraryReference = readNullableLibraryReference();
|
|
return new SymbolConstant(readStringReference(), libraryReference);
|
|
}
|
|
|
|
Constant _readMapConstant() {
|
|
final DartType keyType = readDartType();
|
|
final DartType valueType = readDartType();
|
|
final int length = readUInt30();
|
|
final List<ConstantMapEntry> entries =
|
|
new List<ConstantMapEntry>.generate(length, (_) {
|
|
final Constant key = readConstantReference();
|
|
final Constant value = readConstantReference();
|
|
return new ConstantMapEntry(key, value);
|
|
}, growable: useGrowableLists);
|
|
return new MapConstant(keyType, valueType, entries);
|
|
}
|
|
|
|
Constant _readListConstant() {
|
|
final DartType typeArgument = readDartType();
|
|
List<Constant> entries = _readConstantReferenceList();
|
|
return new ListConstant(typeArgument, entries);
|
|
}
|
|
|
|
Constant _readSetConstant() {
|
|
final DartType typeArgument = readDartType();
|
|
List<Constant> entries = _readConstantReferenceList();
|
|
return new SetConstant(typeArgument, entries);
|
|
}
|
|
|
|
Constant _readRecordConstant() {
|
|
List<Constant> positional = _readConstantReferenceList();
|
|
final int namedLength = readUInt30();
|
|
final List<MapEntry<String, Constant>> named =
|
|
new List<MapEntry<String, Constant>>.generate(namedLength, (_) {
|
|
final String name = readStringReference();
|
|
final Constant value = readConstantReference();
|
|
return new MapEntry<String, Constant>(name, value);
|
|
}, growable: useGrowableLists);
|
|
final RecordType recordType = readDartType() as RecordType;
|
|
return new RecordConstant(
|
|
positional, new Map<String, Constant>.fromEntries(named), recordType);
|
|
}
|
|
|
|
Constant _readInstanceConstant() {
|
|
final Reference classReference = readNonNullClassReference();
|
|
final List<DartType> typeArguments = readDartTypeList();
|
|
final int fieldValueCount = readUInt30();
|
|
final Map<Reference, Constant> fieldValues = <Reference, Constant>{};
|
|
for (int i = 0; i < fieldValueCount; i++) {
|
|
final Reference fieldRef = readNonNullCanonicalNameReference().reference;
|
|
final Constant constant = readConstantReference();
|
|
fieldValues[fieldRef] = constant;
|
|
}
|
|
return new InstanceConstant(classReference, typeArguments, fieldValues);
|
|
}
|
|
|
|
Constant _readInstantiationConstant() {
|
|
final Constant tearOffConstant = readConstantReference();
|
|
final List<DartType> types = readDartTypeList();
|
|
return new InstantiationConstant(tearOffConstant, types);
|
|
}
|
|
|
|
Constant _readTypedefTearOffConstant() {
|
|
final List<TypeParameter> parameters = readAndPushTypeParameterList();
|
|
final TearOffConstant tearOffConstant =
|
|
readConstantReference() as TearOffConstant;
|
|
final List<DartType> types = readDartTypeList();
|
|
typeParameterStack.length -= parameters.length;
|
|
return new TypedefTearOffConstant(parameters, tearOffConstant, types);
|
|
}
|
|
|
|
Constant _readStaticTearOffConstant() {
|
|
final Reference reference = readNonNullCanonicalNameReference().reference;
|
|
return new StaticTearOffConstant.byReference(reference);
|
|
}
|
|
|
|
Constant _readConstructorTearOffConstant() {
|
|
final Reference reference = readNonNullCanonicalNameReference().reference;
|
|
return new ConstructorTearOffConstant.byReference(reference);
|
|
}
|
|
|
|
Constant _readRedirectingFactoryTearOffConstant() {
|
|
final Reference reference = readNonNullCanonicalNameReference().reference;
|
|
return new RedirectingFactoryTearOffConstant.byReference(reference);
|
|
}
|
|
|
|
Constant _readTypeLiteralConstant() {
|
|
final DartType type = readDartType();
|
|
return new TypeLiteralConstant(type);
|
|
}
|
|
|
|
Constant _readUnevaluatedConstant() {
|
|
final Expression expression = readExpression();
|
|
return new UnevaluatedConstant(expression);
|
|
}
|
|
|
|
Constant readConstantReference() {
|
|
final int index = readUInt30();
|
|
Constant constant = _constantTable[index];
|
|
assert(!identical(constant, dummyConstant),
|
|
"No constant found at index $index.");
|
|
return constant;
|
|
}
|
|
|
|
List<Constant> _readConstantReferenceList() {
|
|
final int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfConstant;
|
|
}
|
|
return new List<Constant>.generate(length, (_) => readConstantReference(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
Uri readUriReference() {
|
|
return _sourceUriTable[readUInt30()];
|
|
}
|
|
|
|
String readStringReference() {
|
|
return _stringTable[readUInt30()];
|
|
}
|
|
|
|
List<String> readStringReferenceList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfString;
|
|
}
|
|
return new List<String>.generate(length, (_) => readStringReference(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<Reference> readNonNullReferenceList(List<Reference> result) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
return emptyListOfReference;
|
|
}
|
|
for (int i = 0; i < length; ++i) {
|
|
result.add(readNonNullMemberReference());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String? readStringOrNullIfEmpty() {
|
|
String string = readStringReference();
|
|
return string.isEmpty ? null : string;
|
|
}
|
|
|
|
bool readAndCheckOptionTag() {
|
|
int tag = readByte();
|
|
if (tag == Tag.Nothing) {
|
|
return false;
|
|
} else if (tag == Tag.Something) {
|
|
return true;
|
|
} else {
|
|
throw fail('unexpected option tag: $tag');
|
|
}
|
|
}
|
|
|
|
List<Expression> readAnnotationList([TreeNode? parent]) {
|
|
int length = readUInt30();
|
|
if (length == 0) return const <Expression>[];
|
|
return new List<Expression>.generate(
|
|
length, (_) => readExpression()..parent = parent,
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
void readLinkTable(CanonicalName linkRoot) {
|
|
int length = readUInt30();
|
|
_linkTable = new List<CanonicalName>.filled(
|
|
length,
|
|
// Use [linkRoot] as a dummy default value.
|
|
linkRoot,
|
|
growable: false);
|
|
// Reset simple interface type cache here to make any index into it always
|
|
// be about the corresponding link table entry.
|
|
_cachedSimpleInterfaceTypes = {};
|
|
for (int i = 0; i < length; ++i) {
|
|
int biasedParentIndex = readUInt30();
|
|
String name = readStringReference();
|
|
CanonicalName parent =
|
|
biasedParentIndex == 0 ? linkRoot : _linkTable[biasedParentIndex - 1];
|
|
_linkTable[i] = parent.getChild(name);
|
|
}
|
|
}
|
|
|
|
List<int> _indexComponents() {
|
|
_checkEmptyInput();
|
|
int savedByteOffset = _byteOffset;
|
|
_byteOffset = _bytes.length - 4;
|
|
List<int> index = <int>[];
|
|
while (_byteOffset > 0) {
|
|
int size = readUint32();
|
|
if (size <= 0) {
|
|
throw fail("invalid size '$size' reported at offset $byteOffset");
|
|
}
|
|
int start = _byteOffset - size;
|
|
if (start < 0) {
|
|
throw fail("indicated size does not match file size");
|
|
}
|
|
index.add(size);
|
|
_byteOffset = start - 4;
|
|
}
|
|
_byteOffset = savedByteOffset;
|
|
return new List.of(index.reversed);
|
|
}
|
|
|
|
void _checkEmptyInput() {
|
|
if (_bytes.length == 0) throw new StateError("Empty input given.");
|
|
}
|
|
|
|
void _readAndVerifySdkHash() {
|
|
final String sdkHash = ascii.decode(readBytes(sdkHashLength));
|
|
if (!isValidSdkHash(sdkHash)) {
|
|
throw InvalidKernelSdkVersionError(sdkHash);
|
|
}
|
|
}
|
|
|
|
/// Deserializes a kernel component and stores it in [component].
|
|
///
|
|
/// When linking with a non-empty component, canonical names must have been
|
|
/// computed ahead of time.
|
|
///
|
|
/// The input bytes may contain multiple files concatenated.
|
|
///
|
|
/// If [createView] is true, returns a list of [SubComponentView] - one for
|
|
/// each concatenated dill - each of which knowing where in the combined dill
|
|
/// it came from. If [createView] is false null will be returned.
|
|
List<SubComponentView>? readComponent(Component component,
|
|
{bool checkCanonicalNames = false, bool createView = false}) {
|
|
return Timeline.timeSync<List<SubComponentView>?>(
|
|
"BinaryBuilder.readComponent", () {
|
|
_checkEmptyInput();
|
|
|
|
// Check that we have a .dill file and it has the correct version before
|
|
// we start decoding it. Otherwise we will fail for cryptic reasons.
|
|
int offset = _byteOffset;
|
|
int magic = readUint32();
|
|
if (magic != Tag.ComponentFile) {
|
|
throw ArgumentError('Not a .dill file (wrong magic number).');
|
|
}
|
|
int version = readUint32();
|
|
if (version != Tag.BinaryFormatVersion) {
|
|
throw InvalidKernelVersionError(filename, version);
|
|
}
|
|
|
|
_readAndVerifySdkHash();
|
|
|
|
_byteOffset = offset;
|
|
List<int> componentFileSizes = _indexComponents();
|
|
if (componentFileSizes.length > 1) {
|
|
_disableLazyReading = true;
|
|
_disableLazyClassReading = true;
|
|
}
|
|
int componentFileIndex = 0;
|
|
List<SubComponentView>? views;
|
|
if (createView) {
|
|
views = <SubComponentView>[];
|
|
}
|
|
while (_byteOffset < _bytes.length) {
|
|
SubComponentView? view = _readOneComponent(
|
|
component, componentFileSizes[componentFileIndex],
|
|
createView: createView);
|
|
if (createView) {
|
|
views!.add(view!);
|
|
}
|
|
++componentFileIndex;
|
|
}
|
|
|
|
if (checkCanonicalNames) {
|
|
component.root.checkCanonicalNameChildren();
|
|
}
|
|
return views;
|
|
});
|
|
}
|
|
|
|
/// Deserializes the source and stores it in [component].
|
|
/// Note that the _coverage_ normally included in the source in the
|
|
/// uri-to-source mapping is _not_ included.
|
|
///
|
|
/// The input bytes may contain multiple files concatenated.
|
|
void readComponentSource(Component component) {
|
|
List<int> componentFileSizes = _indexComponents();
|
|
if (componentFileSizes.length > 1) {
|
|
_disableLazyReading = true;
|
|
_disableLazyClassReading = true;
|
|
}
|
|
int componentFileIndex = 0;
|
|
while (_byteOffset < _bytes.length) {
|
|
_readOneComponentSource(
|
|
component, componentFileSizes[componentFileIndex]);
|
|
++componentFileIndex;
|
|
}
|
|
}
|
|
|
|
/// Reads a single component file from the input and loads it into
|
|
/// [component], overwriting and reusing any existing data in the component.
|
|
///
|
|
/// When linking with a non-empty component, canonical names must have been
|
|
/// computed ahead of time.
|
|
///
|
|
/// This should *only* be used when there is a reason to not allow
|
|
/// concatenated files.
|
|
void readSingleFileComponent(Component component,
|
|
{bool checkCanonicalNames = false}) {
|
|
List<int> componentFileSizes = _indexComponents();
|
|
if (componentFileSizes.isEmpty) throw fail("invalid component data");
|
|
_readOneComponent(component, componentFileSizes[0]);
|
|
if (_byteOffset < _bytes.length) {
|
|
if (_byteOffset + 3 < _bytes.length) {
|
|
int magic = readUint32();
|
|
if (magic == Tag.ComponentFile) {
|
|
throw 'Concatenated component file given when a single component '
|
|
'was expected.';
|
|
}
|
|
}
|
|
throw 'Unrecognized bytes following component data';
|
|
}
|
|
|
|
if (checkCanonicalNames) {
|
|
component.root.checkCanonicalNameChildren();
|
|
}
|
|
}
|
|
|
|
_ComponentIndex _readComponentIndex(int componentFileSize) {
|
|
int savedByteIndex = _byteOffset;
|
|
|
|
// There are two fields: file size and library count.
|
|
_byteOffset = _componentStartOffset + componentFileSize - (2) * 4;
|
|
int libraryCount = readUint32();
|
|
// Library offsets are used for start and end offsets, so there is one extra
|
|
// element that this the end offset of the last library
|
|
List<int> libraryOffsets = new List<int>.filled(
|
|
libraryCount + 1,
|
|
// Use `-1` as a dummy default value.
|
|
-1,
|
|
growable: false);
|
|
int componentFileSizeInBytes = readUint32();
|
|
if (componentFileSizeInBytes != componentFileSize) {
|
|
throw "Malformed binary: This component file's component index indicates "
|
|
"that the file size should be $componentFileSize but other component "
|
|
"indexes has indicated that the size should be "
|
|
"${componentFileSizeInBytes}.";
|
|
}
|
|
|
|
// Skip to the start of the index.
|
|
_byteOffset -=
|
|
((libraryCount + 1) + _ComponentIndex.numberOfFixedFields) * 4;
|
|
|
|
// Now read the component index.
|
|
int binaryOffsetForSourceTable = _componentStartOffset + readUint32();
|
|
int binaryOffsetForConstantTable = _componentStartOffset + readUint32();
|
|
int binaryOffsetForConstantTableIndex =
|
|
_componentStartOffset + readUint32();
|
|
int binaryOffsetForCanonicalNames = _componentStartOffset + readUint32();
|
|
int binaryOffsetForMetadataPayloads = _componentStartOffset + readUint32();
|
|
int binaryOffsetForMetadataMappings = _componentStartOffset + readUint32();
|
|
int binaryOffsetForStringTable = _componentStartOffset + readUint32();
|
|
int binaryOffsetForStartOfComponentIndex =
|
|
_componentStartOffset + readUint32();
|
|
int mainMethodReference = readUint32();
|
|
NonNullableByDefaultCompiledMode compiledMode =
|
|
NonNullableByDefaultCompiledMode.values[readUint32()];
|
|
for (int i = 0; i < libraryCount + 1; ++i) {
|
|
libraryOffsets[i] = _componentStartOffset + readUint32();
|
|
}
|
|
|
|
_byteOffset = savedByteIndex;
|
|
|
|
return new _ComponentIndex(
|
|
libraryCount: libraryCount,
|
|
libraryOffsets: libraryOffsets,
|
|
componentFileSizeInBytes: componentFileSizeInBytes,
|
|
binaryOffsetForSourceTable: binaryOffsetForSourceTable,
|
|
binaryOffsetForCanonicalNames: binaryOffsetForCanonicalNames,
|
|
binaryOffsetForMetadataPayloads: binaryOffsetForMetadataPayloads,
|
|
binaryOffsetForMetadataMappings: binaryOffsetForMetadataMappings,
|
|
binaryOffsetForStringTable: binaryOffsetForStringTable,
|
|
binaryOffsetForConstantTable: binaryOffsetForConstantTable,
|
|
binaryOffsetForConstantTableIndex: binaryOffsetForConstantTableIndex,
|
|
binaryOffsetForStartOfComponentIndex:
|
|
binaryOffsetForStartOfComponentIndex,
|
|
mainMethodReference: mainMethodReference,
|
|
compiledMode: compiledMode);
|
|
}
|
|
|
|
void _readOneComponentSource(Component component, int componentFileSize) {
|
|
_componentStartOffset = _byteOffset;
|
|
|
|
final int magic = readUint32();
|
|
if (magic != Tag.ComponentFile) {
|
|
throw ArgumentError('Not a .dill file (wrong magic number).');
|
|
}
|
|
|
|
final int formatVersion = readUint32();
|
|
if (formatVersion != Tag.BinaryFormatVersion) {
|
|
throw InvalidKernelVersionError(filename, formatVersion);
|
|
}
|
|
|
|
_readAndVerifySdkHash();
|
|
|
|
// Read component index from the end of this ComponentFiles serialized data.
|
|
_ComponentIndex index = _readComponentIndex(componentFileSize);
|
|
|
|
_byteOffset = index.binaryOffsetForSourceTable;
|
|
Map<Uri, Source> uriToSource = readUriToSource(readCoverage: false);
|
|
_mergeUriToSource(component.uriToSource, uriToSource);
|
|
|
|
_byteOffset = _componentStartOffset + componentFileSize;
|
|
}
|
|
|
|
SubComponentView? _readOneComponent(
|
|
Component component, int componentFileSize,
|
|
{bool createView = false}) {
|
|
_componentStartOffset = _byteOffset;
|
|
|
|
final int magic = readUint32();
|
|
if (magic != Tag.ComponentFile) {
|
|
throw ArgumentError('Not a .dill file (wrong magic number).');
|
|
}
|
|
|
|
final int formatVersion = readUint32();
|
|
if (formatVersion != Tag.BinaryFormatVersion) {
|
|
throw InvalidKernelVersionError(filename, formatVersion);
|
|
}
|
|
|
|
_readAndVerifySdkHash();
|
|
|
|
List<String>? problemsAsJson = readListOfStrings();
|
|
if (problemsAsJson != null) {
|
|
component.problemsAsJson ??= <String>[];
|
|
component.problemsAsJson!.addAll(problemsAsJson);
|
|
}
|
|
|
|
// Read component index from the end of this ComponentFiles serialized data.
|
|
_ComponentIndex index = _readComponentIndex(componentFileSize);
|
|
if (compilationMode == null) {
|
|
compilationMode = component.modeRaw;
|
|
}
|
|
compilationMode =
|
|
mergeCompilationModeOrThrow(compilationMode, index.compiledMode);
|
|
|
|
_byteOffset = index.binaryOffsetForStringTable;
|
|
readStringTable();
|
|
|
|
_byteOffset = index.binaryOffsetForCanonicalNames;
|
|
readLinkTable(component.root);
|
|
|
|
// TODO(alexmarkov): reverse metadata mappings and read forwards
|
|
_byteOffset = index.binaryOffsetForStringTable; // Read backwards.
|
|
_readMetadataMappings(component, index.binaryOffsetForMetadataPayloads);
|
|
|
|
_associateMetadata(component, _componentStartOffset);
|
|
|
|
_byteOffset = index.binaryOffsetForSourceTable;
|
|
Map<Uri, Source> uriToSource = readUriToSource(readCoverage: true);
|
|
_mergeUriToSource(component.uriToSource, uriToSource);
|
|
|
|
_byteOffset = index.binaryOffsetForConstantTable;
|
|
readConstantTable();
|
|
// We don't need the constant table index on the dart side.
|
|
|
|
int numberOfLibraries = index.libraryCount;
|
|
|
|
SubComponentView? result;
|
|
if (createView) {
|
|
result = new SubComponentView(
|
|
new List<Library>.generate(numberOfLibraries, (int i) {
|
|
_byteOffset = index.libraryOffsets[i];
|
|
return readLibrary(component, index.libraryOffsets[i + 1]);
|
|
}, growable: false),
|
|
_componentStartOffset,
|
|
componentFileSize);
|
|
} else {
|
|
for (int i = 0; i < numberOfLibraries; ++i) {
|
|
_byteOffset = index.libraryOffsets[i];
|
|
readLibrary(component, index.libraryOffsets[i + 1]);
|
|
}
|
|
}
|
|
|
|
Reference? mainMethod =
|
|
getNullableMemberReferenceFromInt(index.mainMethodReference);
|
|
component.setMainMethodAndMode(mainMethod, false, compilationMode!);
|
|
|
|
_byteOffset = _componentStartOffset + componentFileSize;
|
|
|
|
assert(typeParameterStack.isEmpty);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Read a list of strings. If the list is empty, [null] is returned.
|
|
List<String>? readListOfStrings() {
|
|
int length = readUInt30();
|
|
if (length == 0) return null;
|
|
return new List<String>.generate(length, (_) => readString(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
/// Read the uri-to-source part of the binary.
|
|
/// Note that this can include coverage, but that it is only included if
|
|
/// [readCoverage] is true, otherwise coverage will be skipped. Note also that
|
|
/// if [readCoverage] is true, references are read and that the link table
|
|
/// thus has to be read first.
|
|
Map<Uri, Source> readUriToSource({required bool readCoverage}) {
|
|
assert(!readCoverage || (readCoverage && _lateIsInitialized(_linkTable)));
|
|
|
|
int length = readUint32();
|
|
|
|
// Read data.
|
|
_sourceUriTable = new List<Uri>.filled(length, dummyUri, growable: false);
|
|
Map<Uri, Source> uriToSource = <Uri, Source>{};
|
|
for (int i = 0; i < length; ++i) {
|
|
String uriString = readString();
|
|
Uri uri = Uri.parse(uriString);
|
|
_sourceUriTable[i] = uri;
|
|
Uint8List sourceCode = readOrViewByteList();
|
|
int lineCount = readUInt30();
|
|
List<int> lineStarts = new List<int>.filled(
|
|
lineCount,
|
|
// Use `-1` as a dummy default value.
|
|
-1,
|
|
growable: false);
|
|
int previousLineStart = 0;
|
|
for (int j = 0; j < lineCount; ++j) {
|
|
int lineStart = readUInt30() + previousLineStart;
|
|
lineStarts[j] = lineStart;
|
|
previousLineStart = lineStart;
|
|
}
|
|
String importUriString = readString();
|
|
Uri importUri = Uri.parse(importUriString);
|
|
|
|
Set<Reference>? coverageConstructors;
|
|
{
|
|
int constructorCoverageCount = readUInt30();
|
|
if (constructorCoverageCount > 0) {
|
|
if (readCoverage) {
|
|
coverageConstructors = new Set<Reference>();
|
|
for (int j = 0; j < constructorCoverageCount; ++j) {
|
|
coverageConstructors.add(readNonNullMemberReference());
|
|
}
|
|
} else {
|
|
for (int j = 0; j < constructorCoverageCount; ++j) {
|
|
skipMemberReference();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uriToSource[uri] = new Source(lineStarts, sourceCode, importUri, uri)
|
|
..constantCoverageConstructors = coverageConstructors;
|
|
}
|
|
|
|
// Read index.
|
|
for (int i = 0; i < length; ++i) {
|
|
readUint32();
|
|
}
|
|
return uriToSource;
|
|
}
|
|
|
|
// Add everything from [src] into [dst], but don't overwrite a non-empty
|
|
// source with an empty source. Empty sources may be introduced by
|
|
// synthetic, copy-down implementations such as mixin applications or
|
|
// noSuchMethod forwarders.
|
|
void _mergeUriToSource(Map<Uri, Source> dst, Map<Uri, Source> src) {
|
|
if (dst.isEmpty) {
|
|
// Fast path for the common case of one component per binary.
|
|
dst.addAll(src);
|
|
} else {
|
|
src.forEach((Uri key, Source value) {
|
|
Source? originalDestinationSource = dst[key];
|
|
Source? mergeFrom;
|
|
Source mergeTo;
|
|
if (value.source.isNotEmpty || originalDestinationSource == null) {
|
|
dst[key] = value;
|
|
mergeFrom = originalDestinationSource;
|
|
mergeTo = value;
|
|
} else {
|
|
mergeFrom = value;
|
|
mergeTo = originalDestinationSource;
|
|
}
|
|
|
|
// TODO(jensj): Find out what the right thing to do is --- it probably
|
|
// depends on what we do if read the same library twice - do we merge or
|
|
// do we overwrite, and should we even support such a thing?
|
|
|
|
// Merge coverage. Note that mergeFrom might be null.
|
|
if (mergeTo.constantCoverageConstructors == null) {
|
|
mergeTo.constantCoverageConstructors =
|
|
mergeFrom?.constantCoverageConstructors;
|
|
} else if (mergeFrom?.constantCoverageConstructors == null) {
|
|
// Nothing to do.
|
|
} else {
|
|
// Both are non-null: Merge.
|
|
mergeTo.constantCoverageConstructors!
|
|
.addAll(mergeFrom!.constantCoverageConstructors!);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void skipCanonicalNameReference() {
|
|
readUInt30();
|
|
}
|
|
|
|
CanonicalName? readNullableCanonicalNameReference() {
|
|
int index = readUInt30();
|
|
if (index == 0) return null;
|
|
return _linkTable[index - 1];
|
|
}
|
|
|
|
CanonicalName readNonNullCanonicalNameReference() {
|
|
CanonicalName? canonicalName = readNullableCanonicalNameReference();
|
|
if (canonicalName == null) {
|
|
throw new StateError('No canonical name found.');
|
|
}
|
|
return canonicalName;
|
|
}
|
|
|
|
CanonicalName? getNullableCanonicalNameReferenceFromInt(int index) {
|
|
if (index == 0) return null;
|
|
return _linkTable[index - 1];
|
|
}
|
|
|
|
Reference? readNullableLibraryReference() {
|
|
CanonicalName? canonicalName = readNullableCanonicalNameReference();
|
|
return canonicalName?.reference;
|
|
}
|
|
|
|
Reference readNonNullLibraryReference() {
|
|
CanonicalName? canonicalName = readNullableCanonicalNameReference();
|
|
if (canonicalName != null) return canonicalName.reference;
|
|
throw 'Expected a library reference to be valid but was `null`.';
|
|
}
|
|
|
|
LibraryDependency readLibraryDependencyReference() {
|
|
int index = readUInt30();
|
|
return _currentLibrary!.dependencies[index];
|
|
}
|
|
|
|
Reference? readNullableClassReference() {
|
|
CanonicalName? name = readNullableCanonicalNameReference();
|
|
return name?.reference;
|
|
}
|
|
|
|
Reference readNonNullClassReference() {
|
|
CanonicalName? name = readNullableCanonicalNameReference();
|
|
if (name == null) {
|
|
throw 'Expected a class reference to be valid but was `null`.';
|
|
}
|
|
return name.reference;
|
|
}
|
|
|
|
Reference readNonNullExtensionTypeDeclarationReference() {
|
|
CanonicalName? name = readNullableCanonicalNameReference();
|
|
if (name == null) {
|
|
throw 'Expected an extension type declaration reference to be valid but '
|
|
'was `null`.';
|
|
}
|
|
return name.reference;
|
|
}
|
|
|
|
void skipMemberReference() {
|
|
skipCanonicalNameReference();
|
|
}
|
|
|
|
Reference? readNullableMemberReference() {
|
|
CanonicalName? name = readNullableCanonicalNameReference();
|
|
return name?.reference;
|
|
}
|
|
|
|
Reference readNonNullMemberReference() {
|
|
CanonicalName? name = readNullableCanonicalNameReference();
|
|
if (name == null) {
|
|
throw 'Expected a member reference to be valid but was `null`.';
|
|
}
|
|
return name.reference;
|
|
}
|
|
|
|
Reference? readNullableInstanceMemberReference() {
|
|
Reference? reference = readNullableMemberReference();
|
|
readNullableMemberReference(); // Skip origin
|
|
return reference;
|
|
}
|
|
|
|
Reference readNonNullInstanceMemberReference() {
|
|
Reference reference = readNonNullMemberReference();
|
|
readNullableMemberReference(); // Skip origin
|
|
return reference;
|
|
}
|
|
|
|
Reference? getNullableMemberReferenceFromInt(int index) {
|
|
return getNullableCanonicalNameReferenceFromInt(index)?.reference;
|
|
}
|
|
|
|
Reference? readNullableTypedefReference() {
|
|
return readNullableCanonicalNameReference()?.reference;
|
|
}
|
|
|
|
Reference readNonNullTypedefReference() {
|
|
return readNonNullCanonicalNameReference().reference;
|
|
}
|
|
|
|
Name readName() {
|
|
final int stringReference = readUInt30();
|
|
assert(stringReference < (1 << 30));
|
|
final String text = _stringTable[stringReference];
|
|
final bool isPrivate = text.isNotEmpty && text.codeUnitAt(0) == $_;
|
|
final int libraryReferenceIndex;
|
|
final int nameCacheIndex;
|
|
|
|
if (isPrivate) {
|
|
// "Raw" reference index of 0 means null which we don't allow.
|
|
libraryReferenceIndex = readUInt30();
|
|
if (libraryReferenceIndex == 0) {
|
|
throw 'Expected a library reference to be valid but was `null`.';
|
|
}
|
|
|
|
// Check cache using the upper bits for the library reference.
|
|
nameCacheIndex = stringReference | ((libraryReferenceIndex) << 30);
|
|
} else {
|
|
// the 0 will be unused but we need to assign it.
|
|
libraryReferenceIndex = 0;
|
|
nameCacheIndex = stringReference;
|
|
}
|
|
|
|
final Name? cached = _nameCache[nameCacheIndex];
|
|
if (cached != null) {
|
|
return cached;
|
|
}
|
|
|
|
// Not in cache. Create it and cache it.
|
|
final Name name;
|
|
if (isPrivate) {
|
|
// libraryReferenceIndex was checked to be > 0 so we get a canonical name.
|
|
final CanonicalName canonicalName =
|
|
getNullableCanonicalNameReferenceFromInt(libraryReferenceIndex)!;
|
|
final Reference libraryReference = canonicalName.reference;
|
|
name = new Name.byReference(text, libraryReference);
|
|
} else {
|
|
name = new Name(text);
|
|
}
|
|
_nameCache[nameCacheIndex] = name;
|
|
return name;
|
|
}
|
|
|
|
Library readLibrary(Component component, int endOffset) {
|
|
// Read index.
|
|
int savedByteOffset = _byteOffset;
|
|
|
|
// There is a field for the procedure count.
|
|
_byteOffset = endOffset - (1) * 4;
|
|
int procedureCount = readUint32();
|
|
|
|
// There is a field for the procedure count, that number + 1 (for the end)
|
|
// offsets, and then the class count (i.e. procedure count + 3 fields).
|
|
_byteOffset = endOffset - (procedureCount + 3) * 4;
|
|
int classCount = readUint32();
|
|
List<int> procedureOffsets = new List<int>.generate(
|
|
procedureCount + 1, (int index) => _componentStartOffset + readUint32(),
|
|
growable: false);
|
|
|
|
// There is a field for the procedure count, that number + 1 (for the end)
|
|
// offsets, then the class count and that number + 1 (for the end) offsets.
|
|
// (i.e. procedure count + class count + 4 fields).
|
|
_byteOffset = endOffset - (procedureCount + classCount + 4) * 4;
|
|
List<int> classOffsets = new List<int>.generate(
|
|
classCount + 1, (int index) => _componentStartOffset + readUint32(),
|
|
growable: false);
|
|
_byteOffset = savedByteOffset;
|
|
|
|
int flags = readByte();
|
|
|
|
int languageVersionMajor = readUInt30();
|
|
int languageVersionMinor = readUInt30();
|
|
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Library? library = reference.node as Library?;
|
|
String? name = readStringOrNullIfEmpty();
|
|
|
|
// TODO(jensj): We currently save (almost the same) uri twice.
|
|
Uri fileUri = readUriReference();
|
|
|
|
if (alwaysCreateNewNamedNodes) {
|
|
library = null;
|
|
}
|
|
if (library == null) {
|
|
library = new Library(Uri.parse(canonicalName.name),
|
|
reference: reference, fileUri: fileUri);
|
|
component.libraries.add(library..parent = component);
|
|
}
|
|
_currentLibrary = library;
|
|
|
|
List<String>? problemsAsJson = readListOfStrings();
|
|
|
|
library.flags = flags;
|
|
library.setLanguageVersion(
|
|
new Version(languageVersionMajor, languageVersionMinor));
|
|
library.name = name;
|
|
library.fileUri = fileUri;
|
|
library.problemsAsJson = problemsAsJson;
|
|
|
|
assert(
|
|
mergeCompilationModeOrThrow(
|
|
compilationMode, library.nonNullableByDefaultCompiledMode) ==
|
|
compilationMode,
|
|
"Cannot load ${library.nonNullableByDefaultCompiledMode} "
|
|
"into component with mode $compilationMode");
|
|
|
|
assert(() {
|
|
debugPath.add(library!.name ?? library.importUri.toString());
|
|
return true;
|
|
}());
|
|
|
|
library.annotations = readAnnotationList(library);
|
|
_readLibraryDependencies(library);
|
|
_readAdditionalExports(library);
|
|
_readLibraryParts(library);
|
|
_readTypedefList(library);
|
|
_readClassList(library, classOffsets);
|
|
_readExtensionList(library);
|
|
_readExtensionTypeDeclarationList(library);
|
|
library.fieldsInternal = _readFieldList(library);
|
|
library.proceduresInternal = _readProcedureList(library, procedureOffsets);
|
|
|
|
assert(((_) => true)(debugPath.removeLast()));
|
|
_currentLibrary = null;
|
|
return library;
|
|
}
|
|
|
|
void _readTypedefList(Library library) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.typedefsInternal = emptyListOfTypedef;
|
|
} else {
|
|
library.typedefsInternal = new List<Typedef>.generate(
|
|
length, (int index) => readTypedef()..parent = library,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
void _readClassList(Library library, List<int> classOffsets) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.classesInternal = emptyListOfClass;
|
|
} else {
|
|
library.classesInternal = new List<Class>.generate(length, (int index) {
|
|
_byteOffset = classOffsets[index];
|
|
return readClass(classOffsets[index + 1])..parent = library;
|
|
}, growable: useGrowableLists);
|
|
_byteOffset = classOffsets.last;
|
|
}
|
|
}
|
|
|
|
void _readExtensionList(Library library) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.extensionsInternal = emptyListOfExtension;
|
|
} else {
|
|
library.extensionsInternal = new List<Extension>.generate(
|
|
length, (int index) => readExtension()..parent = library,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
void _readExtensionTypeDeclarationList(Library library) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.extensionTypeDeclarationsInternal =
|
|
emptyListOfExtensionTypeDeclaration;
|
|
} else {
|
|
library.extensionTypeDeclarationsInternal =
|
|
new List<ExtensionTypeDeclaration>.generate(length,
|
|
(int index) => readExtensionTypeDeclaration()..parent = library,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
List<Field> _readFieldList(TreeNode parent) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfField;
|
|
}
|
|
return new List<Field>.generate(
|
|
length, (int index) => readField()..parent = parent,
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<Procedure> _readProcedureList(
|
|
TreeNode parent, List<int> procedureOffsets) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfProcedure;
|
|
}
|
|
List<Procedure> list = new List<Procedure>.generate(length, (int index) {
|
|
_byteOffset = procedureOffsets[index];
|
|
return readProcedure(procedureOffsets[index + 1])..parent = parent;
|
|
}, growable: useGrowableLists);
|
|
_byteOffset = procedureOffsets.last;
|
|
return list;
|
|
}
|
|
|
|
List<Procedure> _readProcedureListWithoutOffsets(TreeNode parent) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfProcedure;
|
|
}
|
|
List<Procedure> list = new List<Procedure>.generate(length, (int index) {
|
|
return readProcedure(/* no end offset = */ -1)..parent = parent;
|
|
}, growable: useGrowableLists);
|
|
return list;
|
|
}
|
|
|
|
void _readLibraryDependencies(Library library) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.dependencies = emptyListOfLibraryDependency;
|
|
} else {
|
|
library.dependencies = new List<LibraryDependency>.generate(
|
|
length, (int index) => readLibraryDependency()..parent = library,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
LibraryDependency readLibraryDependency() {
|
|
int fileOffset = readOffset();
|
|
int flags = readByte();
|
|
List<Expression> annotations = readExpressionList();
|
|
Reference targetLibrary = readNonNullLibraryReference();
|
|
String? prefixName = readStringOrNullIfEmpty();
|
|
List<Combinator> names = readCombinatorList();
|
|
return new LibraryDependency.byReference(
|
|
flags, annotations, targetLibrary, prefixName, names)
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
void _readAdditionalExports(Library library) {
|
|
int numExportedReference = readUInt30();
|
|
if (numExportedReference != 0) {
|
|
library.additionalExports.clear();
|
|
for (int i = 0; i < numExportedReference; i++) {
|
|
CanonicalName exportedName = readNonNullCanonicalNameReference();
|
|
Reference reference = exportedName.reference;
|
|
library.additionalExports.add(reference);
|
|
}
|
|
}
|
|
}
|
|
|
|
Combinator readCombinator() {
|
|
bool isShow = readByte() == 1;
|
|
List<String> names = readStringReferenceList();
|
|
return new Combinator(isShow, names);
|
|
}
|
|
|
|
List<Combinator> readCombinatorList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfCombinator;
|
|
}
|
|
return new List<Combinator>.generate(length, (_) => readCombinator(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
void _readLibraryParts(Library library) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
library.parts = emptyListOfLibraryPart;
|
|
} else {
|
|
library.parts = new List<LibraryPart>.generate(
|
|
length, (int index) => readLibraryPart()..parent = library,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
LibraryPart readLibraryPart() {
|
|
List<Expression> annotations = readExpressionList();
|
|
String partUri = readStringReference();
|
|
return new LibraryPart(annotations, partUri);
|
|
}
|
|
|
|
Typedef readTypedef() {
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Typedef? node = reference.node as Typedef?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
Uri fileUri = readUriReference();
|
|
int fileOffset = readOffset();
|
|
String name = readStringReference();
|
|
if (node == null) {
|
|
node = new Typedef(name, null, reference: reference, fileUri: fileUri);
|
|
}
|
|
node.annotations = readAnnotationList(node);
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
DartType type = readDartType();
|
|
typeParameterStack.length = 0;
|
|
variableStack.length = 0;
|
|
node.fileOffset = fileOffset;
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.type = type;
|
|
return node;
|
|
}
|
|
|
|
Class readClass(int endOffset) {
|
|
int tag = readByte();
|
|
assert(tag == Tag.Class);
|
|
|
|
// Read index.
|
|
int savedByteOffset = _byteOffset;
|
|
// There is a field for the procedure count.
|
|
_byteOffset = endOffset - (1) * 4;
|
|
int procedureCount = readUint32();
|
|
// There is a field for the procedure count, that number + 1 (for the end)
|
|
// offsets (i.e. procedure count + 2 fields).
|
|
_byteOffset = endOffset - (procedureCount + 2) * 4;
|
|
List<int> procedureOffsets = new List<int>.generate(
|
|
procedureCount + 1, (_) => _componentStartOffset + readUint32(),
|
|
growable: false);
|
|
_byteOffset = savedByteOffset;
|
|
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Class? node = reference.node as Class?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
Uri fileUri = readUriReference();
|
|
int startFileOffset = readOffset();
|
|
int fileOffset = readOffset();
|
|
int fileEndOffset = readOffset();
|
|
int flags = readUInt30();
|
|
String name = readStringReference();
|
|
if (node == null) {
|
|
node = new Class(name: name, reference: reference, fileUri: fileUri)
|
|
..dirty = false;
|
|
}
|
|
|
|
node.startFileOffset = startFileOffset;
|
|
node.fileOffset = fileOffset;
|
|
node.fileEndOffset = fileEndOffset;
|
|
node.flags = flags;
|
|
List<Expression> annotations = readAnnotationList(node);
|
|
assert(() {
|
|
debugPath.add(name);
|
|
return true;
|
|
}());
|
|
|
|
assert(typeParameterStack.length == 0);
|
|
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
Supertype? supertype = readSupertypeOption();
|
|
Supertype? mixedInType = readSupertypeOption();
|
|
node.implementedTypes = readSupertypeList();
|
|
if (_disableLazyClassReading) {
|
|
readClassPartialContent(node, procedureOffsets);
|
|
} else {
|
|
_setLazyLoadClass(node, procedureOffsets);
|
|
}
|
|
|
|
typeParameterStack.length = 0;
|
|
assert(() {
|
|
debugPath.removeLast();
|
|
return true;
|
|
}());
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.annotations = annotations;
|
|
node.supertype = supertype;
|
|
node.mixedInType = mixedInType;
|
|
|
|
_byteOffset = endOffset;
|
|
|
|
return node;
|
|
}
|
|
|
|
Extension readExtension() {
|
|
int tag = readByte();
|
|
assert(tag == Tag.Extension);
|
|
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Extension? node = reference.node as Extension?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
|
|
String name = readStringReference();
|
|
assert(() {
|
|
debugPath.add(name);
|
|
return true;
|
|
}());
|
|
|
|
List<Expression> annotations = readAnnotationList();
|
|
|
|
Uri fileUri = readUriReference();
|
|
|
|
if (node == null) {
|
|
node = new Extension(name: name, reference: reference, fileUri: fileUri);
|
|
}
|
|
node.annotations = annotations;
|
|
setParents(annotations, node);
|
|
|
|
node.fileOffset = readOffset();
|
|
|
|
node.flags = readByte();
|
|
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
DartType onType = readDartType();
|
|
|
|
typeParameterStack.length = 0;
|
|
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.onType = onType;
|
|
|
|
node.memberDescriptors = _readExtensionMemberDescriptorList();
|
|
|
|
return node;
|
|
}
|
|
|
|
List<ExtensionMemberDescriptor> _readExtensionMemberDescriptorList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
return emptyListOfExtensionMemberDescriptor;
|
|
}
|
|
return new List<ExtensionMemberDescriptor>.generate(
|
|
length, (_) => _readExtensionMemberDescriptor(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
ExtensionMemberDescriptor _readExtensionMemberDescriptor() {
|
|
Name name = readName();
|
|
int kind = readByte();
|
|
int flags = readByte();
|
|
CanonicalName memberName = readNonNullCanonicalNameReference();
|
|
CanonicalName? tearOffName = readNullableCanonicalNameReference();
|
|
return new ExtensionMemberDescriptor(
|
|
name: name,
|
|
kind: ExtensionMemberKind.values[kind],
|
|
memberReference: memberName.reference,
|
|
tearOffReference: tearOffName?.reference)
|
|
..flags = flags;
|
|
}
|
|
|
|
ExtensionTypeDeclaration readExtensionTypeDeclaration() {
|
|
int tag = readByte();
|
|
assert(tag == Tag.ExtensionTypeDeclaration, "Unexpected tag $tag");
|
|
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
ExtensionTypeDeclaration? node =
|
|
reference.node as ExtensionTypeDeclaration?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
|
|
String name = readStringReference();
|
|
assert(() {
|
|
debugPath.add(name);
|
|
return true;
|
|
}());
|
|
|
|
List<Expression> annotations = readAnnotationList();
|
|
|
|
Uri fileUri = readUriReference();
|
|
|
|
if (node == null) {
|
|
node = new ExtensionTypeDeclaration(
|
|
name: name, reference: reference, fileUri: fileUri);
|
|
}
|
|
node.annotations = annotations;
|
|
setParents(annotations, node);
|
|
|
|
node.fileOffset = readOffset();
|
|
|
|
node.flags = readByte();
|
|
|
|
readAndPushTypeParameterList(node.typeParameters, node);
|
|
DartType representationType = readDartType();
|
|
String representationName = readStringReference();
|
|
List<TypeDeclarationType> implements =
|
|
_readExtensionTypeDeclarationImplementsList();
|
|
|
|
node.proceduresInternal = _readProcedureListWithoutOffsets(node);
|
|
typeParameterStack.length = 0;
|
|
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.declaredRepresentationType = representationType;
|
|
node.representationName = representationName;
|
|
|
|
node.implements = implements;
|
|
|
|
node.memberDescriptors = _readExtensionTypeMemberDescriptorList();
|
|
|
|
return node;
|
|
}
|
|
|
|
List<TypeDeclarationType> _readExtensionTypeDeclarationImplementsList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
return emptyListOfTypeDeclarationType;
|
|
}
|
|
return new List<TypeDeclarationType>.generate(
|
|
length, (_) => readDartType() as TypeDeclarationType,
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<ExtensionTypeMemberDescriptor> _readExtensionTypeMemberDescriptorList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
return emptyListOfExtensionTypeMemberDescriptor;
|
|
}
|
|
return new List<ExtensionTypeMemberDescriptor>.generate(
|
|
length, (_) => _readExtensionTypeMemberDescriptor(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
ExtensionTypeMemberDescriptor _readExtensionTypeMemberDescriptor() {
|
|
Name name = readName();
|
|
int kind = readByte();
|
|
int flags = readByte();
|
|
CanonicalName memberName = readNonNullCanonicalNameReference();
|
|
CanonicalName? tearOffName = readNullableCanonicalNameReference();
|
|
return new ExtensionTypeMemberDescriptor(
|
|
name: name,
|
|
kind: ExtensionTypeMemberKind.values[kind],
|
|
memberReference: memberName.reference,
|
|
tearOffReference: tearOffName?.reference)
|
|
..flags = flags;
|
|
}
|
|
|
|
/// Reads the partial content of a class, namely fields, procedures,
|
|
/// constructors and redirecting factory constructors.
|
|
void readClassPartialContent(Class node, List<int> procedureOffsets) {
|
|
node.fieldsInternal = _readFieldList(node);
|
|
_readConstructorList(node);
|
|
node.proceduresInternal = _readProcedureList(node, procedureOffsets);
|
|
}
|
|
|
|
void _readConstructorList(Class node) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
node.constructorsInternal = emptyListOfConstructor;
|
|
} else {
|
|
node.constructorsInternal = new List<Constructor>.generate(
|
|
length, (int index) => readConstructor()..parent = node,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
/// Set the lazyBuilder on the class so it can be lazy loaded in the future.
|
|
void _setLazyLoadClass(Class node, List<int> procedureOffsets) {
|
|
final int savedByteOffset = _byteOffset;
|
|
final int componentStartOffset = _componentStartOffset;
|
|
final Library? currentLibrary = _currentLibrary;
|
|
node.lazyBuilder = () {
|
|
_byteOffset = savedByteOffset;
|
|
_currentLibrary = currentLibrary;
|
|
assert(typeParameterStack.isEmpty);
|
|
_componentStartOffset = componentStartOffset;
|
|
typeParameterStack.addAll(node.typeParameters);
|
|
|
|
readClassPartialContent(node, procedureOffsets);
|
|
typeParameterStack.length = 0;
|
|
};
|
|
}
|
|
|
|
int getAndResetTransformerFlags() {
|
|
int flags = _transformerFlags;
|
|
_transformerFlags = 0;
|
|
return flags;
|
|
}
|
|
|
|
/// Adds the given flag to the current [Member.transformerFlags].
|
|
void addTransformerFlag(int flags) {
|
|
_transformerFlags |= flags;
|
|
}
|
|
|
|
Field readField() {
|
|
int tag = readByte();
|
|
assert(tag == Tag.Field);
|
|
CanonicalName fieldCanonicalName = readNonNullCanonicalNameReference();
|
|
Reference fieldReference = fieldCanonicalName.reference;
|
|
CanonicalName getterCanonicalName = readNonNullCanonicalNameReference();
|
|
Reference getterReference = getterCanonicalName.reference;
|
|
CanonicalName? setterCanonicalName = readNullableCanonicalNameReference();
|
|
Reference? setterReference = setterCanonicalName?.reference;
|
|
Field? node = fieldReference.node as Field?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
Uri fileUri = readUriReference();
|
|
int fileOffset = readOffset();
|
|
int fileEndOffset = readOffset();
|
|
int flags = readUInt30();
|
|
Name name = readName();
|
|
if (node == null) {
|
|
if (setterReference != null) {
|
|
node = new Field.mutable(name,
|
|
fieldReference: fieldReference,
|
|
getterReference: getterReference,
|
|
setterReference: setterReference,
|
|
fileUri: fileUri);
|
|
} else {
|
|
node = new Field.immutable(name,
|
|
fieldReference: fieldReference,
|
|
getterReference: getterReference,
|
|
fileUri: fileUri);
|
|
}
|
|
}
|
|
List<Expression> annotations = readAnnotationList(node);
|
|
assert(() {
|
|
debugPath.add(name.text);
|
|
return true;
|
|
}());
|
|
DartType type = readDartType();
|
|
Expression? initializer = readExpressionOption();
|
|
int transformerFlags = getAndResetTransformerFlags();
|
|
assert(((_) => true)(debugPath.removeLast()));
|
|
node.fileOffset = fileOffset;
|
|
node.fileEndOffset = fileEndOffset;
|
|
node.flags = flags;
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.annotations = annotations;
|
|
node.type = type;
|
|
node.initializer = initializer;
|
|
node.initializer?.parent = node;
|
|
node.transformerFlags = transformerFlags;
|
|
return node;
|
|
}
|
|
|
|
Constructor readConstructor() {
|
|
int tag = readByte();
|
|
assert(tag == Tag.Constructor);
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Constructor? node = reference.node as Constructor?;
|
|
if (alwaysCreateNewNamedNodes) {
|
|
node = null;
|
|
}
|
|
Uri fileUri = readUriReference();
|
|
int startFileOffset = readOffset();
|
|
int fileOffset = readOffset();
|
|
int fileEndOffset = readOffset();
|
|
int flags = readByte();
|
|
Name name = readName();
|
|
List<Expression> annotations = readAnnotationList();
|
|
assert(() {
|
|
debugPath.add(name.text);
|
|
return true;
|
|
}());
|
|
FunctionNode function = readFunctionNode();
|
|
if (node == null) {
|
|
node = new Constructor(function,
|
|
reference: reference, name: name, fileUri: fileUri);
|
|
}
|
|
pushVariableDeclarations(function.positionalParameters);
|
|
pushVariableDeclarations(function.namedParameters);
|
|
_readInitializers(node);
|
|
variableStack.length = 0;
|
|
int transformerFlags = getAndResetTransformerFlags();
|
|
assert(((_) => true)(debugPath.removeLast()));
|
|
node.startFileOffset = startFileOffset;
|
|
node.fileOffset = fileOffset;
|
|
node.fileEndOffset = fileEndOffset;
|
|
node.flags = flags;
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.annotations = annotations;
|
|
setParents(annotations, node);
|
|
node.function = function..parent = node;
|
|
node.transformerFlags = transformerFlags;
|
|
return node;
|
|
}
|
|
|
|
Procedure readProcedure(int endOffset) {
|
|
int tag = readByte();
|
|
assert(tag == Tag.Procedure);
|
|
CanonicalName canonicalName = readNonNullCanonicalNameReference();
|
|
Reference reference = canonicalName.reference;
|
|
Procedure? node;
|
|
if (!alwaysCreateNewNamedNodes) {
|
|
node = reference.node as Procedure?;
|
|
}
|
|
Uri fileUri = readUriReference();
|
|
int startFileOffset = readOffset();
|
|
int fileOffset = readOffset();
|
|
int fileEndOffset = readOffset();
|
|
int kindIndex = readByte();
|
|
ProcedureKind kind = ProcedureKind.values[kindIndex];
|
|
ProcedureStubKind stubKind = ProcedureStubKind.values[readByte()];
|
|
int flags = readUInt30();
|
|
Name name = readName();
|
|
List<Expression> annotations = readAnnotationList();
|
|
assert(() {
|
|
debugPath.add(name.text);
|
|
return true;
|
|
}());
|
|
|
|
int functionNodeSize = endOffset - _byteOffset;
|
|
// Read small factories and extension type declaration procedures
|
|
// (where `endOffset == -1`) up front. Postpone everything else.
|
|
bool readFunctionNodeNow = endOffset == -1 ||
|
|
(kind == ProcedureKind.Factory && functionNodeSize <= 50) ||
|
|
_disableLazyReading;
|
|
Reference? stubTargetReference = readNullableMemberReference();
|
|
FunctionType? signatureType = readDartTypeOption() as FunctionType?;
|
|
FunctionNode function = readFunctionNode(
|
|
lazyLoadBody: !readFunctionNodeNow, outerEndOffset: endOffset);
|
|
if (node == null) {
|
|
node = new Procedure(name, kind, function,
|
|
reference: reference, fileUri: fileUri);
|
|
} else {
|
|
assert(node.kind == kind);
|
|
}
|
|
int transformerFlags = getAndResetTransformerFlags();
|
|
assert(((_) => true)(debugPath.removeLast()));
|
|
node.fileStartOffset = startFileOffset;
|
|
node.fileOffset = fileOffset;
|
|
node.fileEndOffset = fileEndOffset;
|
|
node.flags = flags;
|
|
node.name = name;
|
|
node.fileUri = fileUri;
|
|
node.annotations = annotations;
|
|
setParents(annotations, node);
|
|
node.function = function..parent = node;
|
|
node.setTransformerFlagsWithoutLazyLoading(transformerFlags);
|
|
node.stubKind = stubKind;
|
|
node.stubTargetReference = stubTargetReference;
|
|
node.signatureType = signatureType;
|
|
|
|
assert((node.stubKind == ProcedureStubKind.ConcreteForwardingStub &&
|
|
node.stubTargetReference != null) ||
|
|
!(node.isForwardingStub && node.function.body != null));
|
|
assert(!(node.isMemberSignature && node.stubTargetReference == null),
|
|
"No member signature origin for member signature $node.");
|
|
return node;
|
|
}
|
|
|
|
void _readInitializers(Constructor constructor) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
constructor.initializers = emptyListOfInitializer;
|
|
} else {
|
|
constructor.initializers = new List<Initializer>.generate(
|
|
length, (int index) => readInitializer()..parent = constructor,
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
Initializer readInitializer() {
|
|
int tag = readByte();
|
|
bool isSynthetic = readByte() == 1;
|
|
switch (tag) {
|
|
// 52.71% (43.80% - 59.02%).
|
|
case Tag.FieldInitializer:
|
|
return _readFieldInitializer(isSynthetic);
|
|
|
|
// 42.01% (28.38% - 55.93%)
|
|
case Tag.SuperInitializer:
|
|
return _readSuperInitializer(isSynthetic);
|
|
|
|
// 4.69% (0.00% - 16.00%).
|
|
case Tag.AssertInitializer:
|
|
return _readAssertInitializer();
|
|
|
|
// The rest is < 2% on average in sampled dills.
|
|
case Tag.InvalidInitializer:
|
|
return _readInvalidInitializer();
|
|
case Tag.RedirectingInitializer:
|
|
return _readRedirectingInitializer();
|
|
case Tag.LocalInitializer:
|
|
return _readLocalInitializer();
|
|
default:
|
|
throw fail('unexpected initializer tag: $tag');
|
|
}
|
|
}
|
|
|
|
Initializer _readInvalidInitializer() {
|
|
return new InvalidInitializer();
|
|
}
|
|
|
|
Initializer _readFieldInitializer(bool isSynthetic) {
|
|
int offset = readOffset();
|
|
Reference reference = readNonNullMemberReference();
|
|
Expression value = readExpression();
|
|
return new FieldInitializer.byReference(reference, value)
|
|
..isSynthetic = isSynthetic
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Initializer _readSuperInitializer(bool isSynthetic) {
|
|
int offset = readOffset();
|
|
Reference reference = readNonNullMemberReference();
|
|
Arguments arguments = readArguments();
|
|
return new SuperInitializer.byReference(reference, arguments)
|
|
..isSynthetic = isSynthetic
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Initializer _readRedirectingInitializer() {
|
|
int offset = readOffset();
|
|
return new RedirectingInitializer.byReference(
|
|
readNonNullMemberReference(), readArguments())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Initializer _readLocalInitializer() {
|
|
return new LocalInitializer(readAndPushVariableDeclaration());
|
|
}
|
|
|
|
Initializer _readAssertInitializer() {
|
|
return new AssertInitializer(readStatement() as AssertStatement);
|
|
}
|
|
|
|
FunctionNode readFunctionNode(
|
|
{bool lazyLoadBody = false, int outerEndOffset = -1}) {
|
|
int tag = readByte();
|
|
assert(tag == Tag.FunctionNode);
|
|
int offset = readOffset();
|
|
int endOffset = readOffset();
|
|
AsyncMarker asyncMarker = AsyncMarker.values[readByte()];
|
|
AsyncMarker dartAsyncMarker = AsyncMarker.values[readByte()];
|
|
int typeParameterStackHeight = typeParameterStack.length;
|
|
List<TypeParameter> typeParameters = readAndPushTypeParameterList();
|
|
readUInt30(); // total parameter count.
|
|
int requiredParameterCount = readUInt30();
|
|
int variableStackHeight = variableStack.length;
|
|
List<VariableDeclaration> positional = readAndPushVariableDeclarationList();
|
|
List<VariableDeclaration> named = readAndPushVariableDeclarationList();
|
|
DartType returnType = readDartType();
|
|
DartType? futureValueType = readDartTypeOption();
|
|
RedirectingFactoryTarget? redirectingFactoryTarget;
|
|
if (readAndCheckOptionTag()) {
|
|
Reference? targetReference = readNullableMemberReference();
|
|
List<DartType>? typeArguments;
|
|
if (readAndCheckOptionTag()) {
|
|
typeArguments = readDartTypeList();
|
|
}
|
|
if (readAndCheckOptionTag()) {
|
|
assert(targetReference == null && typeArguments == null);
|
|
String errorMessage = readStringReference();
|
|
redirectingFactoryTarget =
|
|
new RedirectingFactoryTarget.error(errorMessage);
|
|
} else {
|
|
assert(targetReference != null && typeArguments != null);
|
|
redirectingFactoryTarget = new RedirectingFactoryTarget.byReference(
|
|
targetReference!, typeArguments!);
|
|
}
|
|
}
|
|
|
|
int oldLabelStackBase = labelStackBase;
|
|
int oldSwitchCaseStackBase = switchCaseStackBase;
|
|
|
|
if (lazyLoadBody && outerEndOffset > 0) {
|
|
lazyLoadBody = outerEndOffset - _byteOffset >
|
|
2; // e.g. outline has Tag.Something and Tag.EmptyStatement
|
|
}
|
|
|
|
Statement? body;
|
|
if (!lazyLoadBody) {
|
|
labelStackBase = labelStack.length;
|
|
switchCaseStackBase = switchCaseStack.length;
|
|
body = readStatementOption();
|
|
}
|
|
|
|
FunctionNode result = new FunctionNode(body,
|
|
typeParameters: typeParameters,
|
|
requiredParameterCount: requiredParameterCount,
|
|
positionalParameters: positional,
|
|
namedParameters: named,
|
|
returnType: returnType,
|
|
asyncMarker: asyncMarker,
|
|
dartAsyncMarker: dartAsyncMarker,
|
|
futureValueType: futureValueType)
|
|
..fileOffset = offset
|
|
..fileEndOffset = endOffset
|
|
..redirectingFactoryTarget = redirectingFactoryTarget;
|
|
|
|
if (lazyLoadBody) {
|
|
_setLazyLoadFunction(result, oldLabelStackBase, oldSwitchCaseStackBase,
|
|
variableStackHeight);
|
|
}
|
|
|
|
labelStackBase = oldLabelStackBase;
|
|
switchCaseStackBase = oldSwitchCaseStackBase;
|
|
variableStack.length = variableStackHeight;
|
|
typeParameterStack.length = typeParameterStackHeight;
|
|
|
|
return result;
|
|
}
|
|
|
|
void _setLazyLoadFunction(FunctionNode result, int oldLabelStackBase,
|
|
int oldSwitchCaseStackBase, int variableStackHeight) {
|
|
final int savedByteOffset = _byteOffset;
|
|
final int componentStartOffset = _componentStartOffset;
|
|
final List<TypeParameter> typeParameters =
|
|
typeParameterStack.cast<TypeParameter>().toList();
|
|
final List<VariableDeclaration> variables = variableStack.toList();
|
|
final Library currentLibrary = _currentLibrary!;
|
|
result.lazyBuilder = () {
|
|
_byteOffset = savedByteOffset;
|
|
_currentLibrary = currentLibrary;
|
|
typeParameterStack.clear();
|
|
typeParameterStack.addAll(typeParameters);
|
|
variableStack.clear();
|
|
variableStack.addAll(variables);
|
|
_componentStartOffset = componentStartOffset;
|
|
|
|
result.body = readStatementOption();
|
|
result.body?.parent = result;
|
|
labelStackBase = oldLabelStackBase;
|
|
switchCaseStackBase = oldSwitchCaseStackBase;
|
|
variableStack.length = variableStackHeight;
|
|
typeParameterStack.clear();
|
|
TreeNode? parent = result.parent;
|
|
if (parent is Procedure) {
|
|
parent.transformerFlags |= getAndResetTransformerFlags();
|
|
}
|
|
};
|
|
}
|
|
|
|
void pushVariableDeclaration(VariableDeclaration variable) {
|
|
variableStack.add(variable);
|
|
}
|
|
|
|
void pushVariableDeclarations(List<VariableDeclaration> variables) {
|
|
variableStack.addAll(variables);
|
|
}
|
|
|
|
VariableDeclaration readVariableReference() {
|
|
readUInt30(); // offset of the variable declaration in the binary.
|
|
return _readVariableReferenceInternal();
|
|
}
|
|
|
|
VariableDeclaration _readVariableReferenceInternal() {
|
|
int index = readUInt30();
|
|
if (index >= variableStack.length) {
|
|
throw fail('Unexpected variable index: $index. '
|
|
'Current variable count: ${variableStack.length}.');
|
|
}
|
|
return variableStack[index];
|
|
}
|
|
|
|
LogicalExpressionOperator logicalOperatorToEnum(int index) {
|
|
switch (index) {
|
|
case 0:
|
|
return LogicalExpressionOperator.AND;
|
|
case 1:
|
|
return LogicalExpressionOperator.OR;
|
|
default:
|
|
throw fail('unexpected logical operator index: $index');
|
|
}
|
|
}
|
|
|
|
List<Expression> readExpressionList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
return emptyListOfExpression;
|
|
}
|
|
return new List<Expression>.generate(length, (_) => readExpression(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
Expression? readExpressionOption() {
|
|
return readAndCheckOptionTag() ? readExpression() : null;
|
|
}
|
|
|
|
Expression readExpression() {
|
|
int tagByte = readByte();
|
|
int tag = tagByte & Tag.SpecializedTagHighBits == Tag.SpecializedTagHighBits
|
|
? (tagByte & Tag.SpecializedTagMask)
|
|
: tagByte;
|
|
switch (tag) {
|
|
// 18.57% (13.56% - 23.28%).
|
|
case Tag.SpecializedVariableGet:
|
|
return _readSpecializedVariableGet(tagByte);
|
|
|
|
// 12.02% (9.14% - 14.14%).
|
|
case Tag.InstanceGet:
|
|
return _readInstanceGet();
|
|
|
|
// 10.61% (6.82% - 14.13%).
|
|
case Tag.ThisExpression:
|
|
return _readThisLiteral();
|
|
|
|
// 10.19% (6.51% - 15.46%).
|
|
case Tag.ConstantExpression:
|
|
return _readConstantExpression();
|
|
|
|
// 9.95% (5.96% - 13.10%).
|
|
case Tag.InstanceInvocation:
|
|
return _readInstanceInvocation();
|
|
|
|
// 6.20% (2.67% - 12.88%)
|
|
case Tag.StringLiteral:
|
|
return _readStringLiteral();
|
|
|
|
// 4.30% (1.89% - 5.58%).
|
|
case Tag.VariableGet:
|
|
return _readVariableGet();
|
|
|
|
// 3.94% (2.48% - 6.29%).
|
|
case Tag.StaticInvocation:
|
|
return _readStaticInvocation();
|
|
|
|
// 2.95% (1.58% - 5.31%).
|
|
case Tag.SpecializedIntLiteral:
|
|
return _readSpecializedIntLiteral(tagByte);
|
|
|
|
// 2.92% (1.76% - 5.21%).
|
|
case Tag.ConstructorInvocation:
|
|
return _readConstructorInvocation();
|
|
|
|
// The rest is < 2% on average in sampled dills.
|
|
case Tag.LoadLibrary:
|
|
return _readLoadLibrary();
|
|
case Tag.CheckLibraryIsLoaded:
|
|
return _readCheckLibraryIsLoaded();
|
|
case Tag.InvalidExpression:
|
|
return _readInvalidExpression();
|
|
case Tag.VariableSet:
|
|
return _readVariableSet();
|
|
case Tag.SpecializedVariableSet:
|
|
return _readSpecializedVariableSet(tagByte);
|
|
case Tag.InstanceTearOff:
|
|
return _readInstanceTearOff();
|
|
case Tag.DynamicGet:
|
|
return _readDynamicGet();
|
|
case Tag.RecordIndexGet:
|
|
return _readRecordIndexGet();
|
|
case Tag.RecordNameGet:
|
|
return _readRecordNameGet();
|
|
case Tag.InstanceSet:
|
|
return _readInstanceSet();
|
|
case Tag.DynamicSet:
|
|
return _readDynamicSet();
|
|
case Tag.AbstractSuperPropertyGet:
|
|
return _readAbstractSuperPropertyGet();
|
|
case Tag.AbstractSuperPropertySet:
|
|
return _readAbstractSuperPropertySet();
|
|
case Tag.SuperPropertyGet:
|
|
return _readSuperPropertyGet();
|
|
case Tag.SuperPropertySet:
|
|
return _readSuperPropertySet();
|
|
case Tag.StaticGet:
|
|
return _readStaticGet();
|
|
case Tag.StaticTearOff:
|
|
return _readStaticTearOff();
|
|
case Tag.StaticSet:
|
|
return _readStaticSet();
|
|
case Tag.ConstructorTearOff:
|
|
return _readConstructorTearOff();
|
|
case Tag.TypedefTearOff:
|
|
return _readTypedefTearOff();
|
|
case Tag.RedirectingFactoryTearOff:
|
|
return _readRedirectingFactoryTearOff();
|
|
case Tag.InstanceGetterInvocation:
|
|
return _readInstanceGetterInvocation();
|
|
case Tag.DynamicInvocation:
|
|
return _readDynamicInvocation();
|
|
case Tag.FunctionInvocation:
|
|
return _readFunctionInvocation();
|
|
case Tag.FunctionTearOff:
|
|
return _readFunctionTearOff();
|
|
case Tag.LocalFunctionInvocation:
|
|
return _readLocalFunctionInvocation();
|
|
case Tag.EqualsNull:
|
|
return _readEqualsNull();
|
|
case Tag.EqualsCall:
|
|
return _readEqualsCall();
|
|
case Tag.AbstractSuperMethodInvocation:
|
|
return _readAbstractSuperMethodInvocation();
|
|
case Tag.SuperMethodInvocation:
|
|
return _readSuperMethodInvocation();
|
|
case Tag.ConstStaticInvocation:
|
|
return _readConstStaticInvocation();
|
|
case Tag.ConstConstructorInvocation:
|
|
return _readConstConstructorInvocation();
|
|
case Tag.Not:
|
|
return _readNot();
|
|
case Tag.NullCheck:
|
|
return _readNullCheck();
|
|
case Tag.LogicalExpression:
|
|
return _readLogicalExpression();
|
|
case Tag.ConditionalExpression:
|
|
return _readConditionalExpression();
|
|
case Tag.StringConcatenation:
|
|
return _readStringConcatenation();
|
|
case Tag.ListConcatenation:
|
|
return _readListConcatenation();
|
|
case Tag.SetConcatenation:
|
|
return _readSetConcatenation();
|
|
case Tag.MapConcatenation:
|
|
return _readMapConcatenation();
|
|
case Tag.InstanceCreation:
|
|
return _readInstanceCreation();
|
|
case Tag.FileUriExpression:
|
|
return _readFileUriExpression();
|
|
case Tag.IsExpression:
|
|
return _readIsExpression();
|
|
case Tag.AsExpression:
|
|
return _readAsExpression();
|
|
case Tag.PositiveIntLiteral:
|
|
return _readPositiveIntLiteral();
|
|
case Tag.NegativeIntLiteral:
|
|
return _readNegativeIntLiteral();
|
|
case Tag.BigIntLiteral:
|
|
return _readBigIntLiteral();
|
|
case Tag.DoubleLiteral:
|
|
return _readDoubleLiteral();
|
|
case Tag.TrueLiteral:
|
|
return _readTrueLiteral();
|
|
case Tag.FalseLiteral:
|
|
return _readFalseLiteral();
|
|
case Tag.NullLiteral:
|
|
return _readNullLiteral();
|
|
case Tag.SymbolLiteral:
|
|
return _readSymbolLiteral();
|
|
case Tag.TypeLiteral:
|
|
return _readTypeLiteral();
|
|
case Tag.Rethrow:
|
|
return _readRethrow();
|
|
case Tag.Throw:
|
|
return _readThrow();
|
|
case Tag.ListLiteral:
|
|
return _readListLiteral();
|
|
case Tag.ConstListLiteral:
|
|
return _readConstListLiteral();
|
|
case Tag.SetLiteral:
|
|
return _readSetLiteral();
|
|
case Tag.ConstSetLiteral:
|
|
return _readConstSetLiteral();
|
|
case Tag.MapLiteral:
|
|
return _readMapLiteral();
|
|
case Tag.ConstMapLiteral:
|
|
return _readConstMapLiteral();
|
|
case Tag.RecordLiteral:
|
|
return _readRecordLiteral();
|
|
case Tag.ConstRecordLiteral:
|
|
return _readConstRecordLiteral();
|
|
case Tag.AwaitExpression:
|
|
return _readAwaitExpression();
|
|
case Tag.FunctionExpression:
|
|
return _readFunctionExpression();
|
|
case Tag.Let:
|
|
return _readLet();
|
|
case Tag.BlockExpression:
|
|
return _readBlockExpression();
|
|
case Tag.Instantiation:
|
|
return _readInstantiation();
|
|
case Tag.SwitchExpression:
|
|
return _readSwitchExpression();
|
|
case Tag.PatternAssignment:
|
|
return _readPatternAssignment();
|
|
case Tag.FileUriConstantExpression:
|
|
return _readFileUriConstantExpression();
|
|
default:
|
|
throw fail('unexpected expression tag: $tag');
|
|
}
|
|
}
|
|
|
|
Expression _readLoadLibrary() {
|
|
int offset = readOffset();
|
|
return new LoadLibrary(readLibraryDependencyReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readCheckLibraryIsLoaded() {
|
|
int offset = readOffset();
|
|
return new CheckLibraryIsLoaded(readLibraryDependencyReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInvalidExpression() {
|
|
int offset = readOffset();
|
|
return new InvalidExpression(
|
|
readStringOrNullIfEmpty(), readExpressionOption())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readVariableGet() {
|
|
int offset = readOffset();
|
|
return new VariableGet(readVariableReference(), readDartTypeOption())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSpecializedVariableGet(int tagByte) {
|
|
int index = tagByte & Tag.SpecializedPayloadMask;
|
|
int offset = readOffset();
|
|
readUInt30(); // offset of the variable declaration in the binary.
|
|
return new VariableGet(variableStack[index])..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readVariableSet() {
|
|
int offset = readOffset();
|
|
return new VariableSet(readVariableReference(), readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSpecializedVariableSet(int tagByte) {
|
|
int index = tagByte & Tag.SpecializedPayloadMask;
|
|
int offset = readOffset();
|
|
readUInt30(); // offset of the variable declaration in the binary.
|
|
return new VariableSet(variableStack[index], readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstanceGet() {
|
|
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new InstanceGet.byReference(kind, readExpression(), readName(),
|
|
resultType: readDartType(),
|
|
interfaceTargetReference: readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstanceTearOff() {
|
|
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new InstanceTearOff.byReference(kind, readExpression(), readName(),
|
|
resultType: readDartType(),
|
|
interfaceTargetReference: readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readDynamicGet() {
|
|
DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new DynamicGet(kind, readExpression(), readName())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readRecordIndexGet() {
|
|
int offset = readOffset();
|
|
Expression receiver = readExpression();
|
|
RecordType receiverType = readDartType() as RecordType;
|
|
int index = readUInt30();
|
|
return RecordIndexGet(receiver, receiverType, index)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readRecordNameGet() {
|
|
int offset = readOffset();
|
|
Expression receiver = readExpression();
|
|
RecordType receiverType = readDartType() as RecordType;
|
|
String name = readStringReference();
|
|
return RecordNameGet(receiver, receiverType, name)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstanceSet() {
|
|
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new InstanceSet.byReference(
|
|
kind, readExpression(), readName(), readExpression(),
|
|
interfaceTargetReference: readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readDynamicSet() {
|
|
DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new DynamicSet(kind, readExpression(), readName(), readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readAbstractSuperPropertyGet() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new AbstractSuperPropertyGet.byReference(
|
|
readName(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readAbstractSuperPropertySet() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new AbstractSuperPropertySet.byReference(
|
|
readName(), readExpression(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSuperPropertyGet() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperPropertyGet.byReference(
|
|
readName(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSuperPropertySet() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperPropertySet.byReference(
|
|
readName(), readExpression(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readStaticGet() {
|
|
int offset = readOffset();
|
|
return new StaticGet.byReference(readNonNullMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstructorTearOff() {
|
|
int offset = readOffset();
|
|
Reference constructorReference = readNonNullMemberReference();
|
|
return new ConstructorTearOff.byReference(constructorReference)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readTypedefTearOff() {
|
|
int offset = readOffset();
|
|
List<TypeParameter> typeParameters = readAndPushTypeParameterList();
|
|
Expression expression = readExpression();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
typeParameterStack.length -= typeParameters.length;
|
|
return new TypedefTearOff(typeParameters, expression, typeArguments)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readRedirectingFactoryTearOff() {
|
|
int offset = readOffset();
|
|
Reference constructorReference = readNonNullMemberReference();
|
|
return new RedirectingFactoryTearOff.byReference(constructorReference)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readStaticTearOff() {
|
|
int offset = readOffset();
|
|
return new StaticTearOff.byReference(readNonNullMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readStaticSet() {
|
|
int offset = readOffset();
|
|
return new StaticSet.byReference(
|
|
readNonNullMemberReference(), readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstanceInvocation() {
|
|
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
|
|
int flags = readByte();
|
|
int offset = readOffset();
|
|
return new InstanceInvocation.byReference(
|
|
kind, readExpression(), readName(), readArguments(),
|
|
functionType: readDartType() as FunctionType,
|
|
interfaceTargetReference: readNonNullInstanceMemberReference())
|
|
..fileOffset = offset
|
|
..flags = flags;
|
|
}
|
|
|
|
Expression _readInstanceGetterInvocation() {
|
|
InstanceAccessKind kind = InstanceAccessKind.values[readByte()];
|
|
int flags = readByte();
|
|
int offset = readOffset();
|
|
Expression receiver = readExpression();
|
|
Name name = readName();
|
|
Arguments arguments = readArguments();
|
|
DartType functionType = readDartType();
|
|
// `const DynamicType()` is used to encode a missing function type.
|
|
assert(functionType is FunctionType || functionType is DynamicType,
|
|
"Unexpected function type $functionType for InstanceGetterInvocation");
|
|
Reference interfaceTargetReference = readNonNullInstanceMemberReference();
|
|
return new InstanceGetterInvocation.byReference(
|
|
kind, receiver, name, arguments,
|
|
functionType: functionType is FunctionType ? functionType : null,
|
|
interfaceTargetReference: interfaceTargetReference)
|
|
..fileOffset = offset
|
|
..flags = flags;
|
|
}
|
|
|
|
Expression _readDynamicInvocation() {
|
|
DynamicAccessKind kind = DynamicAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
return new DynamicInvocation(
|
|
kind, readExpression(), readName(), readArguments())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readFunctionInvocation() {
|
|
FunctionAccessKind kind = FunctionAccessKind.values[readByte()];
|
|
int offset = readOffset();
|
|
Expression receiver = readExpression();
|
|
Arguments arguments = readArguments();
|
|
DartType functionType = readDartType();
|
|
// `const DynamicType()` is used to encode a missing function type.
|
|
assert(functionType is FunctionType || functionType is DynamicType,
|
|
"Unexpected function type $functionType for FunctionInvocation");
|
|
return new FunctionInvocation(kind, receiver, arguments,
|
|
functionType: functionType is FunctionType ? functionType : null)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readFunctionTearOff() {
|
|
int offset = readOffset();
|
|
return new FunctionTearOff(readExpression())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readLocalFunctionInvocation() {
|
|
int offset = readOffset();
|
|
VariableDeclaration variable = readVariableReference();
|
|
return new LocalFunctionInvocation(variable, readArguments(),
|
|
functionType: readDartType() as FunctionType)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readEqualsNull() {
|
|
int offset = readOffset();
|
|
return new EqualsNull(readExpression())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readEqualsCall() {
|
|
int offset = readOffset();
|
|
return new EqualsCall.byReference(readExpression(), readExpression(),
|
|
functionType: readDartType() as FunctionType,
|
|
interfaceTargetReference: readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readAbstractSuperMethodInvocation() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new AbstractSuperMethodInvocation.byReference(
|
|
readName(), readArguments(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSuperMethodInvocation() {
|
|
int offset = readOffset();
|
|
addTransformerFlag(TransformerFlag.superCalls);
|
|
return new SuperMethodInvocation.byReference(
|
|
readName(), readArguments(), readNonNullInstanceMemberReference())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readStaticInvocation() {
|
|
int offset = readOffset();
|
|
return new StaticInvocation.byReference(
|
|
readNonNullMemberReference(), readArguments(),
|
|
isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstStaticInvocation() {
|
|
int offset = readOffset();
|
|
return new StaticInvocation.byReference(
|
|
readNonNullMemberReference(), readArguments(),
|
|
isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstructorInvocation() {
|
|
int offset = readOffset();
|
|
return new ConstructorInvocation.byReference(
|
|
readNonNullMemberReference(), readArguments(),
|
|
isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstConstructorInvocation() {
|
|
int offset = readOffset();
|
|
return new ConstructorInvocation.byReference(
|
|
readNonNullMemberReference(), readArguments(),
|
|
isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readNot() {
|
|
int offset = readOffset();
|
|
return new Not(readExpression())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readNullCheck() {
|
|
int offset = readOffset();
|
|
return new NullCheck(readExpression())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readLogicalExpression() {
|
|
int offset = readOffset();
|
|
return new LogicalExpression(
|
|
readExpression(), logicalOperatorToEnum(readByte()), readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConditionalExpression() {
|
|
int offset = readOffset();
|
|
return new ConditionalExpression(
|
|
readExpression(),
|
|
readExpression(),
|
|
readExpression(),
|
|
// TODO(johnniwinther): Change this to use `readDartType`.
|
|
readDartTypeOption()!)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readStringConcatenation() {
|
|
int offset = readOffset();
|
|
return new StringConcatenation(readExpressionList())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readListConcatenation() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new ListConcatenation(readExpressionList(),
|
|
typeArgument: typeArgument)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSetConcatenation() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new SetConcatenation(readExpressionList(),
|
|
typeArgument: typeArgument)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readMapConcatenation() {
|
|
int offset = readOffset();
|
|
DartType keyType = readDartType();
|
|
DartType valueType = readDartType();
|
|
return new MapConcatenation(readExpressionList(),
|
|
keyType: keyType, valueType: valueType)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstanceCreation() {
|
|
int offset = readOffset();
|
|
Reference classReference = readNonNullClassReference();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
int fieldValueCount = readUInt30();
|
|
Map<Reference, Expression> fieldValues = <Reference, Expression>{};
|
|
for (int i = 0; i < fieldValueCount; i++) {
|
|
final Reference fieldRef = readNonNullCanonicalNameReference().reference;
|
|
final Expression value = readExpression();
|
|
fieldValues[fieldRef] = value;
|
|
}
|
|
int assertCount = readUInt30();
|
|
List<AssertStatement> asserts;
|
|
|
|
if (!useGrowableLists && assertCount == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
asserts = emptyListOfAssertStatement;
|
|
} else {
|
|
asserts = new List<AssertStatement>.generate(
|
|
assertCount, (_) => readStatement() as AssertStatement,
|
|
growable: false);
|
|
}
|
|
List<Expression> unusedArguments = readExpressionList();
|
|
return new InstanceCreation(
|
|
classReference, typeArguments, fieldValues, asserts, unusedArguments)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readFileUriExpression() {
|
|
Uri fileUri = readUriReference();
|
|
int offset = readOffset();
|
|
return new FileUriExpression(readExpression(), fileUri)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readIsExpression() {
|
|
int offset = readOffset();
|
|
int flags = readByte();
|
|
return new IsExpression(readExpression(), readDartType())
|
|
..fileOffset = offset
|
|
..flags = flags;
|
|
}
|
|
|
|
Expression _readAsExpression() {
|
|
int offset = readOffset();
|
|
int flags = readByte();
|
|
return new AsExpression(readExpression(), readDartType())
|
|
..fileOffset = offset
|
|
..flags = flags;
|
|
}
|
|
|
|
Expression _readStringLiteral() {
|
|
int offset = readOffset();
|
|
return new StringLiteral(readStringReference())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSpecializedIntLiteral(int tagByte) {
|
|
int biasedValue = tagByte & Tag.SpecializedPayloadMask;
|
|
return new IntLiteral(biasedValue - Tag.SpecializedIntLiteralBias)
|
|
..fileOffset = readOffset();
|
|
}
|
|
|
|
Expression _readPositiveIntLiteral() {
|
|
int offset = readOffset();
|
|
int value = readUInt30();
|
|
return new IntLiteral(value)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readNegativeIntLiteral() {
|
|
int offset = readOffset();
|
|
int value = -readUInt30();
|
|
return new IntLiteral(value)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readBigIntLiteral() {
|
|
int offset = readOffset();
|
|
int value = int.parse(readStringReference());
|
|
return new IntLiteral(value)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readDoubleLiteral() {
|
|
int offset = readOffset();
|
|
double value = readDouble();
|
|
return new DoubleLiteral(value)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readTrueLiteral() {
|
|
return new BoolLiteral(true)..fileOffset = readOffset();
|
|
}
|
|
|
|
Expression _readFalseLiteral() {
|
|
return new BoolLiteral(false)..fileOffset = readOffset();
|
|
}
|
|
|
|
Expression _readNullLiteral() {
|
|
return new NullLiteral()..fileOffset = readOffset();
|
|
}
|
|
|
|
Expression _readSymbolLiteral() {
|
|
int offset = readOffset();
|
|
String value = readStringReference();
|
|
return new SymbolLiteral(value)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readTypeLiteral() {
|
|
int offset = readOffset();
|
|
return new TypeLiteral(readDartType())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readThisLiteral() {
|
|
return new ThisExpression()..fileOffset = readOffset();
|
|
}
|
|
|
|
Expression _readRethrow() {
|
|
int offset = readOffset();
|
|
return new Rethrow()..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readThrow() {
|
|
int offset = readOffset();
|
|
return new Throw(readExpression())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readListLiteral() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new ListLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstListLiteral() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new ListLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readSetLiteral() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new SetLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstSetLiteral() {
|
|
int offset = readOffset();
|
|
DartType typeArgument = readDartType();
|
|
return new SetLiteral(readExpressionList(),
|
|
typeArgument: typeArgument, isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readMapLiteral() {
|
|
int offset = readOffset();
|
|
DartType keyType = readDartType();
|
|
DartType valueType = readDartType();
|
|
return new MapLiteral(readMapLiteralEntryList(),
|
|
keyType: keyType, valueType: valueType, isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstMapLiteral() {
|
|
int offset = readOffset();
|
|
DartType keyType = readDartType();
|
|
DartType valueType = readDartType();
|
|
return new MapLiteral(readMapLiteralEntryList(),
|
|
keyType: keyType, valueType: valueType, isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readRecordLiteral() {
|
|
int offset = readOffset();
|
|
List<Expression> positional = readExpressionList();
|
|
List<NamedExpression> named = readNamedExpressionList();
|
|
RecordType recordType = readDartType() as RecordType;
|
|
return new RecordLiteral(positional, named, recordType, isConst: false)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstRecordLiteral() {
|
|
int offset = readOffset();
|
|
List<Expression> positional = readExpressionList();
|
|
List<NamedExpression> named = readNamedExpressionList();
|
|
RecordType recordType = readDartType() as RecordType;
|
|
return new RecordLiteral(positional, named, recordType, isConst: true)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readAwaitExpression() {
|
|
int offset = readOffset();
|
|
return new AwaitExpression(readExpression())
|
|
..fileOffset = offset
|
|
..runtimeCheckType = readDartTypeOption();
|
|
}
|
|
|
|
Expression _readFunctionExpression() {
|
|
int offset = readOffset();
|
|
return new FunctionExpression(readFunctionNode())..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readLet() {
|
|
int offset = readOffset();
|
|
VariableDeclaration variable = readVariableDeclaration();
|
|
int stackHeight = variableStack.length;
|
|
pushVariableDeclaration(variable);
|
|
Expression body = readExpression();
|
|
variableStack.length = stackHeight;
|
|
return new Let(variable, body)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readBlockExpression() {
|
|
int offset = readOffset();
|
|
int stackHeight = variableStack.length;
|
|
List<Statement> statements = readStatementListAlwaysGrowable();
|
|
Expression value = readExpression();
|
|
variableStack.length = stackHeight;
|
|
return new BlockExpression(new Block(statements), value)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readInstantiation() {
|
|
int offset = readOffset();
|
|
Expression expression = readExpression();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
return new Instantiation(expression, typeArguments)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readConstantExpression() {
|
|
int offset = readOffset();
|
|
DartType type = readDartType();
|
|
Constant constant = readConstantReference();
|
|
return new ConstantExpression(constant, type)..fileOffset = offset;
|
|
}
|
|
|
|
Expression _readFileUriConstantExpression() {
|
|
int offset = readOffset();
|
|
Uri fileUri = readUriReference();
|
|
DartType type = readDartType();
|
|
Constant constant = readConstantReference();
|
|
return new FileUriConstantExpression(constant, type: type, fileUri: fileUri)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
List<MapLiteralEntry> readMapLiteralEntryList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfMapLiteralEntry;
|
|
}
|
|
return new List<MapLiteralEntry>.generate(length, (_) => readMapEntry(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
MapLiteralEntry readMapEntry() {
|
|
return new MapLiteralEntry(readExpression(), readExpression());
|
|
}
|
|
|
|
Pattern _readPattern() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.AndPattern:
|
|
return _readAndPattern();
|
|
case Tag.AssignedVariablePattern:
|
|
return _readAssignedVariablePattern();
|
|
case Tag.CastPattern:
|
|
return _readCastPattern();
|
|
case Tag.ConstantPattern:
|
|
return _readConstantPattern();
|
|
case Tag.InvalidPattern:
|
|
return _readInvalidPattern();
|
|
case Tag.ListPattern:
|
|
return _readListPattern();
|
|
case Tag.MapPattern:
|
|
return _readMapPattern();
|
|
case Tag.NamedPattern:
|
|
return _readNamedPattern();
|
|
case Tag.NullAssertPattern:
|
|
return _readNullAssertPattern();
|
|
case Tag.NullCheckPattern:
|
|
return _readNullCheckPattern();
|
|
case Tag.ObjectPattern:
|
|
return _readObjectPattern();
|
|
case Tag.OrPattern:
|
|
return _readOrPattern();
|
|
case Tag.RecordPattern:
|
|
return _readRecordPattern();
|
|
case Tag.RelationalPattern:
|
|
return _readRelationalPattern();
|
|
case Tag.RestPattern:
|
|
return _readRestPattern();
|
|
case Tag.VariablePattern:
|
|
return _readVariablePattern();
|
|
case Tag.WildcardPattern:
|
|
return _readWildcardPattern();
|
|
default:
|
|
throw fail('unexpected pattern tag: $tag');
|
|
}
|
|
}
|
|
|
|
Pattern? _readOptionalPattern() {
|
|
return readAndCheckOptionTag() ? _readPattern() : null;
|
|
}
|
|
|
|
List<Pattern> _readPatternList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfPattern;
|
|
}
|
|
return new List<Pattern>.generate(length, (_) => _readPattern(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<NamedPattern> _readNamedPatternList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfNamedPattern;
|
|
}
|
|
return new List<NamedPattern>.generate(
|
|
length, (_) => _readPattern() as NamedPattern,
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<VariableDeclaration> _readVariableReferenceList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfVariableDeclaration;
|
|
}
|
|
return new List<VariableDeclaration>.generate(
|
|
length, (_) => readVariableReference(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<MapPatternEntry> _readMapPatternEntryList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfMapPatternEntry;
|
|
}
|
|
return new List<MapPatternEntry>.generate(
|
|
length, (_) => _readMapPatternEntry(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
AndPattern _readAndPattern() {
|
|
int fileOffset = readOffset();
|
|
return new AndPattern(_readPattern(), _readPattern())
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
AssignedVariablePattern _readAssignedVariablePattern() {
|
|
int fileOffset = readOffset();
|
|
VariableDeclaration variable = readVariableReference();
|
|
DartType? matchedType = readDartTypeOption();
|
|
bool needsCheck = readByte() == 1;
|
|
return AssignedVariablePattern(variable)
|
|
..fileOffset = fileOffset
|
|
..matchedValueType = matchedType
|
|
..needsCast = needsCheck;
|
|
}
|
|
|
|
CastPattern _readCastPattern() {
|
|
int fileOffset = readOffset();
|
|
return new CastPattern(_readPattern(), readDartType())
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
ConstantPattern _readConstantPattern() {
|
|
int fileOffset = readOffset();
|
|
Expression expression = readExpression();
|
|
DartType? expressionType = readDartTypeOption();
|
|
Reference? equalsTargetReference = readNullableMemberReference();
|
|
FunctionType? equalsType = readDartTypeOption() as FunctionType?;
|
|
return new ConstantPattern(expression)
|
|
..expressionType = expressionType
|
|
..equalsTargetReference = equalsTargetReference
|
|
..equalsType = equalsType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
InvalidPattern _readInvalidPattern() {
|
|
int fileOffset = readOffset();
|
|
Expression invalidExpression = readExpression();
|
|
List<VariableDeclaration> declaredVariables =
|
|
readAndPushVariableDeclarationList();
|
|
return InvalidPattern(invalidExpression,
|
|
declaredVariables: declaredVariables)
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
ListPattern _readListPattern() {
|
|
int fileOffset = readOffset();
|
|
DartType? typeArgument = readDartTypeOption();
|
|
List<Pattern> patterns = _readPatternList();
|
|
DartType? requiredType = readDartTypeOption();
|
|
DartType? matchedValueType = readDartTypeOption();
|
|
int flags = readByte();
|
|
bool needsCheck = flags & 0x1 != 0;
|
|
bool hasRestPattern = flags & 0x2 != 0;
|
|
DartType? lookupType = readDartTypeOption();
|
|
Reference? lengthTargetReference = readNullableMemberReference();
|
|
DartType? lengthType = readDartTypeOption();
|
|
Reference? lengthCheckTargetReference = readNullableMemberReference();
|
|
FunctionType? lengthCheckType = readDartTypeOption() as FunctionType?;
|
|
Reference? sublistTargetReference = readNullableMemberReference();
|
|
FunctionType? sublistType = readDartTypeOption() as FunctionType?;
|
|
Reference? minusTargetReference = readNullableMemberReference();
|
|
FunctionType? minusType = readDartTypeOption() as FunctionType?;
|
|
Reference? indexGetTargetReference = readNullableMemberReference();
|
|
FunctionType? indexGetType = readDartTypeOption() as FunctionType?;
|
|
return new ListPattern(typeArgument, patterns)
|
|
..requiredType = requiredType
|
|
..matchedValueType = matchedValueType
|
|
..needsCheck = needsCheck
|
|
..lookupType = lookupType
|
|
..hasRestPattern = hasRestPattern
|
|
..lengthTargetReference = lengthTargetReference
|
|
..lengthType = lengthType
|
|
..lengthCheckTargetReference = lengthCheckTargetReference
|
|
..lengthCheckType = lengthCheckType
|
|
..sublistTargetReference = sublistTargetReference
|
|
..sublistType = sublistType
|
|
..minusTargetReference = minusTargetReference
|
|
..minusType = minusType
|
|
..indexGetTargetReference = indexGetTargetReference
|
|
..indexGetType = indexGetType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
MapPattern _readMapPattern() {
|
|
int fileOffset = readOffset();
|
|
DartType? keyType = readDartTypeOption();
|
|
DartType? valueType = readDartTypeOption();
|
|
List<MapPatternEntry> entries = _readMapPatternEntryList();
|
|
DartType? requiredType = readDartTypeOption();
|
|
DartType? matchedValueType = readDartTypeOption();
|
|
int flags = readByte();
|
|
bool needsCheck = flags & 0x1 != 0;
|
|
DartType? lookupType = readDartTypeOption();
|
|
Reference? containsKeyTargetReference = readNullableMemberReference();
|
|
FunctionType? containsKeyType = readDartTypeOption() as FunctionType?;
|
|
Reference? indexGetTargetReference = readNullableMemberReference();
|
|
FunctionType? indexGetType = readDartTypeOption() as FunctionType?;
|
|
return new MapPattern(keyType, valueType, entries)
|
|
..requiredType = requiredType
|
|
..matchedValueType = matchedValueType
|
|
..needsCheck = needsCheck
|
|
..lookupType = lookupType
|
|
..containsKeyTargetReference = containsKeyTargetReference
|
|
..containsKeyType = containsKeyType
|
|
..indexGetTargetReference = indexGetTargetReference
|
|
..indexGetType = indexGetType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
NamedPattern _readNamedPattern() {
|
|
int fileOffset = readOffset();
|
|
String name = readStringReference();
|
|
Pattern pattern = _readPattern();
|
|
Name fieldName = readName();
|
|
ObjectAccessKind accessKind = ObjectAccessKind.values[readByte()];
|
|
Reference? targetReference = readNullableMemberReference();
|
|
DartType? resultType = readDartTypeOption();
|
|
RecordType? recordType = readDartTypeOption() as RecordType?;
|
|
int recordFieldIndex = readUInt30();
|
|
FunctionType? functionType = readDartTypeOption() as FunctionType?;
|
|
List<DartType>? typeArguments;
|
|
if (readAndCheckOptionTag()) {
|
|
typeArguments = readDartTypeList();
|
|
}
|
|
return new NamedPattern(name, pattern)
|
|
..fieldName = fieldName
|
|
..accessKind = accessKind
|
|
..targetReference = targetReference
|
|
..resultType = resultType
|
|
..recordType = recordType
|
|
..recordFieldIndex = recordFieldIndex
|
|
..functionType = functionType
|
|
..typeArguments = typeArguments
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
NullAssertPattern _readNullAssertPattern() {
|
|
int fileOffset = readOffset();
|
|
Pattern pattern = _readPattern();
|
|
return new NullAssertPattern(pattern)..fileOffset = fileOffset;
|
|
}
|
|
|
|
NullCheckPattern _readNullCheckPattern() {
|
|
int fileOffset = readOffset();
|
|
Pattern pattern = _readPattern();
|
|
return new NullCheckPattern(pattern)..fileOffset = fileOffset;
|
|
}
|
|
|
|
ObjectPattern _readObjectPattern() {
|
|
int fileOffset = readOffset();
|
|
DartType type = readDartType();
|
|
List<NamedPattern> fields = _readNamedPatternList();
|
|
DartType? matchedType = readDartTypeOption();
|
|
bool needsCheck = readByte() == 1;
|
|
DartType? objectType = readDartTypeOption();
|
|
return new ObjectPattern(type, fields)
|
|
..matchedValueType = matchedType
|
|
..needsCheck = needsCheck
|
|
..lookupType = objectType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
OrPattern _readOrPattern() {
|
|
int fileOffset = readOffset();
|
|
Pattern left = _readPattern();
|
|
Pattern right = _readPattern();
|
|
List<VariableDeclaration> orPatternJointVariables =
|
|
_readVariableReferenceList();
|
|
return new OrPattern(left, right,
|
|
orPatternJointVariables: orPatternJointVariables)
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
RecordPattern _readRecordPattern() {
|
|
int fileOffset = readOffset();
|
|
List<Pattern> patterns = _readPatternList();
|
|
RecordType? type = readDartTypeOption() as RecordType?;
|
|
DartType? matchedType = readDartTypeOption();
|
|
bool needsCheck = readByte() == 1;
|
|
RecordType? recordType = readDartTypeOption() as RecordType?;
|
|
return new RecordPattern(patterns)
|
|
..requiredType = type
|
|
..matchedValueType = matchedType
|
|
..needsCheck = needsCheck
|
|
..lookupType = recordType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
RelationalPattern _readRelationalPattern() {
|
|
int fileOffset = readOffset();
|
|
RelationalPatternKind kind = RelationalPatternKind.values[readByte()];
|
|
Expression expression = readExpression();
|
|
DartType? expressionType = readDartTypeOption();
|
|
DartType? matchedType = readDartTypeOption();
|
|
RelationalAccessKind accessKind = RelationalAccessKind.values[readByte()];
|
|
Name name = readName();
|
|
Reference? targetReference = readNullableMemberReference();
|
|
List<DartType>? typeArguments;
|
|
if (readAndCheckOptionTag()) {
|
|
typeArguments = readDartTypeList();
|
|
}
|
|
FunctionType? functionType = readDartTypeOption() as FunctionType?;
|
|
return new RelationalPattern(kind, expression)
|
|
..expressionType = expressionType
|
|
..matchedValueType = matchedType
|
|
..accessKind = accessKind
|
|
..name = name
|
|
..targetReference = targetReference
|
|
..typeArguments = typeArguments
|
|
..functionType = functionType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
RestPattern _readRestPattern() {
|
|
int fileOffset = readOffset();
|
|
Pattern? subPattern = _readOptionalPattern();
|
|
return new RestPattern(subPattern)..fileOffset = fileOffset;
|
|
}
|
|
|
|
VariablePattern _readVariablePattern() {
|
|
int fileOffset = readOffset();
|
|
DartType? type = readDartTypeOption();
|
|
VariableDeclaration variable = readVariableDeclaration();
|
|
DartType? matchedType = readDartTypeOption();
|
|
return new VariablePattern(type, variable)
|
|
..matchedValueType = matchedType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
WildcardPattern _readWildcardPattern() {
|
|
int fileOffset = readOffset();
|
|
DartType? type = readDartTypeOption();
|
|
return new WildcardPattern(type)..fileOffset = fileOffset;
|
|
}
|
|
|
|
MapPatternEntry _readMapPatternEntry() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
case Tag.MapPatternEntry:
|
|
int fileOffset = readOffset();
|
|
Expression key = readExpression();
|
|
Pattern value = _readPattern();
|
|
DartType? keyType = readDartTypeOption();
|
|
return new MapPatternEntry(key, value)
|
|
..keyType = keyType
|
|
..fileOffset = fileOffset;
|
|
case Tag.MapPatternRestEntry:
|
|
int fileOffset = readOffset();
|
|
return new MapPatternRestEntry()..fileOffset = fileOffset;
|
|
default:
|
|
throw fail('unexpected pattern tag: $tag');
|
|
}
|
|
}
|
|
|
|
SwitchExpression _readSwitchExpression() {
|
|
int fileOffset = readOffset();
|
|
Expression expression = readExpression();
|
|
DartType? expressionType = readDartTypeOption();
|
|
List<SwitchExpressionCase> cases = _readSwitchExpressionCaseList();
|
|
DartType? staticType = readDartTypeOption();
|
|
return new SwitchExpression(expression, cases)
|
|
..expressionType = expressionType
|
|
..staticType = staticType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
List<SwitchExpressionCase> _readSwitchExpressionCaseList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfSwitchExpressionCase;
|
|
}
|
|
return new List<SwitchExpressionCase>.generate(
|
|
length, (_) => _readSwitchExpressionCase(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
SwitchExpressionCase _readSwitchExpressionCase() {
|
|
int fileOffset = readOffset();
|
|
PatternGuard patternGuard = _readPatternGuard();
|
|
Expression expression = readExpression();
|
|
return new SwitchExpressionCase(patternGuard, expression)
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
PatternGuard _readPatternGuard() {
|
|
int fileOffset = readOffset();
|
|
Pattern pattern = _readPattern();
|
|
Expression? guard = readExpressionOption();
|
|
return new PatternGuard(pattern, guard)..fileOffset = fileOffset;
|
|
}
|
|
|
|
IfCaseStatement _readIfCaseStatement() {
|
|
int fileOffset = readOffset();
|
|
Expression expression = readExpression();
|
|
PatternGuard patternGuard = _readPatternGuard();
|
|
Statement then = readStatement();
|
|
Statement? otherwise = readStatementOption();
|
|
DartType? matchedValueType = readDartTypeOption();
|
|
return new IfCaseStatement(expression, patternGuard, then, otherwise)
|
|
..matchedValueType = matchedValueType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
PatternAssignment _readPatternAssignment() {
|
|
int fileOffset = readOffset();
|
|
Pattern pattern = _readPattern();
|
|
Expression expression = readExpression();
|
|
DartType? matchedValueType = readDartTypeOption();
|
|
return new PatternAssignment(pattern, expression)
|
|
..matchedValueType = matchedValueType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
PatternVariableDeclaration _readPatternVariableDeclaration() {
|
|
int fileOffset = readOffset();
|
|
Pattern pattern = _readPattern();
|
|
Expression expression = readExpression();
|
|
bool isFinal = readByte() == 1;
|
|
DartType? matchedValueType = readDartTypeOption();
|
|
return new PatternVariableDeclaration(pattern, expression, isFinal: isFinal)
|
|
..matchedValueType = matchedValueType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
PatternSwitchStatement _readPatternSwitchStatement() {
|
|
int fileOffset = readOffset();
|
|
Expression expression = readExpression();
|
|
DartType? expressionType = readDartTypeOption();
|
|
int count = readUInt30();
|
|
List<PatternSwitchCase> cases;
|
|
if (!useGrowableLists && count == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
cases = emptyListOfPatternSwitchCase;
|
|
} else {
|
|
cases = new List<PatternSwitchCase>.generate(
|
|
count,
|
|
(_) => new PatternSwitchCase([], [], dummyStatement,
|
|
isDefault: false,
|
|
hasLabel: false,
|
|
jointVariables: [],
|
|
jointVariableFirstUseOffsets: null),
|
|
growable: useGrowableLists);
|
|
}
|
|
switchCaseStack.addAll(cases);
|
|
for (int i = 0; i < cases.length; ++i) {
|
|
_readPatternSwitchCaseInto(cases[i]);
|
|
}
|
|
switchCaseStack.length -= count;
|
|
return new PatternSwitchStatement(expression, cases)
|
|
..expressionTypeInternal = expressionType
|
|
..fileOffset = fileOffset;
|
|
}
|
|
|
|
void _readPatternSwitchCaseInto(PatternSwitchCase caseNode) {
|
|
int variableCount = readUInt30();
|
|
for (int i = 0; i < variableCount; ++i) {
|
|
caseNode.jointVariables.add(readVariableDeclaration()..parent = caseNode);
|
|
}
|
|
int caseCount = readUInt30();
|
|
for (int i = 0; i < caseCount; ++i) {
|
|
caseNode.caseOffsets.add(readOffset());
|
|
caseNode.patternGuards.add(_readPatternGuard()..parent = caseNode);
|
|
}
|
|
int flags = readByte();
|
|
caseNode.isDefault = (flags & 0x1) != 0;
|
|
caseNode.hasLabel = (flags & 0x2) != 0;
|
|
caseNode.body = readStatement()..parent = caseNode;
|
|
}
|
|
|
|
List<Statement> readStatementList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfStatement;
|
|
}
|
|
return new List<Statement>.generate(length, (_) => readStatement(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<Statement> readStatementListAlwaysGrowable() {
|
|
int length = readUInt30();
|
|
return new List<Statement>.generate(length, (_) => readStatement(),
|
|
growable: true);
|
|
}
|
|
|
|
Statement? readStatementOrNullIfEmpty() {
|
|
Statement node = readStatement();
|
|
if (node is EmptyStatement) {
|
|
return null;
|
|
} else {
|
|
return node;
|
|
}
|
|
}
|
|
|
|
Statement? readStatementOption() {
|
|
return readAndCheckOptionTag() ? readStatement() : null;
|
|
}
|
|
|
|
Statement readStatement() {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
// 23.90% (14.98% - 41.04%).
|
|
case Tag.ReturnStatement:
|
|
return _readReturnStatement();
|
|
|
|
// 22.74% (15.27% - 32.36%).
|
|
case Tag.ExpressionStatement:
|
|
return _readExpressionStatement();
|
|
|
|
// 21.29% (17.70% - 25.00%).
|
|
case Tag.Block:
|
|
return _readBlock();
|
|
|
|
// 9.62% (6.92% - 12.64%).
|
|
case Tag.VariableDeclaration:
|
|
return _readVariableDeclaration();
|
|
|
|
// 9.28% (6.69% - 11.18%).
|
|
case Tag.EmptyStatement:
|
|
return _readEmptyStatement();
|
|
|
|
// 9.06% (6.03% - 11.58%).
|
|
case Tag.IfStatement:
|
|
return _readIfStatement();
|
|
|
|
// The rest is < 2% on average in sampled dills.
|
|
case Tag.AssertBlock:
|
|
return _readAssertBlock();
|
|
case Tag.AssertStatement:
|
|
return _readAssertStatement();
|
|
case Tag.LabeledStatement:
|
|
return _readLabeledStatement();
|
|
case Tag.BreakStatement:
|
|
return _readBreakStatement();
|
|
case Tag.WhileStatement:
|
|
return _readWhileStatement();
|
|
case Tag.DoStatement:
|
|
return _readDoStatement();
|
|
case Tag.ForStatement:
|
|
return _readForStatement();
|
|
case Tag.ForInStatement:
|
|
case Tag.AsyncForInStatement:
|
|
return _readForInStatement(tag);
|
|
case Tag.SwitchStatement:
|
|
return _readSwitchStatement();
|
|
case Tag.ContinueSwitchStatement:
|
|
return _readContinueSwitchStatement();
|
|
case Tag.TryCatch:
|
|
return _readTryCatch();
|
|
case Tag.TryFinally:
|
|
return _readTryFinally();
|
|
case Tag.YieldStatement:
|
|
return _readYieldStatement();
|
|
case Tag.FunctionDeclaration:
|
|
return _readFunctionDeclaration();
|
|
case Tag.IfCaseStatement:
|
|
return _readIfCaseStatement();
|
|
case Tag.PatternVariableDeclaration:
|
|
return _readPatternVariableDeclaration();
|
|
case Tag.PatternSwitchStatement:
|
|
return _readPatternSwitchStatement();
|
|
default:
|
|
throw fail('unexpected statement tag: $tag');
|
|
}
|
|
}
|
|
|
|
Statement _readExpressionStatement() {
|
|
return new ExpressionStatement(readExpression());
|
|
}
|
|
|
|
Statement _readEmptyStatement() {
|
|
return new EmptyStatement();
|
|
}
|
|
|
|
Statement _readAssertStatement() {
|
|
return new AssertStatement(readExpression(),
|
|
conditionStartOffset: readOffset(),
|
|
conditionEndOffset: readOffset(),
|
|
message: readExpressionOption());
|
|
}
|
|
|
|
Statement _readLabeledStatement() {
|
|
LabeledStatement label = new LabeledStatement(null);
|
|
labelStack.add(label);
|
|
int offset = readOffset();
|
|
label.fileOffset = offset;
|
|
label.body = readStatement()..parent = label;
|
|
labelStack.removeLast();
|
|
return label;
|
|
}
|
|
|
|
Statement _readBreakStatement() {
|
|
int offset = readOffset();
|
|
int index = readUInt30();
|
|
return new BreakStatement(labelStack[labelStackBase + index])
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readWhileStatement() {
|
|
int offset = readOffset();
|
|
return new WhileStatement(readExpression(), readStatement())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readDoStatement() {
|
|
int offset = readOffset();
|
|
return new DoStatement(readStatement(), readExpression())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readForStatement() {
|
|
int variableStackHeight = variableStack.length;
|
|
int offset = readOffset();
|
|
List<VariableDeclaration> variables = readAndPushVariableDeclarationList();
|
|
Expression? condition = readExpressionOption();
|
|
List<Expression> updates = readExpressionList();
|
|
Statement body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new ForStatement(variables, condition, updates, body)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readForInStatement(int tag) {
|
|
bool isAsync = tag == Tag.AsyncForInStatement;
|
|
int variableStackHeight = variableStack.length;
|
|
int offset = readOffset();
|
|
int bodyOffset = readOffset();
|
|
VariableDeclaration variable = readAndPushVariableDeclaration();
|
|
Expression iterable = readExpression();
|
|
Statement body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new ForInStatement(variable, iterable, body, isAsync: isAsync)
|
|
..fileOffset = offset
|
|
..bodyOffset = bodyOffset;
|
|
}
|
|
|
|
Statement _readSwitchStatement() {
|
|
int offset = readOffset();
|
|
bool isExplicitlyExhaustive = readByte() == 1;
|
|
Expression expression = readExpression();
|
|
DartType? expressionType = readDartTypeOption();
|
|
int count = readUInt30();
|
|
List<SwitchCase> cases;
|
|
if (!useGrowableLists && count == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
cases = emptyListOfSwitchCase;
|
|
} else {
|
|
cases = new List<SwitchCase>.generate(
|
|
count,
|
|
(_) => new SwitchCase(<Expression>[], <int>[], dummyStatement,
|
|
isDefault: false),
|
|
growable: useGrowableLists);
|
|
}
|
|
switchCaseStack.addAll(cases);
|
|
for (int i = 0; i < cases.length; ++i) {
|
|
_readSwitchCaseInto(cases[i]);
|
|
}
|
|
switchCaseStack.length -= count;
|
|
return new SwitchStatement(expression, cases,
|
|
isExplicitlyExhaustive: isExplicitlyExhaustive)
|
|
..expressionTypeInternal = expressionType
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readContinueSwitchStatement() {
|
|
int offset = readOffset();
|
|
int index = readUInt30();
|
|
return new ContinueSwitchStatement(
|
|
switchCaseStack[switchCaseStackBase + index])
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readIfStatement() {
|
|
int offset = readOffset();
|
|
return new IfStatement(
|
|
readExpression(), readStatement(), readStatementOrNullIfEmpty())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readReturnStatement() {
|
|
int offset = readOffset();
|
|
return new ReturnStatement(readExpressionOption())..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readTryCatch() {
|
|
int offset = readOffset();
|
|
Statement body = readStatement();
|
|
int flags = readByte();
|
|
return new TryCatch(body, readCatchList(), isSynthetic: flags & 2 == 2)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readTryFinally() {
|
|
int offset = readOffset();
|
|
return new TryFinally(readStatement(), readStatement())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readYieldStatement() {
|
|
int offset = readOffset();
|
|
int flags = readByte();
|
|
return new YieldStatement(readExpression(),
|
|
isYieldStar: flags & YieldStatement.FlagYieldStar != 0)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Statement _readVariableDeclaration() {
|
|
VariableDeclaration variable = readVariableDeclaration();
|
|
variableStack.add(variable); // Will be popped by the enclosing scope.
|
|
return variable;
|
|
}
|
|
|
|
Statement _readFunctionDeclaration() {
|
|
int offset = readOffset();
|
|
VariableDeclaration variable = readVariableDeclaration();
|
|
variableStack.add(variable); // Will be popped by the enclosing scope.
|
|
return new FunctionDeclaration(variable, readFunctionNode())
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
void _readSwitchCaseInto(SwitchCase caseNode) {
|
|
int offset = readOffset();
|
|
caseNode.fileOffset = offset;
|
|
int length = readUInt30();
|
|
for (int i = 0; i < length; ++i) {
|
|
caseNode.expressionOffsets.add(readOffset());
|
|
caseNode.expressions.add(readExpression()..parent = caseNode);
|
|
}
|
|
caseNode.isDefault = readByte() == 1;
|
|
caseNode.body = readStatement()..parent = caseNode;
|
|
}
|
|
|
|
List<Catch> readCatchList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfCatch;
|
|
}
|
|
return new List<Catch>.generate(length, (_) => readCatch(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
Catch readCatch() {
|
|
int variableStackHeight = variableStack.length;
|
|
int offset = readOffset();
|
|
DartType guard = readDartType();
|
|
VariableDeclaration? exception = readAndPushVariableDeclarationOption();
|
|
VariableDeclaration? stackTrace = readAndPushVariableDeclarationOption();
|
|
Statement body = readStatement();
|
|
variableStack.length = variableStackHeight;
|
|
return new Catch(exception, body, guard: guard, stackTrace: stackTrace)
|
|
..fileOffset = offset;
|
|
}
|
|
|
|
Block _readBlock() {
|
|
int stackHeight = variableStack.length;
|
|
int offset = readOffset();
|
|
int endOffset = readOffset();
|
|
List<Statement> body = readStatementListAlwaysGrowable();
|
|
variableStack.length = stackHeight;
|
|
return new Block(body)
|
|
..fileOffset = offset
|
|
..fileEndOffset = endOffset;
|
|
}
|
|
|
|
AssertBlock _readAssertBlock() {
|
|
int stackHeight = variableStack.length;
|
|
List<Statement> body = readStatementListAlwaysGrowable();
|
|
variableStack.length = stackHeight;
|
|
return new AssertBlock(body);
|
|
}
|
|
|
|
Supertype readSupertype() {
|
|
InterfaceType type = readDartType(forSupertype: true) as InterfaceType;
|
|
assert(
|
|
type.nullability == _currentLibrary!.nonNullable,
|
|
"In serialized form supertypes should have Nullability.legacy if they "
|
|
"are in a library that is opted out of the NNBD feature. If they are "
|
|
"in an opted-in library, they should have Nullability.nonNullable.");
|
|
return new Supertype.byReference(type.classReference, type.typeArguments);
|
|
}
|
|
|
|
Supertype? readSupertypeOption() {
|
|
return readAndCheckOptionTag() ? readSupertype() : null;
|
|
}
|
|
|
|
List<Supertype> readSupertypeList([List<Supertype>? result]) {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfSupertype;
|
|
}
|
|
if (result != null) {
|
|
for (int i = 0; i < length; ++i) {
|
|
result.add(readSupertype());
|
|
}
|
|
return result;
|
|
} else {
|
|
return new List<Supertype>.generate(length, (_) => readSupertype(),
|
|
growable: useGrowableLists);
|
|
}
|
|
}
|
|
|
|
List<DartType> readDartTypeList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfDartType;
|
|
}
|
|
return new List<DartType>.generate(length, (_) => readDartType(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
List<NamedType> readNamedTypeList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use a
|
|
// constant one for the empty list.
|
|
return emptyListOfNamedType;
|
|
}
|
|
return new List<NamedType>.generate(length, (_) => readNamedType(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
NamedType readNamedType() {
|
|
String name = readStringReference();
|
|
DartType type = readDartType();
|
|
int flags = readByte();
|
|
return new NamedType(name, type,
|
|
isRequired: (flags & NamedType.FlagRequiredNamedType) != 0);
|
|
}
|
|
|
|
DartType? readDartTypeOption() {
|
|
return readAndCheckOptionTag() ? readDartType() : null;
|
|
}
|
|
|
|
DartType readDartType({bool forSupertype = false}) {
|
|
int tag = readByte();
|
|
switch (tag) {
|
|
// 67.66% (59.53% - 77.94%).
|
|
case Tag.SimpleInterfaceType:
|
|
return _readSimpleInterfaceType(forSupertype);
|
|
|
|
// 11.64% (9.11% - 15.49%).
|
|
case Tag.SimpleFunctionType:
|
|
return _readSimpleFunctionType();
|
|
|
|
// 7.33% (5.11% - 8.76%).
|
|
case Tag.InterfaceType:
|
|
return _readInterfaceType();
|
|
|
|
// 5.84% (4.13% - 8.86%).
|
|
case Tag.VoidType:
|
|
return _readVoidType();
|
|
|
|
// 3.64% (1.20% - 7.55%).
|
|
case Tag.TypeParameterType:
|
|
return _readTypeParameterType();
|
|
|
|
// 2.75% (1.03% - 4.13%).
|
|
case Tag.DynamicType:
|
|
return _readDynamicType();
|
|
|
|
// The rest is < 2% on average in sampled dills.
|
|
case Tag.TypedefType:
|
|
return _readTypedefType();
|
|
case Tag.InvalidType:
|
|
return _readInvalidType();
|
|
case Tag.NeverType:
|
|
return _readNeverType();
|
|
case Tag.NullType:
|
|
return _readNullType();
|
|
case Tag.ExtensionType:
|
|
return _readExtensionType();
|
|
case Tag.FunctionType:
|
|
return _readFunctionType();
|
|
case Tag.IntersectionType:
|
|
return _readIntersectionType();
|
|
case Tag.RecordType:
|
|
return _readRecordType();
|
|
case Tag.FutureOrType:
|
|
return _readFutureOrType();
|
|
default:
|
|
throw fail('unexpected dart type tag: $tag');
|
|
}
|
|
}
|
|
|
|
DartType _readTypedefType() {
|
|
int nullabilityIndex = readByte();
|
|
return new TypedefType.byReference(readNonNullTypedefReference(),
|
|
Nullability.values[nullabilityIndex], readDartTypeList());
|
|
}
|
|
|
|
DartType _readInvalidType() {
|
|
return const InvalidType();
|
|
}
|
|
|
|
DartType _readDynamicType() {
|
|
return const DynamicType();
|
|
}
|
|
|
|
DartType _readVoidType() {
|
|
return const VoidType();
|
|
}
|
|
|
|
DartType _readNeverType() {
|
|
int nullabilityIndex = readByte();
|
|
return NeverType.fromNullability(Nullability.values[nullabilityIndex]);
|
|
}
|
|
|
|
DartType _readNullType() {
|
|
return const NullType();
|
|
}
|
|
|
|
DartType _readInterfaceType() {
|
|
int nullabilityIndex = readByte();
|
|
Reference reference = readNonNullClassReference();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
return new InterfaceType.byReference(
|
|
reference, Nullability.values[nullabilityIndex], typeArguments);
|
|
}
|
|
|
|
DartType _readSimpleInterfaceType(bool forSupertype) {
|
|
final int nullabilityIndex = readByte();
|
|
final int classReferenceIndex = readUInt30();
|
|
final CanonicalName? canonicalName =
|
|
getNullableCanonicalNameReferenceFromInt(classReferenceIndex);
|
|
if (canonicalName == null) {
|
|
throw 'Expected a class reference to be valid but was `null`.';
|
|
}
|
|
|
|
// Check cache.
|
|
final int cacheIndex =
|
|
(classReferenceIndex - 1) * Nullability.values.length +
|
|
nullabilityIndex;
|
|
final DartType? cached = _cachedSimpleInterfaceTypes[cacheIndex];
|
|
if (cached != null) {
|
|
return cached;
|
|
}
|
|
|
|
// Not in cache.
|
|
final Reference classReference = canonicalName.reference;
|
|
final DartType result = new InterfaceType.byReference(classReference,
|
|
Nullability.values[nullabilityIndex], const <DartType>[]);
|
|
_cachedSimpleInterfaceTypes[cacheIndex] = result;
|
|
return result;
|
|
}
|
|
|
|
DartType _readFutureOrType() {
|
|
int nullabilityIndex = readByte();
|
|
DartType typeArgument = readDartType();
|
|
return new FutureOrType(typeArgument, Nullability.values[nullabilityIndex]);
|
|
}
|
|
|
|
DartType _readExtensionType() {
|
|
int nullabilityIndex = readByte();
|
|
Reference reference = readNonNullExtensionTypeDeclarationReference();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
readDartType(); // Read type erasure.
|
|
return new ExtensionType.byReference(
|
|
reference, Nullability.values[nullabilityIndex], typeArguments);
|
|
}
|
|
|
|
DartType _readFunctionType() {
|
|
int typeParameterStackHeight = typeParameterStack.length;
|
|
int nullabilityIndex = readByte();
|
|
List<StructuralParameter> typeParameters =
|
|
readAndPushStructuralParameterList();
|
|
int requiredParameterCount = readUInt30();
|
|
int totalParameterCount = readUInt30();
|
|
List<DartType> positional = readDartTypeList();
|
|
List<NamedType> named = readNamedTypeList();
|
|
assert(positional.length + named.length == totalParameterCount);
|
|
DartType returnType = readDartType();
|
|
typeParameterStack.length = typeParameterStackHeight;
|
|
return new FunctionType(
|
|
positional, returnType, Nullability.values[nullabilityIndex],
|
|
typeParameters: typeParameters,
|
|
requiredParameterCount: requiredParameterCount,
|
|
namedParameters: named);
|
|
}
|
|
|
|
DartType _readSimpleFunctionType() {
|
|
int nullabilityIndex = readByte();
|
|
List<DartType> positional = readDartTypeList();
|
|
DartType returnType = readDartType();
|
|
if (positional.isEmpty && returnType is VoidType) {
|
|
// "FunctionType(void Function())" with different nullabilities.
|
|
assert(
|
|
_voidFunctionFunctionTypesCache.length == Nullability.values.length);
|
|
FunctionType? cached = _voidFunctionFunctionTypesCache[nullabilityIndex];
|
|
if (cached != null) {
|
|
return cached;
|
|
}
|
|
FunctionType result = new FunctionType(
|
|
const [], const VoidType(), Nullability.values[nullabilityIndex]);
|
|
_voidFunctionFunctionTypesCache[nullabilityIndex] = result;
|
|
return result;
|
|
}
|
|
return new FunctionType(
|
|
positional, returnType, Nullability.values[nullabilityIndex]);
|
|
}
|
|
|
|
DartType _readTypeParameterType() {
|
|
int declaredNullabilityIndex = readByte();
|
|
int index = readUInt30();
|
|
Object typeParameter = typeParameterStack[index];
|
|
if (typeParameter is TypeParameter) {
|
|
return new TypeParameterType(
|
|
typeParameter, Nullability.values[declaredNullabilityIndex]);
|
|
} else {
|
|
typeParameter as StructuralParameter;
|
|
return new StructuralParameterType(
|
|
typeParameter, Nullability.values[declaredNullabilityIndex]);
|
|
}
|
|
}
|
|
|
|
DartType _readIntersectionType() {
|
|
TypeParameterType left = readDartType() as TypeParameterType;
|
|
DartType right = readDartType();
|
|
return new IntersectionType(left, right);
|
|
}
|
|
|
|
DartType _readRecordType() {
|
|
int nullabilityIndex = readByte();
|
|
List<DartType> positional = readDartTypeList();
|
|
List<NamedType> named = readNamedTypeList();
|
|
return new RecordType(
|
|
positional, named, Nullability.values[nullabilityIndex]);
|
|
}
|
|
|
|
List<TypeParameter> readAndPushTypeParameterList(
|
|
[List<TypeParameter>? list, GenericDeclaration? declaration]) {
|
|
int length = readUInt30();
|
|
if (length == 0) {
|
|
if (list != null) return list;
|
|
if (useGrowableLists) {
|
|
return <TypeParameter>[];
|
|
} else {
|
|
return emptyListOfTypeParameter;
|
|
}
|
|
}
|
|
if (list == null) {
|
|
list = new List<TypeParameter>.generate(length,
|
|
(_) => new TypeParameter(null, null)..declaration = declaration,
|
|
growable: useGrowableLists);
|
|
} else if (list.length != length) {
|
|
for (int i = 0; i < length; ++i) {
|
|
list.add(new TypeParameter(null, null)..declaration = declaration);
|
|
}
|
|
}
|
|
typeParameterStack.addAll(list);
|
|
for (int i = 0; i < list.length; ++i) {
|
|
readTypeParameter(list[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
List<StructuralParameter> readAndPushStructuralParameterList(
|
|
[List<StructuralParameter>? list]) {
|
|
int length = readUInt30();
|
|
if (length == 0) {
|
|
if (list != null) return list;
|
|
if (useGrowableLists) {
|
|
return <StructuralParameter>[];
|
|
} else {
|
|
return emptyListOfStructuralParameter;
|
|
}
|
|
}
|
|
if (list == null) {
|
|
list = new List<StructuralParameter>.generate(
|
|
length, (_) => new StructuralParameter(null, null),
|
|
growable: useGrowableLists);
|
|
} else if (list.length != length) {
|
|
for (int i = 0; i < length; ++i) {
|
|
list.add(new StructuralParameter(null, null));
|
|
}
|
|
}
|
|
typeParameterStack.addAll(list);
|
|
for (int i = 0; i < list.length; ++i) {
|
|
readStructuralParameter(list[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
void readTypeParameter(TypeParameter node) {
|
|
node.flags = readByte();
|
|
node.annotations = readAnnotationList(node);
|
|
int variance = readByte();
|
|
if (variance == TypeParameter.legacyCovariantSerializationMarker) {
|
|
node.variance = null;
|
|
} else {
|
|
node.variance = variance;
|
|
}
|
|
node.name = readStringOrNullIfEmpty();
|
|
node.bound = readDartType();
|
|
node.defaultType = readDartType();
|
|
}
|
|
|
|
void readStructuralParameter(StructuralParameter node) {
|
|
node.flags = readByte();
|
|
// For now, [StructuralParameter] objects are encoded as
|
|
// [TypeParameter] objects, to preserve compatibility with the binary format
|
|
// consumers.
|
|
// TODO(cstefantsova): Eventually remove the annotations from the binary
|
|
// encoding of [StructuralParameter] objects.
|
|
readAnnotationList();
|
|
int variance = readByte();
|
|
if (variance == TypeParameter.legacyCovariantSerializationMarker) {
|
|
node.variance = null;
|
|
} else {
|
|
node.variance = variance;
|
|
}
|
|
node.name = readStringOrNullIfEmpty();
|
|
node.bound = readDartType();
|
|
node.defaultType = readDartType();
|
|
}
|
|
|
|
Arguments readArguments() {
|
|
int numArguments = readUInt30();
|
|
List<DartType> typeArguments = readDartTypeList();
|
|
List<Expression> positional = readExpressionList();
|
|
List<NamedExpression> named = readNamedExpressionList();
|
|
assert(numArguments == positional.length + named.length);
|
|
return new Arguments(positional, types: typeArguments, named: named);
|
|
}
|
|
|
|
List<NamedExpression> readNamedExpressionList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost-constant one for the empty list.
|
|
return emptyListOfNamedExpression;
|
|
}
|
|
return new List<NamedExpression>.generate(
|
|
length, (_) => readNamedExpression(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
NamedExpression readNamedExpression() {
|
|
return new NamedExpression(readStringReference(), readExpression());
|
|
}
|
|
|
|
List<VariableDeclaration> readAndPushVariableDeclarationList() {
|
|
int length = readUInt30();
|
|
if (!useGrowableLists && length == 0) {
|
|
// When lists don't have to be growable anyway, we might as well use an
|
|
// almost constant one for the empty list.
|
|
return emptyListOfVariableDeclaration;
|
|
}
|
|
return new List<VariableDeclaration>.generate(
|
|
length, (_) => readAndPushVariableDeclaration(),
|
|
growable: useGrowableLists);
|
|
}
|
|
|
|
VariableDeclaration? readAndPushVariableDeclarationOption() {
|
|
return readAndCheckOptionTag() ? readAndPushVariableDeclaration() : null;
|
|
}
|
|
|
|
VariableDeclaration readAndPushVariableDeclaration() {
|
|
VariableDeclaration variable = readVariableDeclaration();
|
|
variableStack.add(variable);
|
|
return variable;
|
|
}
|
|
|
|
VariableDeclaration readVariableDeclaration() {
|
|
int offset = readOffset();
|
|
int fileEqualsOffset = readOffset();
|
|
// The [VariableDeclaration] instance is not created at this point yet,
|
|
// so `null` is temporarily set as the parent of the annotation nodes.
|
|
List<Expression> annotations = readAnnotationList(null);
|
|
int flags = readUInt30();
|
|
VariableDeclaration node = new VariableDeclaration(
|
|
readStringOrNullIfEmpty(),
|
|
type: readDartType(),
|
|
initializer: readExpressionOption(),
|
|
flags: flags)
|
|
..fileOffset = offset
|
|
..fileEqualsOffset = fileEqualsOffset;
|
|
if (annotations.isNotEmpty) {
|
|
for (int i = 0; i < annotations.length; ++i) {
|
|
Expression annotation = annotations[i];
|
|
annotation.parent = node;
|
|
}
|
|
node.annotations = annotations;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
int readOffset() {
|
|
// Offset is saved as unsigned,
|
|
// but actually ranges from -1 and up (thus the -1)
|
|
return readUInt30() - 1;
|
|
}
|
|
}
|
|
|
|
class BinaryBuilderWithMetadata extends BinaryBuilder implements BinarySource {
|
|
/// List of metadata subsections that have corresponding [MetadataRepository]
|
|
/// and are awaiting to be parsed and attached to nodes.
|
|
List<_MetadataSubsection>? _subsections;
|
|
|
|
BinaryBuilderWithMetadata(List<int> bytes,
|
|
{String? filename,
|
|
bool disableLazyReading = false,
|
|
bool disableLazyClassReading = false,
|
|
bool? alwaysCreateNewNamedNodes})
|
|
: super(bytes,
|
|
filename: filename,
|
|
disableLazyReading: disableLazyReading,
|
|
disableLazyClassReading: disableLazyClassReading,
|
|
alwaysCreateNewNamedNodes: alwaysCreateNewNamedNodes);
|
|
|
|
@override
|
|
void _readMetadataMappings(
|
|
Component component, int binaryOffsetForMetadataPayloads) {
|
|
// At the beginning of this function _byteOffset points right past
|
|
// metadataMappings to string table.
|
|
|
|
// Read the length of metadataMappings.
|
|
_byteOffset -= 4;
|
|
final int subSectionCount = readUint32();
|
|
|
|
int endOffset = _byteOffset - 4; // End offset of the current subsection.
|
|
for (int i = 0; i < subSectionCount; i++) {
|
|
// RList<Pair<UInt32, UInt32>> nodeOffsetToMetadataOffset
|
|
_byteOffset = endOffset - 4;
|
|
final int mappingLength = readUint32();
|
|
final int mappingStart = (endOffset - 4) - 4 * 2 * mappingLength;
|
|
_byteOffset = mappingStart - 4;
|
|
|
|
// UInt32 tag (fixed size StringReference)
|
|
final String tag = _stringTable[readUint32()];
|
|
|
|
final MetadataRepository<dynamic>? repository = component.metadata[tag];
|
|
if (repository != null) {
|
|
// Read nodeOffsetToMetadataOffset mapping.
|
|
final Map<int, int> mapping = <int, int>{};
|
|
_byteOffset = mappingStart;
|
|
for (int j = 0; j < mappingLength; j++) {
|
|
final int nodeOffset = readUint32();
|
|
final int metadataOffset =
|
|
binaryOffsetForMetadataPayloads + readUint32();
|
|
mapping[nodeOffset] = metadataOffset;
|
|
}
|
|
|
|
(_subsections ??= <_MetadataSubsection>[])
|
|
.add(new _MetadataSubsection(repository, mapping));
|
|
}
|
|
|
|
// Start of the subsection and the end of the previous one.
|
|
endOffset = mappingStart - 4;
|
|
}
|
|
}
|
|
|
|
Object _readMetadata(Node node, MetadataRepository repository, int offset) {
|
|
final int savedOffset = _byteOffset;
|
|
_byteOffset = offset;
|
|
|
|
final Object metadata = repository.readFromBinary(node, this);
|
|
|
|
_byteOffset = savedOffset;
|
|
return metadata;
|
|
}
|
|
|
|
@override
|
|
void enterScope({List<TypeParameter>? typeParameters}) {
|
|
if (typeParameters != null) {
|
|
typeParameterStack.addAll(typeParameters);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void leaveScope({List<TypeParameter>? typeParameters}) {
|
|
if (typeParameters != null) {
|
|
typeParameterStack.length -= typeParameters.length;
|
|
}
|
|
}
|
|
|
|
@override
|
|
T _associateMetadata<T extends Node>(T node, int nodeOffset) {
|
|
if (_subsections == null) {
|
|
return node;
|
|
}
|
|
|
|
for (_MetadataSubsection subsection in _subsections!) {
|
|
// First check if there is any metadata associated with this node.
|
|
final int? metadataOffset = subsection.mapping[nodeOffset];
|
|
if (metadataOffset != null) {
|
|
subsection.repository.mapping[node] =
|
|
_readMetadata(node, subsection.repository, metadataOffset);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
@override
|
|
DartType readDartType({bool forSupertype = false}) {
|
|
final int nodeOffset = _byteOffset;
|
|
final DartType result = super.readDartType(forSupertype: forSupertype);
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Library readLibrary(Component component, int endOffset) {
|
|
final int nodeOffset = _byteOffset;
|
|
final Library result = super.readLibrary(component, endOffset);
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Typedef readTypedef() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Typedef result = super.readTypedef();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Class readClass(int endOffset) {
|
|
final int nodeOffset = _byteOffset;
|
|
final Class result = super.readClass(endOffset);
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Extension readExtension() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Extension result = super.readExtension();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
ExtensionTypeDeclaration readExtensionTypeDeclaration() {
|
|
final int nodeOffset = _byteOffset;
|
|
final ExtensionTypeDeclaration result =
|
|
super.readExtensionTypeDeclaration();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Field readField() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Field result = super.readField();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Constructor readConstructor() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Constructor result = super.readConstructor();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Procedure readProcedure(int endOffset) {
|
|
final int nodeOffset = _byteOffset;
|
|
final Procedure result = super.readProcedure(endOffset);
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Initializer readInitializer() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Initializer result = super.readInitializer();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
FunctionNode readFunctionNode(
|
|
{bool lazyLoadBody = false, int outerEndOffset = -1}) {
|
|
final int nodeOffset = _byteOffset;
|
|
final FunctionNode result = super.readFunctionNode(
|
|
lazyLoadBody: lazyLoadBody, outerEndOffset: outerEndOffset);
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Expression readExpression() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Expression result = super.readExpression();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Arguments readArguments() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Arguments result = super.readArguments();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
NamedExpression readNamedExpression() {
|
|
final int nodeOffset = _byteOffset;
|
|
final NamedExpression result = super.readNamedExpression();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
VariableDeclaration readVariableDeclaration() {
|
|
final int nodeOffset = _byteOffset;
|
|
final VariableDeclaration result = super.readVariableDeclaration();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Statement readStatement() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Statement result = super.readStatement();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Combinator readCombinator() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Combinator result = super.readCombinator();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
LibraryDependency readLibraryDependency() {
|
|
final int nodeOffset = _byteOffset;
|
|
final LibraryDependency result = super.readLibraryDependency();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
LibraryPart readLibraryPart() {
|
|
final int nodeOffset = _byteOffset;
|
|
final LibraryPart result = super.readLibraryPart();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
void _readSwitchCaseInto(SwitchCase caseNode) {
|
|
_associateMetadata(caseNode, _byteOffset);
|
|
super._readSwitchCaseInto(caseNode);
|
|
}
|
|
|
|
@override
|
|
void readTypeParameter(TypeParameter param) {
|
|
_associateMetadata(param, _byteOffset);
|
|
super.readTypeParameter(param);
|
|
}
|
|
|
|
@override
|
|
Supertype readSupertype() {
|
|
final int nodeOffset = _byteOffset;
|
|
InterfaceType type =
|
|
super.readDartType(forSupertype: true) as InterfaceType;
|
|
return _associateMetadata(
|
|
new Supertype.byReference(type.classReference, type.typeArguments),
|
|
nodeOffset);
|
|
}
|
|
|
|
@override
|
|
Name readName() {
|
|
final int nodeOffset = _byteOffset;
|
|
final Name result = super.readName();
|
|
return _associateMetadata(result, nodeOffset);
|
|
}
|
|
|
|
@override
|
|
int get currentOffset => _byteOffset;
|
|
|
|
@override
|
|
List<int> get bytes => _bytes;
|
|
}
|
|
|
|
/// Deserialized MetadataMapping corresponding to the given metadata repository.
|
|
class _MetadataSubsection {
|
|
/// [MetadataRepository] that can read this subsection.
|
|
final MetadataRepository repository;
|
|
|
|
/// Deserialized mapping from node offsets to metadata offsets.
|
|
final Map<int, int> mapping;
|
|
|
|
_MetadataSubsection(this.repository, this.mapping);
|
|
}
|
|
|
|
/// Merges two compilation modes or throws if they are not compatible.
|
|
NonNullableByDefaultCompiledMode mergeCompilationModeOrThrow(
|
|
NonNullableByDefaultCompiledMode? a, NonNullableByDefaultCompiledMode b) {
|
|
if (a == null || a == b) {
|
|
return b;
|
|
}
|
|
|
|
// If something is invalid, it should always merge as invalid.
|
|
if (a == NonNullableByDefaultCompiledMode.Invalid) {
|
|
return a;
|
|
}
|
|
if (b == NonNullableByDefaultCompiledMode.Invalid) {
|
|
return b;
|
|
}
|
|
|
|
if (a == NonNullableByDefaultCompiledMode.Agnostic) {
|
|
return b;
|
|
}
|
|
if (b == NonNullableByDefaultCompiledMode.Agnostic) {
|
|
// Keep as-is.
|
|
return a;
|
|
}
|
|
|
|
// Mixed mode where agnostic isn't involved.
|
|
throw new CompilationModeError("Mixed compilation mode found: $a and $b");
|
|
}
|