diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index a8074dfce7..25bfbbed03 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -621,141 +621,6 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) { } } -static void FormatFieldKind(Formatter& format, - const TailCallTableInfo::FieldEntryInfo& entry) { - // In here we convert the runtime value of entry.type_card back into a - // sequence of literal enum labels. We use the mnenonic labels for nicer - // codegen. - namespace fl = internal::field_layout; - const uint16_t type_card = entry.type_card; - const int rep_index = (type_card & fl::kRepMask) >> fl::kRepShift; - const int tv_index = (type_card & fl::kTvMask) >> fl::kTvShift; - - // Use `0|` prefix to eagerly convert the enums to int to avoid enum-enum - // operations. They are deprecated in C++20. - format("(0 | "); - static constexpr const char* kFieldCardNames[] = {"Singular", "Optional", - "Repeated", "Oneof"}; - static_assert((fl::kFcSingular >> fl::kFcShift) == 0, ""); - static_assert((fl::kFcOptional >> fl::kFcShift) == 1, ""); - static_assert((fl::kFcRepeated >> fl::kFcShift) == 2, ""); - static_assert((fl::kFcOneof >> fl::kFcShift) == 3, ""); - - format("::_fl::kFc$1$", - kFieldCardNames[(type_card & fl::kFcMask) >> fl::kFcShift]); - -#define PROTOBUF_INTERNAL_TYPE_CARD_CASE(x) \ - case fl::k##x: \ - format(" | ::_fl::k" #x); \ - break - - switch (type_card & fl::kFkMask) { - case fl::kFkString: { - switch (type_card & ~fl::kFcMask & ~fl::kRepMask & ~fl::kSplitMask) { - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bytes); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(RawString); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Utf8String); - default: - ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; - } - - static constexpr const char* kRepNames[] = {"AString", "IString", "Cord", - "SPiece", "SString"}; - static_assert((fl::kRepAString >> fl::kRepShift) == 0, ""); - static_assert((fl::kRepIString >> fl::kRepShift) == 1, ""); - static_assert((fl::kRepCord >> fl::kRepShift) == 2, ""); - static_assert((fl::kRepSPiece >> fl::kRepShift) == 3, ""); - static_assert((fl::kRepSString >> fl::kRepShift) == 4, ""); - - format(" | ::_fl::kRep$1$", kRepNames[rep_index]); - break; - } - - case fl::kFkMessage: { - format(" | ::_fl::kMessage"); - - static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy"}; - static_assert((fl::kRepGroup >> fl::kRepShift) == 1, ""); - static_assert((fl::kRepLazy >> fl::kRepShift) == 2, ""); - - if (auto* rep = kRepNames[rep_index]) { - format(" | ::_fl::kRep$1$", rep); - } - - static constexpr const char* kXFormNames[2][4] = { - {nullptr, "Default", "Table", "WeakPtr"}, {nullptr, "Eager", "Lazy"}}; - - static_assert((fl::kTvDefault >> fl::kTvShift) == 1, ""); - static_assert((fl::kTvTable >> fl::kTvShift) == 2, ""); - static_assert((fl::kTvWeakPtr >> fl::kTvShift) == 3, ""); - static_assert((fl::kTvEager >> fl::kTvShift) == 1, ""); - static_assert((fl::kTvLazy >> fl::kTvShift) == 2, ""); - - if (auto* xform = kXFormNames[rep_index == 2][tv_index]) { - format(" | ::_fl::kTv$1$", xform); - } - break; - } - - case fl::kFkMap: - format(" | ::_fl::kMap"); - break; - - case fl::kFkNone: - break; - - case fl::kFkVarint: - case fl::kFkPackedVarint: - case fl::kFkFixed: - case fl::kFkPackedFixed: { - switch (type_card & ~fl::kFcMask & ~fl::kSplitMask) { - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bool); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Float); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Enum); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(EnumRange); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(OpenEnum); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(Double); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedBool); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt32); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFloat); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnum); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnumRange); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedOpenEnum); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt64); - PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedDouble); - default: - ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; - } - } - } - - if (type_card & fl::kSplitMask) { - format(" | ::_fl::kSplitTrue"); - } - -#undef PROTOBUF_INTERNAL_TYPE_CARD_CASE - - format(")"); -} - void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) { for (const auto& entry : tc_table_info_->field_entries) { const FieldDescriptor* field = entry.field; @@ -787,7 +652,9 @@ void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) { format("0, "); } format("$1$,\n ", entry.aux_idx); - FormatFieldKind(format, entry); + // Use `0|` prefix to eagerly convert the enums to int to avoid enum-enum + // operations. They are deprecated in C++20. + format("(0 | $1$)", internal::TypeCardToString(entry.type_card)); } format("},\n"); } diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h index 629cfb7293..22aa54b681 100644 --- a/src/google/protobuf/generated_message_tctable_decl.h +++ b/src/google/protobuf/generated_message_tctable_decl.h @@ -18,6 +18,7 @@ #include #include +#include "absl/types/span.h" #include "google/protobuf/message_lite.h" #include "google/protobuf/parse_context.h" @@ -375,6 +376,9 @@ struct alignas(uint64_t) TcParseTableBase { return reinterpret_cast( reinterpret_cast(this) + field_entries_offset); } + absl::Span field_entries() const { + return {field_entries_begin(), num_field_entries}; + } FieldEntry* field_entries_begin() { return reinterpret_cast(reinterpret_cast(this) + field_entries_offset); diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 42a56084b3..fb111e34fe 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -943,6 +943,10 @@ inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop( return ptr; } +// Prints the type card as or of labels, using known higher level labels. +// Used for code generation, but also useful for debugging. +PROTOBUF_EXPORT std::string TypeCardToString(uint16_t type_card); + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc index 104a22a857..e37a208372 100644 --- a/src/google/protobuf/generated_message_tctable_lite.cc +++ b/src/google/protobuf/generated_message_tctable_lite.cc @@ -18,6 +18,7 @@ #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" #include "absl/numeric/bits.h" +#include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "google/protobuf/generated_message_tctable_decl.h" #include "google/protobuf/generated_message_tctable_impl.h" @@ -2800,6 +2801,138 @@ PROTOBUF_NOINLINE const char* TcParser::MpMap(PROTOBUF_TC_PARAM_DECL) { PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS); } +std::string TypeCardToString(uint16_t type_card) { + // In here we convert the runtime value of entry.type_card back into a + // sequence of literal enum labels. We use the mnenonic labels for nicer + // codegen. + namespace fl = internal::field_layout; + const int rep_index = (type_card & fl::kRepMask) >> fl::kRepShift; + const int tv_index = (type_card & fl::kTvMask) >> fl::kTvShift; + + static constexpr const char* kFieldCardNames[] = {"Singular", "Optional", + "Repeated", "Oneof"}; + static_assert((fl::kFcSingular >> fl::kFcShift) == 0, ""); + static_assert((fl::kFcOptional >> fl::kFcShift) == 1, ""); + static_assert((fl::kFcRepeated >> fl::kFcShift) == 2, ""); + static_assert((fl::kFcOneof >> fl::kFcShift) == 3, ""); + + std::string out; + + absl::StrAppend(&out, "::_fl::kFc", + kFieldCardNames[(type_card & fl::kFcMask) >> fl::kFcShift]); + +#define PROTOBUF_INTERNAL_TYPE_CARD_CASE(x) \ + case fl::k##x: \ + absl::StrAppend(&out, " | ::_fl::k" #x); \ + break + + switch (type_card & fl::kFkMask) { + case fl::kFkString: { + switch (type_card & ~fl::kFcMask & ~fl::kRepMask & ~fl::kSplitMask) { + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bytes); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(RawString); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Utf8String); + default: + ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; + } + + static constexpr const char* kRepNames[] = {"AString", "IString", "Cord", + "SPiece", "SString"}; + static_assert((fl::kRepAString >> fl::kRepShift) == 0, ""); + static_assert((fl::kRepIString >> fl::kRepShift) == 1, ""); + static_assert((fl::kRepCord >> fl::kRepShift) == 2, ""); + static_assert((fl::kRepSPiece >> fl::kRepShift) == 3, ""); + static_assert((fl::kRepSString >> fl::kRepShift) == 4, ""); + + absl::StrAppend(&out, " | ::_fl::kRep", kRepNames[rep_index]); + break; + } + + case fl::kFkMessage: { + absl::StrAppend(&out, " | ::_fl::kMessage"); + + static constexpr const char* kRepNames[] = {nullptr, "Group", "Lazy"}; + static_assert((fl::kRepGroup >> fl::kRepShift) == 1, ""); + static_assert((fl::kRepLazy >> fl::kRepShift) == 2, ""); + + if (auto* rep = kRepNames[rep_index]) { + absl::StrAppend(&out, " | ::_fl::kRep", rep); + } + + static constexpr const char* kXFormNames[2][4] = { + {nullptr, "Default", "Table", "WeakPtr"}, {nullptr, "Eager", "Lazy"}}; + + static_assert((fl::kTvDefault >> fl::kTvShift) == 1, ""); + static_assert((fl::kTvTable >> fl::kTvShift) == 2, ""); + static_assert((fl::kTvWeakPtr >> fl::kTvShift) == 3, ""); + static_assert((fl::kTvEager >> fl::kTvShift) == 1, ""); + static_assert((fl::kTvLazy >> fl::kTvShift) == 2, ""); + + if (auto* xform = kXFormNames[rep_index == 2][tv_index]) { + absl::StrAppend(&out, " | ::_fl::kTv", xform); + } + break; + } + + case fl::kFkMap: + absl::StrAppend(&out, " | ::_fl::kMap"); + break; + + case fl::kFkNone: + break; + + case fl::kFkVarint: + case fl::kFkPackedVarint: + case fl::kFkFixed: + case fl::kFkPackedFixed: { + switch (type_card & ~fl::kFcMask & ~fl::kSplitMask) { + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Bool); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Float); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Enum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(EnumRange); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(OpenEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Fixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(UInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Int64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(SInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(Double); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedBool); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt32); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFloat); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedEnumRange); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedOpenEnum); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedUInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSFixed64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedSInt64); + PROTOBUF_INTERNAL_TYPE_CARD_CASE(PackedDouble); + default: + ABSL_LOG(FATAL) << "Unknown type_card: 0x" << type_card; + } + } + } + + if (type_card & fl::kSplitMask) { + absl::StrAppend(&out, " | ::_fl::kSplitTrue"); + } + +#undef PROTOBUF_INTERNAL_TYPE_CARD_CASE + + return out; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc index d037852b3d..8648712446 100644 --- a/src/google/protobuf/generated_message_tctable_lite_test.cc +++ b/src/google/protobuf/generated_message_tctable_lite_test.cc @@ -20,6 +20,7 @@ namespace internal { namespace { +using ::testing::ElementsAreArray; using ::testing::Eq; using ::testing::Not; using ::testing::Optional; @@ -899,6 +900,7 @@ TEST(GeneratedMessageTctableLiteTest, EXPECT_LE(proto.vals().Capacity(), 2048); } + } // namespace internal } // namespace protobuf } // namespace google