Skip to content

Commit 75389dd

Browse files
authored
Allow dart protos to be sent through sendports (and therefore to other isolates) (#452)
Decoded protos in Dart are represented in memory as instances of `GeneratedMessage` subclasses. The `GeneratedMessage` stores the field state in a `_FieldSet` and `UnknownFieldSet`. The `_FieldSet._meta` field points to a `BuilderInfo` object, which represents the metadata of the proto message. Sending this reference to `BuilderInfo` makes it hard to send dart protos to other isolates, because a) `BuilderInfo` hangs on to non-static closures, which cannot be sent to to other isolates atm b) Sending a transitive copy would copy the `BuilderInfo` object (and it's transitive closure). That can cause big waste of memory since an isolate would have this metadata possibly many times. To avoid these two issues, this CL does the following: * We replace `_FieldSet._meta` with a getter that accesses the `BuilderInfo` via the `_FieldSet._message.info_` getter. This getter is implemented in `GeneratedMessage` subclasses and reads from a static field. => We effectively replace a load of the `_meta` field with load + interface call + static field load. * To avoid performance regressions we avoid accessing the new `_FieldSet._meta` getter in the hot decoding loops. Instead we obtain this metadata once and pass it down to various methods that are part of decoding. * For similar reasons, we remove the `PbMap._entryBuilderInfo` field - which also refers to a `BuilderInfo`. Instead we obtain the neccessary map-specific `BuilderInfo` in the main decoder loop. This CL has to remove the 2 year long deprecated `PbMap.add()` functiondeprecated.
1 parent 0d03fd5 commit 75389dd

11 files changed

+244
-158
lines changed

protobuf/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 2.0.0-nullsafety.1
2+
3+
* Remove `PbMap.add` method which was deprecated in 0.13.3
4+
15
## 2.0.0-nullsafety.0
26

37
* Require at least Dart SDK 2.12.0 and support null safety. Use `protoc_plugin`

protobuf/lib/src/protobuf/coded_buffer.dart

Lines changed: 67 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,17 @@ void _writeToCodedBufferWriter(_FieldSet fs, CodedBufferWriter out) {
2626
}
2727
}
2828

29-
void _mergeFromCodedBufferReader(
30-
_FieldSet fs, CodedBufferReader input, ExtensionRegistry registry) {
29+
void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs,
30+
CodedBufferReader input, ExtensionRegistry registry) {
3131
ArgumentError.checkNotNull(registry);
32-
3332
while (true) {
3433
var tag = input.readTag();
3534
if (tag == 0) return;
3635
var wireType = tag & 0x7;
3736
var tagNumber = tag >> 3;
3837

39-
var fi = fs._nonExtensionInfo(tagNumber);
40-
fi ??= registry.getExtension(fs._messageName, tagNumber);
38+
var fi = fs._nonExtensionInfo(meta, tagNumber);
39+
fi ??= registry.getExtension(meta.qualifiedMessageName, tagNumber);
4140

4241
if (fi == null || !_wireTypeMatches(fi.type, wireType)) {
4342
if (!fs._ensureUnknownFields().mergeFieldFromBuffer(tag, input)) {
@@ -51,156 +50,167 @@ void _mergeFromCodedBufferReader(
5150
fieldType &= ~(PbFieldType._PACKED_BIT | PbFieldType._REQUIRED_BIT);
5251
switch (fieldType) {
5352
case PbFieldType._OPTIONAL_BOOL:
54-
fs._setFieldUnchecked(fi, input.readBool());
53+
fs._setFieldUnchecked(meta, fi, input.readBool());
5554
break;
5655
case PbFieldType._OPTIONAL_BYTES:
57-
fs._setFieldUnchecked(fi, input.readBytes());
56+
fs._setFieldUnchecked(meta, fi, input.readBytes());
5857
break;
5958
case PbFieldType._OPTIONAL_STRING:
60-
fs._setFieldUnchecked(fi, input.readString());
59+
fs._setFieldUnchecked(meta, fi, input.readString());
6160
break;
6261
case PbFieldType._OPTIONAL_FLOAT:
63-
fs._setFieldUnchecked(fi, input.readFloat());
62+
fs._setFieldUnchecked(meta, fi, input.readFloat());
6463
break;
6564
case PbFieldType._OPTIONAL_DOUBLE:
66-
fs._setFieldUnchecked(fi, input.readDouble());
65+
fs._setFieldUnchecked(meta, fi, input.readDouble());
6766
break;
6867
case PbFieldType._OPTIONAL_ENUM:
6968
var rawValue = input.readEnum();
70-
var value = fs._meta._decodeEnum(tagNumber, registry, rawValue);
69+
var value = meta._decodeEnum(tagNumber, registry, rawValue);
7170
if (value == null) {
7271
var unknown = fs._ensureUnknownFields();
7372
unknown.mergeVarintField(tagNumber, Int64(rawValue));
7473
} else {
75-
fs._setFieldUnchecked(fi, value);
74+
fs._setFieldUnchecked(meta, fi, value);
7675
}
7776
break;
7877
case PbFieldType._OPTIONAL_GROUP:
79-
var subMessage = fs._meta._makeEmptyMessage(tagNumber, registry);
78+
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
8079
var oldValue = fs._getFieldOrNull(fi);
8180
if (oldValue != null) {
8281
subMessage.mergeFromMessage(oldValue);
8382
}
8483
input.readGroup(tagNumber, subMessage, registry);
85-
fs._setFieldUnchecked(fi, subMessage);
84+
fs._setFieldUnchecked(meta, fi, subMessage);
8685
break;
8786
case PbFieldType._OPTIONAL_INT32:
88-
fs._setFieldUnchecked(fi, input.readInt32());
87+
fs._setFieldUnchecked(meta, fi, input.readInt32());
8988
break;
9089
case PbFieldType._OPTIONAL_INT64:
91-
fs._setFieldUnchecked(fi, input.readInt64());
90+
fs._setFieldUnchecked(meta, fi, input.readInt64());
9291
break;
9392
case PbFieldType._OPTIONAL_SINT32:
94-
fs._setFieldUnchecked(fi, input.readSint32());
93+
fs._setFieldUnchecked(meta, fi, input.readSint32());
9594
break;
9695
case PbFieldType._OPTIONAL_SINT64:
97-
fs._setFieldUnchecked(fi, input.readSint64());
96+
fs._setFieldUnchecked(meta, fi, input.readSint64());
9897
break;
9998
case PbFieldType._OPTIONAL_UINT32:
100-
fs._setFieldUnchecked(fi, input.readUint32());
99+
fs._setFieldUnchecked(meta, fi, input.readUint32());
101100
break;
102101
case PbFieldType._OPTIONAL_UINT64:
103-
fs._setFieldUnchecked(fi, input.readUint64());
102+
fs._setFieldUnchecked(meta, fi, input.readUint64());
104103
break;
105104
case PbFieldType._OPTIONAL_FIXED32:
106-
fs._setFieldUnchecked(fi, input.readFixed32());
105+
fs._setFieldUnchecked(meta, fi, input.readFixed32());
107106
break;
108107
case PbFieldType._OPTIONAL_FIXED64:
109-
fs._setFieldUnchecked(fi, input.readFixed64());
108+
fs._setFieldUnchecked(meta, fi, input.readFixed64());
110109
break;
111110
case PbFieldType._OPTIONAL_SFIXED32:
112-
fs._setFieldUnchecked(fi, input.readSfixed32());
111+
fs._setFieldUnchecked(meta, fi, input.readSfixed32());
113112
break;
114113
case PbFieldType._OPTIONAL_SFIXED64:
115-
fs._setFieldUnchecked(fi, input.readSfixed64());
114+
fs._setFieldUnchecked(meta, fi, input.readSfixed64());
116115
break;
117116
case PbFieldType._OPTIONAL_MESSAGE:
118-
var subMessage = fs._meta._makeEmptyMessage(tagNumber, registry);
117+
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
119118
var oldValue = fs._getFieldOrNull(fi);
120119
if (oldValue != null) {
121120
subMessage.mergeFromMessage(oldValue);
122121
}
123122
input.readMessage(subMessage, registry);
124-
fs._setFieldUnchecked(fi, subMessage);
123+
fs._setFieldUnchecked(meta, fi, subMessage);
125124
break;
126125
case PbFieldType._REPEATED_BOOL:
127-
_readPackable(fs, input, wireType, fi, input.readBool);
126+
_readPackable(meta, fs, input, wireType, fi, input.readBool);
128127
break;
129128
case PbFieldType._REPEATED_BYTES:
130-
fs._ensureRepeatedField(fi).add(input.readBytes());
129+
fs._ensureRepeatedField(meta, fi).add(input.readBytes());
131130
break;
132131
case PbFieldType._REPEATED_STRING:
133-
fs._ensureRepeatedField(fi).add(input.readString());
132+
fs._ensureRepeatedField(meta, fi).add(input.readString());
134133
break;
135134
case PbFieldType._REPEATED_FLOAT:
136-
_readPackable(fs, input, wireType, fi, input.readFloat);
135+
_readPackable(meta, fs, input, wireType, fi, input.readFloat);
137136
break;
138137
case PbFieldType._REPEATED_DOUBLE:
139-
_readPackable(fs, input, wireType, fi, input.readDouble);
138+
_readPackable(meta, fs, input, wireType, fi, input.readDouble);
140139
break;
141140
case PbFieldType._REPEATED_ENUM:
142-
_readPackableToListEnum(fs, input, wireType, fi, tagNumber, registry);
141+
_readPackableToListEnum(
142+
meta, fs, input, wireType, fi, tagNumber, registry);
143143
break;
144144
case PbFieldType._REPEATED_GROUP:
145-
var subMessage = fs._meta._makeEmptyMessage(tagNumber, registry);
145+
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
146146
input.readGroup(tagNumber, subMessage, registry);
147-
fs._ensureRepeatedField(fi).add(subMessage);
147+
fs._ensureRepeatedField(meta, fi).add(subMessage);
148148
break;
149149
case PbFieldType._REPEATED_INT32:
150-
_readPackable(fs, input, wireType, fi, input.readInt32);
150+
_readPackable(meta, fs, input, wireType, fi, input.readInt32);
151151
break;
152152
case PbFieldType._REPEATED_INT64:
153-
_readPackable(fs, input, wireType, fi, input.readInt64);
153+
_readPackable(meta, fs, input, wireType, fi, input.readInt64);
154154
break;
155155
case PbFieldType._REPEATED_SINT32:
156-
_readPackable(fs, input, wireType, fi, input.readSint32);
156+
_readPackable(meta, fs, input, wireType, fi, input.readSint32);
157157
break;
158158
case PbFieldType._REPEATED_SINT64:
159-
_readPackable(fs, input, wireType, fi, input.readSint64);
159+
_readPackable(meta, fs, input, wireType, fi, input.readSint64);
160160
break;
161161
case PbFieldType._REPEATED_UINT32:
162-
_readPackable(fs, input, wireType, fi, input.readUint32);
162+
_readPackable(meta, fs, input, wireType, fi, input.readUint32);
163163
break;
164164
case PbFieldType._REPEATED_UINT64:
165-
_readPackable(fs, input, wireType, fi, input.readUint64);
165+
_readPackable(meta, fs, input, wireType, fi, input.readUint64);
166166
break;
167167
case PbFieldType._REPEATED_FIXED32:
168-
_readPackable(fs, input, wireType, fi, input.readFixed32);
168+
_readPackable(meta, fs, input, wireType, fi, input.readFixed32);
169169
break;
170170
case PbFieldType._REPEATED_FIXED64:
171-
_readPackable(fs, input, wireType, fi, input.readFixed64);
171+
_readPackable(meta, fs, input, wireType, fi, input.readFixed64);
172172
break;
173173
case PbFieldType._REPEATED_SFIXED32:
174-
_readPackable(fs, input, wireType, fi, input.readSfixed32);
174+
_readPackable(meta, fs, input, wireType, fi, input.readSfixed32);
175175
break;
176176
case PbFieldType._REPEATED_SFIXED64:
177-
_readPackable(fs, input, wireType, fi, input.readSfixed64);
177+
_readPackable(meta, fs, input, wireType, fi, input.readSfixed64);
178178
break;
179179
case PbFieldType._REPEATED_MESSAGE:
180-
var subMessage = fs._meta._makeEmptyMessage(tagNumber, registry);
180+
var subMessage = meta._makeEmptyMessage(tagNumber, registry);
181181
input.readMessage(subMessage, registry);
182-
fs._ensureRepeatedField(fi).add(subMessage);
182+
fs._ensureRepeatedField(meta, fi).add(subMessage);
183183
break;
184184
case PbFieldType._MAP:
185-
fs._ensureMapField(fi as MapFieldInfo)._mergeEntry(input, registry);
185+
final mapFieldInfo = fi as MapFieldInfo;
186+
final mapEntryMeta = mapFieldInfo.mapEntryBuilderInfo;
187+
fs
188+
._ensureMapField(meta, mapFieldInfo)
189+
._mergeEntry(mapEntryMeta, input, registry);
186190
break;
187191
default:
188192
throw 'Unknown field type $fieldType';
189193
}
190194
}
191195
}
192196

193-
void _readPackable(_FieldSet fs, CodedBufferReader input, int wireType,
194-
FieldInfo fi, Function readFunc) {
197+
void _readPackable(BuilderInfo meta, _FieldSet fs, CodedBufferReader input,
198+
int wireType, FieldInfo fi, Function readFunc) {
195199
void readToList(List list) => list.add(readFunc());
196-
_readPackableToList(fs, input, wireType, fi, readToList);
200+
_readPackableToList(meta, fs, input, wireType, fi, readToList);
197201
}
198202

199-
void _readPackableToListEnum(_FieldSet fs, CodedBufferReader input,
200-
int wireType, FieldInfo fi, int tagNumber, ExtensionRegistry registry) {
203+
void _readPackableToListEnum(
204+
BuilderInfo meta,
205+
_FieldSet fs,
206+
CodedBufferReader input,
207+
int wireType,
208+
FieldInfo fi,
209+
int tagNumber,
210+
ExtensionRegistry registry) {
201211
void readToList(List list) {
202212
var rawValue = input.readEnum();
203-
var value = fs._meta._decodeEnum(tagNumber, registry, rawValue);
213+
var value = meta._decodeEnum(tagNumber, registry, rawValue);
204214
if (value == null) {
205215
var unknown = fs._ensureUnknownFields();
206216
unknown.mergeVarintField(tagNumber, Int64(rawValue));
@@ -209,12 +219,12 @@ void _readPackableToListEnum(_FieldSet fs, CodedBufferReader input,
209219
}
210220
}
211221

212-
_readPackableToList(fs, input, wireType, fi, readToList);
222+
_readPackableToList(meta, fs, input, wireType, fi, readToList);
213223
}
214224

215-
void _readPackableToList(_FieldSet fs, CodedBufferReader input, int wireType,
216-
FieldInfo fi, Function readToList) {
217-
var list = fs._ensureRepeatedField(fi);
225+
void _readPackableToList(BuilderInfo meta, _FieldSet fs,
226+
CodedBufferReader input, int wireType, FieldInfo fi, Function readToList) {
227+
var list = fs._ensureRepeatedField(meta, fi);
218228

219229
if (wireType == WIRETYPE_LENGTH_DELIMITED) {
220230
// Packed.

protobuf/lib/src/protobuf/field_info.dart

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ class FieldInfo<T> {
176176

177177
/// Convenience method to thread this FieldInfo's reified type parameter to
178178
/// _FieldSet._ensureRepeatedField.
179-
List<T?> _ensureRepeatedField(_FieldSet fs) {
180-
return fs._ensureRepeatedField<T>(this);
179+
List<T?> _ensureRepeatedField(BuilderInfo meta, _FieldSet fs) {
180+
return fs._ensureRepeatedField<T>(meta, this);
181181
}
182182

183183
@override
@@ -192,6 +192,9 @@ String _unCamelCase(String name) {
192192
}
193193

194194
class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {
195+
static dynamic throwYouShouldNotCallThis() =>
196+
throw StateError('You should not call this.');
197+
195198
final int? keyFieldType;
196199
final int? valueFieldType;
197200

@@ -213,8 +216,7 @@ class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {
213216
this.valueCreator,
214217
{String? protoName})
215218
: super(name, tagNumber, index, type,
216-
defaultOrMaker: () =>
217-
PbMap<K, V>(keyFieldType, valueFieldType, mapEntryBuilderInfo),
219+
defaultOrMaker: () => throwYouShouldNotCallThis,
218220
protoName: protoName) {
219221
ArgumentError.checkNotNull(name, 'name');
220222
ArgumentError.checkNotNull(tagNumber, 'tagNumber');
@@ -225,8 +227,8 @@ class MapFieldInfo<K, V> extends FieldInfo<PbMap<K, V>?> {
225227
FieldInfo get valueFieldInfo =>
226228
mapEntryBuilderInfo.fieldInfo[PbMap._valueFieldNumber]!;
227229

228-
Map<K, V> _ensureMapField(_FieldSet fs) {
229-
return fs._ensureMapField<K, V>(this);
230+
Map<K, V> _ensureMapField(BuilderInfo meta, _FieldSet fs) {
231+
return fs._ensureMapField<K, V>(meta, this);
230232
}
231233

232234
Map<K, V> _createMapField(GeneratedMessage m) {

0 commit comments

Comments
 (0)