@@ -393,45 +393,6 @@ inline PROTOBUF_ALWAYS_INLINE void InvertPacked(TcFieldData& data) {
393393 data.data ^= Wt ^ WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
394394}
395395
396- constexpr uint32_t kAccumulatorBytesOnStack = 256 ;
397-
398- // Accumulates fields to buffer repeated fields on parsing path to avoid growing
399- // repeated field container type too frequently. It flushes to the backing
400- // repeated fields if it's full or out of the scope. A larger buffer (e.g. 2KiB)
401- // is actually harmful due to:
402- // - increased stack overflow risk
403- // - extra cache misses on accessing local variables
404- // - less competitive to the cost of growing large buffer
405- template <typename ElementType, typename ContainerType>
406- class ScopedFieldAccumulator {
407- public:
408- constexpr explicit ScopedFieldAccumulator (ContainerType& field)
409- : field_(field) {}
410-
411- ~ScopedFieldAccumulator () {
412- if (ABSL_PREDICT_TRUE (current_size_ > 0 )) {
413- field_.MergeFromArray (buffer_, current_size_);
414- }
415- }
416-
417- PROTOBUF_NODISCARD ElementType& Next () {
418- if (ABSL_PREDICT_FALSE (current_size_ == kSize )) {
419- field_.MergeFromArray (buffer_, kSize );
420- current_size_ = 0 ;
421- }
422- return buffer_[current_size_++];
423- }
424-
425- private:
426- static constexpr uint32_t kSize =
427- kAccumulatorBytesOnStack / sizeof (ElementType);
428- static_assert (kSize > 0 , " Size cannot be zero" );
429-
430- uint32_t current_size_ = 0 ;
431- ElementType buffer_[kSize ];
432- ContainerType& field_;
433- };
434-
435396} // namespace
436397
437398// ////////////////////////////////////////////////////////////////////////////
@@ -659,17 +620,14 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedFixed(
659620 }
660621 auto & field = RefAt<RepeatedField<LayoutType>>(msg, data.offset ());
661622 const auto tag = UnalignedLoad<TagType>(ptr);
662- {
663- ScopedFieldAccumulator<LayoutType, decltype (field)> accumulator (field);
664- do {
665- accumulator.Next () = UnalignedLoad<LayoutType>(ptr + sizeof (TagType));
666- ptr += sizeof (TagType) + sizeof (LayoutType);
667- if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
668- } while (UnalignedLoad<TagType>(ptr) == tag);
669- }
623+ do {
624+ field.Add (UnalignedLoad<LayoutType>(ptr + sizeof (TagType)));
625+ ptr += sizeof (TagType) + sizeof (LayoutType);
626+ if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) {
627+ PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
628+ }
629+ } while (UnalignedLoad<TagType>(ptr) == tag);
670630 PROTOBUF_MUSTTAIL return ToTagDispatch (PROTOBUF_TC_PARAM_NO_DATA_PASS);
671- parse_loop:
672- PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
673631}
674632
675633PROTOBUF_NOINLINE const char * TcParser::FastF32R1 (PROTOBUF_TC_PARAM_DECL) {
@@ -1003,22 +961,19 @@ PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedVarint(
1003961 }
1004962 auto & field = RefAt<RepeatedField<FieldType>>(msg, data.offset ());
1005963 const auto expected_tag = UnalignedLoad<TagType>(ptr);
1006- {
1007- ScopedFieldAccumulator<FieldType, decltype (field)> accumulator (field);
1008- do {
1009- ptr += sizeof (TagType);
1010- FieldType tmp;
1011- ptr = ParseVarint (ptr, &tmp);
1012- if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) goto error;
1013- accumulator.Next () = ZigZagDecodeHelper<FieldType, zigzag>(tmp);
1014- if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
1015- } while (UnalignedLoad<TagType>(ptr) == expected_tag);
1016- }
964+ do {
965+ ptr += sizeof (TagType);
966+ FieldType tmp;
967+ ptr = ParseVarint (ptr, &tmp);
968+ if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) {
969+ PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
970+ }
971+ field.Add (ZigZagDecodeHelper<FieldType, zigzag>(tmp));
972+ if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) {
973+ PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
974+ }
975+ } while (UnalignedLoad<TagType>(ptr) == expected_tag);
1017976 PROTOBUF_MUSTTAIL return ToTagDispatch (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1018- parse_loop:
1019- PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1020- error:
1021- PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1022977}
1023978
1024979PROTOBUF_NOINLINE const char * TcParser::FastV8R1 (PROTOBUF_TC_PARAM_DECL) {
@@ -1080,8 +1035,7 @@ const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
10801035 // pending hasbits now:
10811036 SyncHasbits (msg, hasbits, table);
10821037 auto * field = &RefAt<RepeatedField<FieldType>>(msg, data.offset ());
1083- ScopedFieldAccumulator<FieldType, decltype (*field)> accumulator (*field);
1084- return ctx->ReadPackedVarint (ptr, [&](uint64_t varint) {
1038+ return ctx->ReadPackedVarint (ptr, [field](uint64_t varint) {
10851039 FieldType val;
10861040 if (zigzag) {
10871041 if (sizeof (FieldType) == 8 ) {
@@ -1092,7 +1046,7 @@ const char* TcParser::PackedVarint(PROTOBUF_TC_PARAM_DECL) {
10921046 } else {
10931047 val = varint;
10941048 }
1095- accumulator. Next () = val;
1049+ field-> Add ( val) ;
10961050 });
10971051}
10981052
@@ -1227,33 +1181,28 @@ const char* TcParser::RepeatedEnum(PROTOBUF_TC_PARAM_DECL) {
12271181 auto & field = RefAt<RepeatedField<int32_t >>(msg, data.offset ());
12281182 const auto expected_tag = UnalignedLoad<TagType>(ptr);
12291183 const TcParseTableBase::FieldAux aux = *table->field_aux (data.aux_idx ());
1230- {
1231- ScopedFieldAccumulator<int32_t , decltype (field)> accumulator (field);
1232- do {
1233- const char * ptr2 = ptr; // save for unknown enum case
1234- ptr += sizeof (TagType);
1235- uint64_t tmp;
1236- ptr = ParseVarint (ptr, &tmp);
1237- if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) goto error;
1238- if (PROTOBUF_PREDICT_FALSE (
1239- !EnumIsValidAux (static_cast <int32_t >(tmp), xform_val, aux))) {
1240- // We can avoid duplicate work in MiniParse by directly calling
1241- // table->fallback.
1242- ptr = ptr2;
1243- goto unknown_enum_fallback;
1244- }
1245- accumulator.Next () = static_cast <int32_t >(tmp);
1246- if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
1247- } while (UnalignedLoad<TagType>(ptr) == expected_tag);
1248- }
1184+ do {
1185+ const char * ptr2 = ptr; // save for unknown enum case
1186+ ptr += sizeof (TagType);
1187+ uint64_t tmp;
1188+ ptr = ParseVarint (ptr, &tmp);
1189+ if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) {
1190+ PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1191+ }
1192+ if (PROTOBUF_PREDICT_FALSE (
1193+ !EnumIsValidAux (static_cast <int32_t >(tmp), xform_val, aux))) {
1194+ // We can avoid duplicate work in MiniParse by directly calling
1195+ // table->fallback.
1196+ ptr = ptr2;
1197+ PROTOBUF_MUSTTAIL return FastUnknownEnumFallback (PROTOBUF_TC_PARAM_PASS);
1198+ }
1199+ field.Add (static_cast <int32_t >(tmp));
1200+ if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) {
1201+ PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1202+ }
1203+ } while (UnalignedLoad<TagType>(ptr) == expected_tag);
12491204
12501205 PROTOBUF_MUSTTAIL return ToTagDispatch (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1251- parse_loop:
1252- PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1253- error:
1254- PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1255- unknown_enum_fallback:
1256- PROTOBUF_MUSTTAIL return FastUnknownEnumFallback (PROTOBUF_TC_PARAM_PASS);
12571206}
12581207
12591208const TcParser::UnknownFieldOps& TcParser::GetUnknownFieldOps (
@@ -1387,22 +1336,19 @@ const char* TcParser::RepeatedEnumSmallRange(PROTOBUF_TC_PARAM_DECL) {
13871336 auto & field = RefAt<RepeatedField<int32_t >>(msg, data.offset ());
13881337 auto expected_tag = UnalignedLoad<TagType>(ptr);
13891338 const uint8_t max = data.aux_idx ();
1390- {
1391- ScopedFieldAccumulator<int32_t , decltype (field)> accumulator (field);
1392- do {
1393- uint8_t v = ptr[sizeof (TagType)];
1394- if (PROTOBUF_PREDICT_FALSE (min > v || v > max)) goto mini_parse;
1395- accumulator.Next () = static_cast <int32_t >(v);
1396- ptr += sizeof (TagType) + 1 ;
1397- if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
1398- } while (UnalignedLoad<TagType>(ptr) == expected_tag);
1399- }
1339+ do {
1340+ uint8_t v = ptr[sizeof (TagType)];
1341+ if (PROTOBUF_PREDICT_FALSE (min > v || v > max)) {
1342+ PROTOBUF_MUSTTAIL return MiniParse (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1343+ }
1344+ field.Add (static_cast <int32_t >(v));
1345+ ptr += sizeof (TagType) + 1 ;
1346+ if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) {
1347+ PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1348+ }
1349+ } while (UnalignedLoad<TagType>(ptr) == expected_tag);
14001350
14011351 PROTOBUF_MUSTTAIL return ToTagDispatch (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1402- parse_loop:
1403- PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
1404- mini_parse:
1405- PROTOBUF_MUSTTAIL return MiniParse (PROTOBUF_TC_PARAM_NO_DATA_PASS);
14061352}
14071353
14081354PROTOBUF_NOINLINE const char * TcParser::FastEr0R1 (PROTOBUF_TC_PARAM_DECL) {
@@ -1904,10 +1850,9 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedFixed(
19041850 constexpr auto size = sizeof (uint64_t );
19051851 const char * ptr2 = ptr;
19061852 uint32_t next_tag;
1907- ScopedFieldAccumulator<uint64_t , decltype (field)> accumulator (field);
19081853 do {
19091854 ptr = ptr2;
1910- accumulator. Next () = UnalignedLoad<uint64_t >(ptr);
1855+ *field. Add () = UnalignedLoad<uint64_t >(ptr);
19111856 ptr += size;
19121857 if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
19131858 ptr2 = ReadTag (ptr, &next_tag);
@@ -1922,10 +1867,9 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedFixed(
19221867 constexpr auto size = sizeof (uint32_t );
19231868 const char * ptr2 = ptr;
19241869 uint32_t next_tag;
1925- ScopedFieldAccumulator<uint32_t , decltype (field)> accumulator (field);
19261870 do {
19271871 ptr = ptr2;
1928- accumulator. Next () = UnalignedLoad<uint32_t >(ptr);
1872+ *field. Add () = UnalignedLoad<uint32_t >(ptr);
19291873 ptr += size;
19301874 if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
19311875 ptr2 = ReadTag (ptr, &next_tag);
@@ -2055,13 +1999,11 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
20551999 auto & field = RefAt<RepeatedField<uint64_t >>(msg, entry.offset );
20562000 const char * ptr2 = ptr;
20572001 uint32_t next_tag;
2058- ScopedFieldAccumulator<uint64_t , decltype (field)> accumulator (field);
20592002 do {
20602003 uint64_t tmp;
20612004 ptr = ParseVarint (ptr2, &tmp);
20622005 if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) goto error;
2063- accumulator.Next () =
2064- is_zigzag ? WireFormatLite::ZigZagDecode64 (tmp) : tmp;
2006+ field.Add (is_zigzag ? WireFormatLite::ZigZagDecode64 (tmp) : tmp);
20652007 if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
20662008 ptr2 = ReadTag (ptr, &next_tag);
20672009 if (PROTOBUF_PREDICT_FALSE (ptr2 == nullptr )) goto error;
@@ -2070,20 +2012,20 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
20702012 auto & field = RefAt<RepeatedField<uint32_t >>(msg, entry.offset );
20712013 const char * ptr2 = ptr;
20722014 uint32_t next_tag;
2073- ScopedFieldAccumulator<uint32_t , decltype (field)> accumulator (field);
20742015 do {
20752016 uint64_t tmp;
20762017 ptr = ParseVarint (ptr2, &tmp);
20772018 if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) goto error;
20782019 if (is_validated_enum) {
20792020 if (!EnumIsValidAux (tmp, xform_val, *table->field_aux (&entry))) {
20802021 ptr = ptr2;
2081- goto unknown_enum_fallback;
2022+ PROTOBUF_MUSTTAIL return MpUnknownEnumFallback (
2023+ PROTOBUF_TC_PARAM_PASS);
20822024 }
20832025 } else if (is_zigzag) {
20842026 tmp = WireFormatLite::ZigZagDecode32 (tmp);
20852027 }
2086- accumulator. Next () = tmp;
2028+ field. Add ( tmp) ;
20872029 if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
20882030 ptr2 = ReadTag (ptr, &next_tag);
20892031 if (PROTOBUF_PREDICT_FALSE (ptr2 == nullptr )) goto error;
@@ -2093,12 +2035,11 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
20932035 auto & field = RefAt<RepeatedField<bool >>(msg, entry.offset );
20942036 const char * ptr2 = ptr;
20952037 uint32_t next_tag;
2096- ScopedFieldAccumulator<bool , decltype (field)> accumulator (field);
20972038 do {
20982039 uint64_t tmp;
20992040 ptr = ParseVarint (ptr2, &tmp);
21002041 if (PROTOBUF_PREDICT_FALSE (ptr == nullptr )) goto error;
2101- accumulator. Next () = static_cast <bool >(tmp);
2042+ field. Add ( static_cast <bool >(tmp) );
21022043 if (PROTOBUF_PREDICT_FALSE (!ctx->DataAvailable (ptr))) goto parse_loop;
21032044 ptr2 = ReadTag (ptr, &next_tag);
21042045 if (PROTOBUF_PREDICT_FALSE (ptr2 == nullptr )) goto error;
@@ -2110,8 +2051,6 @@ PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
21102051 PROTOBUF_MUSTTAIL return ToParseLoop (PROTOBUF_TC_PARAM_NO_DATA_PASS);
21112052error:
21122053 PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
2113- unknown_enum_fallback:
2114- PROTOBUF_MUSTTAIL return MpUnknownEnumFallback (PROTOBUF_TC_PARAM_PASS);
21152054}
21162055
21172056PROTOBUF_NOINLINE const char * TcParser::MpPackedVarint (PROTOBUF_TC_PARAM_DECL) {
@@ -2133,41 +2072,33 @@ PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
21332072
21342073 uint16_t rep = type_card & field_layout::kRepMask ;
21352074 if (rep == field_layout::kRep64Bits ) {
2136- auto & field = RefAt<RepeatedField<uint64_t >>(msg, entry.offset );
2137- ScopedFieldAccumulator<uint64_t , decltype (field)> accumulator (field);
2138- return ctx->ReadPackedVarint (
2139- ptr, [&accumulator, is_zigzag](uint64_t value) {
2140- accumulator.Next () =
2141- is_zigzag ? WireFormatLite::ZigZagDecode64 (value) : value;
2142- });
2075+ auto * field = &RefAt<RepeatedField<uint64_t >>(msg, entry.offset );
2076+ return ctx->ReadPackedVarint (ptr, [field, is_zigzag](uint64_t value) {
2077+ field->Add (is_zigzag ? WireFormatLite::ZigZagDecode64 (value) : value);
2078+ });
21432079 } else if (rep == field_layout::kRep32Bits ) {
2144- auto & field = RefAt<RepeatedField<uint32_t >>(msg, entry.offset );
2080+ auto * field = & RefAt<RepeatedField<uint32_t >>(msg, entry.offset );
21452081 if (is_validated_enum) {
21462082 const TcParseTableBase::FieldAux aux = *table->field_aux (entry.aux_idx );
2147- ScopedFieldAccumulator<uint32_t , decltype (field)> accumulator (field);
2148- return ctx->ReadPackedVarint (ptr, [=, &accumulator](int32_t value) {
2083+ return ctx->ReadPackedVarint (ptr, [=](int32_t value) {
21492084 if (!EnumIsValidAux (value, xform_val, aux)) {
21502085 AddUnknownEnum (msg, table, data.tag (), value);
21512086 } else {
2152- accumulator. Next () = value;
2087+ field-> Add ( value) ;
21532088 }
21542089 });
21552090 } else {
2156- ScopedFieldAccumulator<uint32_t , decltype (field)> accumulator (field);
2157- return ctx->ReadPackedVarint (
2158- ptr, [&accumulator, is_zigzag](uint64_t value) {
2159- accumulator.Next () = is_zigzag ? WireFormatLite::ZigZagDecode32 (
2160- static_cast <uint32_t >(value))
2161- : value;
2162- });
2091+ return ctx->ReadPackedVarint (ptr, [field, is_zigzag](uint64_t value) {
2092+ field->Add (is_zigzag ? WireFormatLite::ZigZagDecode32 (
2093+ static_cast <uint32_t >(value))
2094+ : value);
2095+ });
21632096 }
21642097 } else {
21652098 ABSL_DCHECK_EQ (rep, static_cast <uint16_t >(field_layout::kRep8Bits ));
2166- auto & field = RefAt<RepeatedField<bool >>(msg, entry.offset );
2167- ScopedFieldAccumulator<bool , decltype (field)> accumulator (field);
2168- return ctx->ReadPackedVarint (ptr, [&](uint64_t value) {
2169- accumulator.Next () = static_cast <bool >(value);
2170- });
2099+ auto * field = &RefAt<RepeatedField<bool >>(msg, entry.offset );
2100+ return ctx->ReadPackedVarint (
2101+ ptr, [field](uint64_t value) { field->Add (static_cast <bool >(value)); });
21712102 }
21722103
21732104 PROTOBUF_MUSTTAIL return Error (PROTOBUF_TC_PARAM_NO_DATA_PASS);
0 commit comments