From 5a76e633ea9b5adb215e93fdc11e1c0c08b3fc74 Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Thu, 17 Nov 2016 16:48:38 -0800 Subject: Integrated internal changes from Google --- src/google/protobuf/io/coded_stream.h | 125 +++++++++++++++++++++++++--------- 1 file changed, 91 insertions(+), 34 deletions(-) (limited to 'src/google/protobuf/io/coded_stream.h') diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index 1402cc17..d2a3e279 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -249,12 +249,16 @@ class LIBPROTOBUF_EXPORT CodedInputStream { bool ReadVarintSizeAsInt(int* value); // Read a tag. This calls ReadVarint32() and returns the result, or returns - // zero (which is not a valid tag) if ReadVarint32() fails. Also, it updates - // the last tag value, which can be checked with LastTagWas(). + // zero (which is not a valid tag) if ReadVarint32() fails. Also, ReadTag + // (but not ReadTagNoLastTag) updates the last tag value, which can be checked + // with LastTagWas(). + // // Always inline because this is only called in one place per parse loop // but it is called for every iteration of said loop, so it should be fast. // GCC doesn't want to inline this by default. GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTag(); + GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTagNoLastTag(); + // This usually a faster alternative to ReadTag() when cutoff is a manifest // constant. It does particularly well for cutoff >= 127. The first part @@ -266,6 +270,8 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // to avoid an extra "is tag == 0?" check here.) GOOGLE_ATTRIBUTE_ALWAYS_INLINE std::pair ReadTagWithCutoff( uint32 cutoff); + GOOGLE_ATTRIBUTE_ALWAYS_INLINE std::pair ReadTagWithCutoffNoLastTag( + uint32 cutoff); // Usually returns true if calling ReadVarint32() now would produce the given // value. Will always return false if ReadVarint32() would not return the @@ -293,8 +299,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // zero, and ConsumedEntireMessage() will return true. bool ExpectAtEnd(); - // If the last call to ReadTag() or ReadTagWithCutoff() returned the - // given value, returns true. Otherwise, returns false; + // If the last call to ReadTag() or ReadTagWithCutoff() returned the given + // value, returns true. Otherwise, returns false. + // ReadTagNoLastTag/ReadTagWithCutoffNoLastTag do not preserve the last + // returned value. // // This is needed because parsers for some types of embedded messages // (with field type TYPE_GROUP) don't actually know that they've reached the @@ -612,6 +620,13 @@ class LIBPROTOBUF_EXPORT CodedInputStream { int ReadVarintSizeAsIntSlow(); bool ReadLittleEndian32Fallback(uint32* value); bool ReadLittleEndian64Fallback(uint64* value); + + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE uint32 ReadTagImplementation(); + template + GOOGLE_ATTRIBUTE_ALWAYS_INLINE + std::pair ReadTagWithCutoffImplementation(uint32 cutoff); + // Fallback/slow methods for reading tags. These do not update last_tag_, // but will set legitimate_message_end_ if we are at the end of the input // stream. @@ -622,7 +637,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Return the size of the buffer. int BufferSize() const; - static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + static const int kDefaultTotalBytesLimit = INT_MAX; static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB @@ -842,10 +857,10 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { serialization_deterministic_override_ = value; } // See above. Also, note that users of this CodedOutputStream may need to - // call IsSerializationDeterminstic() to serialize in the intended way. This + // call IsSerializationDeterministic() to serialize in the intended way. This // CodedOutputStream cannot enforce a desire for deterministic serialization // by itself. - bool IsSerializationDeterminstic() const { + bool IsSerializationDeterministic() const { return serialization_deterministic_is_overridden_ ? serialization_deterministic_override_ : default_serialization_deterministic_; @@ -879,16 +894,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // If this write might cross the end of the buffer, we compose the bytes first // then use WriteRaw(). void WriteVarint32SlowPath(uint32 value); - - // Always-inlined versions of WriteVarint* functions so that code can be - // reused, while still controlling size. For instance, WriteVarint32ToArray() - // should not directly call this: since it is inlined itself, doing so - // would greatly increase the size of generated code. Instead, it should call - // WriteVarint32FallbackToArray. Meanwhile, WriteVarint32() is already - // out-of-line, so it should just invoke this directly to avoid any extra - // function call overhead. - GOOGLE_ATTRIBUTE_ALWAYS_INLINE static uint8* WriteVarint64ToArrayInline( - uint64 value, uint8* target); + void WriteVarint64SlowPath(uint64 value); static size_t VarintSize32Fallback(uint32 value); @@ -1007,21 +1013,47 @@ inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { } inline uint32 CodedInputStream::ReadTag() { + return ReadTagImplementation(); +} + +inline uint32 CodedInputStream::ReadTagNoLastTag() { + return ReadTagImplementation(); +} + +template +inline uint32 CodedInputStream::ReadTagImplementation() { uint32 v = 0; if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) { v = *buffer_; if (v < 0x80) { - last_tag_ = v; + if (update_last_tag) { + last_tag_ = v; + } Advance(1); return v; } } - last_tag_ = ReadTagFallback(v); - return last_tag_; + v = ReadTagFallback(v); + if (update_last_tag) { + last_tag_ = v; + } + return v; } inline std::pair CodedInputStream::ReadTagWithCutoff( uint32 cutoff) { + return ReadTagWithCutoffImplementation(cutoff); +} + +inline std::pair CodedInputStream::ReadTagWithCutoffNoLastTag( + uint32 cutoff) { + return ReadTagWithCutoffImplementation(cutoff); +} + +template +inline std::pair +CodedInputStream::ReadTagWithCutoffImplementation( + uint32 cutoff) { // In performance-sensitive code we can expect cutoff to be a compile-time // constant, and things like "cutoff >= kMax1ByteVarint" to be evaluated at // compile time. @@ -1033,7 +1065,10 @@ inline std::pair CodedInputStream::ReadTagWithCutoff( first_byte_or_zero = buffer_[0]; if (static_cast(buffer_[0]) > 0) { const uint32 kMax1ByteVarint = 0x7f; - uint32 tag = last_tag_ = buffer_[0]; + uint32 tag = buffer_[0]; + if (update_last_tag) { + last_tag_ = tag; + } Advance(1); return std::make_pair(tag, cutoff >= kMax1ByteVarint || tag <= cutoff); } @@ -1044,7 +1079,10 @@ inline std::pair CodedInputStream::ReadTagWithCutoff( GOOGLE_PREDICT_TRUE(buffer_ + 1 < buffer_end_) && GOOGLE_PREDICT_TRUE((buffer_[0] & ~buffer_[1]) >= 0x80)) { const uint32 kMax2ByteVarint = (0x7f << 7) + 0x7f; - uint32 tag = last_tag_ = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80); + uint32 tag = (1u << 7) * buffer_[1] + (buffer_[0] - 0x80); + if (update_last_tag) { + last_tag_ = tag; + } Advance(2); // It might make sense to test for tag == 0 now, but it is so rare that // that we don't bother. A varint-encoded 0 should be one byte unless @@ -1057,8 +1095,11 @@ inline std::pair CodedInputStream::ReadTagWithCutoff( } } // Slow path - last_tag_ = ReadTagFallback(first_byte_or_zero); - return std::make_pair(last_tag_, static_cast(last_tag_ - 1) < cutoff); + const uint32 tag = ReadTagFallback(first_byte_or_zero); + if (update_last_tag) { + last_tag_ = tag; + } + return std::make_pair(tag, static_cast(tag - 1) < cutoff); } inline bool CodedInputStream::LastTagWas(uint32 expected) { @@ -1153,21 +1194,24 @@ inline uint8* CodedOutputStream::WriteVarint32ToArray(uint32 value, return target + 1; } -inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { - if (value < 0) { - WriteVarint64(static_cast(value)); - } else { - WriteVarint32(static_cast(value)); +inline uint8* CodedOutputStream::WriteVarint64ToArray(uint64 value, + uint8* target) { + while (value >= 0x80) { + *target = static_cast(value | 0x80); + value >>= 7; + ++target; } + *target = static_cast(value); + return target + 1; +} + +inline void CodedOutputStream::WriteVarint32SignExtended(int32 value) { + WriteVarint64(static_cast(value)); } inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( int32 value, uint8* target) { - if (value < 0) { - return WriteVarint64ToArray(static_cast(value), target); - } else { - return WriteVarint32ToArray(static_cast(value), target); - } + return WriteVarint64ToArray(static_cast(value), target); } inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, @@ -1216,6 +1260,19 @@ inline void CodedOutputStream::WriteVarint32(uint32 value) { } } +inline void CodedOutputStream::WriteVarint64(uint64 value) { + if (buffer_size_ >= 10) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this write won't cross the end, so we can skip the checks. + uint8* target = buffer_; + uint8* end = WriteVarint64ToArray(value, target); + int size = static_cast(end - target); + Advance(size); + } else { + WriteVarint64SlowPath(value); + } +} + inline void CodedOutputStream::WriteTag(uint32 value) { WriteVarint32(value); } -- cgit v1.2.3