diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart index c5c52a7175c..c408ccca80a 100644 --- a/pkg/compiler/lib/src/serialization/binary_sink.dart +++ b/pkg/compiler/lib/src/serialization/binary_sink.dart @@ -2,16 +2,17 @@ // 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. -// @dart = 2.10 - -part of 'serialization.dart'; +import 'dart:convert'; +import 'package:kernel/binary/ast_to_binary.dart'; +import 'data_sink.dart'; /// [DataSink] that writes data as a sequence of bytes. /// /// This data sink works together with [BinarySourceWriter]. class BinaryDataSink implements DataSink { final Sink> sink; - BufferedSink _bufferedSink; + // Nullable and non-final to allow storage to be released. + BufferedSink? _bufferedSink; int _length = 0; BinaryDataSink(this.sink) : _bufferedSink = BufferedSink(sink); @@ -33,7 +34,7 @@ class BinaryDataSink implements DataSink { void writeString(String value) { List bytes = utf8.encode(value); writeInt(bytes.length); - _bufferedSink.addBytes(bytes); + _bufferedSink!.addBytes(bytes); _length += bytes.length; } @@ -41,13 +42,13 @@ class BinaryDataSink implements DataSink { void writeInt(int value) { assert(value >= 0 && value >> 30 == 0); if (value < 0x80) { - _bufferedSink.addByte(value); + _bufferedSink!.addByte(value); _length += 1; } else if (value < 0x4000) { - _bufferedSink.addByte2((value >> 8) | 0x80, value & 0xFF); + _bufferedSink!.addByte2((value >> 8) | 0x80, value & 0xFF); _length += 2; } else { - _bufferedSink.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF, + _bufferedSink!.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF); _length += 4; } @@ -60,7 +61,7 @@ class BinaryDataSink implements DataSink { @override void close() { - _bufferedSink.flushAndDestroy(); + _bufferedSink!.flushAndDestroy(); _bufferedSink = null; sink.close(); } diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart index 00d1291d37b..59f40ffe3a7 100644 --- a/pkg/compiler/lib/src/serialization/binary_source.dart +++ b/pkg/compiler/lib/src/serialization/binary_source.dart @@ -2,9 +2,10 @@ // 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. -// @dart = 2.10 - -part of 'serialization.dart'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'data_source.dart'; +import 'serialization_interfaces.dart' show StringInterner; /// [DataSource] that reads data from a sequence of bytes. /// @@ -12,10 +13,12 @@ part of 'serialization.dart'; class BinaryDataSource implements DataSource { int _byteOffset = 0; final List _bytes; - final StringInterner _stringInterner; + final StringInterner? _stringInterner; - BinaryDataSource(this._bytes, {StringInterner stringInterner}) - : _stringInterner = stringInterner; + BinaryDataSource(this._bytes, {StringInterner? stringInterner}) + : _stringInterner = stringInterner { + assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound. + } @override void begin(String tag) {} @@ -33,7 +36,7 @@ class BinaryDataSource implements DataSource { _byteOffset += bytes.length; String string = utf8.decode(bytes); if (_stringInterner == null) return string; - return _stringInterner.internString(string); + return _stringInterner!.internString(string); } @override diff --git a/pkg/compiler/lib/src/serialization/data_sink.dart b/pkg/compiler/lib/src/serialization/data_sink.dart new file mode 100644 index 00000000000..b87ebcd921c --- /dev/null +++ b/pkg/compiler/lib/src/serialization/data_sink.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2018, 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. + +/// Interface handling [DataSinkWriter] low-level data serialization. +/// +/// Each implementation of [DataSink] should have a corresponding +/// [DataSource] that deserializes data serialized by that implementation. +// TODO(48820): Move this interface back to 'sink.dart'. +abstract class DataSink { + int get length; + + /// Serialization of a non-negative integer value. + void writeInt(int value); + + /// Serialization of an enum value. + void writeEnum(dynamic value); + + /// Serialization of a String value. + void writeString(String value); + + /// Serialization of a section begin tag. May be omitted by some writers. + void beginTag(String tag); + + /// Serialization of a section end tag. May be omitted by some writers. + void endTag(String tag); + + /// Closes any underlying data sinks. + void close(); +} diff --git a/pkg/compiler/lib/src/serialization/data_source.dart b/pkg/compiler/lib/src/serialization/data_source.dart new file mode 100644 index 00000000000..ee73699fd19 --- /dev/null +++ b/pkg/compiler/lib/src/serialization/data_source.dart @@ -0,0 +1,29 @@ +// Copyright (c) 2018, 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. + +/// Interface handling [DataSourceReader] low-level data deserialization. +/// +/// Each implementation of [DataSource] should have a corresponding +/// [DataSink] for which it deserializes data. +abstract class DataSource { + /// Deserialization of a section begin tag. + void begin(String tag); + + /// Deserialization of a section end tag. + void end(String tag); + + /// Deserialization of a string value. + String readString(); + + /// Deserialization of a non-negative integer value. + int readInt(); + + /// Deserialization of an enum value in [values]. + E readEnum(List values); + + /// Returns a string representation of the current state of the data source + /// useful for debugging in consistencies between serialization and + /// deserialization. + String get errorContext; +} diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart index 51e28e186a1..46791baac2c 100644 --- a/pkg/compiler/lib/src/serialization/helpers.dart +++ b/pkg/compiler/lib/src/serialization/helpers.dart @@ -166,66 +166,3 @@ class DartTypeNodeWriter visitTypes(node.typeArguments, functionTypeVariables); } } - -/// Data sink helper that canonicalizes [E] values using indices. -class IndexedSink { - final DataSink _sink; - Map cache; - - IndexedSink(this._sink, {this.cache}) { - // [cache] slot 0 is pre-allocated to `null`. - this.cache ??= {null: 0}; - } - - /// Write a reference to [value] to the data sink. - /// - /// If [value] has not been canonicalized yet, [writeValue] is called to - /// serialize the [value] itself. - void write(E value, void writeValue(E value)) { - const int pending = -1; - int index = cache[value]; - if (index == null) { - index = cache.length; - _sink.writeInt(index); - cache[value] = pending; // Increments length to allocate slot. - writeValue(value); - cache[value] = index; - } else if (index == pending) { - throw ArgumentError("Cyclic dependency on cached value: $value"); - } else { - _sink.writeInt(index); - } - } -} - -/// Data source helper reads canonicalized [E] values through indices. -class IndexedSource { - final DataSource _sourceReader; - List cache; - - IndexedSource(this._sourceReader, {this.cache}) { - // [cache] slot 0 is pre-allocated to `null`. - this.cache ??= [null]; - } - - /// Reads a reference to an [E] value from the data source. - /// - /// If the value hasn't yet been read, [readValue] is called to deserialize - /// the value itself. - E read(E readValue()) { - int index = _sourceReader.readInt(); - if (index >= cache.length) { - assert(index == cache.length); - cache.add(null); // placeholder. - E value = readValue(); - cache[index] = value; - return value; - } else { - E value = cache[index]; - if (value == null && index != 0) { - throw StateError('Unfilled index $index of $E'); - } - return value; - } - } -} diff --git a/pkg/compiler/lib/src/serialization/indexed_sink_source.dart b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart new file mode 100644 index 00000000000..82db5e00010 --- /dev/null +++ b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart @@ -0,0 +1,75 @@ +// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'data_sink.dart'; +import 'data_source.dart'; + +/// Data sink helper that canonicalizes [E?] values using indices. +class IndexedSink { + final DataSink _sink; + final Map cache; + + IndexedSink._(this._sink, this.cache); + + factory IndexedSink(DataSink sink, {Map? cache}) { + // [cache] slot 0 is pre-allocated to `null`. + cache ??= {null: 0}; + return IndexedSink._(sink, cache); + } + + /// Write a reference to [value] to the data sink. + /// + /// If [value] has not been canonicalized yet, [writeValue] is called to + /// serialize the [value] itself. + void write(E? value, void writeValue(E value)) { + const int pending = -1; + int? index = cache[value]; + if (index == null) { + index = cache.length; + _sink.writeInt(index); + cache[value] = pending; // Increments length to allocate slot. + writeValue(value!); // `null` would have been found in slot 0. + cache[value] = index; + } else if (index == pending) { + throw ArgumentError("Cyclic dependency on cached value: $value"); + } else { + _sink.writeInt(index); + } + } +} + +/// Data source helper reads canonicalized [E?] values through indices. +class IndexedSource { + final DataSource _source; + final List cache; + + IndexedSource._(this._source, this.cache); + + factory IndexedSource(DataSource source, {List? cache}) { + // [cache] slot 0 is pre-allocated to `null`. + cache ??= [null]; + return IndexedSource._(source, cache); + } + + /// Reads a reference to an [E] value from the data source. + /// + /// If the value hasn't yet been read, [readValue] is called to deserialize + /// the value itself. + E? read(E readValue()) { + int index = _source.readInt(); + if (index >= cache.length) { + assert(index == cache.length); + cache.add(null); // placeholder. + E value = readValue(); + cache[index] = value; + return value; + } else { + E? value = cache[index]; + if (value == null && index != 0) { + throw StateError('Unfilled index $index of $E'); + } + return value; + } + } +} diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart index d5b54b4b5ef..3bbbd3b3765 100644 --- a/pkg/compiler/lib/src/serialization/object_sink.dart +++ b/pkg/compiler/lib/src/serialization/object_sink.dart @@ -2,45 +2,45 @@ // 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. -// @dart = 2.10 - -part of 'serialization.dart'; +import 'data_sink.dart'; +import 'tags.dart' show Tag; /// [DataSinkWriter] that writes to a list of objects, useful for debugging /// inconsistencies between serialization and deserialization. /// /// This data sink writer works together with [ObjectDataSource]. class ObjectDataSink implements DataSink { - List _data; + // [_data] is nullable and non-final to allow storage to be released. + List? _data; ObjectDataSink(this._data); @override void beginTag(String tag) { - _data.add(Tag('begin:$tag')); + _data!.add(Tag('begin:$tag')); } @override void endTag(String tag) { - _data.add(Tag('end:$tag')); + _data!.add(Tag('end:$tag')); } @override void writeEnum(dynamic value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override void writeInt(int value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override void writeString(String value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override @@ -50,5 +50,5 @@ class ObjectDataSink implements DataSink { /// Returns the number of objects written to this data sink. @override - int get length => _data.length; + int get length => _data!.length; } diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart index bc349940458..f8279a2820b 100644 --- a/pkg/compiler/lib/src/serialization/object_source.dart +++ b/pkg/compiler/lib/src/serialization/object_source.dart @@ -2,9 +2,8 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// @dart = 2.10 - -part of 'serialization.dart'; +import 'data_source.dart'; +import 'tags.dart' show Tag; /// [DataSource] that read from a list of objects, useful for debugging /// inconsistencies between serialization and deserialization. @@ -17,9 +16,9 @@ class ObjectDataSource implements DataSource { ObjectDataSource(this._data); T _read() { - dynamic value = _data[_index++]; - assert(value is T, "Expected $T value, found $value.$errorContext"); - return value; + Object? value = _data[_index++]; + if (value is T) return value; + throw StateError('Expected $T value, found $value.$errorContext'); } @override diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart index a863d059c7e..d0aa69e7e70 100644 --- a/pkg/compiler/lib/src/serialization/serialization.dart +++ b/pkg/compiler/lib/src/serialization/serialization.dart @@ -5,10 +5,8 @@ // @dart = 2.10 import 'dart:collection'; -import 'dart:convert'; import 'dart:typed_data'; import 'package:kernel/ast.dart' as ir; -import 'package:kernel/binary/ast_to_binary.dart'; import '../closure.dart'; import '../constants/constant_system.dart' as constant_system; import '../constants/values.dart'; @@ -25,24 +23,24 @@ import '../js_model/closure.dart'; import '../js_model/locals.dart'; import '../js_model/type_recipe.dart' show TypeRecipe; +import 'data_sink.dart'; +import 'data_source.dart'; import 'member_data.dart'; -export 'member_data.dart' show ComponentLookup, computeMemberName; import 'serialization_interfaces.dart' as migrated show DataSourceReader, DataSinkWriter; +import 'indexed_sink_source.dart'; import 'tags.dart'; + +export 'binary_sink.dart'; +export 'binary_source.dart'; +export 'member_data.dart' show ComponentLookup, computeMemberName; +export 'object_sink.dart'; +export 'object_source.dart'; export 'tags.dart'; part 'sink.dart'; part 'source.dart'; -part 'binary_sink.dart'; -part 'binary_source.dart'; part 'helpers.dart'; -part 'object_sink.dart'; -part 'object_source.dart'; - -abstract class StringInterner { - String internString(String string); -} class ValueInterner { final Map _dartTypeMap = HashMap(); diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart index a2ee9ddbd9b..efa9bb1ad82 100644 --- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart +++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart @@ -9,6 +9,10 @@ import '../elements/types.dart' show DartType; export 'tags.dart'; +abstract class StringInterner { + String internString(String string); +} + /// NNBD-migrated interface for methods of DataSinkWriter. /// /// This is a pure interface or facade for DataSinkWriter. @@ -73,6 +77,7 @@ abstract class DataSinkWriter { {bool allowNull = false}); void writeCached(E value, void f(E value)); + void writeList(Iterable values, void f(E value), {bool allowNull = false}); } @@ -112,6 +117,7 @@ abstract class DataSourceReader { Map? readTreeNodeMapInContextOrNull(V f()); E readCached(E f()); + List readList(E f()); List? readListOrNull(E f()); } diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart index 67ec6b5cdcb..214b6e9f413 100644 --- a/pkg/compiler/lib/src/serialization/sink.dart +++ b/pkg/compiler/lib/src/serialization/sink.dart @@ -6,32 +6,6 @@ part of 'serialization.dart'; -/// Interface handling [DataSinkWriter] low-level data serialization. -/// -/// Each implementation of [DataSink] should have a corresponding -/// [DataSource] that deserializes data serialized by that implementation. -abstract class DataSink { - int get length; - - /// Serialization of a non-negative integer value. - void writeInt(int value); - - /// Serialization of an enum value. - void writeEnum(dynamic value); - - /// Serialization of a String value. - void writeString(String value); - - /// Serialization of a section begin tag. May be omitted by some writers. - void beginTag(String tag); - - /// Serialization of a section end tag. May be omitted by some writers. - void endTag(String tag); - - /// Closes any underlying data sinks. - void close(); -} - /// Serialization writer /// /// To be used with [DataSourceReader] to read and write serialized data. diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart index 806731c75f1..2d0855ceecb 100644 --- a/pkg/compiler/lib/src/serialization/source.dart +++ b/pkg/compiler/lib/src/serialization/source.dart @@ -6,32 +6,6 @@ part of 'serialization.dart'; -/// Interface handling [DataSourceReader] low-level data deserialization. -/// -/// Each implementation of [DataSource] should have a corresponding -/// [DataSink] for which it deserializes data. -abstract class DataSource { - /// Deserialization of a section begin tag. - void begin(String tag); - - /// Deserialization of a section end tag. - void end(String tag); - - /// Deserialization of a string value. - String readString(); - - /// Deserialization of a non-negative integer value. - int readInt(); - - /// Deserialization of an enum value in [values]. - E readEnum(List values); - - /// Returns a string representation of the current state of the data source - /// useful for debugging in consistencies between serialization and - /// deserialization. - String get errorContext; -} - /// Deserialization reader /// /// To be used with [DataSinkWriter] to read and write serialized data. diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart index 6f9d2c46f02..b4e8b0b6ec4 100644 --- a/pkg/compiler/lib/src/serialization/task.dart +++ b/pkg/compiler/lib/src/serialization/task.dart @@ -29,6 +29,7 @@ import '../options.dart'; import '../util/sink_adapter.dart'; import '../world.dart'; import 'serialization.dart'; +import 'serialization_interfaces.dart' show StringInterner; /// A data class holding a [JsClosedWorld] and the associated /// [DataSourceIndices].