diff --git a/protobuf/lib/src/protobuf/coded_buffer.dart b/protobuf/lib/src/protobuf/coded_buffer.dart index 1bcb864f..0ef638d5 100644 --- a/protobuf/lib/src/protobuf/coded_buffer.dart +++ b/protobuf/lib/src/protobuf/coded_buffer.dart @@ -29,8 +29,8 @@ void _writeToCodedBufferWriter(_FieldSet fs, CodedBufferWriter out) { } } -void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs, - CodedBufferReader input, ExtensionRegistry registry) { +void _mergeFromCodedBufferReader(final BuilderInfo meta, final _FieldSet fs, + final CodedBufferReader input, final ExtensionRegistry registry) { fs._ensureWritable(); while (true) { final tag = input.readTag(); @@ -129,33 +129,65 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs, case PbFieldType._REPEATED_BOOL: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readBool())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + // No need to check the element as for `bool` fields we only need to + // check that the value is not null, and we know in `add` below that + // the value isn't null (`readBool` doesn't return `null`). + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readBool()); + } + }); + } } else { - list.add(input.readBool()); + list._checkModifiable('add'); + list._addUnchecked(input.readBool()); } break; case PbFieldType._REPEATED_BYTES: final list = fs._ensureRepeatedField(meta, fi); - list.add(input.readBytes()); + list._checkModifiable('add'); + list._addUnchecked(input.readBytes()); break; case PbFieldType._REPEATED_STRING: final list = fs._ensureRepeatedField(meta, fi); - list.add(input.readString()); + list._checkModifiable('add'); + list._addUnchecked(input.readString()); break; case PbFieldType._REPEATED_FLOAT: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readFloat())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readFloat()); + } + }); + } } else { - list.add(input.readFloat()); + list._checkModifiable('add'); + list._addUnchecked(input.readFloat()); } break; case PbFieldType._REPEATED_DOUBLE: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readDouble())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readDouble()); + } + }); + } } else { - list.add(input.readDouble()); + list._checkModifiable('add'); + list._addUnchecked(input.readDouble()); } break; case PbFieldType._REPEATED_ENUM: @@ -172,81 +204,171 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs, case PbFieldType._REPEATED_INT32: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readInt32())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readInt32()); + } + }); + } } else { - list.add(input.readInt32()); + list._checkModifiable('add'); + list._addUnchecked(input.readInt32()); } break; case PbFieldType._REPEATED_INT64: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readInt64())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readInt64()); + } + }); + } } else { - list.add(input.readInt64()); + list._checkModifiable('add'); + list._addUnchecked(input.readInt64()); } break; case PbFieldType._REPEATED_SINT32: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readSint32())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readSint32()); + } + }); + } } else { - list.add(input.readSint32()); + list._checkModifiable('add'); + list._addUnchecked(input.readSint32()); } break; case PbFieldType._REPEATED_SINT64: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readSint64())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readSint64()); + } + }); + } } else { - list.add(input.readSint64()); + list._checkModifiable('add'); + list._addUnchecked(input.readSint64()); } break; case PbFieldType._REPEATED_UINT32: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readUint32())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readUint32()); + } + }); + } } else { - list.add(input.readUint32()); + list._checkModifiable('add'); + list._addUnchecked(input.readUint32()); } break; case PbFieldType._REPEATED_UINT64: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readUint64())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readUint64()); + } + }); + } } else { - list.add(input.readUint64()); + list._checkModifiable('add'); + list._addUnchecked(input.readUint64()); } break; case PbFieldType._REPEATED_FIXED32: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readFixed32())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readFixed32()); + } + }); + } } else { - list.add(input.readFixed32()); + list._checkModifiable('add'); + list._addUnchecked(input.readFixed32()); } break; case PbFieldType._REPEATED_FIXED64: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readFixed64())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readFixed64()); + } + }); + } } else { - list.add(input.readFixed64()); + list._checkModifiable('add'); + list._addUnchecked(input.readFixed64()); } break; case PbFieldType._REPEATED_SFIXED32: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readSfixed32())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readSfixed32()); + } + }); + } } else { - list.add(input.readSfixed32()); + list._checkModifiable('add'); + list._addUnchecked(input.readSfixed32()); } break; case PbFieldType._REPEATED_SFIXED64: final list = fs._ensureRepeatedField(meta, fi); if (wireType == WIRETYPE_LENGTH_DELIMITED) { - _readPacked(input, () => list.add(input.readSfixed64())); + final limit = input.readInt32(); + if (limit != 0) { + list._checkModifiable('add'); + input._withLimit(limit, () { + while (!input.isAtEnd()) { + list._addUnchecked(input.readSfixed64()); + } + }); + } } else { - list.add(input.readSfixed64()); + list._checkModifiable('add'); + list._addUnchecked(input.readSfixed64()); } break; case PbFieldType._REPEATED_MESSAGE: @@ -268,14 +390,6 @@ void _mergeFromCodedBufferReader(BuilderInfo meta, _FieldSet fs, } } -void _readPacked(CodedBufferReader input, void Function() readFunc) { - input._withLimit(input.readInt32(), () { - while (!input.isAtEnd()) { - readFunc(); - } - }); -} - void _readPackableToListEnum( List list, BuilderInfo meta, diff --git a/protobuf/lib/src/protobuf/coded_buffer_reader.dart b/protobuf/lib/src/protobuf/coded_buffer_reader.dart index cc7e3ddf..c4c49ee2 100644 --- a/protobuf/lib/src/protobuf/coded_buffer_reader.dart +++ b/protobuf/lib/src/protobuf/coded_buffer_reader.dart @@ -42,14 +42,17 @@ class CodedBufferReader { throw InvalidProtocolBufferException.truncatedMessage(); } + @pragma('vm:prefer-inline') void checkLastTagWas(int value) { if (_lastTag != value) { throw InvalidProtocolBufferException.invalidEndTag(); } } + @pragma('vm:prefer-inline') bool isAtEnd() => _bufferPos >= _currentLimit; + @pragma('vm:prefer-inline') void _withLimit(int byteLimit, Function() callback) { if (byteLimit < 0) { throw ArgumentError( @@ -66,6 +69,7 @@ class CodedBufferReader { _currentLimit = oldLimit; } + @pragma('vm:prefer-inline') void _checkLimit(int increment) { assert(_currentLimit != -1); _bufferPos += increment; @@ -121,28 +125,45 @@ class CodedBufferReader { _currentLimit = oldLimit; } + @pragma('vm:prefer-inline') int readEnum() => readInt32(); + + @pragma('vm:prefer-inline') int readInt32() => _readRawVarint32(true); + + @pragma('vm:prefer-inline') Int64 readInt64() => _readRawVarint64(); + + @pragma('vm:prefer-inline') int readUint32() => _readRawVarint32(false); + + @pragma('vm:prefer-inline') Int64 readUint64() => _readRawVarint64(); + + @pragma('vm:prefer-inline') int readSint32() => _decodeZigZag32(readUint32()); + + @pragma('vm:prefer-inline') Int64 readSint64() => _decodeZigZag64(readUint64()); + @pragma('vm:prefer-inline') int readFixed32() { final pos = _bufferPos; _checkLimit(4); return _byteData.getUint32(pos, Endian.little); } + @pragma('vm:prefer-inline') Int64 readFixed64() => readSfixed64(); + @pragma('vm:prefer-inline') int readSfixed32() { final pos = _bufferPos; _checkLimit(4); return _byteData.getInt32(pos, Endian.little); } + @pragma('vm:prefer-inline') Int64 readSfixed64() { final pos = _bufferPos; _checkLimit(8); @@ -150,15 +171,18 @@ class CodedBufferReader { return Int64.fromBytes(view); } + @pragma('vm:prefer-inline') bool readBool() => _readRawVarint32(true) != 0; /// Read a length-delimited field as bytes. + @pragma('vm:prefer-inline') Uint8List readBytes() => Uint8List.fromList(readBytesAsView()); /// Read a length-delimited field as a view of the [CodedBufferReader]'s /// buffer. When storing the returned value directly (instead of e.g. parsing /// it as a UTF-8 string and copying) use [readBytes] instead to avoid /// holding on to the whole message, or copy the returned view. + @pragma('vm:prefer-inline') Uint8List readBytesAsView() { final length = readInt32(); _checkLimit(length); @@ -166,6 +190,7 @@ class CodedBufferReader { _buffer.buffer, _buffer.offsetInBytes + _bufferPos - length, length); } + @pragma('vm:prefer-inline') String readString() { final length = readInt32(); final stringPos = _bufferPos; @@ -174,18 +199,21 @@ class CodedBufferReader { .convert(_buffer, stringPos, stringPos + length); } + @pragma('vm:prefer-inline') double readFloat() { final pos = _bufferPos; _checkLimit(4); return _byteData.getFloat32(pos, Endian.little); } + @pragma('vm:prefer-inline') double readDouble() { final pos = _bufferPos; _checkLimit(8); return _byteData.getFloat64(pos, Endian.little); } + @pragma('vm:prefer-inline') int readTag() { if (isAtEnd()) { _lastTag = 0; @@ -228,6 +256,7 @@ class CodedBufferReader { } } + @pragma('vm:prefer-inline') static int _decodeZigZag32(int value) { if ((value & 0x1) == 1) { return -(value >> 1) - 1; @@ -236,11 +265,13 @@ class CodedBufferReader { } } + @pragma('vm:prefer-inline') static Int64 _decodeZigZag64(Int64 value) { if ((value & 0x1) == 1) value = -value; return value >> 1; } + @pragma('vm:prefer-inline') int _readRawVarintByte() { _checkLimit(1); return _buffer[_bufferPos - 1]; diff --git a/protobuf/lib/src/protobuf/extension_field_set.dart b/protobuf/lib/src/protobuf/extension_field_set.dart index f90bb909..28582dea 100644 --- a/protobuf/lib/src/protobuf/extension_field_set.dart +++ b/protobuf/lib/src/protobuf/extension_field_set.dart @@ -66,6 +66,7 @@ class _ExtensionFieldSet { return newList; } + @pragma('vm:prefer-inline') dynamic _getFieldOrNull(Extension extension) => _values[extension.tagNumber]; void _clearFieldAndInfo(Extension fi) { diff --git a/protobuf/lib/src/protobuf/field_set.dart b/protobuf/lib/src/protobuf/field_set.dart index ea3dac84..5d518805 100644 --- a/protobuf/lib/src/protobuf/field_set.dart +++ b/protobuf/lib/src/protobuf/field_set.dart @@ -4,6 +4,7 @@ part of '../../protobuf.dart'; +@pragma('vm:never-inline') void _throwFrozenMessageModificationError(String messageName, [String? methodName]) { if (methodName != null) { diff --git a/protobuf/lib/src/protobuf/pb_list.dart b/protobuf/lib/src/protobuf/pb_list.dart index 792bfff4..64b04658 100644 --- a/protobuf/lib/src/protobuf/pb_list.dart +++ b/protobuf/lib/src/protobuf/pb_list.dart @@ -52,6 +52,12 @@ class PbList extends ListBase { _wrappedList.add(element); } + @pragma('dart2js:tryInline') + @pragma('vm:prefer-inline') + void _addUnchecked(E element) { + _wrappedList.add(element); + } + @override @pragma('dart2js:never-inline') void addAll(Iterable iterable) {