[dart2js] Migrate more of serialization/ to NNBD

This CL reduces the number of part files in serialization/ by moving
classes into smaller libraries.

This allows the {Data,Binary,Object}{Sink,Source} to be migrated to
NNBD while sink.dart and source.dart still have dependencies.

Change-Id: I0ea44f95841f18978e78c2e1697fbc97a3bf73c4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243711
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
This commit is contained in:
Stephen Adams 2022-05-05 20:04:45 +00:00 committed by Commit Bot
parent 5898dcd1ad
commit 56765625e0
13 changed files with 188 additions and 161 deletions

View file

@ -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<List<int>> 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<int> 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();
}

View file

@ -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<int> _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

View file

@ -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();
}

View file

@ -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<E>(List<E> 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;
}

View file

@ -166,66 +166,3 @@ class DartTypeNodeWriter
visitTypes(node.typeArguments, functionTypeVariables);
}
}
/// Data sink helper that canonicalizes [E] values using indices.
class IndexedSink<E> {
final DataSink _sink;
Map<E, int> 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<E> {
final DataSource _sourceReader;
List<E> 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;
}
}
}

View file

@ -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<E extends Object> {
final DataSink _sink;
final Map<E?, int> cache;
IndexedSink._(this._sink, this.cache);
factory IndexedSink(DataSink sink, {Map<E?, int>? 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<E extends Object> {
final DataSource _source;
final List<E?> cache;
IndexedSource._(this._source, this.cache);
factory IndexedSource(DataSource source, {List<E?>? 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;
}
}
}

View file

@ -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<dynamic> _data;
// [_data] is nullable and non-final to allow storage to be released.
List<dynamic>? _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;
}

View file

@ -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<T>() {
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

View file

@ -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<DartType, DartType> _dartTypeMap = HashMap();

View file

@ -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 extends Object>(E value, void f(E value));
void writeList<E extends Object>(Iterable<E> values, void f(E value),
{bool allowNull = false});
}
@ -112,6 +117,7 @@ abstract class DataSourceReader {
Map<K, V>? readTreeNodeMapInContextOrNull<K extends ir.TreeNode, V>(V f());
E readCached<E extends Object>(E f());
List<E> readList<E extends Object>(E f());
List<E>? readListOrNull<E extends Object>(E f());
}

View file

@ -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.

View file

@ -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<E>(List<E> 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.

View file

@ -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].