|
|
|
@ -360,35 +360,21 @@ class PROTOBUF_EXPORT TcParser final { |
|
|
|
|
static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL); |
|
|
|
|
|
|
|
|
|
// Manually unrolled and specialized Varint parsing.
|
|
|
|
|
template <typename FieldType, int data_offset, int hasbit_idx> |
|
|
|
|
template <typename FieldType> |
|
|
|
|
static const char* FastTV32S1(PROTOBUF_TC_PARAM_DECL); |
|
|
|
|
template <typename FieldType, int data_offset, int hasbit_idx> |
|
|
|
|
template <typename FieldType> |
|
|
|
|
static const char* FastTV64S1(PROTOBUF_TC_PARAM_DECL); |
|
|
|
|
template <int data_offset, int hasbit_idx> |
|
|
|
|
static const char* FastTV8S1(PROTOBUF_TC_PARAM_DECL); |
|
|
|
|
|
|
|
|
|
template <typename FieldType, int data_offset, int hasbit_idx> |
|
|
|
|
template <typename FieldType, int unused_data_offset, int unused_hasbit_idx> |
|
|
|
|
static constexpr TailCallParseFunc SingularVarintNoZag1() { |
|
|
|
|
if (sizeof(FieldType) == 1) { |
|
|
|
|
if (data_offset < 100) { |
|
|
|
|
return &FastTV8S1<data_offset, hasbit_idx>; |
|
|
|
|
} else { |
|
|
|
|
return &FastV8S1; |
|
|
|
|
} |
|
|
|
|
return &FastV8S1; |
|
|
|
|
} |
|
|
|
|
if (sizeof(FieldType) == 4) { |
|
|
|
|
if (data_offset < 100) { |
|
|
|
|
return &FastTV32S1<FieldType, data_offset, hasbit_idx>; |
|
|
|
|
} else { //
|
|
|
|
|
return &FastV32S1; |
|
|
|
|
} |
|
|
|
|
return &FastTV32S1<FieldType>; |
|
|
|
|
} |
|
|
|
|
if (sizeof(FieldType) == 8) { |
|
|
|
|
if (data_offset < 128) { |
|
|
|
|
return &FastTV64S1<FieldType, data_offset, hasbit_idx>; |
|
|
|
|
} else { |
|
|
|
|
return &FastV64S1; |
|
|
|
|
} |
|
|
|
|
return &FastTV64S1<FieldType>; |
|
|
|
|
} |
|
|
|
|
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 || |
|
|
|
|
sizeof(FieldType) == 8, |
|
|
|
@ -856,67 +842,15 @@ done10: |
|
|
|
|
return {p + 10, res1 & res2 & res3}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Notes:
|
|
|
|
|
// 1) if data_offset is negative, it's read from data.offset()
|
|
|
|
|
// 2) if hasbit_idx is negative, it's read from data.hasbit_idx()
|
|
|
|
|
template <int data_offset, int hasbit_idx> |
|
|
|
|
PROTOBUF_NOINLINE const char* TcParser::FastTV8S1(PROTOBUF_TC_PARAM_DECL) { |
|
|
|
|
using TagType = uint8_t; |
|
|
|
|
|
|
|
|
|
// Special case for a varint bool field with a tag of 1 byte:
|
|
|
|
|
// The coded_tag() field will actually contain the value too and we can check
|
|
|
|
|
// both at the same time.
|
|
|
|
|
auto coded_tag = data.coded_tag<uint16_t>(); |
|
|
|
|
if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) { |
|
|
|
|
auto& field = |
|
|
|
|
RefAt<bool>(msg, data_offset >= 0 ? data_offset : data.offset()); |
|
|
|
|
// Note: we use `data.data` because Clang generates suboptimal code when
|
|
|
|
|
// using coded_tag.
|
|
|
|
|
// In x86_64 this uses the CH register to read the second byte out of
|
|
|
|
|
// `data`.
|
|
|
|
|
uint8_t value = data.data >> 8; |
|
|
|
|
// The assume allows using a mov instead of test+setne.
|
|
|
|
|
PROTOBUF_ASSUME(value <= 1); |
|
|
|
|
field = static_cast<bool>(value); |
|
|
|
|
|
|
|
|
|
ptr += sizeof(TagType) + 1; // Consume the tag and the value.
|
|
|
|
|
if (hasbit_idx < 0) { |
|
|
|
|
hasbits |= (uint64_t{1} << data.hasbit_idx()); |
|
|
|
|
} else { |
|
|
|
|
if (hasbit_idx < 32) { |
|
|
|
|
// `& 31` avoids a compiler warning when hasbit_idx is negative.
|
|
|
|
|
hasbits |= (uint64_t{1} << (hasbit_idx & 31)); |
|
|
|
|
} else { |
|
|
|
|
static_assert(hasbit_idx == 63 || (hasbit_idx < 32), |
|
|
|
|
"hard-coded hasbit_idx should be 0-31, or the special" |
|
|
|
|
"value 63, which indicates the field has no has-bit."); |
|
|
|
|
// TODO(jorg): investigate whether higher hasbit indices are worth
|
|
|
|
|
// supporting. Something like:
|
|
|
|
|
// auto& hasblock = TcParser::RefAt<uint32_t>(msg, hasbit_idx / 32 * 4);
|
|
|
|
|
// hasblock |= uint32_t{1} << (hasbit_idx % 32);
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If it didn't match above either the tag is wrong, or the value is encoded
|
|
|
|
|
// non-canonically.
|
|
|
|
|
// Jump to MiniParse as wrong tag is the most probable reason.
|
|
|
|
|
PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename FieldType, int data_offset, int hasbit_idx> |
|
|
|
|
template <typename FieldType> |
|
|
|
|
PROTOBUF_NOINLINE const char* TcParser::FastTV64S1(PROTOBUF_TC_PARAM_DECL) { |
|
|
|
|
using TagType = uint8_t; |
|
|
|
|
// super-early success test...
|
|
|
|
|
if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) { |
|
|
|
|
ptr += sizeof(TagType); // Consume tag
|
|
|
|
|
if (hasbit_idx < 32) { |
|
|
|
|
hasbits |= (uint64_t{1} << hasbit_idx); |
|
|
|
|
} |
|
|
|
|
hasbits |= (uint64_t{1} << data.hasbit_idx()); |
|
|
|
|
uint8_t value = data.data >> 8; |
|
|
|
|
RefAt<FieldType>(msg, data_offset) = value; |
|
|
|
|
RefAt<FieldType>(msg, data.offset()) = value; |
|
|
|
|
ptr += 1; |
|
|
|
|
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
@ -924,33 +858,30 @@ PROTOBUF_NOINLINE const char* TcParser::FastTV64S1(PROTOBUF_TC_PARAM_DECL) { |
|
|
|
|
PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
ptr += sizeof(TagType); // Consume tag
|
|
|
|
|
if (hasbit_idx < 32) { |
|
|
|
|
hasbits |= (uint64_t{1} << hasbit_idx); |
|
|
|
|
} |
|
|
|
|
hasbits |= (uint64_t{1} << data.hasbit_idx()); |
|
|
|
|
|
|
|
|
|
auto tmp = |
|
|
|
|
ParseFallbackPair<uint64_t>(ptr, static_cast<int8_t>(data.data >> 8)); |
|
|
|
|
data.data = 0; // Indicate to the compiler that we don't need this anymore.
|
|
|
|
|
ptr = tmp.first; |
|
|
|
|
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) { |
|
|
|
|
data.data = 0; // Indicate to the compiler that we don't need this anymore.
|
|
|
|
|
return Error(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second); |
|
|
|
|
RefAt<FieldType>(msg, data.offset()) = static_cast<FieldType>(tmp.second); |
|
|
|
|
data.data = 0; // Indicate to the compiler that we don't need this anymore.
|
|
|
|
|
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename FieldType, int data_offset, int hasbit_idx> |
|
|
|
|
template <typename FieldType> |
|
|
|
|
PROTOBUF_NOINLINE const char* TcParser::FastTV32S1(PROTOBUF_TC_PARAM_DECL) { |
|
|
|
|
using TagType = uint8_t; |
|
|
|
|
// super-early success test...
|
|
|
|
|
if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) { |
|
|
|
|
ptr += sizeof(TagType); // Consume tag
|
|
|
|
|
if (hasbit_idx < 32) { |
|
|
|
|
hasbits |= (uint64_t{1} << hasbit_idx); |
|
|
|
|
} |
|
|
|
|
hasbits |= (uint64_t{1} << data.hasbit_idx()); |
|
|
|
|
uint8_t value = data.data >> 8; |
|
|
|
|
RefAt<FieldType>(msg, data_offset) = value; |
|
|
|
|
RefAt<FieldType>(msg, data.offset()) = value; |
|
|
|
|
ptr += 1; |
|
|
|
|
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
@ -958,19 +889,17 @@ PROTOBUF_NOINLINE const char* TcParser::FastTV32S1(PROTOBUF_TC_PARAM_DECL) { |
|
|
|
|
PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
ptr += sizeof(TagType); // Consume tag
|
|
|
|
|
if (hasbit_idx < 32) { |
|
|
|
|
hasbits |= (uint64_t{1} << hasbit_idx); |
|
|
|
|
} |
|
|
|
|
hasbits |= (uint64_t{1} << data.hasbit_idx()); |
|
|
|
|
|
|
|
|
|
auto tmp = |
|
|
|
|
ParseFallbackPair<uint32_t>(ptr, static_cast<int8_t>(data.data >> 8)); |
|
|
|
|
data.data = 0; // Indicate to the compiler that we don't need this anymore.
|
|
|
|
|
ptr = tmp.first; |
|
|
|
|
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) { |
|
|
|
|
return Error(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second); |
|
|
|
|
RefAt<FieldType>(msg, data.offset()) = static_cast<FieldType>(tmp.second); |
|
|
|
|
data.data = 0; // Indicate to the compiler that we don't need this anymore.
|
|
|
|
|
PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|