From 5e9a9a87bcb4466ed7034cccb33cf41ea750e1e9 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Wed, 6 Sep 2023 08:10:32 -0700 Subject: [PATCH] Use the TcParseFunction enum instead of strings when generating the table instructions. This avoids the string creation in the reflection case altogether, as well as the map lookups. PiperOrigin-RevId: 563108247 --- .../compiler/cpp/parse_function_generator.cc | 18 +++++++++++--- .../protobuf/generated_message_reflection.cc | 24 +++++++++---------- .../protobuf/generated_message_tctable_gen.cc | 15 +++--------- .../protobuf/generated_message_tctable_gen.h | 5 ++-- .../protobuf/generated_message_tctable_impl.h | 3 ++- 5 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index edabb7dc8e..bb4e9de934 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -585,17 +585,29 @@ void ParseFunctionGenerator::GenerateTailCallTable(io::Printer* printer) { format("};\n\n"); // _table_ } +static std::string TcParseFunctionName(internal::TcParseFunction func) { +#define PROTOBUF_TC_PARSE_FUNCTION_X(value) #value, + static constexpr absl::string_view kNames[] = { + {}, PROTOBUF_TC_PARSE_FUNCTION_LIST}; +#undef PROTOBUF_TC_PARSE_FUNCTION_X + const int func_index = static_cast(func); + ABSL_CHECK_GE(func_index, 0); + ABSL_CHECK_LT(func_index, std::end(kNames) - std::begin(kNames)); + static constexpr absl::string_view ns = "::_pbi::TcParser::"; + return absl::StrCat(ns, kNames[func_index]); +} + void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) { for (const auto& info : tc_table_info_->fast_path_fields) { if (auto* nonfield = info.AsNonField()) { // Fast slot that is not associated with a field. Eg end group tags. - format("{$1$, {$2$, $3$}},\n", nonfield->func_name, nonfield->coded_tag, - nonfield->nonfield_info); + format("{$1$, {$2$, $3$}},\n", TcParseFunctionName(nonfield->func), + nonfield->coded_tag, nonfield->nonfield_info); } else if (auto* as_field = info.AsField()) { PrintFieldComment(format, as_field->field, options_); ABSL_CHECK(!ShouldSplit(as_field->field, options_)); - std::string func_name = as_field->func_name; + std::string func_name = TcParseFunctionName(as_field->func); if (GetOptimizeFor(as_field->field->file(), options_) == FileOptions::SPEED) { // For 1-byte tags we have a more optimized version of the varint parser diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 5cd3830fd9..2f04be4d6c 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -54,6 +54,7 @@ #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor_legacy.h" #include "google/protobuf/extension_set.h" +#include "google/protobuf/generated_message_tctable_decl.h" #include "google/protobuf/generated_message_tctable_gen.h" #include "google/protobuf/generated_message_tctable_impl.h" #include "google/protobuf/generated_message_util.h" @@ -3218,21 +3219,20 @@ static uint32_t AlignTo(uint32_t v) { } static internal::TailCallParseFunc GetFastParseFunction( - absl::string_view func_name) { -#define PROTOBUF_TC_PARSE_FUNCTION_X(value) \ - {"::_pbi::TcParser::" #value, internal::TcParser::value}, - static const auto* const map = - new absl::flat_hash_map{ - PROTOBUF_TC_PARSE_FUNCTION_LIST}; + internal::TcParseFunction func) { +#define PROTOBUF_TC_PARSE_FUNCTION_X(value) internal::TcParser::value, + static constexpr internal::TailCallParseFunc kFuncs[] = { + {}, PROTOBUF_TC_PARSE_FUNCTION_LIST}; #undef PROTOBUF_TC_PARSE_FUNCTION_X - auto it = map->find(func_name); - if (it == map->end()) { - ABSL_DLOG(FATAL) << "Failed to find function: " << func_name; + const int index = static_cast(func); + if (index < 0 || index >= std::end(kFuncs) - std::begin(kFuncs) || + kFuncs[index] == nullptr) { + ABSL_DLOG(FATAL) << "Failed to find function: " << static_cast(func); // Let's not crash in opt, just in case. // MiniParse is always a valid parser. return &internal::TcParser::MiniParse; } - return it->second; + return kFuncs[index]; } const internal::TcParseTableBase* Reflection::CreateTcParseTableReflectionOnly() @@ -3259,11 +3259,11 @@ void Reflection::PopulateTcParseFastEntries( for (const auto& fast_field : table_info.fast_path_fields) { if (auto* nonfield = fast_field.AsNonField()) { // No field, but still a special entry. - *fast_entries++ = {GetFastParseFunction(nonfield->func_name), + *fast_entries++ = {GetFastParseFunction(nonfield->func), {nonfield->coded_tag, nonfield->nonfield_info}}; } else if (auto* as_field = fast_field.AsField()) { *fast_entries++ = { - GetFastParseFunction(as_field->func_name), + GetFastParseFunction(as_field->func), {as_field->coded_tag, as_field->hasbit_idx, as_field->aux_idx, static_cast(schema_.GetFieldOffset(as_field->field))}}; } else { diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc index 80e0fbc592..1a86ff2922 100644 --- a/src/google/protobuf/generated_message_tctable_gen.cc +++ b/src/google/protobuf/generated_message_tctable_gen.cc @@ -80,14 +80,6 @@ bool GetEnumValidationRange(const EnumDescriptor* enum_type, int16_t& start, } } -absl::string_view ParseFunctionValue(TcParseFunction function) { -#define PROTOBUF_TC_PARSE_FUNCTION_X(value) #value, - static constexpr absl::string_view functions[] = { - {}, PROTOBUF_TC_PARSE_FUNCTION_LIST}; -#undef PROTOBUF_TC_PARSE_FUNCTION_X - return functions[static_cast(function)]; -}; - enum class EnumRangeInfo { kNone, // No contiguous range kContiguous, // Has a contiguous range @@ -238,8 +230,7 @@ TailCallTableInfo::FastFieldInfo::Field MakeFastFieldEntry( } ABSL_CHECK(picked != TcParseFunction::kNone); - static constexpr absl::string_view ns = "::_pbi::TcParser::"; - info.func_name = absl::StrCat(ns, ParseFunctionValue(picked)); + info.func = picked; return info; #undef PROTOBUF_PICK_FUNCTION @@ -393,8 +384,8 @@ std::vector SplitFastFieldsForSize( TailCallTableInfo::FastFieldInfo& info = result[fast_idx]; info.data = TailCallTableInfo::FastFieldInfo::NonField{ - absl::StrCat("::_pbi::TcParser::FastEndG", - *end_group_tag < 128 ? "1" : "2"), + *end_group_tag < 128 ? TcParseFunction::kFastEndG1 + : TcParseFunction::kFastEndG2, static_cast(tag), static_cast(*end_group_tag), }; diff --git a/src/google/protobuf/generated_message_tctable_gen.h b/src/google/protobuf/generated_message_tctable_gen.h index 773c880ea4..3a3b6e2dd9 100644 --- a/src/google/protobuf/generated_message_tctable_gen.h +++ b/src/google/protobuf/generated_message_tctable_gen.h @@ -50,6 +50,7 @@ namespace google { namespace protobuf { namespace internal { +enum class TcParseFunction : uint8_t; namespace field_layout { enum TransformValidation : uint16_t; @@ -90,14 +91,14 @@ struct PROTOBUF_EXPORT TailCallTableInfo { struct FastFieldInfo { struct Empty {}; struct Field { - std::string func_name; + TcParseFunction func; uint16_t coded_tag; const FieldDescriptor* field; uint8_t hasbit_idx; uint8_t aux_idx; }; struct NonField { - std::string func_name; + TcParseFunction func; uint16_t coded_tag; uint16_t nonfield_info; }; diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h index 7fde171cea..d437f99632 100644 --- a/src/google/protobuf/generated_message_tctable_impl.h +++ b/src/google/protobuf/generated_message_tctable_impl.h @@ -37,6 +37,7 @@ #include #include +#include "absl/log/absl_log.h" #include "google/protobuf/extension_set.h" #include "google/protobuf/generated_message_tctable_decl.h" #include "google/protobuf/map.h" @@ -379,7 +380,7 @@ inline void AlignFail(std::integral_constant, PROTOBUF_TC_PARSE_FUNCTION_LIST_END_GROUP() #define PROTOBUF_TC_PARSE_FUNCTION_X(value) k##value, -enum class TcParseFunction { kNone, PROTOBUF_TC_PARSE_FUNCTION_LIST }; +enum class TcParseFunction : uint8_t { kNone, PROTOBUF_TC_PARSE_FUNCTION_LIST }; #undef PROTOBUF_TC_PARSE_FUNCTION_X // TcParser implements most of the parsing logic for tailcall tables.