diff options
author | mikhnenko <[email protected]> | 2024-06-25 08:50:35 +0300 |
---|---|---|
committer | mikhnenko <[email protected]> | 2024-06-25 09:00:27 +0300 |
commit | 509c9fc9e7b9c3b8be7307d72a4c966e5f9aa194 (patch) | |
tree | 4b8a6a44009906ac852e59efa0bc78bb12043a5b /contrib/libs/protoc/src/google/protobuf/compiler/cpp | |
parent | 7688f2313619a39a60ef3c2734d8efbc49a0a6db (diff) |
Update protobuf to 3.20.2 and pyprotobuf to 3.20.3
Если это pull-request что-то сломал, то:
- если это тест с канонизацией и еще нет pr с переканонизацией, то переканонизируйте пожалуйста сами
- проверьте, что тест не флапает
- приходите в [DEVTOOLSSUPPORT](https://st.yandex-team.ru/createTicket?queue=DEVTOOLSSUPPORT) - там вам обязательно помогут
987be5ed151f827f7f292f32420470b04b71a91d
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/cpp')
31 files changed, 1927 insertions, 1975 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc index 4ecd6a9cf76..960dfcadf79 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -38,10 +38,10 @@ #include <limits> #include <map> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_names.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_names.h> namespace google { namespace protobuf { @@ -88,7 +88,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, variables_["nested_name"] = descriptor_->name(); variables_["resolved_name"] = ResolveKeyword(descriptor_->name()); variables_["prefix"] = - (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; + (descriptor_->containing_type() == nullptr) ? "" : classname_ + "_"; } EnumGenerator::~EnumGenerator() {} @@ -405,7 +405,7 @@ void EnumGenerator::GenerateMethods(int idx, io::Printer* printer) { descriptor_->value_count()); } - if (descriptor_->containing_type() != NULL) { + if (descriptor_->containing_type() != nullptr) { TProtoStringType parent = ClassName(descriptor_->containing_type(), false); // Before C++17, we must define the static constants which were // declared in the header, to give the linker a place to put them. diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h index 43f1e5f4a5c..652a26b6db8 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -38,8 +38,9 @@ #include <map> #include <set> #include <string> -#include <google/protobuf/compiler/cpp/cpp_options.h> + #include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 79fa488b5fc..f50fca4926a 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -33,10 +33,11 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_enum_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> + #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { namespace protobuf { @@ -53,6 +54,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["type"] = QualifiedClassName(descriptor->enum_type(), options); (*variables)["default"] = Int32ToString(default_value->number()); (*variables)["full_name"] = descriptor->full_name(); + (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor); + (*variables)["cached_byte_size_field"] = + MakeVarintCachedSizeFieldName(descriptor); } } // namespace @@ -90,7 +94,7 @@ void EnumFieldGenerator::GenerateInlineAccessorDefinitions( Formatter format(printer, variables_); format( "inline $type$ $classname$::_internal_$name$() const {\n" - " return static_cast< $type$ >($name$_);\n" + " return static_cast< $type$ >($field$);\n" "}\n" "inline $type$ $classname$::$name$() const {\n" "$annotate_get$" @@ -103,7 +107,7 @@ void EnumFieldGenerator::GenerateInlineAccessorDefinitions( } format( " $set_hasbit$\n" - " $name$_ = value;\n" + " $field$ = value;\n" "}\n" "inline void $classname$::set_$name$($type$ value) {\n" " _internal_set_$name$(value);\n" @@ -114,7 +118,7 @@ void EnumFieldGenerator::GenerateInlineAccessorDefinitions( void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = $default$;\n"); + format("$field$ = $default$;\n"); } void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { @@ -124,18 +128,18 @@ void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("swap($name$_, other->$name$_);\n"); + format("swap($field$, other->$field$);\n"); } void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = $default$;\n"); + format("$field$ = $default$;\n"); } void EnumFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = from.$name$_;\n"); + format("$field$ = from.$field$;\n"); } void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -143,7 +147,7 @@ void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( Formatter format(printer, variables_); format( "target = stream->EnsureSpace(target);\n" - "target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + "target = ::_pbi::WireFormatLite::WriteEnumToArray(\n" " $number$, this->_internal_$name$(), target);\n"); } @@ -151,9 +155,7 @@ void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { Formatter format(printer, variables_); format( "total_size += $tag_size$ +\n" - " " - "::$proto_ns$::internal::WireFormatLite::EnumSize(this->_internal_$name$(" - "));\n"); + " ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n"); } void EnumFieldGenerator::GenerateConstinitInitializer( @@ -178,7 +180,7 @@ void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline $type$ $classname$::_internal_$name$() const {\n" " if (_internal_has_$name$()) {\n" - " return static_cast< $type$ >($field_member$);\n" + " return static_cast< $type$ >($field$);\n" " }\n" " return static_cast< $type$ >($default$);\n" "}\n" @@ -196,7 +198,7 @@ void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( " clear_$oneof_name$();\n" " set_has_$name$();\n" " }\n" - " $field_member$ = value;\n" + " $field$ = value;\n" "}\n" "inline void $classname$::set_$name$($type$ value) {\n" " _internal_set_$name$(value);\n" @@ -207,7 +209,7 @@ void EnumOneofFieldGenerator::GenerateInlineAccessorDefinitions( void EnumOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$field_member$ = $default$;\n"); + format("$field$ = $default$;\n"); } void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { @@ -217,7 +219,7 @@ void EnumOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { void EnumOneofFieldGenerator::GenerateConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); + format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n"); } // =================================================================== @@ -236,7 +238,7 @@ void RepeatedEnumFieldGenerator::GeneratePrivateMembers( format("::$proto_ns$::RepeatedField<int> $name$_;\n"); if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file(), options_)) { - format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); + format("mutable std::atomic<int> $cached_byte_size_name$;\n"); } } @@ -265,7 +267,7 @@ void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( Formatter format(printer, variables_); format( "inline $type$ $classname$::_internal_$name$(int index) const {\n" - " return static_cast< $type$ >($name$_.Get(index));\n" + " return static_cast< $type$ >($field$.Get(index));\n" "}\n" "inline $type$ $classname$::$name$(int index) const {\n" "$annotate_get$" @@ -277,7 +279,7 @@ void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( format(" assert($type$_IsValid(value));\n"); } format( - " $name$_.Set(index, value);\n" + " $field$.Set(index, value);\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" @@ -286,7 +288,7 @@ void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( format(" assert($type$_IsValid(value));\n"); } format( - " $name$_.Add(value);\n" + " $field$.Add(value);\n" "}\n" "inline void $classname$::add_$name$($type$ value) {\n" " _internal_add_$name$(value);\n" @@ -297,11 +299,11 @@ void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( "$classname$::$name$() const {\n" "$annotate_list$" " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" + " return $field$;\n" "}\n" "inline ::$proto_ns$::RepeatedField<int>*\n" "$classname$::_internal_mutable_$name$() {\n" - " return &$name$_;\n" + " return &$field$;\n" "}\n" "inline ::$proto_ns$::RepeatedField<int>*\n" "$classname$::mutable_$name$() {\n" @@ -314,19 +316,19 @@ void RepeatedEnumFieldGenerator::GenerateInlineAccessorDefinitions( void RepeatedEnumFieldGenerator::GenerateClearingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.Clear();\n"); + format("$field$.Clear();\n"); } void RepeatedEnumFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.MergeFrom(from.$name$_);\n"); + format("$field$.MergeFrom(from.$field$);\n"); } void RepeatedEnumFieldGenerator::GenerateSwappingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.InternalSwap(&other->$name$_);\n"); + format("$field$.InternalSwap(&other->$field$);\n"); } void RepeatedEnumFieldGenerator::GenerateConstructorCode( @@ -342,17 +344,17 @@ void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( format( "{\n" " int byte_size = " - "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n" + "$cached_byte_size_field$.load(std::memory_order_relaxed);\n" " if (byte_size > 0) {\n" " target = stream->WriteEnumPacked(\n" - " $number$, $name$_, byte_size, target);\n" + " $number$, $field$, byte_size, target);\n" " }\n" "}\n"); } else { format( "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" " target = stream->EnsureSpace(target);\n" - " target = ::$proto_ns$::internal::WireFormatLite::WriteEnumToArray(\n" + " target = ::_pbi::WireFormatLite::WriteEnumToArray(\n" " $number$, this->_internal_$name$(i), target);\n" "}\n"); } @@ -368,7 +370,7 @@ void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { format.Indent(); format( "for (unsigned int i = 0; i < count; i++) {\n" - " data_size += ::$proto_ns$::internal::WireFormatLite::EnumSize(\n" + " data_size += ::_pbi::WireFormatLite::EnumSize(\n" " this->_internal_$name$(static_cast<int>(i)));\n" "}\n"); @@ -376,11 +378,11 @@ void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { format( "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" - " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" - " static_cast<$int32$>(data_size));\n" + " " + "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" "}\n" - "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" - "_$name$_cached_byte_size_.store(cached_size,\n" + "int cached_size = ::_pbi::ToCachedSize(data_size);\n" + "$cached_byte_size_field$.store(cached_size,\n" " std::memory_order_relaxed);\n" "total_size += data_size;\n"); } else { @@ -396,7 +398,7 @@ void RepeatedEnumFieldGenerator::GenerateConstinitInitializer( format("$name$_()"); if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, _$name$_cached_byte_size_(0)"); + format("\n, $cached_byte_size_name$(0)"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h index e65ec0f5c07..2a4ca5162bf 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -37,6 +37,7 @@ #include <map> #include <string> + #include <google/protobuf/compiler/cpp/cpp_field.h> namespace google { @@ -47,7 +48,7 @@ namespace cpp { class EnumFieldGenerator : public FieldGenerator { public: EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~EnumFieldGenerator(); + ~EnumFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -71,7 +72,7 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator { public: EnumOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~EnumOneofFieldGenerator(); + ~EnumOneofFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -87,7 +88,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { public: RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~RepeatedEnumFieldGenerator(); + ~RepeatedEnumFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc index 72893b81c94..ef6cc81241f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -33,11 +33,13 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_extension.h> + #include <map> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/descriptor.pb.h> + #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/descriptor.pb.h> namespace google { namespace protobuf { @@ -76,6 +78,7 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, break; } SetCommonVars(options, &variables_); + SetCommonMessageDataVariables(&variables_); variables_["extendee"] = QualifiedClassName(descriptor_->containing_type(), options_); variables_["type_traits"] = type_traits_; @@ -91,6 +94,19 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, variables_["scope"] = scope; variables_["scoped_name"] = ExtensionName(descriptor_); variables_["number"] = StrCat(descriptor_->number()); + + bool add_verify_fn = + // Only verify msgs. + descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + // Options say to verify. + ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) && + ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_); + + variables_["verify_fn"] = + add_verify_fn + ? StrCat("&", FieldMessageTypeName(descriptor_, options_), + "::InternalVerify") + : "nullptr"; } ExtensionGenerator::~ExtensionGenerator() {} @@ -164,23 +180,11 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { } format( - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 " "::$proto_ns$::internal::ExtensionIdentifier< $extendee$,\n" - " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" - " $scoped_name$($constant_name$, $1$);\n", + " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$>\n" + " $scoped_name$($constant_name$, $1$, $verify_fn$);\n", default_str); - - // Register extension verify function if needed. - if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) && - ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_)) { - format( - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " - "::$proto_ns$::internal::RegisterExtensionVerify< $extendee$,\n" - " $1$, $number$> $2$_$name$_register;\n", - ClassName(descriptor_->message_type(), true), - IsScoped() ? ClassName(descriptor_->extension_scope(), false) : ""); - } } } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc index 5f167a4d019..895f094c701 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -38,19 +38,19 @@ #include <memory> #include <string> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_primitive_field.h> #include <google/protobuf/compiler/cpp/cpp_string_field.h> -#include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/stubs/substitute.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> #include <google/protobuf/compiler/cpp/cpp_enum_field.h> #include <google/protobuf/compiler/cpp/cpp_map_field.h> #include <google/protobuf/compiler/cpp/cpp_message_field.h> #include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/wire_format.h> namespace google { namespace protobuf { @@ -81,7 +81,7 @@ TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descripto TProtoStringType field_name = google::protobuf::compiler::cpp::FieldName(descriptor); TProtoStringType field_pointer = descriptor->options().ctype() == google::protobuf::FieldOptions::STRING - ? "$0.GetPointer()" + ? "$0.UnsafeGetPointer()" : "$0"; if (descriptor->default_value_string().empty()) { @@ -103,7 +103,7 @@ TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descripto return strings::Substitute( StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ", default_value_pointer), - field_member, MakeDefaultName(descriptor)); + field_member, MakeDefaultFieldName(descriptor)); } TProtoStringType GenerateTemplateForSingleString(const FieldDescriptor* descriptor, @@ -114,8 +114,8 @@ TProtoStringType GenerateTemplateForSingleString(const FieldDescriptor* descript if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) { return strings::Substitute( - "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member, - MakeDefaultName(descriptor)); + "$0.IsDefault() ? &$1.get() : $0.UnsafeGetPointer()", field_member, + MakeDefaultFieldName(descriptor)); } return StrCat("&", field_member); @@ -150,14 +150,12 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, google::protobuf::FileOptions::LITE_RUNTIME) { return; } - TProtoStringType field_member = (*variables)["field_member"]; + TProtoStringType field_member = (*variables)["field"]; const google::protobuf::OneofDescriptor* oneof_member = descriptor->real_containing_oneof(); - if (oneof_member) { - field_member = StrCat(oneof_member->name(), "_.", field_member); - } const TProtoStringType proto_ns = (*variables)["proto_ns"]; - const TProtoStringType substitute_template_prefix = " _tracker_.$1<$0>(this, "; + const TProtoStringType substitute_template_prefix = + StrCat(" ", (*variables)["tracker"], ".$1<$0>(this, "); TProtoStringType prepared_template; // Flat template is needed if the prepared one is introspecting the values @@ -178,7 +176,7 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, } else if (descriptor->is_map()) { prepared_template = "nullptr"; } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE && - !descriptor->options().lazy()) { + !IsExplicitLazy(descriptor)) { prepared_template = "nullptr"; } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { if (oneof_member) { @@ -238,13 +236,15 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables, const Options& options) { SetCommonVars(options, variables); + SetCommonMessageDataVariables(variables); + (*variables)["ns"] = Namespace(descriptor, options); (*variables)["name"] = FieldName(descriptor); (*variables)["index"] = StrCat(descriptor->index()); (*variables)["number"] = StrCat(descriptor->number()); (*variables)["classname"] = ClassName(FieldScope(descriptor), false); (*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); - (*variables)["field_member"] = FieldName(descriptor) + "_"; + (*variables)["field"] = FieldMemberName(descriptor); (*variables)["tag_size"] = StrCat( WireFormat::TagSize(descriptor->number(), descriptor->type())); @@ -254,7 +254,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["clear_hasbit"] = ""; if (HasHasbit(descriptor)) { (*variables)["set_hasbit_io"] = - "_Internal::set_has_" + FieldName(descriptor) + "(&_has_bits_);"; + StrCat("_Internal::set_has_", FieldName(descriptor), "(&", + (*variables)["has_bits"], ");"); } else { (*variables)["set_hasbit_io"] = ""; } @@ -275,10 +276,10 @@ void FieldGenerator::SetHasBitIndex(arc_i32 has_bit_index) { return; } variables_["set_hasbit"] = StrCat( - "_has_bits_[", has_bit_index / 32, "] |= 0x", + variables_["has_bits"], "[", has_bit_index / 32, "] |= 0x", strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); variables_["clear_hasbit"] = StrCat( - "_has_bits_[", has_bit_index / 32, "] &= ~0x", + variables_["has_bits"], "[", has_bit_index / 32, "] &= ~0x", strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); } @@ -287,12 +288,17 @@ void FieldGenerator::SetInlinedStringIndex(arc_i32 inlined_string_index) { GOOGLE_CHECK_EQ(inlined_string_index, -1); return; } + // The first bit is the tracking bit for on demand registering ArenaDtor. + GOOGLE_CHECK_GT(inlined_string_index, 0) + << "_inlined_string_donated_'s bit 0 is reserved for arena dtor tracking"; variables_["inlined_string_donated"] = StrCat( - "(_inlined_string_donated_[", inlined_string_index / 32, "] & 0x", + "(", variables_["inlined_string_donated_array"], "[", + inlined_string_index / 32, "] & 0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), "u) != 0;"); variables_["donating_states_word"] = - StrCat("_inlined_string_donated_[", inlined_string_index / 32, "]"); + StrCat(variables_["inlined_string_donated_array"], "[", + inlined_string_index / 32, "]"); variables_["mask_for_undonate"] = StrCat( "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), "u"); @@ -303,8 +309,6 @@ void SetCommonOneofFieldVariables( std::map<TProtoStringType, TProtoStringType>* variables) { const TProtoStringType prefix = descriptor->containing_oneof()->name() + "_."; (*variables)["oneof_name"] = descriptor->containing_oneof()->name(); - (*variables)["field_member"] = - StrCat(prefix, (*variables)["name"], "_"); } FieldGenerator::~FieldGenerator() {} diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h index e3386f446a3..9c3ec7fde4b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h @@ -40,9 +40,9 @@ #include <memory> #include <string> +#include <google/protobuf/descriptor.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_options.h> -#include <google/protobuf/descriptor.h> namespace google { namespace protobuf { @@ -158,11 +158,10 @@ class FieldGenerator { // Generate a manual destructor invocation for use when the message is on an // arena. The code that this method generates will be executed inside a // shared-for-the-whole-message-class method registered with - // OwnDestructor(). The method should return |true| if it generated any code - // that requires a call; this allows the message generator to eliminate the - // OwnDestructor() registration if no fields require it. - virtual bool GenerateArenaDestructorCode(io::Printer* printer) const { - return false; + // OwnDestructor(). + virtual void GenerateArenaDestructorCode(io::Printer* printer) const { + GOOGLE_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone) + << descriptor_->cpp_type_name(); } // Generate initialization code for private members declared by @@ -187,6 +186,10 @@ class FieldGenerator { virtual bool IsInlined() const { return false; } + virtual ArenaDtorNeeds NeedsArenaDestructor() const { + return ArenaDtorNeeds::kNone; + } + void SetHasBitIndex(arc_i32 has_bit_index); void SetInlinedStringIndex(arc_i32 inlined_string_index); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc index 2a98ad0b02c..f27d876e2ac 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -43,16 +43,16 @@ #include <unordered_set> #include <vector> +#include <google/protobuf/compiler/scc.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> #include <google/protobuf/compiler/cpp/cpp_enum.h> #include <google/protobuf/compiler/cpp/cpp_extension.h> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_message.h> #include <google/protobuf/compiler/cpp/cpp_service.h> -#include <google/protobuf/compiler/scc.h> #include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/stubs/strutil.h> // Must be last. #include <google/protobuf/port_def.inc> @@ -88,6 +88,23 @@ std::vector<const T*> Sorted(const std::unordered_set<const T*>& vals) { return sorted; } +// TODO(b/203101078): remove pragmas that suppresses uninitialized warnings when +// clang bug is fixed. +inline void MuteWuninitialized(Formatter& format) { + format( + "#if defined(__llvm__)\n" + " #pragma clang diagnostic push\n" + " #pragma clang diagnostic ignored \"-Wuninitialized\"\n" + "#endif // __llvm__\n"); +} + +inline void UnmuteWuninitialized(Formatter& format) { + format( + "#if defined(__llvm__)\n" + " #pragma clang diagnostic pop\n" + "#endif // __llvm__\n"); +} + } // namespace FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) @@ -347,7 +364,14 @@ void FileGenerator::DoIncludeFile(const TProtoStringType& google3_name, options_.runtime_include_base, path); } } else { - format("#include \"$1$\"", google3_name); + TProtoStringType path = google3_name; + // The bootstrapped proto generated code needs to use the + // third_party/protobuf header paths to avoid circular dependencies. + if (options_.bootstrap) { + path = StringReplace(google3_name, "net/proto2/public", + "third_party/protobuf", false); + } + format("#include \"$1$\"", path); } if (do_export) { @@ -444,12 +468,28 @@ void FileGenerator::GenerateSourceIncludes(io::Printer* printer) { format("// @@protoc_insertion_point(includes)\n"); IncludeFile("net/proto2/public/port_def.inc", printer); +} + +void FileGenerator::GenerateSourcePrelude(io::Printer* printer) { + Formatter format(printer, variables_); // For MSVC builds, we use #pragma init_seg to move the initialization of our // libraries to happen before the user code. // This worksaround the fact that MSVC does not do constant initializers when // required by the standard. format("\nPROTOBUF_PRAGMA_INIT_SEG\n"); + + // Generate convenience aliases. + format( + "\n" + "namespace _pb = ::$1$;\n" + "namespace _pbi = _pb::internal;\n", + ProtobufNamespace(options_)); + if (HasGeneratedMethods(file_, options_) && + options_.tctable_mode != Options::kTCTableNever) { + format("namespace _fl = _pbi::field_layout;\n"); + } + format("\n"); } void FileGenerator::GenerateSourceDefaultInstance(int idx, @@ -462,8 +502,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, // destructor that we need to elide. format( "struct $1$ {\n" - " constexpr $1$()\n" - " : _instance(::$proto_ns$::internal::ConstantInitialized{}) {}\n" + " PROTOBUF_CONSTEXPR $1$()\n" + " : _instance(::_pbi::ConstantInitialized{}) {}\n" " ~$1$() {}\n" " union {\n" " $2$ _instance;\n" @@ -475,7 +515,8 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, // enough. However, the empty destructor fails to be elided in some // configurations (like non-opt or with certain sanitizers). NO_DESTROY is // there just to improve performance and binary size in these builds. - format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT $1$ $2$;\n", + format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT " + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n", DefaultInstanceType(generator->descriptor_, options_), DefaultInstanceName(generator->descriptor_, options_)); @@ -484,19 +525,21 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, if (IsStringInlined(field, options_)) { // Force the initialization of the inlined string in the default instance. format( - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY std::true_type " + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type " "$1$::_init_inline_$2$_ = " - "($3$._instance.$2$_.Init(), std::true_type{});\n", + "($3$._instance.$4$.Init(), std::true_type{});\n", ClassName(generator->descriptor_), FieldName(field), - DefaultInstanceName(generator->descriptor_, options_)); + DefaultInstanceName(generator->descriptor_, options_), + FieldMemberName(field)); } } if (options_.lite_implicit_weak_fields) { - format("$1$* $2$ = &$3$;\n", - DefaultInstanceType(generator->descriptor_, options_), - DefaultInstancePtr(generator->descriptor_, options_), - DefaultInstanceName(generator->descriptor_, options_)); + format( + "PROTOBUF_CONSTINIT const void* $1$ =\n" + " &$2$;\n", + DefaultInstancePtr(generator->descriptor_, options_), + DefaultInstanceName(generator->descriptor_, options_)); } } @@ -550,11 +593,10 @@ void FileGenerator::GenerateInternalForwardDeclarations( for (auto instance : Sorted(refs.weak_default_instances)) { ns.ChangeTo(Namespace(instance, options_)); if (options_.lite_implicit_weak_fields) { - format("extern $1$ $2$;\n", DefaultInstanceType(instance, options_), - DefaultInstanceName(instance, options_)); - format("__attribute__((weak)) $1$* $2$ = nullptr;\n", - DefaultInstanceType(instance, options_), - DefaultInstancePtr(instance, options_)); + format( + "PROTOBUF_CONSTINIT __attribute__((weak)) const void* $1$ =\n" + " &::_pbi::implicit_weak_message_default_instance;\n", + DefaultInstancePtr(instance, options_)); } else { format("extern __attribute__((weak)) $1$ $2$;\n", DefaultInstanceType(instance, options_), @@ -565,8 +607,7 @@ void FileGenerator::GenerateInternalForwardDeclarations( for (auto file : Sorted(refs.weak_reflection_files)) { format( - "extern __attribute__((weak)) const " - "::$proto_ns$::internal::DescriptorTable $1$;\n", + "extern __attribute__((weak)) const ::_pbi::DescriptorTable $1$;\n", DescriptorTableName(file, options_)); } } @@ -574,6 +615,9 @@ void FileGenerator::GenerateInternalForwardDeclarations( void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { Formatter format(printer, variables_); GenerateSourceIncludes(printer); + GenerateSourcePrelude(printer); + + if (IsAnyMessage(file_, options_)) MuteWuninitialized(format); CrossFileReferences refs; ForEachField(message_generators_[idx]->descriptor_, @@ -602,6 +646,8 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { message_generators_[idx]->GenerateSourceInProto2Namespace(printer); } + if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format); + format( "\n" "// @@protoc_insertion_point(global_scope)\n"); @@ -610,6 +656,7 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { Formatter format(printer, variables_); GenerateSourceIncludes(printer); + GenerateSourcePrelude(printer); NamespaceOpener ns(Namespace(file_, options_), format); extension_generators_[idx]->GenerateDefinition(printer); } @@ -617,10 +664,9 @@ void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { void FileGenerator::GenerateGlobalSource(io::Printer* printer) { Formatter format(printer, variables_); GenerateSourceIncludes(printer); + GenerateSourcePrelude(printer); { - GenerateTables(printer); - // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. if (HasDescriptorMethods(file_, options_)) { @@ -639,10 +685,13 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { void FileGenerator::GenerateSource(io::Printer* printer) { Formatter format(printer, variables_); GenerateSourceIncludes(printer); + GenerateSourcePrelude(printer); CrossFileReferences refs; GetCrossFileReferencesForFile(file_, &refs); GenerateInternalForwardDeclarations(refs, printer); + if (IsAnyMessage(file_, options_)) MuteWuninitialized(format); + { NamespaceOpener ns(Namespace(file_, options_), format); @@ -653,8 +702,6 @@ void FileGenerator::GenerateSource(io::Printer* printer) { } { - GenerateTables(printer); - if (HasDescriptorMethods(file_, options_)) { // Define the code to initialize reflection. This code uses a global // constructor to register reflection data with the runtime pre-main. @@ -711,6 +758,8 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "\n" "// @@protoc_insertion_point(global_scope)\n"); + if (IsAnyMessage(file_, options_)) UnmuteWuninitialized(format); + IncludeFile("net/proto2/public/port_undef.inc", printer); } @@ -718,31 +767,30 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { Formatter format(printer, variables_); if (!message_generators_.empty()) { - format("static ::$proto_ns$::Metadata $file_level_metadata$[$1$];\n", + format("static ::_pb::Metadata $file_level_metadata$[$1$];\n", message_generators_.size()); } if (!enum_generators_.empty()) { format( - "static " - "const ::$proto_ns$::EnumDescriptor* " + "static const ::_pb::EnumDescriptor* " "$file_level_enum_descriptors$[$1$];\n", enum_generators_.size()); } else { format( "static " - "constexpr ::$proto_ns$::EnumDescriptor const** " + "constexpr ::_pb::EnumDescriptor const** " "$file_level_enum_descriptors$ = nullptr;\n"); } if (HasGenericServices(file_, options_) && file_->service_count() > 0) { format( "static " - "const ::$proto_ns$::ServiceDescriptor* " + "const ::_pb::ServiceDescriptor* " "$file_level_service_descriptors$[$1$];\n", file_->service_count()); } else { format( "static " - "constexpr ::$proto_ns$::ServiceDescriptor const** " + "constexpr ::_pb::ServiceDescriptor const** " "$file_level_service_descriptors$ = nullptr;\n"); } @@ -760,7 +808,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { format.Outdent(); format( "};\n" - "static const ::$proto_ns$::internal::MigrationSchema schemas[] " + "static const ::_pbi::MigrationSchema schemas[] " "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); format.Indent(); { @@ -774,16 +822,13 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { format.Outdent(); format( "};\n" - "\nstatic " - "::$proto_ns$::Message const * const file_default_instances[] = {\n"); + "\nstatic const ::_pb::Message* const file_default_instances[] = {\n"); format.Indent(); for (int i = 0; i < message_generators_.size(); i++) { const Descriptor* descriptor = message_generators_[i]->descriptor_; - format( - "reinterpret_cast<const " - "::$proto_ns$::Message*>(&$1$::_$2$_default_instance_),\n", - Namespace(descriptor, options_), // 1 - ClassName(descriptor)); // 2 + format("&$1$::_$2$_default_instance_._instance,\n", + Namespace(descriptor, options_), // 1 + ClassName(descriptor)); // 2 } format.Outdent(); format( @@ -794,10 +839,8 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { format( // MSVC doesn't like empty arrays, so we add a dummy. "const $uint32$ $tablename$::offsets[1] = {};\n" - "static constexpr ::$proto_ns$::internal::MigrationSchema* schemas = " - "nullptr;" - "\n" - "static constexpr ::$proto_ns$::Message* const* " + "static constexpr ::_pbi::MigrationSchema* schemas = nullptr;\n" + "static constexpr ::_pb::Message* const* " "file_default_instances = nullptr;\n" "\n"); } @@ -852,7 +895,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // Build array of DescriptorTable deps. if (num_deps > 0) { format( - "static const ::$proto_ns$::internal::DescriptorTable*const " + "static const ::_pbi::DescriptorTable* const " "$desc_table$_deps[$1$] = {\n", num_deps); @@ -872,13 +915,14 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // so disable for now. bool eager = false; format( - "static ::$proto_ns$::internal::once_flag $desc_table$_once;\n" - "const ::$proto_ns$::internal::DescriptorTable $desc_table$ = {\n" - " false, $1$, $2$, $3$, \"$filename$\", \n" - " &$desc_table$_once, $4$, $5$, $6$,\n" - " schemas, file_default_instances, $tablename$::offsets,\n" - " $7$, $file_level_enum_descriptors$, " - "$file_level_service_descriptors$,\n" + "static ::_pbi::once_flag $desc_table$_once;\n" + "const ::_pbi::DescriptorTable $desc_table$ = {\n" + " false, $1$, $2$, $3$,\n" + " \"$filename$\",\n" + " &$desc_table$_once, $4$, $5$, $6$,\n" + " schemas, file_default_instances, $tablename$::offsets,\n" + " $7$, $file_level_enum_descriptors$,\n" + " $file_level_service_descriptors$,\n" "};\n" // This function exists to be marked as weak. // It can significantly speed up compilation by breaking up LLVM's SCC in @@ -891,7 +935,7 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { // vtables -> GetMetadata // By adding a weak function here we break the connection from the // individual vtables back into the descriptor table. - "PROTOBUF_ATTRIBUTE_WEAK const ::$proto_ns$::internal::DescriptorTable* " + "PROTOBUF_ATTRIBUTE_WEAK const ::_pbi::DescriptorTable* " "$desc_table$_getter() {\n" " return &$desc_table$;\n" "}\n" @@ -909,123 +953,12 @@ void FileGenerator::GenerateReflectionInitializationCode(io::Printer* printer) { if (file_->name() != "net/proto2/proto/descriptor.proto") { format( "// Force running AddDescriptors() at dynamic initialization time.\n" - "PROTOBUF_ATTRIBUTE_INIT_PRIORITY " - "static ::$proto_ns$::internal::AddDescriptorsRunner " - "$1$(&$desc_table$);\n", + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 " + "static ::_pbi::AddDescriptorsRunner $1$(&$desc_table$);\n", UniqueName("dynamic_init_dummy", file_, options_)); } } -void FileGenerator::GenerateTables(io::Printer* printer) { - Formatter format(printer, variables_); - if (options_.table_driven_parsing) { - // TODO(ckennelly): Gate this with the same options flag to enable - // table-driven parsing. - format( - "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTableField\n" - " const $tablename$::entries[] " - "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); - format.Indent(); - - std::vector<size_t> entries; - size_t count = 0; - for (int i = 0; i < message_generators_.size(); i++) { - size_t value = message_generators_[i]->GenerateParseOffsets(printer); - entries.push_back(value); - count += value; - } - - // We need these arrays to exist, and MSVC does not like empty arrays. - if (count == 0) { - format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); - } - - format.Outdent(); - format( - "};\n" - "\n" - "PROTOBUF_CONSTEXPR_VAR " - "::$proto_ns$::internal::AuxiliaryParseTableField\n" - " const $tablename$::aux[] " - "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); - format.Indent(); - - std::vector<size_t> aux_entries; - count = 0; - for (int i = 0; i < message_generators_.size(); i++) { - size_t value = message_generators_[i]->GenerateParseAuxTable(printer); - aux_entries.push_back(value); - count += value; - } - - if (count == 0) { - format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); - } - - format.Outdent(); - format( - "};\n" - "PROTOBUF_CONSTEXPR_VAR ::$proto_ns$::internal::ParseTable const\n" - " $tablename$::schema[] " - "PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {\n"); - format.Indent(); - - size_t offset = 0; - size_t aux_offset = 0; - for (int i = 0; i < message_generators_.size(); i++) { - message_generators_[i]->GenerateParseTable(printer, offset, aux_offset); - offset += entries[i]; - aux_offset += aux_entries[i]; - } - - if (message_generators_.empty()) { - format("{ nullptr, nullptr, 0, -1, -1, false },\n"); - } - - format.Outdent(); - format( - "};\n" - "\n"); - } - - if (!message_generators_.empty() && options_.table_driven_serialization) { - format( - "const ::$proto_ns$::internal::FieldMetadata " - "$tablename$::field_metadata[] " - "= {\n"); - format.Indent(); - std::vector<int> field_metadata_offsets; - int idx = 0; - for (int i = 0; i < message_generators_.size(); i++) { - field_metadata_offsets.push_back(idx); - idx += message_generators_[i]->GenerateFieldMetadata(printer); - } - field_metadata_offsets.push_back(idx); - format.Outdent(); - format( - "};\n" - "const ::$proto_ns$::internal::SerializationTable " - "$tablename$::serialization_table[] = {\n"); - format.Indent(); - // We rely on the order we layout the tables to match the order we - // calculate them with FlattenMessagesInFile, so we check here that - // these match exactly. - std::vector<const Descriptor*> calculated_order = - FlattenMessagesInFile(file_); - GOOGLE_CHECK_EQ(calculated_order.size(), message_generators_.size()); - for (int i = 0; i < message_generators_.size(); i++) { - GOOGLE_CHECK_EQ(calculated_order[i], message_generators_[i]->descriptor_); - format("{$1$, $tablename$::field_metadata + $2$},\n", - field_metadata_offsets[i + 1] - field_metadata_offsets[i], // 1 - field_metadata_offsets[i]); // 2 - } - format.Outdent(); - format( - "};\n" - "\n"); - } -} - class FileGenerator::ForwardDeclarations { public: void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; } @@ -1229,7 +1162,6 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (HasSimpleBaseClasses(file_, options_)) { IncludeFile("net/proto2/public/generated_message_bases.h", printer); } - IncludeFile("net/proto2/public/generated_message_table_driven.h", printer); if (HasGeneratedMethods(file_, options_) && options_.tctable_mode != Options::kTCTableNever) { IncludeFile("net/proto2/public/generated_message_tctable_decl.h", printer); @@ -1362,20 +1294,8 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( "\n" "// Internal implementation detail -- do not use these members.\n" "struct $dllexport_decl $$tablename$ {\n" - // These tables describe how to serialize and parse messages. Used - // for table driven code. - " static const ::$proto_ns$::internal::ParseTableField entries[]\n" - " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" - " static const ::$proto_ns$::internal::AuxiliaryParseTableField aux[]\n" - " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" - " static const ::$proto_ns$::internal::ParseTable schema[$1$]\n" - " PROTOBUF_SECTION_VARIABLE(protodesc_cold);\n" - " static const ::$proto_ns$::internal::FieldMetadata field_metadata[];\n" - " static const ::$proto_ns$::internal::SerializationTable " - "serialization_table[];\n" " static const $uint32$ offsets[];\n" - "};\n", - std::max(size_t(1), message_generators_.size())); + "};\n"); if (HasDescriptorMethods(file_, options_)) { format( "$dllexport_decl $extern const ::$proto_ns$::internal::DescriptorTable " diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h index 041d5ea4aba..d8eff2feedb 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h @@ -40,11 +40,12 @@ #include <set> #include <string> #include <vector> + #include <google/protobuf/stubs/common.h> #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/compiler/scc.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -123,11 +124,11 @@ class FileGenerator { void GenerateInternalForwardDeclarations(const CrossFileReferences& refs, io::Printer* printer); void GenerateSourceIncludes(io::Printer* printer); + void GenerateSourcePrelude(io::Printer* printer); void GenerateSourceDefaultInstance(int idx, io::Printer* printer); void GenerateInitForSCC(const SCC* scc, const CrossFileReferences& refs, io::Printer* printer); - void GenerateTables(io::Printer* printer); void GenerateReflectionInitializationCode(io::Printer* printer); // For other imports, generates their forward-declarations. diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc index 3673c09a617..69443f5bf2f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -40,11 +40,11 @@ #include <vector> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/compiler/cpp/cpp_file.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/io/zero_copy_stream.h> namespace google { namespace protobuf { @@ -82,6 +82,12 @@ bool CppGenerator::Generate(const FileDescriptor* file, // FOO_EXPORT is a macro which should expand to __declspec(dllexport) or // __declspec(dllimport) depending on what is being compiled. // + // If the proto_h option is passed to the compiler, we will generate all + // classes and enums so that they can be forward-declared from files that + // need them from imports. + // + // If the lite option is passed to the compiler, we will generate the + // current files and all transitive dependencies using the LITE runtime. Options file_options; file_options.opensource_runtime = opensource_runtime_; @@ -109,8 +115,10 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.lite_implicit_weak_fields = true; if (!options[i].second.empty()) { file_options.num_cc_files = - strto32(options[i].second.c_str(), NULL, 10); + strto32(options[i].second.c_str(), nullptr, 10); } + } else if (options[i].first == "proto_h") { + file_options.proto_h = true; } else if (options[i].first == "annotate_accessor") { file_options.annotate_accessor = true; } else if (options[i].first == "inject_field_listener_events") { @@ -127,14 +135,14 @@ bool CppGenerator::Generate(const FileDescriptor* file, .insert(options[i].second.substr(pos, next_pos - pos)); pos = next_pos + 1; } while (pos < options[i].second.size()); + } else if (options[i].first == "verified_lazy_message_sets") { + file_options.unverified_lazy_message_sets = false; + } else if (options[i].first == "unverified_lazy_message_sets") { + file_options.unverified_lazy_message_sets = true; } else if (options[i].first == "eagerly_verified_lazy") { file_options.eagerly_verified_lazy = true; } else if (options[i].first == "force_eagerly_verified_lazy") { file_options.force_eagerly_verified_lazy = true; - } else if (options[i].first == "table_driven_parsing") { - file_options.table_driven_parsing = true; - } else if (options[i].first == "table_driven_serialization") { - file_options.table_driven_serialization = true; } else if (options[i].first == "experimental_tail_call_table_mode") { if (options[i].second == "never") { file_options.tctable_mode = Options::kTCTableNever; @@ -185,7 +193,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, TProtoStringType info_path = basename + ".proto.h.meta"; io::Printer printer( output.get(), '$', - file_options.annotate_headers ? &annotation_collector : NULL); + file_options.annotate_headers ? &annotation_collector : nullptr); file_generator.GenerateProtoHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { @@ -204,7 +212,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, TProtoStringType info_path = basename + ".pb.h.meta"; io::Printer printer( output.get(), '$', - file_options.annotate_headers ? &annotation_collector : NULL); + file_options.annotate_headers ? &annotation_collector : nullptr); file_generator.GeneratePBHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h index 235d02325f0..aa63845d300 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h @@ -40,6 +40,7 @@ #include <string> #include <google/protobuf/compiler/code_generator.h> +// Must be included last. #include <google/protobuf/port_def.inc> namespace google { @@ -54,7 +55,7 @@ namespace cpp { class PROTOC_EXPORT CppGenerator : public CodeGenerator { public: CppGenerator(); - ~CppGenerator(); + ~CppGenerator() override; enum class Runtime { kGoogle3, // Use the internal google3 runtime. diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 5191a7e7309..f726d0fc9b5 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -44,10 +44,10 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/descriptor.h> #include <google/protobuf/compiler/cpp/cpp_names.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/descriptor.h> #include <google/protobuf/compiler/scc.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> @@ -233,6 +233,18 @@ void SetCommonVars(const Options& options, (*variables)["string"] = "TProtoStringType"; } +void SetCommonMessageDataVariables( + std::map<TProtoStringType, TProtoStringType>* variables) { + (*variables)["any_metadata"] = "_any_metadata_"; + (*variables)["cached_size"] = "_cached_size_"; + (*variables)["extensions"] = "_extensions_"; + (*variables)["has_bits"] = "_has_bits_"; + (*variables)["inlined_string_donated_array"] = "_inlined_string_donated_"; + (*variables)["oneof_case"] = "_oneof_case_"; + (*variables)["tracker"] = "_tracker_"; + (*variables)["weak_field_map"] = "_weak_field_map_"; +} + void SetUnknownFieldsVariable(const Descriptor* descriptor, const Options& options, std::map<TProtoStringType, TProtoStringType>* variables) { @@ -457,6 +469,14 @@ TProtoStringType FieldName(const FieldDescriptor* field) { return result; } +TProtoStringType FieldMemberName(const FieldDescriptor* field) { + if (field->real_containing_oneof() == nullptr) { + return StrCat(FieldName(field), "_"); + } + return StrCat(field->containing_oneof()->name(), "_.", FieldName(field), + "_"); +} + TProtoStringType OneofCaseConstantName(const FieldDescriptor* field) { GOOGLE_DCHECK(field->containing_oneof()); TProtoStringType field_name = UnderscoresToCamelCase(field->name(), true); @@ -1151,7 +1171,6 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, return UsingImplicitWeakFields(field->file(), options) && field->type() == FieldDescriptor::TYPE_MESSAGE && !field->is_required() && !field->is_map() && !field->is_extension() && - !field->real_containing_oneof() && !IsWellKnownMessage(field->message_type()->file()) && field->message_type()->file()->name() != "net/proto2/proto/descriptor.proto" && @@ -1268,7 +1287,7 @@ bool GetBootstrapBasename(const Options& options, const TProtoStringType& basena std::unordered_map<TProtoStringType, TProtoStringType> bootstrap_mapping{ {"net/proto2/proto/descriptor", - "net/proto2/internal/descriptor"}, + "third_party/protobuf/descriptor"}, {"net/proto2/compiler/proto/plugin", "net/proto2/compiler/proto/plugin"}, {"net/proto2/compiler/proto/profile", @@ -1301,7 +1320,7 @@ bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, *basename = bootstrap_basename; return false; } else { - TProtoStringType forward_to_basename = bootstrap_basename; + const TProtoStringType& forward_to_basename = bootstrap_basename; // Generate forwarding headers and empty .pb.cc. { @@ -1490,8 +1509,9 @@ FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, return FileOptions::SPEED; } -bool EnableMessageOwnedArena(const Descriptor* desc) { +bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options) { (void)desc; + (void)options; return false; } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h index ceb9a54f389..f7735da12f0 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -41,10 +41,10 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_options.h> -#include <google/protobuf/compiler/cpp/cpp_names.h> #include <google/protobuf/compiler/scc.h> #include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/cpp/cpp_names.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> @@ -59,6 +59,8 @@ namespace protobuf { namespace compiler { namespace cpp { +enum class ArenaDtorNeeds { kNone = 0, kOnDemand = 1, kRequired = 2 }; + inline TProtoStringType ProtobufNamespace(const Options& /* options */) { return "PROTOBUF_NAMESPACE_ID"; } @@ -85,6 +87,10 @@ extern const char kThinSeparator[]; void SetCommonVars(const Options& options, std::map<TProtoStringType, TProtoStringType>* variables); +// Variables to access message data from the message scope. +void SetCommonMessageDataVariables( + std::map<TProtoStringType, TProtoStringType>* variables); + void SetUnknownFieldsVariable(const Descriptor* descriptor, const Options& options, std::map<TProtoStringType, TProtoStringType>* variables); @@ -186,6 +192,9 @@ TProtoStringType ResolveKeyword(const TProtoStringType& name); // anyway, so normally this just returns field->name(). TProtoStringType FieldName(const FieldDescriptor* field); +// Returns the (unqualified) private member name for this field in C++ code. +TProtoStringType FieldMemberName(const FieldDescriptor* field); + // Returns an estimate of the compiler's alignment for the field. This // can't guarantee to be correct because the generated code could be compiled on // different systems with different alignment rules. The estimates below assume @@ -348,9 +357,16 @@ bool HasLazyFields(const FileDescriptor* file, const Options& options, bool IsLazy(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer); +// Is this an explicit (non-profile driven) lazy field, as denoted by +// lazy/unverified_lazy in the descriptor? +inline bool IsExplicitLazy(const FieldDescriptor* field) { + return field->options().lazy() || field->options().unverified_lazy(); +} + inline bool IsLazilyVerifiedLazy(const FieldDescriptor* field, const Options& options) { - return field->options().lazy() && !field->is_repeated() && + // TODO(b/211906113): Make lazy() imply eagerly verified lazy. + return IsExplicitLazy(field) && !field->is_repeated() && field->type() == FieldDescriptor::TYPE_MESSAGE && GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME && !options.opensource_runtime; @@ -359,7 +375,8 @@ inline bool IsLazilyVerifiedLazy(const FieldDescriptor* field, inline bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer) { - return IsLazy(field, options, scc_analyzer) && !field->options().lazy(); + // TODO(b/211906113): Make lazy() imply eagerly verified lazy. + return IsLazy(field, options, scc_analyzer) && !IsExplicitLazy(field); } inline bool IsFieldUsed(const FieldDescriptor* /* field */, @@ -472,6 +489,43 @@ inline TProtoStringType MakeDefaultName(const FieldDescriptor* field) { "_"; } +// Semantically distinct from MakeDefaultName in that it gives the C++ code +// referencing a default field from the message scope, rather than just the +// variable name. +// For example, declarations of default variables should always use just +// MakeDefaultName to produce code like: +// Type _i_give_permission_to_break_this_code_default_field_; +// +// Code that references these should use MakeDefaultFieldName, in case the field +// exists at some nested level like: +// internal_container_._i_give_permission_to_break_this_code_default_field_; +inline TProtoStringType MakeDefaultFieldName(const FieldDescriptor* field) { + return MakeDefaultName(field); +} + +inline TProtoStringType MakeVarintCachedSizeName(const FieldDescriptor* field) { + return StrCat("_", FieldName(field), "_cached_byte_size_"); +} + +// Semantically distinct from MakeVarintCachedSizeName in that it gives the C++ +// code referencing the object from the message scope, rather than just the +// variable name. +// For example, declarations of default variables should always use just +// MakeVarintCachedSizeName to produce code like: +// Type _field_cached_byte_size_; +// +// Code that references these variables should use +// MakeVarintCachedSizeFieldName, in case the field exists at some nested level +// like: +// internal_container_._field_cached_byte_size_; +inline TProtoStringType MakeVarintCachedSizeFieldName(const FieldDescriptor* field) { + return StrCat("_", FieldName(field), "_cached_byte_size_"); +} + +// Note: A lot of libraries detect Any protos based on Descriptor::full_name() +// while the two functions below use FileDescriptor::name(). In a sane world the +// two approaches should be equivalent. But if you are dealing with descriptors +// from untrusted sources, you might need to match semantics across libraries. bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options); bool IsAnyMessage(const Descriptor* descriptor, const Options& options); @@ -956,7 +1010,7 @@ inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); -bool EnableMessageOwnedArena(const Descriptor* desc); +bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options); bool ShouldVerify(const Descriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc index c5028fdb1d2..4d3e00ac89b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -30,10 +30,10 @@ #include <google/protobuf/compiler/cpp/cpp_map_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { @@ -53,10 +53,8 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["type"] = ClassName(descriptor->message_type(), false); (*variables)["full_name"] = descriptor->full_name(); - const FieldDescriptor* key = - descriptor->message_type()->FindFieldByName("key"); - const FieldDescriptor* val = - descriptor->message_type()->FindFieldByName("value"); + const FieldDescriptor* key = descriptor->message_type()->map_key(); + const FieldDescriptor* val = descriptor->message_type()->map_value(); (*variables)["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); switch (val->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: @@ -128,7 +126,7 @@ void MapFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" "$classname$::_internal_$name$() const {\n" - " return $name$_.GetMap();\n" + " return $field$.GetMap();\n" "}\n" "inline const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n" "$classname$::$name$() const {\n" @@ -138,7 +136,7 @@ void MapFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" "$classname$::_internal_mutable_$name$() {\n" - " return $name$_.MutableMap();\n" + " return $field$.MutableMap();\n" "}\n" "inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n" "$classname$::mutable_$name$() {\n" @@ -150,17 +148,17 @@ void MapFieldGenerator::GenerateInlineAccessorDefinitions( void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.Clear();\n"); + format("$field$.Clear();\n"); } void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.MergeFrom(from.$name$_);\n"); + format("$field$.MergeFrom(from.$field$);\n"); } void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.InternalSwap(&other->$name$_);\n"); + format("$field$.InternalSwap(&other->$field$);\n"); } void MapFieldGenerator::GenerateCopyConstructorCode( @@ -169,35 +167,27 @@ void MapFieldGenerator::GenerateCopyConstructorCode( GenerateMergingCode(printer); } -static void GenerateSerializationLoop(const Formatter& format, bool string_key, +static void GenerateSerializationLoop(Formatter& format, bool string_key, bool string_value, bool is_deterministic) { - TProtoStringType ptr; if (is_deterministic) { - format("for (size_type i = 0; i < n; i++) {\n"); - ptr = string_key ? "items[static_cast<ptrdiff_t>(i)]" - : "items[static_cast<ptrdiff_t>(i)].second"; - } else { format( - "for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = this->_internal_$name$().begin();\n" - " it != this->_internal_$name$().end(); ++it) {\n"); - ptr = "it"; + "for (const auto& entry : " + "::_pbi::MapSorter$1$<MapType>(map_field)) {\n", + (string_key ? "Ptr" : "Flat")); + } else { + format("for (const auto& entry : map_field) {\n"); } - format.Indent(); + { + auto loop_scope = format.ScopedIndent(); + format( + "target = WireHelper::InternalSerialize($number$, " + "entry.first, entry.second, target, stream);\n"); - format( - "target = $map_classname$::Funcs::InternalSerialize($number$, " - "$1$->first, $1$->second, target, stream);\n", - ptr); - - if (string_key || string_value) { - // ptr is either an actual pointer or an iterator, either way we can - // create a pointer by taking the address after de-referencing it. - format("Utf8Check::Check(&(*$1$));\n", ptr); + if (string_key || string_value) { + format("check_utf8(entry);\n"); + } } - - format.Outdent(); format("}\n"); } @@ -206,77 +196,53 @@ void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray( Formatter format(printer, variables_); format("if (!this->_internal_$name$().empty()) {\n"); format.Indent(); - const FieldDescriptor* key_field = - descriptor_->message_type()->FindFieldByName("key"); - const FieldDescriptor* value_field = - descriptor_->message_type()->FindFieldByName("value"); + const FieldDescriptor* key_field = descriptor_->message_type()->map_key(); + const FieldDescriptor* value_field = descriptor_->message_type()->map_value(); const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING; const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING; format( - "typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_pointer\n" - " ConstPtr;\n"); - if (string_key) { - format( - "typedef ConstPtr SortItem;\n" - "typedef ::$proto_ns$::internal::" - "CompareByDerefFirst<SortItem> Less;\n"); - } else { - format( - "typedef ::$proto_ns$::internal::SortItem< $key_cpp$, ConstPtr > " - "SortItem;\n" - "typedef ::$proto_ns$::internal::CompareByFirstField<SortItem> " - "Less;\n"); - } + "using MapType = ::_pb::Map<$key_cpp$, $val_cpp$>;\n" + "using WireHelper = $map_classname$::Funcs;\n" + "const auto& map_field = this->_internal_$name$();\n"); bool utf8_check = string_key || string_value; if (utf8_check) { - format( - "struct Utf8Check {\n" - " static void Check(ConstPtr p) {\n" - // p may be unused when GetUtf8CheckMode evaluates to kNone, - // thus disabling the validation. - " (void)p;\n"); - format.Indent(); - format.Indent(); - if (string_key) { - GenerateUtf8CheckCodeForString( - key_field, options_, false, - "p->first.data(), static_cast<int>(p->first.length()),\n", format); + format("auto check_utf8 = [](const MapType::value_type& entry) {\n"); + { + auto check_scope = format.ScopedIndent(); + // p may be unused when GetUtf8CheckMode evaluates to kNone, + // thus disabling the validation. + format("(void)entry;\n"); + if (string_key) { + GenerateUtf8CheckCodeForString( + key_field, options_, false, + "entry.first.data(), static_cast<int>(entry.first.length()),\n", + format); + } + if (string_value) { + GenerateUtf8CheckCodeForString( + value_field, options_, false, + "entry.second.data(), static_cast<int>(entry.second.length()),\n", + format); + } } - if (string_value) { - GenerateUtf8CheckCodeForString( - value_field, options_, false, - "p->second.data(), static_cast<int>(p->second.length()),\n", format); - } - format.Outdent(); - format.Outdent(); format( - " }\n" "};\n"); } format( "\n" - "if (stream->IsSerializationDeterministic() &&\n" - " this->_internal_$name$().size() > 1) {\n" - " ::std::unique_ptr<SortItem[]> items(\n" - " new SortItem[this->_internal_$name$().size()]);\n" - " typedef ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::size_type " - "size_type;\n" - " size_type n = 0;\n" - " for (::$proto_ns$::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" - " it = this->_internal_$name$().begin();\n" - " it != this->_internal_$name$().end(); ++it, ++n) {\n" - " items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n" - " }\n" - " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n"); - format.Indent(); - GenerateSerializationLoop(format, string_key, string_value, true); - format.Outdent(); + "if (stream->IsSerializationDeterministic() && " + "map_field.size() > 1) {\n"); + { + auto deterministic_scope = format.ScopedIndent(); + GenerateSerializationLoop(format, string_key, string_value, true); + } format("} else {\n"); - format.Indent(); - GenerateSerializationLoop(format, string_key, string_value, false); - format.Outdent(); + { + auto map_order_scope = format.ScopedIndent(); + GenerateSerializationLoop(format, string_key, string_value, false); + } format("}\n"); format.Outdent(); format("}\n"); @@ -301,7 +267,7 @@ void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { Formatter format(printer, variables_); format( - "if (!::$proto_ns$::internal::AllAreInitialized($name$_)) return " + "if (!::$proto_ns$::internal::AllAreInitialized($field$)) return " "false;\n"); } @@ -315,17 +281,28 @@ void MapFieldGenerator::GenerateConstinitInitializer( } } -bool MapFieldGenerator::GenerateArenaDestructorCode( - io::Printer* printer) const { +void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + Formatter format(printer, variables_); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - // _this is the object being destructed (we are inside a static method - // here). - format("_this->$name$_. ~MapField();\n"); - return true; - } else { - return false; + format("$field$.Destruct();\n"); +} + +void MapFieldGenerator::GenerateArenaDestructorCode( + io::Printer* printer) const { + if (NeedsArenaDestructor() == ArenaDtorNeeds::kNone) { + return; } + + Formatter format(printer, variables_); + // _this is the object being destructed (we are inside a static method here). + format("_this->$field$.Destruct();\n"); +} + +ArenaDtorNeeds MapFieldGenerator::NeedsArenaDestructor() const { + return HasDescriptorMethods(descriptor_->file(), options_) + ? ArenaDtorNeeds::kRequired + : ArenaDtorNeeds::kNone; } } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h index c01ae498b1a..9e71267c0f1 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -62,7 +62,9 @@ class MapFieldGenerator : public FieldGenerator { void GenerateByteSize(io::Printer* printer) const override; void GenerateIsInitialized(io::Printer* printer) const override; void GenerateConstinitInitializer(io::Printer* printer) const override; - bool GenerateArenaDestructorCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateArenaDestructorCode(io::Printer* printer) const override; + ArenaDtorNeeds NeedsArenaDestructor() const override; private: const bool has_required_fields_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc index 4b5e0f2e95c..a56c6fbda1e 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -44,22 +44,21 @@ #include <vector> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/cpp/cpp_enum.h> -#include <google/protobuf/compiler/cpp/cpp_extension.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> -#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/generated_message_table_driven.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/map_entry_lite.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/compiler/cpp/cpp_enum.h> +#include <google/protobuf/compiler/cpp/cpp_extension.h> +#include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> +#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/hash.h> @@ -109,7 +108,7 @@ void PrintPresenceCheck(const Formatter& format, const FieldDescriptor* field, int has_bit_index = has_bit_indices[field->index()]; if (*cached_has_word_index != (has_bit_index / 32)) { *cached_has_word_index = (has_bit_index / 32); - format("cached_has_bits = _has_bits_[$1$];\n", *cached_has_word_index); + format("cached_has_bits = $has_bits$[$1$];\n", *cached_has_word_index); } const TProtoStringType mask = StrCat(strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); @@ -276,8 +275,8 @@ void CollectMapInfo(const Options& options, const Descriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables) { GOOGLE_CHECK(IsMapEntryMessage(descriptor)); std::map<TProtoStringType, TProtoStringType>& vars = *variables; - const FieldDescriptor* key = descriptor->FindFieldByName("key"); - const FieldDescriptor* val = descriptor->FindFieldByName("value"); + const FieldDescriptor* key = descriptor->map_key(); + const FieldDescriptor* val = descriptor->map_value(); vars["key_cpp"] = PrimitiveTypeName(options, key->cpp_type()); switch (val->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: @@ -323,64 +322,6 @@ bool ShouldSerializeInOrder(const Descriptor* descriptor, return true; } -bool TableDrivenParsingEnabled(const Descriptor* descriptor, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - if (!options.table_driven_parsing) { - return false; - } - - // Consider table-driven parsing. We only do this if: - // - We have has_bits for fields. This avoids a check on every field we set - // when are present (the common case). - bool has_hasbit = false; - for (int i = 0; i < descriptor->field_count(); i++) { - if (HasHasbit(descriptor->field(i))) { - has_hasbit = true; - break; - } - } - - if (!has_hasbit) return false; - - const double table_sparseness = 0.5; - int max_field_number = 0; - for (auto field : FieldRange(descriptor)) { - if (max_field_number < field->number()) { - max_field_number = field->number(); - } - - // - There are no weak fields. - if (IsWeak(field, options)) { - return false; - } - - // - There are no lazy fields (they require the non-lite library). - if (IsLazy(field, options, scc_analyzer)) { - return false; - } - } - - // - There range of field numbers is "small" - if (max_field_number >= (2 << 14)) { - return false; - } - - // - Field numbers are relatively dense within the actual number of fields. - // We check for strictly greater than in the case where there are no fields - // (only extensions) so max_field_number == descriptor->field_count() == 0. - if (max_field_number * table_sparseness > descriptor->field_count()) { - return false; - } - - // - This is not a MapEntryMessage. - if (IsMapEntryMessage(descriptor)) { - return false; - } - - return true; -} - bool IsCrossFileMapField(const FieldDescriptor* field) { if (!field->is_map()) { return false; @@ -406,8 +347,8 @@ bool IsRequired(const std::vector<const FieldDescriptor*>& v) { bool HasSingularString(const Descriptor* desc, const Options& options) { for (const auto* field : FieldRange(desc)) { - if (IsString(field, options) && !IsStringInlined(field, options) && - !field->is_repeated() && !field->real_containing_oneof()) { + if (IsString(field, options) && !field->is_repeated() && + !field->real_containing_oneof()) { return true; } } @@ -470,6 +411,7 @@ class ColdChunkSkipper { access_info_map_(options.access_info_map), cold_threshold_(cold_threshold) { SetCommonVars(options, &variables_); + SetCommonMessageDataVariables(&variables_); } // May open an external if check for a batch of cold fields. "from" is the @@ -610,6 +552,8 @@ void GenerateExtensionAnnotations( google::protobuf::FileOptions::LITE_RUNTIME) { return; } + StringPiece tracker = (*variables)["tracker"]; + StringPiece extensions = (*variables)["extensions"]; for (const auto& annotation : accessor_annotations_to_hooks) { const TProtoStringType& annotation_name = annotation.first; const TProtoStringType& listener_call = annotation.second; @@ -619,29 +563,29 @@ void GenerateExtensionAnnotations( // Primitive fields accessors. // "Has" is here as users calling "has" on a repeated field is a mistake. (*variables)[annotation_name] = StrCat( - " _tracker_.", listener_call, - "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), " - "_extensions_, id.default_value_ref()));"); + " ", tracker, ".", listener_call, + "(this, id.number(), _proto_TypeTraits::GetPtr(id.number(), ", + extensions, ", id.default_value_ref()));"); } else if (StrContains(annotation_name, "repeated") && !StrContains(annotation_name, "list") && !StrContains(annotation_name, "size")) { // Repeated index accessors. TProtoStringType str_index = "index"; if (StrContains(annotation_name, "add")) { - str_index = "_extensions_.ExtensionSize(id.number()) - 1"; + str_index = StrCat(extensions, ".ExtensionSize(id.number()) - 1"); } (*variables)[annotation_name] = - StrCat(" _tracker_.", listener_call, + StrCat(" ", tracker, ".", listener_call, "(this, id.number(), " - "_proto_TypeTraits::GetPtr(id.number(), _extensions_, ", - str_index, "));"); + "_proto_TypeTraits::GetPtr(id.number(), ", + extensions, ", ", str_index, "));"); } else if (StrContains(annotation_name, "list") || StrContains(annotation_name, "size")) { // Repeated full accessors. (*variables)[annotation_name] = StrCat( - " _tracker_.", listener_call, - "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), " - "_extensions_));"); + " ", tracker, ".", listener_call, + "(this, id.number(), _proto_TypeTraits::GetRepeatedPtr(id.number(), ", + extensions, "));"); } else { // Generic accessors such as "clear". // TODO(b/190614678): Generalize clear from both repeated and non repeated @@ -673,6 +617,7 @@ MessageGenerator::MessageGenerator( if (!message_layout_helper_) { message_layout_helper_.reset(new PaddingOptimizer()); } + SetCommonMessageDataVariables(&variables_); // Variables that apply to this class variables_["classname"] = classname_; @@ -688,7 +633,8 @@ MessageGenerator::MessageGenerator( if (options.field_listener_options.inject_field_listener_events && descriptor->file()->options().optimize_for() != google::protobuf::FileOptions::LITE_RUNTIME) { - const TProtoStringType injector_template = " _tracker_."; + const TProtoStringType injector_template = + StrCat(" ", variables_["tracker"], "."); MaySetAnnotationVariable(options, "serialize", injector_template, "OnSerialize(this);\n", &variables_); @@ -738,6 +684,9 @@ MessageGenerator::MessageGenerator( if (IsStringInlined(field, options_)) { if (inlined_string_indices_.empty()) { inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit); + // The bitset[0] is for arena dtor tracking. Donating states start from + // bitset[1]; + max_inlined_string_index_++; } inlined_string_indices_[field->index()] = max_inlined_string_index_++; } @@ -758,8 +707,6 @@ MessageGenerator::MessageGenerator( } } - table_driven_ = - TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_); parse_function_generator_.reset(new ParseFunctionGenerator( descriptor_, max_has_bit_index_, has_bit_indices_, inlined_string_indices_, options_, scc_analyzer_, variables_)); @@ -903,7 +850,7 @@ inline bool HasExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { $annotate_extension_has$ - return _extensions_.Has(id.number()); + return $extensions$.Has(id.number()); } template <typename _proto_TypeTraits, @@ -912,7 +859,7 @@ template <typename _proto_TypeTraits, inline void ClearExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { - _extensions_.ClearExtension(id.number()); + $extensions$.ClearExtension(id.number()); $annotate_extension_clear$ } @@ -923,7 +870,7 @@ inline int ExtensionSize( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { $annotate_extension_repeated_size$ - return _extensions_.ExtensionSize(id.number()); + return $extensions$.ExtensionSize(id.number()); } template <typename _proto_TypeTraits, @@ -933,7 +880,7 @@ inline typename _proto_TypeTraits::Singular::ConstType GetExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { $annotate_extension_get$ - return _proto_TypeTraits::Get(id.number(), _extensions_, + return _proto_TypeTraits::Get(id.number(), $extensions$, id.default_value()); } @@ -945,7 +892,7 @@ inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { $annotate_extension_mutable$ return _proto_TypeTraits::Mutable(id.number(), _field_type, - &_extensions_); + &$extensions$); } template <typename _proto_TypeTraits, @@ -955,7 +902,7 @@ inline void SetExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, typename _proto_TypeTraits::Singular::ConstType value) { - _proto_TypeTraits::Set(id.number(), _field_type, value, &_extensions_); + _proto_TypeTraits::Set(id.number(), _field_type, value, &$extensions$); $annotate_extension_set$ } @@ -967,7 +914,7 @@ inline void SetAllocatedExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, typename _proto_TypeTraits::Singular::MutableType value) { _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, - &_extensions_); + &$extensions$); $annotate_extension_set$ } template <typename _proto_TypeTraits, @@ -978,7 +925,7 @@ inline void UnsafeArenaSetAllocatedExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, typename _proto_TypeTraits::Singular::MutableType value) { _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, - value, &_extensions_); + value, &$extensions$); $annotate_extension_set$ } template <typename _proto_TypeTraits, @@ -991,7 +938,7 @@ PROTOBUF_NODISCARD inline $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { $annotate_extension_release$ return _proto_TypeTraits::Release(id.number(), _field_type, - &_extensions_); + &$extensions$); } template <typename _proto_TypeTraits, ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, @@ -1002,7 +949,7 @@ UnsafeArenaReleaseExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { $annotate_extension_release$ return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, - &_extensions_); + &$extensions$); } template <typename _proto_TypeTraits, @@ -1013,7 +960,7 @@ inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, int index) const { $annotate_repeated_extension_get$ - return _proto_TypeTraits::Get(id.number(), _extensions_, index); + return _proto_TypeTraits::Get(id.number(), $extensions$, index); } template <typename _proto_TypeTraits, @@ -1024,7 +971,7 @@ inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, int index) { $annotate_repeated_extension_mutable$ - return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); + return _proto_TypeTraits::Mutable(id.number(), index, &$extensions$); } template <typename _proto_TypeTraits, @@ -1034,7 +981,7 @@ inline void SetExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, int index, typename _proto_TypeTraits::Repeated::ConstType value) { - _proto_TypeTraits::Set(id.number(), index, value, &_extensions_); + _proto_TypeTraits::Set(id.number(), index, value, &$extensions$); $annotate_repeated_extension_set$ } @@ -1045,7 +992,7 @@ inline typename _proto_TypeTraits::Repeated::MutableType AddExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { typename _proto_TypeTraits::Repeated::MutableType to_add = - _proto_TypeTraits::Add(id.number(), _field_type, &_extensions_); + _proto_TypeTraits::Add(id.number(), _field_type, &$extensions$); $annotate_repeated_extension_add_mutable$ return to_add; } @@ -1058,7 +1005,7 @@ inline void AddExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, typename _proto_TypeTraits::Repeated::ConstType value) { _proto_TypeTraits::Add(id.number(), _field_type, _is_packed, value, - &_extensions_); + &$extensions$); $annotate_repeated_extension_add$ } @@ -1070,7 +1017,7 @@ GetRepeatedExtension( const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) const { $annotate_repeated_extension_list$ - return _proto_TypeTraits::GetRepeated(id.number(), _extensions_); + return _proto_TypeTraits::GetRepeated(id.number(), $extensions$); } template <typename _proto_TypeTraits, @@ -1082,7 +1029,7 @@ MutableRepeatedExtension( $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { $annotate_repeated_extension_list_mutable$ return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, - _is_packed, &_extensions_); + _is_packed, &$extensions$); } )"); @@ -1119,7 +1066,7 @@ void MessageGenerator::GenerateSingularFieldHasBits( format( "inline bool $classname$::has_$name$() const {\n" "$annotate_has$" - " return _weak_field_map_.Has($number$);\n" + " return $weak_field_map$.Has($number$);\n" "}\n"); return; } @@ -1133,14 +1080,14 @@ void MessageGenerator::GenerateSingularFieldHasBits( format( "inline bool $classname$::_internal_has_$name$() const {\n" " bool value = " - "(_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"); + "($has_bits$[$has_array_index$] & 0x$has_mask$u) != 0;\n"); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !IsLazy(field, options_, scc_analyzer_)) { // We maintain the invariant that for a submessage x, has_x() returning // true implies that x_ is not null. By giving this information to the // compiler, we allow it to eliminate unnecessary null checks later on. - format(" PROTOBUF_ASSUME(!value || $name$_ != nullptr);\n"); + format(" PROTOBUF_ASSUME(!value || $field$ != nullptr);\n"); } format( @@ -1155,13 +1102,13 @@ void MessageGenerator::GenerateSingularFieldHasBits( if (IsLazy(field, options_, scc_analyzer_)) { format( "inline bool $classname$::_internal_has_$name$() const {\n" - " return !$name$_.IsCleared();\n" + " return !$field$.IsCleared();\n" "}\n"); } else { format( "inline bool $classname$::_internal_has_$name$() const {\n" " return this != internal_default_instance() " - "&& $name$_ != nullptr;\n" + "&& $field$ != nullptr;\n" "}\n"); } format( @@ -1183,7 +1130,7 @@ void MessageGenerator::GenerateOneofHasBits(io::Printer* printer) { " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" "}\n" "inline void $classname$::clear_has_$oneof_name$() {\n" - " _oneof_case_[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" + " $oneof_case$[$oneof_index$] = $cap_oneof_name$_NOT_SET;\n" "}\n"); } } @@ -1229,7 +1176,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, // annotated. format( "inline void $classname$::set_has_$name$() {\n" - " _oneof_case_[$oneof_index$] = k$field_name$;\n" + " $oneof_case$[$oneof_index$] = k$field_name$;\n" "}\n"); } @@ -1264,7 +1211,7 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, format.Set("has_array_index", has_bit_index / 32); format.Set("has_mask", strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8)); - format("_has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"); + format("$has_bits$[$has_array_index$] &= ~0x$has_mask$u;\n"); } } format("$annotate_clear$"); @@ -1298,12 +1245,13 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) { } else { format( "inline int $classname$::_internal_$name$_size() const {\n" - " return $name$_$1$.size();\n" + " return $1$$2$.size();\n" "}\n" "inline int $classname$::$name$_size() const {\n" "$annotate_size$" " return _internal_$name$_size();\n" "}\n", + FieldMemberName(field), IsImplicitWeakField(field, options_, scc_analyzer_) && field->message_type() ? ".weak" @@ -1360,7 +1308,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " ::$proto_ns$::internal::WireFormatLite::$val_wire_type$> " "SuperType;\n" " $classname$();\n" - " explicit constexpr $classname$(\n" + " explicit PROTOBUF_CONSTEXPR $classname$(\n" " ::$proto_ns$::internal::ConstantInitialized);\n" " explicit $classname$(::$proto_ns$::Arena* arena);\n" " void MergeFrom(const $classname$& other);\n" @@ -1432,7 +1380,9 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "" " ::$proto_ns$::Metadata GetMetadata() const final;\n"); } - format("};\n"); + format( + " friend struct ::$tablename$;\n" + "};\n"); return; } @@ -1444,11 +1394,10 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format(" public:\n"); format.Indent(); - if (EnableMessageOwnedArena(descriptor_)) { + if (EnableMessageOwnedArena(descriptor_, options_)) { format( "inline $classname$() : $classname$(" - "::$proto_ns$::Arena::InternalHelper<$classname$>::\n" - " CreateMessageOwnedArena(), true) {}\n"); + "::$proto_ns$::Arena::InternalCreateMessageOwnedArena(), true) {}\n"); } else { format("inline $classname$() : $classname$(nullptr) {}\n"); } @@ -1456,7 +1405,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format("~$classname$() override;\n"); } format( - "explicit constexpr " + "explicit PROTOBUF_CONSTEXPR " "$classname$(::$proto_ns$::internal::ConstantInitialized);\n" "\n" "$classname$(const $classname$& from);\n" @@ -1484,14 +1433,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "}\n" "\n"); - if (options_.table_driven_serialization) { - format( - "private:\n" - "const void* InternalGetTable() const override;\n" - "public:\n" - "\n"); - } - if (PublicUnknownFieldsAccessors(descriptor_)) { format( "inline const $unknown_fields_type$& unknown_fields() const {\n" @@ -1569,16 +1510,16 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_)) { format( "bool PackFrom(const ::$proto_ns$::Message& message) {\n" - " return _any_metadata_.PackFrom(GetArena(), message);\n" + " return $any_metadata$.PackFrom(GetArena(), message);\n" "}\n" "bool PackFrom(const ::$proto_ns$::Message& message,\n" " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " "type_url_prefix) {\n" - " return _any_metadata_.PackFrom(GetArena(), message, " + " return $any_metadata$.PackFrom(GetArena(), message, " "type_url_prefix);\n" "}\n" "bool UnpackTo(::$proto_ns$::Message* message) const {\n" - " return _any_metadata_.UnpackTo(message);\n" + " return $any_metadata$.UnpackTo(message);\n" "}\n" "static bool GetAnyFieldDescriptors(\n" " const ::$proto_ns$::Message& message,\n" @@ -1588,7 +1529,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "!std::is_convertible<T, const ::$proto_ns$::Message&>" "::value>::type>\n" "bool PackFrom(const T& message) {\n" - " return _any_metadata_.PackFrom<T>(GetArena(), message);\n" + " return $any_metadata$.PackFrom<T>(GetArena(), message);\n" "}\n" "template <typename T, class = typename std::enable_if<" "!std::is_convertible<T, const ::$proto_ns$::Message&>" @@ -1596,36 +1537,36 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "bool PackFrom(const T& message,\n" " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " "type_url_prefix) {\n" - " return _any_metadata_.PackFrom<T>(GetArena(), message, " + " return $any_metadata$.PackFrom<T>(GetArena(), message, " "type_url_prefix);" "}\n" "template <typename T, class = typename std::enable_if<" "!std::is_convertible<T, const ::$proto_ns$::Message&>" "::value>::type>\n" "bool UnpackTo(T* message) const {\n" - " return _any_metadata_.UnpackTo<T>(message);\n" + " return $any_metadata$.UnpackTo<T>(message);\n" "}\n"); } else { format( "template <typename T>\n" "bool PackFrom(const T& message) {\n" - " return _any_metadata_.PackFrom(GetArena(), message);\n" + " return $any_metadata$.PackFrom(GetArena(), message);\n" "}\n" "template <typename T>\n" "bool PackFrom(const T& message,\n" " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " "type_url_prefix) {\n" - " return _any_metadata_.PackFrom(GetArena(), message, " + " return $any_metadata$.PackFrom(GetArena(), message, " "type_url_prefix);\n" "}\n" "template <typename T>\n" "bool UnpackTo(T* message) const {\n" - " return _any_metadata_.UnpackTo(message);\n" + " return $any_metadata$.UnpackTo(message);\n" "}\n"); } format( "template<typename T> bool Is() const {\n" - " return _any_metadata_.Is<T>();\n" + " return $any_metadata$.Is<T>();\n" "}\n" "static bool ParseAnyTypeUrl(::PROTOBUF_NAMESPACE_ID::ConstStringParam " "type_url,\n" @@ -1732,7 +1673,8 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { if (!HasSimpleBaseClass(descriptor_, options_)) { format( - "int GetCachedSize() const final { return _cached_size_.Get(); }" + "int GetCachedSize() const final { return " + "$cached_size$.Get(); }" "\n\nprivate:\n" "void SharedCtor();\n" "void SharedDtor();\n" @@ -1756,13 +1698,32 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // we rely on. "protected:\n" "explicit $classname$(::$proto_ns$::Arena* arena,\n" - " bool is_message_owned = false);\n" - "private:\n"); + " bool is_message_owned = false);\n"); - if (!HasSimpleBaseClass(descriptor_, options_)) { - format( - "static void ArenaDtor(void* object);\n" - "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n"); + switch (NeedsArenaDestructor()) { + case ArenaDtorNeeds::kOnDemand: + format( + "private:\n" + "static void ArenaDtor(void* object);\n" + "inline void OnDemandRegisterArenaDtor(::$proto_ns$::Arena* arena) " + "override {\n" + " if (arena == nullptr || ($inlined_string_donated_array$[0] & " + "0x1u) " + "== " + "0) {\n" + " return;\n" + " }\n" + " $inlined_string_donated_array$[0] &= 0xFFFFFFFEu;\n" + " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" + "}\n"); + break; + case ArenaDtorNeeds::kRequired: + format( + "private:\n" + "static void ArenaDtor(void* object);\n"); + break; + case ArenaDtorNeeds::kNone: + break; } format( @@ -1866,7 +1827,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // Prepare decls for _cached_size_ and _has_bits_. Their position in the // output will be determined later. - bool need_to_emit_cached_size = true; + bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_); const TProtoStringType cached_size_decl = "mutable ::$proto_ns$::internal::CachedSize _cached_size_;\n"; @@ -1917,8 +1878,10 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // _cached_size_ together with _has_bits_ improves cache locality despite // potential alignment padding. format(has_bits_decl.c_str()); - format(cached_size_decl.c_str()); - need_to_emit_cached_size = false; + if (need_to_emit_cached_size) { + format(cached_size_decl.c_str()); + need_to_emit_cached_size = false; + } } // Field members: @@ -2001,73 +1964,12 @@ void MessageGenerator::GenerateInlineMethods(io::Printer* printer) { "inline $classname$::$camel_oneof_name$Case $classname$::" "${1$$oneof_name$_case$}$() const {\n" " return $classname$::$camel_oneof_name$Case(" - "_oneof_case_[$oneof_index$]);\n" + "$oneof_case$[$oneof_index$]);\n" "}\n", oneof); } } -bool MessageGenerator::GenerateParseTable(io::Printer* printer, size_t offset, - size_t aux_offset) { - Formatter format(printer, variables_); - - if (!table_driven_) { - format("{ nullptr, nullptr, 0, -1, -1, -1, -1, nullptr, false },\n"); - return false; - } - - int max_field_number = 0; - for (auto field : FieldRange(descriptor_)) { - if (max_field_number < field->number()) { - max_field_number = field->number(); - } - } - - format("{\n"); - format.Indent(); - - format( - "$tablename$::entries + $1$,\n" - "$tablename$::aux + $2$,\n" - "$3$,\n", - offset, aux_offset, max_field_number); - - if (has_bit_indices_.empty()) { - // If no fields have hasbits, then _has_bits_ does not exist. - format("-1,\n"); - } else { - format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n"); - } - - if (descriptor_->real_oneof_decl_count() > 0) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_),\n"); - } else { - format("-1, // no _oneof_case_\n"); - } - - if (descriptor_->extension_range_count() > 0) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _extensions_),\n"); - } else { - format("-1, // no _extensions_\n"); - } - - // TODO(ckennelly): Consolidate this with the calculation for - // AuxiliaryParseTableField. - format( - "PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n" - "&$package_ns$::_$classname$_default_instance_,\n"); - - if (UseUnknownFieldSet(descriptor_->file(), options_)) { - format("true,\n"); - } else { - format("false,\n"); - } - - format.Outdent(); - format("},\n"); - return true; -} - void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, int has_offset) { Formatter format(printer, variables_); @@ -2087,218 +1989,6 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, inlined_string_indices_offset); } -namespace { - -// We need to calculate for each field what function the table driven code -// should use to serialize it. This returns the index in a lookup table. -arc_ui32 CalcFieldNum(const FieldGenerator& generator, - const FieldDescriptor* field, const Options& options) { - bool is_a_map = IsMapEntryMessage(field->containing_type()); - int type = field->type(); - if (type == FieldDescriptor::TYPE_STRING || - type == FieldDescriptor::TYPE_BYTES) { - // string field - if (generator.IsInlined()) { - type = internal::FieldMetadata::kInlinedType; - } else if (IsCord(field, options)) { - type = internal::FieldMetadata::kCordType; - } else if (IsStringPiece(field, options)) { - type = internal::FieldMetadata::kStringPieceType; - } - } - - if (field->real_containing_oneof()) { - return internal::FieldMetadata::CalculateType( - type, internal::FieldMetadata::kOneOf); - } else if (field->is_packed()) { - return internal::FieldMetadata::CalculateType( - type, internal::FieldMetadata::kPacked); - } else if (field->is_repeated()) { - return internal::FieldMetadata::CalculateType( - type, internal::FieldMetadata::kRepeated); - } else if (HasHasbit(field) || field->real_containing_oneof() || is_a_map) { - return internal::FieldMetadata::CalculateType( - type, internal::FieldMetadata::kPresence); - } else { - return internal::FieldMetadata::CalculateType( - type, internal::FieldMetadata::kNoPresence); - } -} - -int FindMessageIndexInFile(const Descriptor* descriptor) { - std::vector<const Descriptor*> flatten = - FlattenMessagesInFile(descriptor->file()); - return std::find(flatten.begin(), flatten.end(), descriptor) - - flatten.begin(); -} - -} // namespace - -int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { - Formatter format(printer, variables_); - if (!options_.table_driven_serialization) { - return 0; - } - - std::vector<const FieldDescriptor*> sorted = SortFieldsByNumber(descriptor_); - if (IsMapEntryMessage(descriptor_)) { - for (int i = 0; i < 2; i++) { - const FieldDescriptor* field = sorted[i]; - const FieldGenerator& generator = field_generators_.get(field); - - arc_ui32 tag = internal::WireFormatLite::MakeTag( - field->number(), WireFormat::WireTypeForFieldType(field->type())); - - std::map<TProtoStringType, TProtoStringType> vars; - vars["classtype"] = QualifiedClassName(descriptor_, options_); - vars["field_name"] = FieldName(field); - vars["tag"] = StrCat(tag); - vars["hasbit"] = StrCat(i); - vars["type"] = StrCat(CalcFieldNum(generator, field, options_)); - vars["ptr"] = "nullptr"; - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); - vars["ptr"] = - "::" + UniqueName("TableStruct", field->message_type(), options_) + - "::serialization_table + " + - StrCat(FindMessageIndexInFile(field->message_type())); - } - Formatter::SaveState saver(&format); - format.AddMap(vars); - format( - "{PROTOBUF_FIELD_OFFSET(" - "::$proto_ns$::internal::MapEntryHelper<$classtype$::" - "SuperType>, $field_name$_), $tag$," - "PROTOBUF_FIELD_OFFSET(" - "::$proto_ns$::internal::MapEntryHelper<$classtype$::" - "SuperType>, _has_bits_) * 8 + $hasbit$, $type$, " - "$ptr$},\n"); - } - return 2; - } - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, _cached_size_)," - " 0, 0, 0, nullptr},\n"); - std::vector<const Descriptor::ExtensionRange*> sorted_extensions; - sorted_extensions.reserve(descriptor_->extension_range_count()); - for (int i = 0; i < descriptor_->extension_range_count(); ++i) { - sorted_extensions.push_back(descriptor_->extension_range(i)); - } - std::sort(sorted_extensions.begin(), sorted_extensions.end(), - ExtensionRangeSorter()); - for (int i = 0, extension_idx = 0; /* no range */; i++) { - for (; extension_idx < sorted_extensions.size() && - (i == sorted.size() || - sorted_extensions[extension_idx]->start < sorted[i]->number()); - extension_idx++) { - const Descriptor::ExtensionRange* range = - sorted_extensions[extension_idx]; - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, _extensions_), " - "$1$, $2$, ::$proto_ns$::internal::FieldMetadata::kSpecial, " - "reinterpret_cast<const " - "void*>(::$proto_ns$::internal::ExtensionSerializer)},\n", - range->start, range->end); - } - if (i == sorted.size()) break; - const FieldDescriptor* field = sorted[i]; - - arc_ui32 tag = internal::WireFormatLite::MakeTag( - field->number(), WireFormat::WireTypeForFieldType(field->type())); - if (field->is_packed()) { - tag = internal::WireFormatLite::MakeTag( - field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED); - } - - TProtoStringType classfieldname = FieldName(field); - if (field->real_containing_oneof()) { - classfieldname = field->containing_oneof()->name(); - } - format.Set("field_name", classfieldname); - TProtoStringType ptr = "nullptr"; - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (IsMapEntryMessage(field->message_type())) { - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$, $2$, " - "::$proto_ns$::internal::FieldMetadata::kSpecial, " - "reinterpret_cast<const void*>(static_cast< " - "::$proto_ns$::internal::SpecialSerializer>(" - "::$proto_ns$::internal::MapFieldSerializer< " - "::$proto_ns$::internal::MapEntryToMapField<" - "$3$>::MapFieldType, " - "$tablename$::serialization_table>))},\n", - tag, FindMessageIndexInFile(field->message_type()), - QualifiedClassName(field->message_type(), options_)); - continue; - } else if (!field->message_type()->options().message_set_wire_format()) { - // message_set doesn't have the usual table and we need to - // dispatch to generated serializer, hence ptr stays zero. - ptr = - "::" + UniqueName("TableStruct", field->message_type(), options_) + - "::serialization_table + " + - StrCat(FindMessageIndexInFile(field->message_type())); - } - } - - const FieldGenerator& generator = field_generators_.get(field); - int type = CalcFieldNum(generator, field, options_); - - if (IsLazy(field, options_, scc_analyzer_)) { - type = internal::FieldMetadata::kSpecial; - ptr = "reinterpret_cast<const void*>(::" + variables_["proto_ns"] + - "::internal::LazyFieldSerializer"; - if (field->real_containing_oneof()) { - ptr += "OneOf"; - } else if (!HasHasbit(field)) { - ptr += "NoPresence"; - } - ptr += ")"; - } - - if (field->options().weak()) { - // TODO(gerbens) merge weak fields into ranges - format( - "{PROTOBUF_FIELD_OFFSET(" - "$classtype$, _weak_field_map_), $1$, $1$, " - "::$proto_ns$::internal::FieldMetadata::kSpecial, " - "reinterpret_cast<const " - "void*>(::$proto_ns$::internal::WeakFieldSerializer)},\n", - tag); - } else if (field->real_containing_oneof()) { - format.Set("oneofoffset", - sizeof(arc_ui32) * field->containing_oneof()->index()); - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), $1$," - " PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_) + " - "$oneofoffset$, $2$, $3$},\n", - tag, type, ptr); - } else if (HasHasbit(field)) { - format.Set("hasbitsoffset", has_bit_indices_[field->index()]); - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), " - "$1$, PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_) * 8 + " - "$hasbitsoffset$, $2$, $3$},\n", - tag, type, ptr); - } else { - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, $field_name$_), " - "$1$, ~0u, $2$, $3$},\n", - tag, type, ptr); - } - } - int num_field_metadata = 1 + sorted.size() + sorted_extensions.size(); - num_field_metadata++; - TProtoStringType serializer = UseUnknownFieldSet(descriptor_->file(), options_) - ? "UnknownFieldSetSerializer" - : "UnknownFieldSerializerLite"; - format( - "{PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_), 0, ~0u, " - "::$proto_ns$::internal::FieldMetadata::kSpecial, reinterpret_cast<const " - "void*>(::$proto_ns$::internal::$1$)},\n", - serializer); - return num_field_metadata; -} - void MessageGenerator::GenerateClassMethods(io::Printer* printer) { Formatter format(printer, variables_); if (IsMapEntryMessage(descriptor_)) { @@ -2314,7 +2004,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format( "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" "$annotate_reflection$" - " return ::$proto_ns$::internal::AssignDescriptors(\n" + " return ::_pbi::AssignDescriptors(\n" " &$desc_table$_getter, &$desc_table$_once,\n" " $file_level_metadata$[$1$]);\n" "}\n", @@ -2322,7 +2012,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { } else { format( "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" - " return ::$proto_ns$::internal::AssignDescriptors(\n" + " return ::_pbi::AssignDescriptors(\n" " &$desc_table$_getter, &$desc_table$_once,\n" " $file_level_metadata$[$1$]);\n" "}\n", @@ -2339,7 +2029,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { " const ::$proto_ns$::Message& message,\n" " const ::$proto_ns$::FieldDescriptor** type_url_field,\n" " const ::$proto_ns$::FieldDescriptor** value_field) {\n" - " return ::$proto_ns$::internal::GetAnyFieldDescriptors(\n" + " return ::_pbi::GetAnyFieldDescriptors(\n" " message, type_url_field, value_field);\n" "}\n"); } @@ -2347,8 +2037,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { "bool $classname$::ParseAnyTypeUrl(\n" " ::PROTOBUF_NAMESPACE_ID::ConstStringParam type_url,\n" " TProtoStringType* full_type_name) {\n" - " return ::$proto_ns$::internal::ParseAnyTypeUrl(type_url,\n" - " full_type_name);\n" + " return ::_pbi::ParseAnyTypeUrl(type_url, full_type_name);\n" "}\n" "\n"); } @@ -2359,7 +2048,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format.Indent(); if (!has_bit_indices_.empty()) { format( - "using HasBits = decltype(std::declval<$classname$>()._has_bits_);\n"); + "using HasBits = " + "decltype(std::declval<$classname$>().$has_bits$);\n"); } for (auto field : FieldRange(descriptor_)) { field_generators_.get(field).GenerateInternalAccessorDeclarations(printer); @@ -2455,20 +2145,12 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { GenerateSwap(printer); format("\n"); - if (options_.table_driven_serialization) { - format( - "const void* $classname$::InternalGetTable() const {\n" - " return ::$tablename$::serialization_table + $1$;\n" - "}\n" - "\n", - index_in_file_messages_); - } if (HasDescriptorMethods(descriptor_->file(), options_)) { if (!descriptor_->options().map_entry()) { format( "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" "$annotate_reflection$" - " return ::$proto_ns$::internal::AssignDescriptors(\n" + " return ::_pbi::AssignDescriptors(\n" " &$desc_table$_getter, &$desc_table$_once,\n" " $file_level_metadata$[$1$]);\n" "}\n", @@ -2476,7 +2158,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { } else { format( "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" - " return ::$proto_ns$::internal::AssignDescriptors(\n" + " return ::_pbi::AssignDescriptors(\n" " &$desc_table$_getter, &$desc_table$_once,\n" " $file_level_metadata$[$1$]);\n" "}\n", @@ -2495,234 +2177,40 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { google::protobuf::FileOptions::LITE_RUNTIME) { format( "::$proto_ns$::AccessListener<$classtype$> " - "$1$::_tracker_(&FullMessageName);\n", + "$1$::$tracker$(&FullMessageName);\n", ClassName(descriptor_)); } } -size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { - Formatter format(printer, variables_); - - if (!table_driven_) { - return 0; - } - - // Field "0" is special: We use it in our switch statement of processing - // types to handle the successful end tag case. - format("{0, 0, 0, ::$proto_ns$::internal::kInvalidMask, 0, 0},\n"); - int last_field_number = 1; - - std::vector<const FieldDescriptor*> ordered_fields = - SortFieldsByNumber(descriptor_); - - for (auto field : ordered_fields) { - Formatter::SaveState saver(&format); - GOOGLE_CHECK_GE(field->number(), last_field_number); - - for (; last_field_number < field->number(); last_field_number++) { - format( - "{ 0, 0, ::$proto_ns$::internal::kInvalidMask,\n" - " ::$proto_ns$::internal::kInvalidMask, 0, 0 },\n"); - } - last_field_number++; - - unsigned char normal_wiretype, packed_wiretype, processing_type; - normal_wiretype = WireFormat::WireTypeForFieldType(field->type()); - - if (field->is_packable()) { - packed_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; - } else { - packed_wiretype = internal::kNotPackedMask; - } - - processing_type = static_cast<unsigned>(field->type()); - const FieldGenerator& generator = field_generators_.get(field); - if (field->type() == FieldDescriptor::TYPE_STRING) { - switch (EffectiveStringCType(field, options_)) { - case FieldOptions::STRING: - if (generator.IsInlined()) { - processing_type = internal::TYPE_STRING_INLINED; - } - break; - case FieldOptions::CORD: - processing_type = internal::TYPE_STRING_CORD; - break; - case FieldOptions::STRING_PIECE: - processing_type = internal::TYPE_STRING_STRING_PIECE; - break; - } - } else if (field->type() == FieldDescriptor::TYPE_BYTES) { - switch (EffectiveStringCType(field, options_)) { - case FieldOptions::STRING: - if (generator.IsInlined()) { - processing_type = internal::TYPE_BYTES_INLINED; - } - break; - case FieldOptions::CORD: - processing_type = internal::TYPE_BYTES_CORD; - break; - case FieldOptions::STRING_PIECE: - processing_type = internal::TYPE_BYTES_STRING_PIECE; - break; - } - } - - processing_type |= static_cast<unsigned>( - field->is_repeated() ? internal::kRepeatedMask : 0); - processing_type |= static_cast<unsigned>( - field->real_containing_oneof() ? internal::kOneofMask : 0); - - if (field->is_map()) { - processing_type = internal::TYPE_MAP; - } - - const unsigned char tag_size = - WireFormat::TagSize(field->number(), field->type()); - - std::map<TProtoStringType, TProtoStringType> vars; - if (field->real_containing_oneof()) { - vars["name"] = field->containing_oneof()->name(); - vars["presence"] = StrCat(field->containing_oneof()->index()); - } else { - vars["name"] = FieldName(field); - vars["presence"] = StrCat(has_bit_indices_[field->index()]); - } - vars["nwtype"] = StrCat(normal_wiretype); - vars["pwtype"] = StrCat(packed_wiretype); - vars["ptype"] = StrCat(processing_type); - vars["tag_size"] = StrCat(tag_size); - - format.AddMap(vars); - - format( - "{\n" - " PROTOBUF_FIELD_OFFSET($classtype$, $name$_),\n" - " static_cast<$uint32$>($presence$),\n" - " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" - "},\n"); - } - - return last_field_number; -} - -size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { - Formatter format(printer, variables_); - - if (!table_driven_) { - return 0; - } - - std::vector<const FieldDescriptor*> ordered_fields = - SortFieldsByNumber(descriptor_); - - format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); - int last_field_number = 1; - for (auto field : ordered_fields) { - Formatter::SaveState saver(&format); - - GOOGLE_CHECK_GE(field->number(), last_field_number); - for (; last_field_number < field->number(); last_field_number++) { - format("::$proto_ns$::internal::AuxiliaryParseTableField(),\n"); - } - - std::map<TProtoStringType, TProtoStringType> vars; - SetCommonFieldVariables(field, &vars, options_); - format.AddMap(vars); - - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_ENUM: - if (HasPreservingUnknownEnumSemantics(field)) { - format( - "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{" - "nullptr}},\n"); - } else { - format( - "{::$proto_ns$::internal::AuxiliaryParseTableField::enum_aux{" - "$1$_IsValid}},\n", - ClassName(field->enum_type(), true)); - } - last_field_number++; - break; - case FieldDescriptor::CPPTYPE_MESSAGE: { - if (field->is_map()) { - format( - "{::$proto_ns$::internal::AuxiliaryParseTableField::map_" - "aux{&::$proto_ns$::internal::ParseMap<$1$>}},\n", - QualifiedClassName(field->message_type(), options_)); - last_field_number++; - break; - } - format.Set("field_classname", ClassName(field->message_type(), false)); - format.Set("default_instance", QualifiedDefaultInstanceName( - field->message_type(), options_)); - - format( - "{::$proto_ns$::internal::AuxiliaryParseTableField::message_aux{\n" - " &$default_instance$}},\n"); - last_field_number++; - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - TProtoStringType default_val; - switch (EffectiveStringCType(field, options_)) { - case FieldOptions::STRING: - default_val = field->default_value_string().empty() - ? "&::" + variables_["proto_ns"] + - "::internal::fixed_address_empty_string" - : "&" + - QualifiedClassName(descriptor_, options_) + - "::" + MakeDefaultName(field); - break; - case FieldOptions::CORD: - case FieldOptions::STRING_PIECE: - default_val = - "\"" + CEscape(field->default_value_string()) + "\""; - break; - } - format( - "{::$proto_ns$::internal::AuxiliaryParseTableField::string_aux{\n" - " $1$,\n" - " \"$2$\"\n" - "}},\n", - default_val, field->full_name()); - last_field_number++; - break; - } - default: - break; - } - } - - return last_field_number; -} - std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( io::Printer* printer) { Formatter format(printer, variables_); if (!has_bit_indices_.empty() || IsMapEntryMessage(descriptor_)) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _has_bits_),\n"); + format("PROTOBUF_FIELD_OFFSET($classtype$, $has_bits$),\n"); } else { format("~0u, // no _has_bits_\n"); } format("PROTOBUF_FIELD_OFFSET($classtype$, _internal_metadata_),\n"); if (descriptor_->extension_range_count() > 0) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _extensions_),\n"); + format("PROTOBUF_FIELD_OFFSET($classtype$, $extensions$),\n"); } else { format("~0u, // no _extensions_\n"); } if (descriptor_->real_oneof_decl_count() > 0) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _oneof_case_[0]),\n"); + format("PROTOBUF_FIELD_OFFSET($classtype$, $oneof_case$[0]),\n"); } else { format("~0u, // no _oneof_case_\n"); } if (num_weak_fields_ > 0) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _weak_field_map_),\n"); + format("PROTOBUF_FIELD_OFFSET($classtype$, $weak_field_map$),\n"); } else { format("~0u, // no _weak_field_map_\n"); } if (!inlined_string_indices_.empty()) { - format("PROTOBUF_FIELD_OFFSET($classtype$, _inlined_string_donated_),\n"); + format( + "PROTOBUF_FIELD_OFFSET($classtype$, " + "$inlined_string_donated_array$),\n"); } else { format("~0u, // no _inlined_string_donated_\n"); } @@ -2740,9 +2228,9 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( if (field->options().weak() || field->real_containing_oneof()) { // Mark the field to prevent unintentional access through reflection. // Don't use the top bit because that is for unused fields. - format("::$proto_ns$::internal::kInvalidFieldOffsetTag"); + format("::_pbi::kInvalidFieldOffsetTag"); } else { - format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field)); + format("PROTOBUF_FIELD_OFFSET($classtype$, $1$)", FieldMemberName(field)); } // Some information about a field is in the pdproto profile. The profile is @@ -2750,11 +2238,6 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( // offset of the field, so that the information is available when // reflectively accessing the field at run time. // - // Embed whether the field is used to the MSB of the offset. - if (!IsFieldUsed(field, options_)) { - format(" | 0x80000000u // unused\n"); - } - // Embed whether the field is eagerly verified lazy or inlined string to the // LSB of the offset. if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { @@ -2787,11 +2270,12 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( } if (!inlined_string_indices_.empty()) { entries += inlined_string_indices_.size(); - for (int inlined_string_indice : inlined_string_indices_) { - const TProtoStringType index = inlined_string_indice >= 0 - ? StrCat(inlined_string_indice) - : "~0u"; - format("$1$,\n", index); + for (int inlined_string_index : inlined_string_indices_) { + const TProtoStringType index = + inlined_string_index >= 0 + ? StrCat(inlined_string_index, ", // inlined_string_index") + : "~0u,"; + format("$1$\n", index); } } @@ -2837,7 +2321,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { } if (num_weak_fields_) { - format("_weak_field_map_.ClearAll();\n"); + format("$weak_field_map$.ClearAll();\n"); } format.Outdent(); format( @@ -2845,8 +2329,20 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { "\n"); } +ArenaDtorNeeds MessageGenerator::NeedsArenaDestructor() const { + if (HasSimpleBaseClass(descriptor_, options_)) return ArenaDtorNeeds::kNone; + ArenaDtorNeeds needs = ArenaDtorNeeds::kNone; + for (const auto* field : FieldRange(descriptor_)) { + if (IsFieldStripped(field, options_)) continue; + needs = + std::max(needs, field_generators_.get(field).NeedsArenaDestructor()); + } + return needs; +} + void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { - if (HasSimpleBaseClass(descriptor_, options_)) return; + GOOGLE_CHECK(NeedsArenaDestructor() > ArenaDtorNeeds::kNone); + Formatter format(printer, variables_); // Generate the ArenaDtor() method. Track whether any fields actually produced @@ -2858,56 +2354,33 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { // since that simplifies Arena's destructor list (ordinary function pointers // rather than member function pointers). _this is the object being // destructed. - format( - "$classname$* _this = reinterpret_cast< $classname$* >(object);\n" - // avoid an "unused variable" warning in case no fields have dtor code. - "(void)_this;\n"); + format("$classname$* _this = reinterpret_cast< $classname$* >(object);\n"); - bool need_registration = false; // Process non-oneof fields first. for (auto field : optimized_order_) { - if (field_generators_.get(field).GenerateArenaDestructorCode(printer)) { - need_registration = true; - } + if (IsFieldStripped(field, options_)) continue; + const FieldGenerator& fg = field_generators_.get(field); + fg.GenerateArenaDestructorCode(printer); } // Process oneof fields. - // - // Note: As of 10/5/2016, GenerateArenaDestructorCode does not emit anything - // and returns false for oneof fields. for (auto oneof : OneOfRange(descriptor_)) { for (auto field : FieldRange(oneof)) { - if (!IsFieldStripped(field, options_) && - field_generators_.get(field).GenerateArenaDestructorCode(printer)) { - need_registration = true; - } + if (IsFieldStripped(field, options_)) continue; + field_generators_.get(field).GenerateArenaDestructorCode(printer); } } format.Outdent(); format("}\n"); - - if (need_registration) { - format( - "inline void $classname$::RegisterArenaDtor(::$proto_ns$::Arena* " - "arena) {\n" - " if (arena != nullptr) {\n" - " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" - " }\n" - "}\n"); - } else { - format( - "void $classname$::RegisterArenaDtor(::$proto_ns$::Arena*) {\n" - "}\n"); - } } void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { Formatter format(printer, variables_); format( - "constexpr $classname$::$classname$(\n" - " ::$proto_ns$::internal::ConstantInitialized)"); + "PROTOBUF_CONSTEXPR $classname$::$classname$(\n" + " ::_pbi::ConstantInitialized)"); format.Indent(); const char* field_sep = ":"; const auto put_sep = [&] { @@ -2953,16 +2426,16 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, TProtoStringType pod_template; if (copy_constructor) { pod_template = - "::memcpy(&$first$_, &from.$first$_,\n" - " static_cast<size_t>(reinterpret_cast<char*>(&$last$_) -\n" - " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n"; + "::memcpy(&$first$, &from.$first$,\n" + " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" + " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; } else { pod_template = "::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(\n" - " reinterpret_cast<char*>(&$first$_) - " + " reinterpret_cast<char*>(&$first$) - " "reinterpret_cast<char*>(this)),\n" - " 0, static_cast<size_t>(reinterpret_cast<char*>(&$last$_) -\n" - " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n"; + " 0, static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" + " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; } for (int i = 0; i < optimized_order_.size(); ++i) { @@ -2978,9 +2451,9 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, if (it != runs.end() && it->second > 1) { // Use a memset, then skip run_length fields. const size_t run_length = it->second; - const TProtoStringType first_field_name = FieldName(field); + const TProtoStringType first_field_name = FieldMemberName(field); const TProtoStringType last_field_name = - FieldName(optimized_order_[i + run_length - 1]); + FieldMemberName(optimized_order_[i + run_length - 1]); format.Set("first", first_field_name); format.Set("last", last_field_name); @@ -3049,19 +2522,37 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { if (!inlined_string_indices_.empty()) { // Donate inline string fields. - format(" if (arena != nullptr) {\n"); - for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) { - format(" _inlined_string_donated_[$1$] = ~0u;\n", i); + format.Indent(); + // The last bit is the tracking bit for registering ArenaDtor. The bit is 1 + // means ArenaDtor is not registered on construction, and on demand register + // is needed. + format("if (arena != nullptr) {\n"); + if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) { + format( + " if (!is_message_owned) {\n" + " $inlined_string_donated_array$[0] = ~0u;\n" + " } else {\n" + // We should not register ArenaDtor for MOA. + " $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" + " }\n"); + } else { + format(" $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n"); } - format(" }\n"); + for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) { + format(" $inlined_string_donated_array$[$1$] = ~0u;\n", i); + } + format("}\n"); + format.Outdent(); } if (!HasSimpleBaseClass(descriptor_, options_)) { - format( - " SharedCtor();\n" - " if (!is_message_owned) {\n" - " RegisterArenaDtor(arena);\n" - " }\n"); + format(" SharedCtor();\n"); + if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) { + format( + " if (arena != nullptr && !is_message_owned) {\n" + " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n" + " }\n"); + } } format( " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" @@ -3126,8 +2617,8 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { format( - "_extensions_.MergeFrom(internal_default_instance(), " - "from._extensions_);\n"); + "$extensions$.MergeFrom(internal_default_instance(), " + "from.$extensions$);\n"); } GenerateConstructorBody(printer, processed, true); @@ -3172,10 +2663,19 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { if (!HasSimpleBaseClass(descriptor_, options_)) { format( "$classname$::~$classname$() {\n" - " // @@protoc_insertion_point(destructor:$full_name$)\n" - " if (GetArenaForAllocation() != nullptr) return;\n" + " // @@protoc_insertion_point(destructor:$full_name$)\n"); + format( + " if (auto *arena = " + "_internal_metadata_.DeleteReturnArena<$unknown_fields_type$>()) {\n" + " (void)arena;\n"); + if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { + format(" ArenaDtor(this);\n"); + } + format( + " return;\n" + " }\n"); + format( " SharedDtor();\n" - " _internal_metadata_.Delete<$unknown_fields_type$>();\n" "}\n" "\n"); } else { @@ -3190,13 +2690,15 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { GenerateSharedDestructorCode(printer); // Generate the arena-specific destructor code. - GenerateArenaDestructorCode(printer); + if (NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { + GenerateArenaDestructorCode(printer); + } if (!HasSimpleBaseClass(descriptor_, options_)) { // Generate SetCachedSize. format( "void $classname$::SetCachedSize(int size) const {\n" - " _cached_size_.Set(size);\n" + " $cached_size$.Set(size);\n" "}\n"); } } @@ -3205,8 +2707,8 @@ void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { Formatter format(printer, variables_); format( "template<> " - "PROTOBUF_NOINLINE " - "$classtype$* Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n" + "PROTOBUF_NOINLINE $classtype$*\n" + "Arena::CreateMaybeMessage< $classtype$ >(Arena* arena) {\n" " return Arena::CreateMessageInternal< $classtype$ >(arena);\n" "}\n"); } @@ -3232,7 +2734,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { "(void) cached_has_bits;\n\n"); if (descriptor_->extension_range_count() > 0) { - format("_extensions_.Clear();\n"); + format("$extensions$.Clear();\n"); } // Collect fields into chunks. Each chunk may have an if() condition that @@ -3305,7 +2807,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); - format("cached_has_bits = _has_bits_[$1$];\n", cached_has_word_index); + format("cached_has_bits = $has_bits$[$1$];\n", cached_has_word_index); } format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str); format.Indent(); @@ -3318,10 +2820,10 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { .GenerateMessageClearingCode(printer); } else { format( - "::memset(&$1$_, 0, static_cast<size_t>(\n" - " reinterpret_cast<char*>(&$2$_) -\n" - " reinterpret_cast<char*>(&$1$_)) + sizeof($2$_));\n", - FieldName(memset_start), FieldName(memset_end)); + "::memset(&$1$, 0, static_cast<size_t>(\n" + " reinterpret_cast<char*>(&$2$) -\n" + " reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n", + FieldMemberName(memset_start), FieldMemberName(memset_end)); } } @@ -3367,14 +2869,14 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { } if (num_weak_fields_) { - format("_weak_field_map_.ClearAll();\n"); + format("$weak_field_map$.ClearAll();\n"); } // We don't clear donated status. if (!has_bit_indices_.empty()) { // Step 5: Everything else. - format("_has_bits_.Clear();\n"); + format("$has_bits$.Clear();\n"); } std::map<TProtoStringType, TProtoStringType> vars; @@ -3420,7 +2922,7 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { format.Outdent(); format( "}\n" - "_oneof_case_[$1$] = $2$_NOT_SET;\n", + "$oneof_case$[$1$] = $2$_NOT_SET;\n", i, ToUpper(oneof->name())); format.Outdent(); format( @@ -3440,7 +2942,9 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { if (HasGeneratedMethods(descriptor_->file(), options_)) { if (descriptor_->extension_range_count() > 0) { - format("_extensions_.InternalSwap(&other->_extensions_);\n"); + format( + "$extensions$.InternalSwap(&other->$extensions$);" + "\n"); } std::map<TProtoStringType, TProtoStringType> vars; @@ -3455,7 +2959,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { if (!has_bit_indices_.empty()) { for (int i = 0; i < HasBitsSize(); ++i) { - format("swap(_has_bits_[$1$], other->_has_bits_[$1$]);\n", i); + format("swap($has_bits$[$1$], other->$has_bits$[$1$]);\n", i); } } @@ -3475,20 +2979,20 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { if (it != runs.end() && it->second > 1) { // Use a memswap, then skip run_length fields. const size_t run_length = it->second; - const TProtoStringType first_field_name = FieldName(field); + const TProtoStringType first_field_name = FieldMemberName(field); const TProtoStringType last_field_name = - FieldName(optimized_order_[i + run_length - 1]); + FieldMemberName(optimized_order_[i + run_length - 1]); format.Set("first", first_field_name); format.Set("last", last_field_name); format( "::PROTOBUF_NAMESPACE_ID::internal::memswap<\n" - " PROTOBUF_FIELD_OFFSET($classname$, $last$_)\n" - " + sizeof($classname$::$last$_)\n" - " - PROTOBUF_FIELD_OFFSET($classname$, $first$_)>(\n" - " reinterpret_cast<char*>(&$first$_),\n" - " reinterpret_cast<char*>(&other->$first$_));\n"); + " PROTOBUF_FIELD_OFFSET($classname$, $last$)\n" + " + sizeof($classname$::$last$)\n" + " - PROTOBUF_FIELD_OFFSET($classname$, $first$)>(\n" + " reinterpret_cast<char*>(&$first$),\n" + " reinterpret_cast<char*>(&other->$first$));\n"); i += run_length - 1; // ++i at the top of the loop. @@ -3502,11 +3006,25 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { } for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { - format("swap(_oneof_case_[$1$], other->_oneof_case_[$1$]);\n", i); + format( + "swap($oneof_case$[$1$], " + "other->$oneof_case$[$1$]);\n", + i); } if (num_weak_fields_) { - format("_weak_field_map_.UnsafeArenaSwap(&other->_weak_field_map_);\n"); + format( + "$weak_field_map$.UnsafeArenaSwap(&other->$weak_field_map$)" + ";\n"); + } + + if (!inlined_string_indices_.empty()) { + for (size_t i = 0; i < InlinedStringDonatedSize(); ++i) { + format( + "swap($inlined_string_donated_array$[$1$], " + "other->$inlined_string_donated_array$[$1$]);\n", + i); + } } } else { format("GetReflection()->Swap(this, other);"); @@ -3549,7 +3067,7 @@ void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { format( "void $classname$::CheckTypeAndMergeFrom(\n" " const ::$proto_ns$::MessageLite& from) {\n" - " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n" + " MergeFrom(*::_pbi::DownCast<const $classname$*>(\n" " &from));\n" "}\n"); } @@ -3619,7 +3137,7 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); - format("cached_has_bits = from._has_bits_[$1$];\n", + format("cached_has_bits = from.$has_bits$[$1$];\n", cached_has_word_index); } @@ -3680,7 +3198,7 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { if (deferred_has_bit_changes) { // Flush the has bits for the primitives we deferred. GOOGLE_CHECK_LE(0, cached_has_word_index); - format("_has_bits_[$1$] |= cached_has_bits;\n", cached_has_word_index); + format("$has_bits$[$1$] |= cached_has_bits;\n", cached_has_word_index); } format.Outdent(); @@ -3716,15 +3234,17 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { format("}\n"); } if (num_weak_fields_) { - format("_weak_field_map_.MergeFrom(from._weak_field_map_);\n"); + format( + "$weak_field_map$.MergeFrom(from.$weak_field_map$);" + "\n"); } // Merging of extensions and unknown fields is done last, to maximize // the opportunity for tail calls. if (descriptor_->extension_range_count() > 0) { format( - "_extensions_.MergeFrom(internal_default_instance(), " - "from._extensions_);\n"); + "$extensions$.MergeFrom(internal_default_instance(), " + "from.$extensions$);\n"); } format( @@ -3860,7 +3380,7 @@ void MessageGenerator::GenerateSerializeOneExtensionRange( Formatter format(printer, vars); format("// Extension range [$start$, $end$)\n"); format( - "target = _extensions_._InternalSerialize(\n" + "target = $extensions$._InternalSerialize(\n" "internal_default_instance(), $start$, $end$, target, stream);\n\n"); } @@ -3875,14 +3395,14 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " "const {\n" "$annotate_serialize$" - " target = _extensions_." + " target = $extensions$." "InternalSerializeMessageSetWithCachedSizesToArray(\n" // "internal_default_instance(), target, stream);\n"); std::map<TProtoStringType, TProtoStringType> vars; SetUnknownFieldsVariable(descriptor_, options_, &vars); format.AddMap(vars); format( - " target = ::$proto_ns$::internal::" + " target = ::_pbi::" "InternalSerializeUnknownMessageSetItemsToArray(\n" " $unknown_fields$, target, stream);\n"); format( @@ -4077,8 +3597,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( ExtensionRangeSorter()); if (num_weak_fields_) { format( - "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer(" - "_weak_field_map_);\n"); + "::_pbi::WeakFieldMap::FieldWriter field_writer(" + "$weak_field_map$);\n"); } format( @@ -4126,7 +3646,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( if (UseUnknownFieldSet(descriptor_->file(), options_)) { format( "target = " - "::$proto_ns$::internal::WireFormat::" + "::_pbi::WireFormat::" "InternalSerializeUnknownFieldsToArray(\n" " $unknown_fields$, target, stream);\n"); } else { @@ -4167,8 +3687,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( if (num_weak_fields_) { format( - "::$proto_ns$::internal::WeakFieldMap::FieldWriter field_writer(" - "_weak_field_map_);\n"); + "::_pbi::WeakFieldMap::FieldWriter field_writer(" + "$weak_field_map$);\n"); } format("for (int i = $1$; i >= 0; i-- ) {\n", num_fields - 1); @@ -4218,7 +3738,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBodyShuffled( if (UseUnknownFieldSet(descriptor_->file(), options_)) { format( "target = " - "::$proto_ns$::internal::WireFormat::" + "::_pbi::WireFormat::" "InternalSerializeUnknownFieldsToArray(\n" " $unknown_fields$, target, stream);\n"); } else { @@ -4259,13 +3779,13 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { "size_t $classname$::ByteSizeLong() const {\n" "$annotate_bytesize$" "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " size_t total_size = _extensions_.MessageSetByteSize();\n" + " size_t total_size = $extensions$.MessageSetByteSize();\n" " if ($have_unknown_fields$) {\n" - " total_size += ::$proto_ns$::internal::\n" + " total_size += ::_pbi::\n" " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" " }\n" " int cached_size = " - "::$proto_ns$::internal::ToCachedSize(total_size);\n" + "::_pbi::ToCachedSize(total_size);\n" " SetCachedSize(cached_size);\n" " return total_size;\n" "}\n"); @@ -4312,7 +3832,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { format( - "total_size += _extensions_.ByteSize();\n" + "total_size += $extensions$.ByteSize();\n" "\n"); } @@ -4393,7 +3913,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { if (cached_has_word_index != HasWordIndex(chunk.front())) { cached_has_word_index = HasWordIndex(chunk.front()); - format("cached_has_bits = _has_bits_[$1$];\n", cached_has_word_index); + format("cached_has_bits = $has_bits$[$1$];\n", cached_has_word_index); } format("if (cached_has_bits & 0x$1$u) {\n", chunk_mask_str); format.Indent(); @@ -4473,7 +3993,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { if (num_weak_fields_) { // TagSize + MessageSize - format("total_size += _weak_field_map_.ByteSizeLong();\n"); + format("total_size += $weak_field_map$.ByteSizeLong();\n"); } if (UseUnknownFieldSet(descriptor_->file(), options_)) { @@ -4481,7 +4001,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // unknown fields in tail position. This allows for better code generation // of this function for simple protos. format( - "return MaybeComputeUnknownFieldsSize(total_size, &_cached_size_);\n"); + "return MaybeComputeUnknownFieldsSize(total_size, &$cached_size$);\n"); } else { format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); format(" total_size += $unknown_fields$.size();\n"); @@ -4496,7 +4016,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { // where even relaxed memory order might have perf impact to replace it with // ordinary loads and stores. format( - "int cached_size = ::$proto_ns$::internal::ToCachedSize(total_size);\n" + "int cached_size = ::_pbi::ToCachedSize(total_size);\n" "SetCachedSize(cached_size);\n" "return total_size;\n"); } @@ -4513,14 +4033,14 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { if (descriptor_->extension_range_count() > 0) { format( - "if (!_extensions_.IsInitialized()) {\n" + "if (!$extensions$.IsInitialized()) {\n" " return false;\n" "}\n\n"); } if (num_required_fields_ > 0) { format( - "if (_Internal::MissingRequiredFields(_has_bits_))" + "if (_Internal::MissingRequiredFields($has_bits$))" " return false;\n"); } @@ -4530,7 +4050,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { } if (num_weak_fields_) { // For Weak fields. - format("if (!_weak_field_map_.IsInitialized()) return false;\n"); + format("if (!$weak_field_map$.IsInitialized()) return false;\n"); } // Go through the oneof fields, emitting a switch if any might have required // fields. diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h index 939f21a1dac..5e4bbe84b83 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h @@ -96,22 +96,10 @@ class MessageGenerator { void GenerateFieldAccessorDeclarations(io::Printer* printer); void GenerateFieldAccessorDefinitions(io::Printer* printer); - // Generate the table-driven parsing array. Returns the number of entries - // generated. - size_t GenerateParseOffsets(io::Printer* printer); - size_t GenerateParseAuxTable(io::Printer* printer); - // Generates a ParseTable entry. Returns whether the proto uses - // table-driven parsing. - bool GenerateParseTable(io::Printer* printer, size_t offset, - size_t aux_offset); - // Generate the field offsets array. Returns the a pair of the total number // of entries generated and the index of the first has_bit entry. std::pair<size_t, size_t> GenerateOffsets(io::Printer* printer); void GenerateSchema(io::Printer* printer, int offset, int has_offset); - // For each field generates a table entry describing the field for the - // table driven serializer. - int GenerateFieldMetadata(io::Printer* printer); // Generate constructors and destructor. void GenerateStructors(io::Printer* printer); @@ -177,6 +165,18 @@ class MessageGenerator { std::vector<bool> already_processed, bool copy_constructor) const; + // Returns the level that this message needs ArenaDtor. If the message has + // a field that is not arena-exclusive, it needs an ArenaDtor + // (go/proto-destructor). + // + // - Returning kNone means we don't need to generate ArenaDtor. + // - Returning kOnDemand means we need to generate ArenaDtor, but don't need + // to register ArenaDtor at construction. Such as when the message's + // ArenaDtor code is only for destructing inlined string. + // - Returning kRequired means we meed to generate ArenaDtor and register it + // at construction. + ArenaDtorNeeds NeedsArenaDestructor() const; + size_t HasBitsSize() const; size_t InlinedStringDonatedSize() const; int HasBitIndex(const FieldDescriptor* a) const; @@ -200,7 +200,8 @@ class MessageGenerator { int max_has_bit_index_; // A map from field index to inlined_string index. For non-inlined-string - // fields, the element is -1. + // fields, the element is -1. If there is no inlined string in the message, + // this is empty. std::vector<int> inlined_string_indices_; // The count of inlined_string fields in the message. int max_inlined_string_index_; @@ -209,8 +210,6 @@ class MessageGenerator { std::vector<const ExtensionGenerator*> extension_generators_; int num_required_fields_; int num_weak_fields_; - // table_driven_ indicates the generated message uses table-driven parsing. - bool table_driven_; std::unique_ptr<MessageLayoutHelper> message_layout_helper_; std::unique_ptr<ParseFunctionGenerator> parse_function_generator_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 04f45492c31..3b9f09c8c8b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -33,8 +33,9 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_message_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> + #include <google/protobuf/io/printer.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/stubs/strutil.h> @@ -60,11 +61,16 @@ void SetMessageVariables(const FieldDescriptor* descriptor, SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor, options); (*variables)["casted_member"] = ReinterpretCast( - (*variables)["type"] + "*", (*variables)["name"] + "_", implicit_weak); + (*variables)["type"] + "*", (*variables)["field"], implicit_weak); + (*variables)["casted_member_const"] = + ReinterpretCast("const " + (*variables)["type"] + "&", + "*" + (*variables)["field"], implicit_weak); (*variables)["type_default_instance"] = QualifiedDefaultInstanceName(descriptor->message_type(), options); - (*variables)["type_default_instance_ptr"] = - QualifiedDefaultInstancePtr(descriptor->message_type(), options); + (*variables)["type_default_instance_ptr"] = ReinterpretCast( + "const ::PROTOBUF_NAMESPACE_ID::MessageLite*", + QualifiedDefaultInstancePtr(descriptor->message_type(), options), + implicit_weak); (*variables)["type_reference_function"] = implicit_weak ? (" ::" + (*variables)["proto_ns"] + "::internal::StrongReference(reinterpret_cast<const " + @@ -176,14 +182,13 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( // If we're not on an arena, free whatever we were holding before. // (If we are on arena, we can just forget the earlier pointer.) " if (GetArenaForAllocation() == nullptr) {\n" - " delete reinterpret_cast<::$proto_ns$::MessageLite*>($name$_);\n" + " delete reinterpret_cast<::$proto_ns$::MessageLite*>($field$);\n" " }\n"); if (implicit_weak_field_) { format( - " $name$_ = " - "reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n"); + " $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n"); } else { - format(" $name$_ = $name$;\n"); + format(" $field$ = $name$;\n"); } format( " if ($name$) {\n" @@ -201,7 +206,7 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( "$annotate_release$" " $clear_hasbit$\n" " $type$* temp = $casted_member$;\n" - " $name$_ = nullptr;\n" + " $field$ = nullptr;\n" "#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE\n" " auto* old = reinterpret_cast<::$proto_ns$::MessageLite*>(temp);\n" " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" @@ -219,7 +224,7 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( "$type_reference_function$" " $clear_hasbit$\n" " $type$* temp = $casted_member$;\n" - " $name$_ = nullptr;\n" + " $field$ = nullptr;\n" " return temp;\n" "}\n"); @@ -227,12 +232,12 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( "inline $type$* $classname$::_internal_mutable_$name$() {\n" "$type_reference_function$" " $set_hasbit$\n" - " if ($name$_ == nullptr) {\n" + " if ($field$ == nullptr) {\n" " auto* p = CreateMaybeMessage<$type$>(GetArenaForAllocation());\n"); if (implicit_weak_field_) { - format(" $name$_ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n"); + format(" $field$ = reinterpret_cast<::$proto_ns$::MessageLite*>(p);\n"); } else { - format(" $name$_ = p;\n"); + format(" $field$ = p;\n"); } format( " }\n" @@ -253,9 +258,9 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( format(" if (message_arena == nullptr) {\n"); if (IsCrossFileMessage(descriptor_)) { format( - " delete reinterpret_cast< ::$proto_ns$::MessageLite*>($name$_);\n"); + " delete reinterpret_cast< ::$proto_ns$::MessageLite*>($field$);\n"); } else { - format(" delete $name$_;\n"); + format(" delete $field$;\n"); } format( " }\n" @@ -265,14 +270,13 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( // isn't defined in this file. format( " ::$proto_ns$::Arena* submessage_arena =\n" - " ::$proto_ns$::Arena::InternalHelper<\n" - " ::$proto_ns$::MessageLite>::GetOwningArena(\n" + " ::$proto_ns$::Arena::InternalGetOwningArena(\n" " reinterpret_cast<::$proto_ns$::MessageLite*>(" "$name$));\n"); } else { format( " ::$proto_ns$::Arena* submessage_arena =\n" - " ::$proto_ns$::Arena::InternalHelper<$type$>::GetOwningArena(" + " ::$proto_ns$::Arena::InternalGetOwningArena(" "$name$);\n"); } format( @@ -285,9 +289,9 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions( " $clear_hasbit$\n" " }\n"); if (implicit_weak_field_) { - format(" $name$_ = reinterpret_cast<MessageLite*>($name$);\n"); + format(" $field$ = reinterpret_cast<MessageLite*>($name$);\n"); } else { - format(" $name$_ = $name$;\n"); + format(" $field$ = $name$;\n"); } format( "$annotate_set$" @@ -322,14 +326,10 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions( format( "const ::$proto_ns$::MessageLite& $classname$::_Internal::$name$(\n" " const $classname$* msg) {\n" - " if (msg->$name$_ != nullptr) {\n" - " return *msg->$name$_;\n" - " } else if ($type_default_instance_ptr$ != nullptr) {\n" - " return *reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" - " $type_default_instance_ptr$);\n" + " if (msg->$field$ != nullptr) {\n" + " return *msg->$field$;\n" " } else {\n" - " return " - "*::$proto_ns$::internal::ImplicitWeakMessage::default_instance();\n" + " return *$type_default_instance_ptr$;\n" " }\n" "}\n"); format( @@ -338,20 +338,19 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions( if (HasHasbit(descriptor_)) { format(" msg->$set_hasbit$\n"); } + if (descriptor_->real_containing_oneof() == nullptr) { + format(" if (msg->$field$ == nullptr) {\n"); + } else { + format( + " if (!msg->_internal_has_$name$()) {\n" + " msg->clear_$oneof_name$();\n" + " msg->set_has_$name$();\n"); + } format( - " if (msg->$name$_ == nullptr) {\n" - " if ($type_default_instance_ptr$ == nullptr) {\n" - " msg->$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" - " ::$proto_ns$::internal::ImplicitWeakMessage>(\n" - " msg->GetArenaForAllocation());\n" - " } else {\n" - " msg->$name$_ = \n" - " reinterpret_cast<const ::$proto_ns$::MessageLite*>(\n" - " $type_default_instance_ptr$)->New(\n" - " msg->GetArenaForAllocation());\n" - " }\n" + " msg->$field$ = $type_default_instance_ptr$->New(\n" + " msg->GetArenaForAllocation());\n" " }\n" - " return msg->$name$_;\n" + " return msg->$field$;\n" "}\n"); } else { // This inline accessor directly returns member field and is used in @@ -360,7 +359,7 @@ void MessageFieldGenerator::GenerateInternalAccessorDefinitions( format( "const $type$&\n" "$classname$::_Internal::$name$(const $classname$* msg) {\n" - " return *msg->$field_member$;\n" + " return *msg->$field$;\n" "}\n"); } } @@ -371,14 +370,14 @@ void MessageFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); if (!HasHasbit(descriptor_)) { // If we don't have has-bits, message presence is indicated only by ptr != - // NULL. Thus on clear, we need to delete the object. + // nullptr. Thus on clear, we need to delete the object. format( - "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n" - " delete $name$_;\n" + "if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n" + " delete $field$;\n" "}\n" - "$name$_ = nullptr;\n"); + "$field$ = nullptr;\n"); } else { - format("if ($name$_ != nullptr) $name$_->Clear();\n"); + format("if ($field$ != nullptr) $field$->Clear();\n"); } } @@ -389,16 +388,16 @@ void MessageFieldGenerator::GenerateMessageClearingCode( Formatter format(printer, variables_); if (!HasHasbit(descriptor_)) { // If we don't have has-bits, message presence is indicated only by ptr != - // NULL. Thus on clear, we need to delete the object. + // nullptr. Thus on clear, we need to delete the object. format( - "if (GetArenaForAllocation() == nullptr && $name$_ != nullptr) {\n" - " delete $name$_;\n" + "if (GetArenaForAllocation() == nullptr && $field$ != nullptr) {\n" + " delete $field$;\n" "}\n" - "$name$_ = nullptr;\n"); + "$field$ = nullptr;\n"); } else { format( - "$DCHK$($name$_ != nullptr);\n" - "$name$_->Clear();\n"); + "$DCHK$($field$ != nullptr);\n" + "$field$->Clear();\n"); } } @@ -421,7 +420,7 @@ void MessageFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("swap($name$_, other->$name$_);\n"); + format("swap($field$, other->$field$);\n"); } void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { @@ -436,7 +435,7 @@ void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { // care when handling them. format("if (this != internal_default_instance()) "); } - format("delete $name$_;\n"); + format("delete $field$;\n"); } void MessageFieldGenerator::GenerateConstructorCode( @@ -444,7 +443,7 @@ void MessageFieldGenerator::GenerateConstructorCode( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("$name$_ = nullptr;\n"); + format("$field$ = nullptr;\n"); } void MessageFieldGenerator::GenerateCopyConstructorCode( @@ -454,9 +453,9 @@ void MessageFieldGenerator::GenerateCopyConstructorCode( Formatter format(printer, variables_); format( "if (from._internal_has_$name$()) {\n" - " $name$_ = new $type$(*from.$name$_);\n" + " $field$ = new $type$(*from.$field$);\n" "} else {\n" - " $name$_ = nullptr;\n" + " $field$ = nullptr;\n" "}\n"); } @@ -465,11 +464,18 @@ void MessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format( - "target = stream->EnsureSpace(target);\n" - "target = ::$proto_ns$::internal::WireFormatLite::\n" - " InternalWrite$declared_type$(\n" - " $number$, _Internal::$name$(this), target, stream);\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + format( + "target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, _Internal::$name$(this),\n" + " _Internal::$name$(this).GetCachedSize(), target, stream);\n"); + } else { + format( + "target = stream->EnsureSpace(target);\n" + "target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$(\n" + " $number$, _Internal::$name$(this), target, stream);\n"); + } } void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { @@ -479,7 +485,7 @@ void MessageFieldGenerator::GenerateByteSize(io::Printer* printer) const { format( "total_size += $tag_size$ +\n" " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" - " *$field_member$);\n"); + " *$field$);\n"); } void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { @@ -490,7 +496,7 @@ void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { Formatter format(printer, variables_); format( "if (_internal_has_$name$()) {\n" - " if (!$name$_->IsInitialized()) return false;\n" + " if (!$field$->IsInitialized()) return false;\n" "}\n"); } @@ -524,15 +530,13 @@ void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( // isn't defined in this file. format( " ::$proto_ns$::Arena* submessage_arena =\n" - " ::$proto_ns$::Arena::InternalHelper<\n" - " ::$proto_ns$::MessageLite>::GetOwningArena(\n" + " ::$proto_ns$::Arena::InternalGetOwningArena(\n" " reinterpret_cast<::$proto_ns$::MessageLite*>(" "$name$));\n"); } else { format( " ::$proto_ns$::Arena* submessage_arena =\n" - " ::$proto_ns$::Arena::InternalHelper<" - "$type$>::GetOwningArena($name$);\n"); + " ::$proto_ns$::Arena::InternalGetOwningArena($name$);\n"); } format( " if (message_arena != submessage_arena) {\n" @@ -540,7 +544,7 @@ void MessageOneofFieldGenerator::GenerateNonInlineAccessorDefinitions( " message_arena, $name$, submessage_arena);\n" " }\n" " set_has_$name$();\n" - " $field_member$ = $name$;\n" + " $field$ = $name$;\n" " }\n" "$annotate_set$" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" @@ -554,13 +558,14 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( "inline $type$* $classname$::$release_name$() {\n" "$annotate_release$" " // @@protoc_insertion_point(field_release:$full_name$)\n" + "$type_reference_function$" " if (_internal_has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " $type$* temp = $field_member$;\n" + " $type$* temp = $casted_member$;\n" " if (GetArenaForAllocation() != nullptr) {\n" " temp = ::$proto_ns$::internal::DuplicateIfNonNull(temp);\n" " }\n" - " $field_member$ = nullptr;\n" + " $field$ = nullptr;\n" " return temp;\n" " } else {\n" " return nullptr;\n" @@ -569,8 +574,9 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline const $type$& $classname$::_internal_$name$() const {\n" + "$type_reference_function$" " return _internal_has_$name$()\n" - " ? *$field_member$\n" + " ? $casted_member_const$\n" " : reinterpret_cast< $type$&>($type_default_instance$);\n" "}\n" "inline const $type$& $classname$::$name$() const {\n" @@ -582,10 +588,11 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( "$annotate_release$" " // @@protoc_insertion_point(field_unsafe_arena_release" ":$full_name$)\n" + "$type_reference_function$" " if (_internal_has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " $type$* temp = $field_member$;\n" - " $field_member$ = nullptr;\n" + " $type$* temp = $casted_member$;\n" + " $field$ = nullptr;\n" " return temp;\n" " } else {\n" " return nullptr;\n" @@ -598,21 +605,38 @@ void MessageOneofFieldGenerator::GenerateInlineAccessorDefinitions( // new value. " clear_$oneof_name$();\n" " if ($name$) {\n" - " set_has_$name$();\n" - " $field_member$ = $name$;\n" + " set_has_$name$();\n"); + if (implicit_weak_field_) { + format( + " $field$ = " + "reinterpret_cast<::$proto_ns$::MessageLite*>($name$);\n"); + } else { + format(" $field$ = $name$;\n"); + } + format( " }\n" "$annotate_set$" " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" "$full_name$)\n" "}\n" "inline $type$* $classname$::_internal_mutable_$name$() {\n" + "$type_reference_function$" " if (!_internal_has_$name$()) {\n" " clear_$oneof_name$();\n" - " set_has_$name$();\n" - " $field_member$ = CreateMaybeMessage< $type$ " - ">(GetArenaForAllocation());\n" + " set_has_$name$();\n"); + if (implicit_weak_field_) { + format( + " $field$ = " + "reinterpret_cast<::$proto_ns$::MessageLite*>(CreateMaybeMessage< " + "$type$ >(GetArenaForAllocation()));\n"); + } else { + format( + " $field$ = CreateMaybeMessage< $type$ " + ">(GetArenaForAllocation());\n"); + } + format( " }\n" - " return $field_member$;\n" + " return $casted_member$;\n" "}\n" "inline $type$* $classname$::mutable_$name$() {\n" " $type$* _msg = _internal_mutable_$name$();\n" @@ -629,7 +653,7 @@ void MessageOneofFieldGenerator::GenerateClearingCode( Formatter format(printer, variables_); format( "if (GetArenaForAllocation() == nullptr) {\n" - " delete $field_member$;\n" + " delete $field$;\n" "}\n"); } @@ -662,7 +686,7 @@ void MessageOneofFieldGenerator::GenerateIsInitialized( Formatter format(printer, variables_); format( "if (_internal_has_$name$()) {\n" - " if (!$field_member$->IsInitialized()) return false;\n" + " if (!$field$->IsInitialized()) return false;\n" "}\n"); } @@ -741,21 +765,21 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( // TODO(dlj): move insertion points " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "$type_reference_function$" - " return $name$_$weak$.Mutable(index);\n" + " return $field$$weak$.Mutable(index);\n" "}\n" "inline ::$proto_ns$::RepeatedPtrField< $type$ >*\n" "$classname$::mutable_$name$() {\n" "$annotate_mutable_list$" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" "$type_reference_function$" - " return &$name$_$weak$;\n" + " return &$field$$weak$;\n" "}\n"); if (options_.safe_boundary_check) { format( "inline const $type$& $classname$::_internal_$name$(int index) const " "{\n" - " return $name$_$weak$.InternalCheckedGet(index,\n" + " return $field$$weak$.InternalCheckedGet(index,\n" " reinterpret_cast<const $type$&>($type_default_instance$));\n" "}\n"); } else { @@ -763,7 +787,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( "inline const $type$& $classname$::_internal_$name$(int index) const " "{\n" "$type_reference_function$" - " return $name$_$weak$.Get(index);\n" + " return $field$$weak$.Get(index);\n" "}\n"); } @@ -774,7 +798,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( " return _internal_$name$(index);\n" "}\n" "inline $type$* $classname$::_internal_add_$name$() {\n" - " return $name$_$weak$.Add();\n" + " return $field$$weak$.Add();\n" "}\n" "inline $type$* $classname$::add_$name$() {\n" " $type$* _add = _internal_add_$name$();\n" @@ -789,7 +813,7 @@ void RepeatedMessageFieldGenerator::GenerateInlineAccessorDefinitions( "$annotate_list$" " // @@protoc_insertion_point(field_list:$full_name$)\n" "$type_reference_function$" - " return $name$_$weak$;\n" + " return $field$$weak$;\n" "}\n"); } @@ -798,7 +822,7 @@ void RepeatedMessageFieldGenerator::GenerateClearingCode( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("$name$_.Clear();\n"); + format("$field$.Clear();\n"); } void RepeatedMessageFieldGenerator::GenerateMergingCode( @@ -806,7 +830,7 @@ void RepeatedMessageFieldGenerator::GenerateMergingCode( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("$name$_.MergeFrom(from.$name$_);\n"); + format("$field$.MergeFrom(from.$field$);\n"); } void RepeatedMessageFieldGenerator::GenerateSwappingCode( @@ -814,7 +838,7 @@ void RepeatedMessageFieldGenerator::GenerateSwappingCode( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("$name$_.InternalSwap(&other->$name$_);\n"); + format("$field$.InternalSwap(&other->$field$);\n"); } void RepeatedMessageFieldGenerator::GenerateConstructorCode( @@ -829,23 +853,41 @@ void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( Formatter format(printer, variables_); if (implicit_weak_field_) { format( - "for (auto it = this->$name$_.pointer_begin(),\n" - " end = this->$name$_.pointer_end(); it < end; ++it) {\n" - " target = stream->EnsureSpace(target);\n" - " target = ::$proto_ns$::internal::WireFormatLite::\n" - " InternalWrite$declared_type$($number$, **it, target, stream);\n" - "}\n"); + "for (auto it = this->$field$.pointer_begin(),\n" + " end = this->$field$.pointer_end(); it < end; ++it) {\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + format( + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, " + "**it, (**it).GetCachedSize(), target, stream);\n"); + } else { + format( + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, **it, target, " + "stream);\n"); + } + format("}\n"); } else { format( - "for (unsigned int i = 0,\n" - " n = static_cast<unsigned int>(this->_internal_$name$_size()); i < " - "n; i++) " - "{\n" - " target = stream->EnsureSpace(target);\n" - " target = ::$proto_ns$::internal::WireFormatLite::\n" - " InternalWrite$declared_type$($number$, " - "this->_internal_$name$(i), target, stream);\n" - "}\n"); + "for (unsigned i = 0,\n" + " n = static_cast<unsigned>(this->_internal_$name$_size());" + " i < n; i++) {\n"); + if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { + format( + " const auto& repfield = this->_internal_$name$(i);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, " + "repfield, repfield.GetCachedSize(), target, stream);\n" + "}\n"); + } else { + format( + " target = stream->EnsureSpace(target);\n" + " target = ::$proto_ns$::internal::WireFormatLite::\n" + " InternalWrite$declared_type$($number$, " + "this->_internal_$name$(i), target, stream);\n" + "}\n"); + } } } @@ -856,7 +898,7 @@ void RepeatedMessageFieldGenerator::GenerateByteSize( Formatter format(printer, variables_); format( "total_size += $tag_size$UL * this->_internal_$name$_size();\n" - "for (const auto& msg : this->$name$_) {\n" + "for (const auto& msg : this->$field$) {\n" " total_size +=\n" " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(msg);\n" "}\n"); @@ -871,11 +913,11 @@ void RepeatedMessageFieldGenerator::GenerateIsInitialized( Formatter format(printer, variables_); if (implicit_weak_field_) { format( - "if (!::$proto_ns$::internal::AllAreInitializedWeak($name$_.weak))\n" + "if (!::$proto_ns$::internal::AllAreInitializedWeak($field$.weak))\n" " return false;\n"); } else { format( - "if (!::$proto_ns$::internal::AllAreInitialized($name$_))\n" + "if (!::$proto_ns$::internal::AllAreInitialized($field$))\n" " return false;\n"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h index 2beac6253b9..528b4197048 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -37,6 +37,7 @@ #include <map> #include <string> + #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h index 9d8063d9cab..80860053f17 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h @@ -35,8 +35,8 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ -#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h index 8b745ff21c5..39563cd0cdf 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h @@ -33,6 +33,7 @@ #include <string> +// Must be included last. #include <google/protobuf/port_def.inc> namespace google { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h index 23adb91430e..48512a64c87 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h @@ -58,34 +58,39 @@ struct FieldListenerOptions { // Generator options (see generator.cc for a description of each): struct Options { + const AccessInfoMap* access_info_map = nullptr; TProtoStringType dllexport_decl; + TProtoStringType runtime_include_base; + TProtoStringType annotation_pragma_name; + TProtoStringType annotation_guard_name; + FieldListenerOptions field_listener_options; + EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement; + enum { + kTCTableNever, + kTCTableGuarded, + kTCTableAlways + } tctable_mode = kTCTableNever; + int num_cc_files = 0; bool safe_boundary_check = false; bool proto_h = false; bool transitive_pb_h = true; bool annotate_headers = false; - EnforceOptimizeMode enforce_mode = EnforceOptimizeMode::kNoEnforcement; - bool table_driven_parsing = false; - bool table_driven_serialization = false; bool lite_implicit_weak_fields = false; bool bootstrap = false; bool opensource_runtime = false; bool annotate_accessor = false; bool unused_field_stripping = false; + bool unverified_lazy_message_sets = true; + bool eagerly_verified_lazy = true; bool profile_driven_inline_string = true; - bool force_inline_string = false; - TProtoStringType runtime_include_base; - int num_cc_files = 0; - TProtoStringType annotation_pragma_name; - TProtoStringType annotation_guard_name; - const AccessInfoMap* access_info_map = nullptr; - enum { - kTCTableNever, - kTCTableGuarded, - kTCTableAlways - } tctable_mode = kTCTableNever; - FieldListenerOptions field_listener_options; - bool eagerly_verified_lazy = false; + bool force_split = false; +#ifdef PROTOBUF_STABLE_EXPERIMENTS + bool force_eagerly_verified_lazy = true; + bool force_inline_string = true; +#else // PROTOBUF_STABLE_EXPERIMENTS bool force_eagerly_verified_lazy = false; + bool force_inline_string = false; +#endif // !PROTOBUF_STABLE_EXPERIMENTS }; } // namespace cpp diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc index 0b660c75b7b..f48ba718a54 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc @@ -47,7 +47,7 @@ class FieldGroup { FieldGroup() : preferred_location_(0) {} // A group with a single field. - FieldGroup(float preferred_location, const FieldDescriptor* field) + FieldGroup(double preferred_location, const FieldDescriptor* field) : preferred_location_(preferred_location), fields_(1, field) {} // Append the fields in 'other' to this group. @@ -63,7 +63,7 @@ class FieldGroup { fields_.insert(fields_.end(), other.fields_.begin(), other.fields_.end()); } - void SetPreferredLocation(float location) { preferred_location_ = location; } + void SetPreferredLocation(double location) { preferred_location_ = location; } const std::vector<const FieldDescriptor*>& fields() const { return fields_; } // FieldGroup objects sort by their preferred location. @@ -77,7 +77,7 @@ class FieldGroup { // field in this group in the original ordering of fields. This is very // approximate, but should put this group close to where its member fields // originally went. - float preferred_location_; + double preferred_location_; std::vector<const FieldDescriptor*> fields_; // We rely on the default copy constructor and operator= so this type can be // used in a vector. @@ -203,7 +203,7 @@ void PaddingOptimizer::OptimizeLayout( field_group.SetPreferredLocation(-1); } else { // Move incomplete 4-byte block to the end. - field_group.SetPreferredLocation(fields->size() + 1); + field_group.SetPreferredLocation(double{FieldDescriptor::kMaxNumber}); } } aligned_to_8[f].push_back(field_group); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc index 282d70e3917..e033856f0c7 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc @@ -33,9 +33,10 @@ #include <algorithm> #include <limits> #include <string> +#include <utility> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/wire_format.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { namespace protobuf { @@ -43,7 +44,6 @@ namespace compiler { namespace cpp { namespace { -using google::protobuf::internal::TcFieldData; using google::protobuf::internal::WireFormat; using google::protobuf::internal::WireFormatLite; @@ -73,167 +73,351 @@ int TagSize(arc_ui32 field_number) { return 2; } -const char* CodedTagType(int tag_size) { - return tag_size == 1 ? "uint8_t" : "uint16_t"; -} +TProtoStringType FieldParseFunctionName( + const TailCallTableInfo::FieldEntryInfo& entry, const Options& options); + +bool IsFieldEligibleForFastParsing( + const TailCallTableInfo::FieldEntryInfo& entry, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + const auto* field = entry.field; + // Map, oneof, weak, and lazy fields are not handled on the fast path. + if (field->is_map() || field->real_containing_oneof() || + field->options().weak() || + IsImplicitWeakField(field, options, scc_analyzer) || + IsLazy(field, options, scc_analyzer)) { + return false; + } -const char* TagType(const FieldDescriptor* field) { - return CodedTagType(TagSize(field->number())); -} + // We will check for a valid auxiliary index range later. However, we might + // want to change the value we check for inlined string fields. + int aux_idx = entry.aux_idx; -TProtoStringType TcParserName(const Options& options) { - return StrCat("::", ProtobufNamespace(options), - "::internal::TcParser::"); -} + switch (field->type()) { + case FieldDescriptor::TYPE_ENUM: + // If enum values are not validated at parse time, then this field can be + // handled on the fast path like an int32. + if (HasPreservingUnknownEnumSemantics(field)) { + break; + } + if (field->is_repeated() && field->is_packed()) { + return false; + } + break; + + // Some bytes fields can be handled on fast path. + case FieldDescriptor::TYPE_STRING: + case FieldDescriptor::TYPE_BYTES: + if (field->options().ctype() != FieldOptions::STRING) { + return false; + } + if (IsStringInlined(field, options)) { + GOOGLE_CHECK(!field->is_repeated()); + // For inlined strings, the donation state index is stored in the + // `aux_idx` field of the fast parsing info. We need to check the range + // of that value instead of the auxiliary index. + aux_idx = entry.inlined_string_idx; + } + break; -TProtoStringType MessageTcParseFunctionName(const FieldDescriptor* field, - const Options& options) { - if (field->message_type()->field_count() == 0 || - !HasGeneratedMethods(field->message_type()->file(), options)) { - // For files with `option optimize_for = CODE_SIZE`, or which derive from - // `ZeroFieldsBase`, we need to call the `_InternalParse` function, because - // there is no generated tailcall function. For tailcall parsing, this is - // done by helpers in TcParser. - return StrCat(TcParserName(options), - (field->is_repeated() ? "Repeated" : "Singular"), - "ParseMessage<", - QualifiedClassName(field->message_type()), // - ", ", TagType(field), ">"); + default: + break; } - // This matches macros in generated_message_tctable_impl.h: - return StrCat("PROTOBUF_TC_PARSE_", - (field->is_repeated() ? "REPEATED" : "SINGULAR"), - TagSize(field->number()), "(", - QualifiedClassName(field->message_type()), ")"); + + if (HasHasbit(field)) { + // The tailcall parser can only update the first 32 hasbits. Fields with + // has-bits beyond the first 32 are handled by mini parsing/fallback. + GOOGLE_CHECK_GE(entry.hasbit_idx, 0) << field->DebugString(); + if (entry.hasbit_idx >= 32) return false; + } + + // If the field needs auxiliary data, then the aux index is needed. This + // must fit in a uint8_t. + if (aux_idx > std::numeric_limits<uint8_t>::max()) { + return false; + } + + // The largest tag that can be read by the tailcall parser is two bytes + // when varint-coded. This allows 14 bits for the numeric tag value: + // byte 0 byte 1 + // 1nnnnttt 0nnnnnnn + // ^^^^^^^ ^^^^^^^ + if (field->number() >= 1 << 11) return false; + + return true; } -TProtoStringType FieldParseFunctionName(const FieldDescriptor* field, - const Options& options); +std::vector<TailCallTableInfo::FastFieldInfo> SplitFastFieldsForSize( + const std::vector<TailCallTableInfo::FieldEntryInfo>& field_entries, + int table_size_log2, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + std::vector<TailCallTableInfo::FastFieldInfo> result(1 << table_size_log2); + const arc_ui32 idx_mask = result.size() - 1; -} // namespace + for (const auto& entry : field_entries) { + if (!IsFieldEligibleForFastParsing(entry, options, scc_analyzer)) { + continue; + } -TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, - const Options& options, - const std::vector<int>& has_bit_indices, - MessageSCCAnalyzer* scc_analyzer) { - std::vector<const FieldDescriptor*> ordered_fields = - GetOrderedFields(descriptor, options); - - // The table size is rounded up to the nearest power of 2, clamping at 2^5. - // Note that this is a naive approach: a better approach should only consider - // table-eligible fields. We may also want to push rarely-encountered fields - // into the fallback, to make the table smaller. - table_size_log2 = ordered_fields.size() >= 16 ? 5 - : ordered_fields.size() >= 8 ? 4 - : ordered_fields.size() >= 4 ? 3 - : ordered_fields.size() >= 2 ? 2 - : 1; - const unsigned table_size = 1 << table_size_log2; - - // Construct info for each possible entry. Fields that do not use table-driven - // parsing will still have an entry that nominates the fallback function. - fast_path_fields.resize(table_size); - - for (const auto* field : ordered_fields) { - // Eagerly assume slow path. If we can handle this field on the fast path, - // we will pop its entry from `fallback_fields`. - fallback_fields.push_back(field); - - // Anything difficult slow path: - if (field->is_map()) continue; - if (field->real_containing_oneof()) continue; - if (field->options().weak()) continue; - if (IsImplicitWeakField(field, options, scc_analyzer)) continue; - if (IsLazy(field, options, scc_analyzer)) continue; - - // The largest tag that can be read by the tailcall parser is two bytes - // when varint-coded. This allows 14 bits for the numeric tag value: - // byte 0 byte 1 - // 1nnnnttt 0nnnnnnn - // ^^^^^^^ ^^^^^^^ + const auto* field = entry.field; arc_ui32 tag = WireFormat::MakeTag(field); - if (tag >= 1 << 14) { - continue; - } else if (tag >= 1 << 7) { - tag = ((tag << 1) & 0x7F00) | 0x80 | (tag & 0x7F); + + // Construct the varint-coded tag. If it is more than 7 bits, we need to + // shift the high bits and add a continue bit. + if (arc_ui32 hibits = tag & 0xFFFFFF80) { + tag = tag + hibits + 128; // tag = lobits + 2*hibits + 128 } + // The field index is determined by the low bits of the field number, where // the table size determines the width of the mask. The largest table // supported is 32 entries. The parse loop uses these bits directly, so that // the dispatch does not require arithmetic: - // byte 0 byte 1 - // 1nnnnttt 0nnnnnnn - // ^^^^^ + // byte 0 byte 1 + // tag: 1nnnnttt 0nnnnnnn + // ^^^^^ + // idx (table_size_log2=5) // This means that any field number that does not fit in the lower 4 bits - // will always have the top bit of its table index asserted: - arc_ui32 idx = (tag >> 3) & (table_size - 1); - // If this entry in the table is already used, then this field will be - // handled by the generated fallback function. - if (!fast_path_fields[idx].func_name.empty()) continue; - - // Determine the hasbit mask for this field, if needed. (Note that fields - // without hasbits use different parse functions.) - int hasbit_idx; - if (HasHasbit(field)) { - hasbit_idx = has_bit_indices[field->index()]; - GOOGLE_CHECK_NE(-1, hasbit_idx) << field->DebugString(); - // The tailcall parser can only update the first 32 hasbits. If this - // field's has-bit is beyond that, then it will need to be handled by the - // fallback parse function. - if (hasbit_idx >= 32) continue; + // will always have the top bit of its table index asserted. + const arc_ui32 fast_idx = (tag >> 3) & idx_mask; + + TailCallTableInfo::FastFieldInfo& info = result[fast_idx]; + if (info.field != nullptr) { + // This field entry is already filled. + continue; + } + + // Fill in this field's entry: + GOOGLE_CHECK(info.func_name.empty()) << info.func_name; + info.func_name = FieldParseFunctionName(entry, options); + info.field = field; + info.coded_tag = tag; + // If this field does not have presence, then it can set an out-of-bounds + // bit (tailcall parsing uses a arc_ui64 for hasbits, but only stores 32). + info.hasbit_idx = HasHasbit(field) ? entry.hasbit_idx : 63; + if (IsStringInlined(field, options)) { + GOOGLE_CHECK(!field->is_repeated()); + info.aux_idx = static_cast<uint8_t>(entry.inlined_string_idx); } else { - // The tailcall parser only ever syncs 32 has-bits, so if there is no - // presence, set a bit that will not be used. - hasbit_idx = 63; + info.aux_idx = static_cast<uint8_t>(entry.aux_idx); } + } + return result; +} - // Determine the name of the fastpath parse function to use for this field. - TProtoStringType name; +// Filter out fields that will be handled by mini parsing. +std::vector<const FieldDescriptor*> FilterMiniParsedFields( + const std::vector<const FieldDescriptor*>& fields, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + std::vector<const FieldDescriptor*> generated_fallback_fields; + for (const auto* field : fields) { + bool handled = false; switch (field->type()) { - case FieldDescriptor::TYPE_MESSAGE: - name = MessageTcParseFunctionName(field, options); - break; - - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_SFIXED32: case FieldDescriptor::TYPE_DOUBLE: case FieldDescriptor::TYPE_FLOAT: - case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_BOOL: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_BOOL: - name = FieldParseFunctionName(field, options); + case FieldDescriptor::TYPE_INT64: + // These are handled by MiniParse, so we don't need any generated + // fallback code. + handled = true; break; - case FieldDescriptor::TYPE_BYTES: - if (field->options().ctype() == FieldOptions::STRING && - field->default_value_string().empty() && - !IsStringInlined(field, options)) { - name = FieldParseFunctionName(field, options); + case FieldDescriptor::TYPE_ENUM: + if (field->is_repeated() && + !HasPreservingUnknownEnumSemantics(field)) { + // TODO(b/206890171): handle packed repeated closed enums + // Non-packed repeated can be handled using tables, but we still + // need to generate fallback code for all repeated enums in order to + // handle packed encoding. This is because of the lite/full split + // when handling invalid enum values in a packed field. + handled = false; + } else { + handled = true; + } + break; + + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_STRING: + if (IsStringInlined(field, options)) { + // TODO(b/198211897): support InilnedStringField. + handled = false; + } else { + handled = true; + } + break; + + case FieldDescriptor::TYPE_MESSAGE: + case FieldDescriptor::TYPE_GROUP: + // TODO(b/210762816): support remaining field types. + if (field->is_map() || IsWeak(field, options) || + IsImplicitWeakField(field, options, scc_analyzer) || + IsLazy(field, options, scc_analyzer)) { + handled = false; + } else { + handled = true; } break; default: + handled = false; break; } + if (!handled) generated_fallback_fields.push_back(field); + } - if (name.empty()) { - continue; + return generated_fallback_fields; +} + +} // namespace + +TailCallTableInfo::TailCallTableInfo( + const Descriptor* descriptor, const Options& options, + const std::vector<const FieldDescriptor*>& ordered_fields, + const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, + MessageSCCAnalyzer* scc_analyzer) { + int oneof_count = descriptor->real_oneof_decl_count(); + // If this message has any oneof fields, store the case offset in the first + // auxiliary entry. + if (oneof_count > 0) { + GOOGLE_LOG_IF(DFATAL, ordered_fields.empty()) + << "Invalid message: " << descriptor->full_name() << " has " + << oneof_count << " oneof declarations, but no fields"; + aux_entries.push_back(StrCat( + "_fl::Offset{offsetof(", ClassName(descriptor), ", _oneof_case_)}")); + } + + // If this message has any inlined string fields, store the donation state + // offset in the second auxiliary entry. + if (!inlined_string_indices.empty()) { + aux_entries.resize(2); // pad if necessary + aux_entries[1] = + StrCat("_fl::Offset{offsetof(", ClassName(descriptor), + ", _inlined_string_donated_)}"); + } + + // Fill in mini table entries. + for (const FieldDescriptor* field : ordered_fields) { + field_entries.push_back( + {field, (HasHasbit(field) ? has_bit_indices[field->index()] : -1)}); + auto& entry = field_entries.back(); + + if (field->type() == FieldDescriptor::TYPE_MESSAGE || + field->type() == FieldDescriptor::TYPE_GROUP) { + // Message-typed fields have a FieldAux with the default instance pointer. + if (field->is_map()) { + // TODO(b/205904770): generate aux entries for maps + } else if (IsWeak(field, options)) { + // Don't generate anything for weak fields. They are handled by the + // generated fallback. + } else if (IsImplicitWeakField(field, options, scc_analyzer)) { + // Implicit weak fields don't need to store a default instance pointer. + } else if (IsLazy(field, options, scc_analyzer)) { + // Lazy fields are handled by the generated fallback function. + } else { + field_entries.back().aux_idx = aux_entries.size(); + const Descriptor* field_type = field->message_type(); + aux_entries.push_back(StrCat( + "reinterpret_cast<const ", QualifiedClassName(field_type, options), + "*>(&", QualifiedDefaultInstanceName(field_type, options), ")")); + } + } else if (field->type() == FieldDescriptor::TYPE_ENUM && + !HasPreservingUnknownEnumSemantics(field)) { + // Enum fields which preserve unknown values (proto3 behavior) are + // effectively int32 fields with respect to parsing -- i.e., the value + // does not need to be validated at parse time. + // + // Enum fields which do not preserve unknown values (proto2 behavior) use + // a FieldAux to store validation information. If the enum values are + // sequential (and within a range we can represent), then the FieldAux + // entry represents the range using the minimum value (which must fit in + // an int16_t) and count (a uint16_t). Otherwise, the entry holds a + // pointer to the generated Name_IsValid function. + + entry.aux_idx = aux_entries.size(); + const EnumDescriptor* enum_type = field->enum_type(); + GOOGLE_CHECK_GT(enum_type->value_count(), 0) << enum_type->DebugString(); + + // Check if the enum values are a single, contiguous range. + std::vector<int> enum_values; + for (int i = 0, N = enum_type->value_count(); i < N; ++i) { + enum_values.push_back(enum_type->value(i)->number()); + } + auto values_begin = enum_values.begin(); + auto values_end = enum_values.end(); + std::sort(values_begin, values_end); + enum_values.erase(std::unique(values_begin, values_end), values_end); + + if (enum_values.back() - enum_values[0] == enum_values.size() - 1 && + enum_values[0] >= std::numeric_limits<int16_t>::min() && + enum_values[0] <= std::numeric_limits<int16_t>::max() && + enum_values.size() <= std::numeric_limits<uint16_t>::max()) { + entry.is_enum_range = true; + aux_entries.push_back( + StrCat(enum_values[0], ", ", enum_values.size())); + } else { + entry.is_enum_range = false; + aux_entries.push_back( + StrCat(QualifiedClassName(enum_type, options), "_IsValid")); + } + } else if ((field->type() == FieldDescriptor::TYPE_STRING || + field->type() == FieldDescriptor::TYPE_BYTES) && + IsStringInlined(field, options)) { + GOOGLE_CHECK(!field->is_repeated()); + // Inlined strings have an extra marker to represent their donation state. + int idx = inlined_string_indices[field->index()]; + // For mini parsing, the donation state index is stored as an `offset` + // auxiliary entry. + entry.aux_idx = aux_entries.size(); + aux_entries.push_back(StrCat("_fl::Offset{", idx, "}")); + // For fast table parsing, the donation state index is stored instead of + // the aux_idx (this will limit the range to 8 bits). + entry.inlined_string_idx = idx; + } + } + + // Choose the smallest fast table that covers the maximum number of fields. + table_size_log2 = 0; // fallback value + int num_fast_fields = -1; + for (int try_size_log2 : {0, 1, 2, 3, 4, 5}) { + size_t try_size = 1 << try_size_log2; + auto split_fields = SplitFastFieldsForSize(field_entries, try_size_log2, + options, scc_analyzer); + GOOGLE_CHECK_EQ(split_fields.size(), try_size); + int try_num_fast_fields = 0; + for (const auto& info : split_fields) { + if (info.field != nullptr) ++try_num_fast_fields; + } + // Use this size if (and only if) it covers more fields. + if (try_num_fast_fields > num_fast_fields) { + fast_path_fields = std::move(split_fields); + table_size_log2 = try_size_log2; + num_fast_fields = try_num_fast_fields; + } + // The largest table we allow has the same number of entries as the message + // has fields, rounded up to the next power of 2 (e.g., a message with 5 + // fields can have a fast table of size 8). A larger table *might* cover + // more fields in certain cases, but a larger table in that case would have + // mostly empty entries; so, we cap the size to avoid pathologically sparse + // tables. + if (try_size > ordered_fields.size()) { + break; } - // This field made it into the fast path, so remove it from the fallback - // fields and fill in the table entry. - fallback_fields.pop_back(); - fast_path_fields[idx].func_name = name; - fast_path_fields[idx].bits = TcFieldData(tag, hasbit_idx, 0); - fast_path_fields[idx].field = field; } + // Filter out fields that are handled by MiniParse. We don't need to generate + // a fallback for these, which saves code size. + fallback_fields = FilterMiniParsedFields(ordered_fields, options, + scc_analyzer); + // If there are no fallback fields, and at most one extension range, the // parser can use a generic fallback function. Otherwise, a message-specific // fallback routine is needed. @@ -252,12 +436,15 @@ ParseFunctionGenerator::ParseFunctionGenerator( options_(options), variables_(vars), inlined_string_indices_(inlined_string_indices), + ordered_fields_(GetOrderedFields(descriptor_, options_)), num_hasbits_(max_has_bit_index) { if (should_generate_tctable()) { - tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_, - has_bit_indices, scc_analyzer)); + tc_table_info_.reset(new TailCallTableInfo( + descriptor_, options_, ordered_fields_, has_bit_indices, + inlined_string_indices, scc_analyzer)); } SetCommonVars(options_, &variables_); + SetCommonMessageDataVariables(&variables_); SetUnknownFieldsVariable(descriptor_, options_, &variables_); variables_["classname"] = ClassName(descriptor, false); } @@ -265,45 +452,18 @@ ParseFunctionGenerator::ParseFunctionGenerator( void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) { Formatter format(printer, variables_); if (should_generate_tctable()) { - auto declare_function = [&format](const char* name, - const TProtoStringType& guard) { - if (!guard.empty()) { - format.Outdent(); - format("#if $1$\n", guard); - format.Indent(); - } - format("static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n", name); - if (!guard.empty()) { - format.Outdent(); - format("#endif // $1$\n", guard); - format.Indent(); - } - }; + format.Outdent(); if (should_generate_guarded_tctable()) { - format.Outdent(); format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); - format.Indent(); - } - format("// The Tct_* functions are internal to the protobuf runtime:\n"); - // These guards are defined in port_def.inc: - declare_function("Tct_ParseS1", "PROTOBUF_TC_STATIC_PARSE_SINGULAR1"); - declare_function("Tct_ParseS2", "PROTOBUF_TC_STATIC_PARSE_SINGULAR2"); - declare_function("Tct_ParseR1", "PROTOBUF_TC_STATIC_PARSE_REPEATED1"); - declare_function("Tct_ParseR2", "PROTOBUF_TC_STATIC_PARSE_REPEATED2"); - if (tc_table_info_->use_generated_fallback) { - format.Outdent(); - format( - " private:\n" - " "); - declare_function("Tct_ParseFallback", ""); - format(" public:\n"); - format.Indent(); } + format( + " private:\n" + " static const char* Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL);\n" + " public:\n"); if (should_generate_guarded_tctable()) { - format.Outdent(); format("#endif\n"); - format.Indent(); } + format.Indent(); } format( "const char* _InternalParse(const char* ptr, " @@ -318,9 +478,15 @@ void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) { need_parse_function = false; format( "const char* $classname$::_InternalParse(const char* ptr,\n" - " ::$proto_ns$::internal::ParseContext* ctx) {\n" - "$annotate_deserialize$" - " return _extensions_.ParseMessageSet(ptr, \n" + " ::_pbi::ParseContext* ctx) {\n" + "$annotate_deserialize$"); + if (!options_.unverified_lazy_message_sets && + ShouldVerify(descriptor_, options_, scc_analyzer_)) { + format( + " ctx->set_lazy_eager_verify_func(&$classname$::InternalVerify);\n"); + } + format( + " return $extensions$.ParseMessageSet(ptr, \n" " internal_default_instance(), &_internal_metadata_, ctx);\n" "}\n"); } @@ -339,7 +505,6 @@ void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) { if (tc_table_info_->use_generated_fallback) { GenerateTailcallFallbackFunction(format); } - GenerateTailcallFieldParseFunctions(format); if (should_generate_guarded_tctable()) { if (need_parse_function) { format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); @@ -362,10 +527,10 @@ void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { // Generate an `_InternalParse` that starts the tail-calling loop. format( "const char* $classname$::_InternalParse(\n" - " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n" + " const char* ptr, ::_pbi::ParseContext* ctx) {\n" "$annotate_deserialize$" - " ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n" - " this, ptr, ctx, &_table_.header);\n"); + " ptr = ::_pbi::TcParser::ParseLoop(this, ptr, ctx, " + "&_table_.header);\n"); format( " return ptr;\n" "}\n\n"); @@ -384,6 +549,7 @@ void ParseFunctionGenerator::GenerateTailcallFallbackFunction( // Sync hasbits format("typed_msg->_has_bits_[0] = hasbits;\n"); } + format("arc_ui32 tag = data.tag();\n"); format.Set("msg", "typed_msg->"); format.Set("this", "typed_msg"); @@ -401,62 +567,30 @@ void ParseFunctionGenerator::GenerateTailcallFallbackFunction( "}\n"); } -void ParseFunctionGenerator::GenerateTailcallFieldParseFunctions( - Formatter& format) { - GOOGLE_CHECK(should_generate_tctable()); - // There are four cases where a tailcall target are needed for messages: - // {singular, repeated} x {1, 2}-byte tag - struct { - const char* type; - int size; - } const kTagLayouts[] = { - {"uint8_t", 1}, - {"uint16_t", 2}, - }; - // Singular: - for (const auto& layout : kTagLayouts) { - // Guard macros are defined in port_def.inc. - format( - "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n" - "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n" - " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n" - " PROTOBUF_MUSTTAIL " - "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" - " ptr += $1$;\n" - " hasbits |= (arc_ui64{1} << data.hasbit_idx());\n" - " ::$proto_ns$::internal::TcParser::SyncHasbits" - "(msg, hasbits, table);\n" - " auto& field = ::$proto_ns$::internal::TcParser::" - "RefAt<$classtype$*>(msg, data.offset());\n" - " if (field == nullptr)\n" - " field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n" - " return ctx->ParseMessage(field, ptr);\n" - "}\n" - "#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n", - layout.size, layout.type); - } - // Repeated: - for (const auto& layout : kTagLayouts) { - // Guard macros are defined in port_def.inc. - format( - "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n" - "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n" - " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n" - " PROTOBUF_MUSTTAIL " - "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n" - " }\n" - " ptr += $1$;\n" - " auto& field = ::$proto_ns$::internal::TcParser::RefAt<" - "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n" - " ::$proto_ns$::internal::TcParser::SyncHasbits" - "(msg, hasbits, table);\n" - " ptr = ctx->ParseMessage(field.Add(), ptr);\n" - " return ptr;\n" - "}\n" - "#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n", - layout.size, layout.type); +struct SkipEntry16 { + uint16_t skipmap; + uint16_t field_entry_offset; +}; +struct SkipEntryBlock { + arc_ui32 first_fnum; + std::vector<SkipEntry16> entries; +}; +struct NumToEntryTable { + arc_ui32 skipmap32; // for fields #1 - #32 + std::vector<SkipEntryBlock> blocks; + // Compute the number of uint16_t required to represent this table. + int size16() const { + int size = 2; // for the termination field# + for (const auto& block : blocks) { + // 2 for the field#, 1 for a count of skip entries, 2 for each entry. + size += 3 + block.entries.size() * 2; + } + return size; } -} +}; + +static NumToEntryTable MakeNumToEntryTable( + const std::vector<const FieldDescriptor*>& field_descriptors); void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { if (!should_generate_tctable()) { @@ -468,10 +602,13 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); format.Indent(); } + auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_); format( - "static const ::$proto_ns$::internal::TcParseTable<$1$>\n" - " _table_;\n", - tc_table_info_->table_size_log2); + "static const ::$proto_ns$::internal::" + "TcParseTable<$1$, $2$, $3$, $4$, $5$> _table_;\n", + tc_table_info_->table_size_log2, ordered_fields_.size(), + tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(), + field_num_to_entry_table.size16()); if (should_generate_guarded_tctable()) { format.Outdent(); format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); @@ -496,7 +633,7 @@ void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) { void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format( "const char* $classname$::_InternalParse(const char* ptr, " - "::$proto_ns$::internal::ParseContext* ctx) {\n" + "::_pbi::ParseContext* ctx) {\n" "$annotate_deserialize$" "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n"); format.Indent(); @@ -518,8 +655,10 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format("while (!ctx->Done(&ptr)) {\n"); format.Indent(); - GenerateParseIterationBody(format, descriptor_, - GetOrderedFields(descriptor_, options_)); + format( + "arc_ui32 tag;\n" + "ptr = ::_pbi::ReadTag(ptr, &tag);\n"); + GenerateParseIterationBody(format, descriptor_, ordered_fields_); format.Outdent(); format("} // while\n"); @@ -537,6 +676,68 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { "}\n"); } +static NumToEntryTable MakeNumToEntryTable( + const std::vector<const FieldDescriptor*>& field_descriptors) { + NumToEntryTable num_to_entry_table; + num_to_entry_table.skipmap32 = static_cast<arc_ui32>(-1); + + // skip_entry_block is the current block of SkipEntries that we're + // appending to. cur_block_first_fnum is the number of the first + // field represented by the block. + uint16_t field_entry_index = 0; + uint16_t N = field_descriptors.size(); + // First, handle field numbers 1-32, which affect only the initial + // skipmap32 and don't generate additional skip-entry blocks. + for (; field_entry_index != N; ++field_entry_index) { + auto* field_descriptor = field_descriptors[field_entry_index]; + if (field_descriptor->number() > 32) break; + auto skipmap32_index = field_descriptor->number() - 1; + num_to_entry_table.skipmap32 -= 1 << skipmap32_index; + } + // If all the field numbers were less than or equal to 32, we will have + // no further entries to process, and we are already done. + if (field_entry_index == N) return num_to_entry_table; + + SkipEntryBlock* block = nullptr; + bool start_new_block = true; + // To determine sparseness, track the field number corresponding to + // the start of the most recent skip entry. + arc_ui32 last_skip_entry_start = 0; + for (; field_entry_index != N; ++field_entry_index) { + auto* field_descriptor = field_descriptors[field_entry_index]; + arc_ui32 fnum = field_descriptor->number(); + GOOGLE_CHECK_GT(fnum, last_skip_entry_start); + if (start_new_block == false) { + // If the next field number is within 15 of the last_skip_entry_start, we + // continue writing just to that entry. If it's between 16 and 31 more, + // then we just extend the current block by one. If it's more than 31 + // more, we have to add empty skip entries in order to continue using the + // existing block. Obviously it's just 32 more, it doesn't make sense to + // start a whole new block, since new blocks mean having to write out + // their starting field number, which is 32 bits, as well as the size of + // the additional block, which is 16... while an empty SkipEntry16 only + // costs 32 bits. So if it was 48 more, it's a slight space win; we save + // 16 bits, but probably at the cost of slower run time. We're choosing + // 96 for now. + if (fnum - last_skip_entry_start > 96) start_new_block = true; + } + if (start_new_block) { + num_to_entry_table.blocks.push_back(SkipEntryBlock{fnum}); + block = &num_to_entry_table.blocks.back(); + start_new_block = false; + } + + auto skip_entry_num = (fnum - block->first_fnum) / 16; + auto skip_entry_index = (fnum - block->first_fnum) % 16; + while (skip_entry_num >= block->entries.size()) + block->entries.push_back({0xFFFF, field_entry_index}); + block->entries[skip_entry_num].skipmap -= 1 << (skip_entry_index); + + last_skip_entry_start = fnum - skip_entry_index; + } + return num_to_entry_table; +} + void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { GOOGLE_CHECK(should_generate_tctable()); // All entries without a fast-path parsing function need a fallback. @@ -544,7 +745,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { if (tc_table_info_->use_generated_fallback) { fallback = ClassName(descriptor_) + "::Tct_ParseFallback"; } else { - fallback = TcParserName(options_) + "GenericFallback"; + fallback = "::_pbi::TcParser::GenericFallback"; if (GetOptimizeFor(descriptor_->file(), options_) == FileOptions::LITE_RUNTIME) { fallback += "Lite"; @@ -558,10 +759,15 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { // maps, weak fields, lazy, more than 1 extension range. In the cases // the table is sufficient we can use a generic routine, that just handles // unknown fields and potentially an extension range. + auto field_num_to_entry_table = MakeNumToEntryTable(ordered_fields_); format( - "const ::$proto_ns$::internal::TcParseTable<$1$>\n" - " $classname$::_table_ = {\n", - tc_table_info_->table_size_log2); + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\n" + "const ::_pbi::TcParseTable<$1$, $2$, $3$, $4$, $5$> " + "$classname$::_table_ = " + "{\n", + tc_table_info_->table_size_log2, ordered_fields_.size(), + tc_table_info_->aux_entries.size(), CalculateFieldNamesSize(), + field_num_to_entry_table.size16()); { auto table_scope = format.ScopedIndent(); format("{\n"); @@ -574,86 +780,364 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { } if (descriptor_->extension_range_count() == 1) { format( - "PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n" + "PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n" "$1$, $2$, // extension_range_{low,high}\n", descriptor_->extension_range(0)->start, descriptor_->extension_range(0)->end); } else { format("0, 0, 0, // no _extensions_\n"); } + format("$1$, $2$, // max_field_number, fast_idx_mask\n", + (ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()), + (((1 << tc_table_info_->table_size_log2) - 1) << 3)); + format( + "offsetof(decltype(_table_), field_lookup_table),\n" + "$1$, // skipmap\n", + field_num_to_entry_table.skipmap32); + if (ordered_fields_.empty()) { + format( + "offsetof(decltype(_table_), field_names), // no field_entries\n"); + } else { + format("offsetof(decltype(_table_), field_entries),\n"); + } + + format( + "$1$, // num_field_entries\n" + "$2$, // num_aux_entries\n", + ordered_fields_.size(), tc_table_info_->aux_entries.size()); + if (tc_table_info_->aux_entries.empty()) { + format( + "offsetof(decltype(_table_), field_names), // no aux_entries\n"); + } else { + format("offsetof(decltype(_table_), aux_entries),\n"); + } format( - "$1$, 0, $2$, // fast_idx_mask, reserved, num_fields\n" - "&$3$._instance,\n" - "$4$ // fallback\n", - (((1 << tc_table_info_->table_size_log2) - 1) << 3), - descriptor_->field_count(), + "&$1$._instance,\n" + "$2$, // fallback\n" + "", DefaultInstanceName(descriptor_, options_), fallback); } - format("}, {\n"); + format("}, {{\n"); { + // fast_entries[] auto fast_scope = format.ScopedIndent(); - GenerateFastFieldEntries(format, fallback); + GenerateFastFieldEntries(format); + } + format("}}, {{\n"); + { + // field_lookup_table[] + auto field_lookup_scope = format.ScopedIndent(); + int line_entries = 0; + for (int i = 0, N = field_num_to_entry_table.blocks.size(); i < N; ++i) { + SkipEntryBlock& entry_block = field_num_to_entry_table.blocks[i]; + format("$1$, $2$, $3$,\n", entry_block.first_fnum & 65535, + entry_block.first_fnum / 65536, entry_block.entries.size()); + for (auto se16 : entry_block.entries) { + if (line_entries == 0) { + format("$1$, $2$,", se16.skipmap, se16.field_entry_offset); + ++line_entries; + } else if (line_entries < 5) { + format(" $1$, $2$,", se16.skipmap, se16.field_entry_offset); + ++line_entries; + } else { + format(" $1$, $2$,\n", se16.skipmap, se16.field_entry_offset); + line_entries = 0; + } + } + } + if (line_entries) format("\n"); + format("65535, 65535\n"); + } + if (ordered_fields_.empty()) { + GOOGLE_LOG_IF(DFATAL, !tc_table_info_->aux_entries.empty()) + << "Invalid message: " << descriptor_->full_name() << " has " + << tc_table_info_->aux_entries.size() + << " auxiliary field entries, but no fields"; + format( + "}},\n" + "// no field_entries, or aux_entries\n" + "{{\n"); + } else { + format("}}, {{\n"); + { + // field_entries[] + auto field_scope = format.ScopedIndent(); + GenerateFieldEntries(format); + } + if (tc_table_info_->aux_entries.empty()) { + format( + "}},\n" + "// no aux_entries\n" + "{{\n"); + } else { + format("}}, {{\n"); + { + // aux_entries[] + auto aux_scope = format.ScopedIndent(); + for (const TProtoStringType& aux_entry : tc_table_info_->aux_entries) { + format("{$1$},\n", aux_entry); + } + } + format("}}, {{\n"); + } + } // ordered_fields_.empty() + { + // field_names[] + auto field_name_scope = format.ScopedIndent(); + GenerateFieldNames(format); } - format("},\n"); // entries[] + format("}},\n"); } format("};\n\n"); // _table_ } -void ParseFunctionGenerator::GenerateFastFieldEntries( - Formatter& format, const TProtoStringType& fallback) { +void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) { for (const auto& info : tc_table_info_->fast_path_fields) { if (info.field != nullptr) { PrintFieldComment(format, info.field); } - format("{$1$, ", info.func_name.empty() ? fallback : info.func_name); - if (info.bits.data) { - GOOGLE_DCHECK_NE(nullptr, info.field); + if (info.func_name.empty()) { + format("{::_pbi::TcParser::MiniParse, {}},\n"); + } else { format( - "{$1$, $2$, " - "static_cast<uint16_t>(PROTOBUF_FIELD_OFFSET($classname$, $3$_))}", - info.bits.coded_tag(), info.bits.hasbit_idx(), FieldName(info.field)); + "{$1$,\n" + " {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$, $5$)}},\n", + info.func_name, info.coded_tag, info.hasbit_idx, info.aux_idx, + FieldMemberName(info.field)); + } + } +} + +static void FormatFieldKind(Formatter& format, + const TailCallTableInfo::FieldEntryInfo& entry, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + const FieldDescriptor* field = entry.field; + // Spell the field kind in proto language declaration order, starting with + // cardinality: + format("(::_fl::kFc"); + if (HasHasbit(field)) { + format("Optional"); + } else if (field->is_repeated()) { + format("Repeated"); + } else if (field->real_containing_oneof()) { + format("Oneof"); + } else { + format("Singular"); + } + + // The rest of the type uses convenience aliases: + format(" | ::_fl::k"); + if (field->is_repeated() && field->is_packed()) { + format("Packed"); + } + switch (field->type()) { + case FieldDescriptor::TYPE_DOUBLE: + format("Double"); + break; + case FieldDescriptor::TYPE_FLOAT: + format("Float"); + break; + case FieldDescriptor::TYPE_FIXED32: + format("Fixed32"); + break; + case FieldDescriptor::TYPE_SFIXED32: + format("SFixed32"); + break; + case FieldDescriptor::TYPE_FIXED64: + format("Fixed64"); + break; + case FieldDescriptor::TYPE_SFIXED64: + format("SFixed64"); + break; + case FieldDescriptor::TYPE_BOOL: + format("Bool"); + break; + case FieldDescriptor::TYPE_ENUM: + if (HasPreservingUnknownEnumSemantics(field)) { + // No validation is required. + format("OpenEnum"); + } else if (entry.is_enum_range) { + // Validation is done by range check (start/length in FieldAux). + format("EnumRange"); + } else { + // Validation uses the generated _IsValid function. + format("Enum"); + } + break; + case FieldDescriptor::TYPE_UINT32: + format("UInt32"); + break; + case FieldDescriptor::TYPE_SINT32: + format("SInt32"); + break; + case FieldDescriptor::TYPE_INT32: + format("Int32"); + break; + case FieldDescriptor::TYPE_UINT64: + format("UInt64"); + break; + case FieldDescriptor::TYPE_SINT64: + format("SInt64"); + break; + case FieldDescriptor::TYPE_INT64: + format("Int64"); + break; + + case FieldDescriptor::TYPE_BYTES: + format("Bytes"); + break; + case FieldDescriptor::TYPE_STRING: { + auto mode = GetUtf8CheckMode(field, options); + switch (mode) { + case Utf8CheckMode::kStrict: + format("Utf8String"); + break; + case Utf8CheckMode::kVerify: + format("RawString"); + break; + case Utf8CheckMode::kNone: + // Treat LITE_RUNTIME strings as bytes. + format("Bytes"); + break; + default: + GOOGLE_LOG(FATAL) << "Invalid Utf8CheckMode (" << static_cast<int>(mode) + << ") for " << field->DebugString(); + } + break; + } + + case FieldDescriptor::TYPE_GROUP: + format("Message | ::_fl::kRepGroup"); + break; + case FieldDescriptor::TYPE_MESSAGE: + if (field->is_map()) { + format("Map"); + } else { + format("Message"); + if (IsLazy(field, options, scc_analyzer)) { + format(" | ::_fl::kRepLazy"); + } else if (IsImplicitWeakField(field, options, scc_analyzer)) { + format(" | ::_fl::kRepIWeak"); + } + } + break; + } + + // Fill in extra information about string and bytes field representations. + if (field->type() == FieldDescriptor::TYPE_BYTES || + field->type() == FieldDescriptor::TYPE_STRING) { + if (field->is_repeated()) { + format(" | ::_fl::kRepSString"); + } else { + format(" | ::_fl::kRepAString"); + } + } + + format(")"); +} + +void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) { + for (const auto& entry : tc_table_info_->field_entries) { + const FieldDescriptor* field = entry.field; + PrintFieldComment(format, field); + format("{"); + if (IsWeak(field, options_)) { + // Weak fields are handled by the generated fallback function. + // (These are handled by legacy Google-internal logic.) + format("/* weak */ 0, 0, 0, 0"); } else { - format("{}"); + const OneofDescriptor* oneof = field->real_containing_oneof(); + format("PROTOBUF_FIELD_OFFSET($classname$, $1$), $2$, $3$,\n ", + FieldMemberName(field), + (oneof ? oneof->index() : entry.hasbit_idx), entry.aux_idx); + FormatFieldKind(format, entry, options_, scc_analyzer_); } format("},\n"); } } +static constexpr int kMaxNameLength = 255; + +int ParseFunctionGenerator::CalculateFieldNamesSize() const { + // The full name of the message appears first. + int size = std::min(static_cast<int>(descriptor_->full_name().size()), + kMaxNameLength); + int lengths_size = 1; + for (const auto& entry : tc_table_info_->field_entries) { + const FieldDescriptor* field = entry.field; + GOOGLE_CHECK_LE(field->name().size(), kMaxNameLength); + size += field->name().size(); + lengths_size += 1; + } + // align to an 8-byte boundary + lengths_size = (lengths_size + 7) & -8; + return size + lengths_size + 1; +} + +static void FormatOctal(Formatter& format, int size) { + int octal_size = ((size >> 6) & 3) * 100 + // + ((size >> 3) & 7) * 10 + // + ((size >> 0) & 7); + format("\\$1$", octal_size); +} + +void ParseFunctionGenerator::GenerateFieldNames(Formatter& format) { + // First, we output the size of each string, as an unsigned byte. The first + // string is the message name. + int count = 1; + format("\""); + FormatOctal(format, + std::min(static_cast<int>(descriptor_->full_name().size()), 255)); + for (const auto& entry : tc_table_info_->field_entries) { + FormatOctal(format, entry.field->name().size()); + ++count; + } + while (count & 7) { // align to an 8-byte boundary + format("\\0"); + ++count; + } + format("\"\n"); + // The message name is stored at the beginning of the string + TProtoStringType message_name = descriptor_->full_name(); + if (message_name.size() > kMaxNameLength) { + static constexpr int kNameHalfLength = (kMaxNameLength - 3) / 2; + message_name = StrCat( + message_name.substr(0, kNameHalfLength), "...", + message_name.substr(message_name.size() - kNameHalfLength)); + } + format("\"$1$\"\n", message_name); + // Then we output the actual field names + for (const auto& entry : tc_table_info_->field_entries) { + const FieldDescriptor* field = entry.field; + format("\"$1$\"\n", field->name()); + } +} + void ParseFunctionGenerator::GenerateArenaString(Formatter& format, const FieldDescriptor* field) { if (HasHasbit(field)) { format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); } - TProtoStringType default_string = - field->default_value_string().empty() - ? "::" + ProtobufNamespace(options_) + - "::internal::GetEmptyStringAlreadyInited()" - : QualifiedClassName(field->containing_type(), options_) + - "::" + MakeDefaultName(field) + ".get()"; format( "if (arena != nullptr) {\n" - " ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, arena"); + " ptr = ctx->ReadArenaString(ptr, &$msg$$field$, arena"); if (IsStringInlined(field, options_)) { GOOGLE_DCHECK(!inlined_string_indices_.empty()); int inlined_string_index = inlined_string_indices_[field->index()]; - GOOGLE_DCHECK_GE(inlined_string_index, 0); - format( - ", $msg$_internal_$name$_donated()" - ", &$msg$_inlined_string_donated_[$1$]" - ", ~0x$2$u", - inlined_string_index / 32, - strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8)); + GOOGLE_DCHECK_GT(inlined_string_index, 0); + format(", &$msg$$inlined_string_donated_array$[0], $1$, $this$", + inlined_string_index); } else { GOOGLE_DCHECK(field->default_value_string().empty()); } format( ");\n" "} else {\n" - " ptr = ::$proto_ns$::internal::InlineGreedyStringParser(" - "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n" + " ptr = ::_pbi::InlineGreedyStringParser(" + "$msg$$field$.MutableNoCopy(nullptr), ptr, ctx);\n" "}\n" - "const TProtoStringType* str = &$msg$$name$_.Get(); (void)str;\n", - default_string); + "const TProtoStringType* str = &$msg$$field$.Get(); (void)str;\n"); } void ParseFunctionGenerator::GenerateStrings(Formatter& format, @@ -685,11 +1169,14 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, } format( "auto str = $msg$$1$$2$_$name$();\n" - "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n", + "ptr = ::_pbi::Inline$3$(str, ptr, ctx);\n", HasInternalAccessors(ctype) ? "_internal_" : "", field->is_repeated() && !field->is_packable() ? "add" : "mutable", parser_name); } + // It is intentionally placed before VerifyUTF8 because it doesn't make sense + // to verify UTF8 when we already know parsing failed. + format("CHK_(ptr);\n"); if (!check_utf8) return; // return if this is a bytes field auto level = GetUtf8CheckMode(field, options_); switch (level) { @@ -707,7 +1194,7 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, if (HasDescriptorMethods(field->file(), options_)) { field_name = StrCat("\"", field->full_name(), "\""); } - format("::$proto_ns$::internal::VerifyUTF8(str, $1$)", field_name); + format("::_pbi::VerifyUTF8(str, $1$)", field_name); switch (level) { case Utf8CheckMode::kNone: return; @@ -740,6 +1227,7 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, "$msg$_internal_mutable_$name$(), ptr, ctx);\n", DeclaredTypeMethodName(field->type())); } + format("CHK_(ptr);\n"); } else { auto field_type = field->type(); switch (field_type) { @@ -751,48 +1239,64 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, break; case FieldDescriptor::TYPE_MESSAGE: { if (field->is_map()) { - const FieldDescriptor* val = - field->message_type()->FindFieldByName("value"); + const FieldDescriptor* val = field->message_type()->map_value(); GOOGLE_CHECK(val); if (val->type() == FieldDescriptor::TYPE_ENUM && !HasPreservingUnknownEnumSemantics(field)) { format( "auto object = " "::$proto_ns$::internal::InitEnumParseWrapper<" - "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, " + "$unknown_fields_type$>(&$msg$$field$, $1$_IsValid, " "$2$, &$msg$_internal_metadata_);\n" "ptr = ctx->ParseMessage(&object, ptr);\n", QualifiedClassName(val->enum_type(), options_), field->number()); } else { - format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n"); + format("ptr = ctx->ParseMessage(&$msg$$field$, ptr);\n"); } } else if (IsLazy(field, options_, scc_analyzer_)) { + bool eager_verify = + IsEagerlyVerifiedLazy(field, options_, scc_analyzer_); + if (ShouldVerify(descriptor_, options_, scc_analyzer_)) { + format( + "ctx->set_lazy_eager_verify_func($1$);\n", + eager_verify + ? StrCat("&", ClassName(field->message_type(), true), + "::InternalVerify") + : "nullptr"); + } if (field->real_containing_oneof()) { format( "if (!$msg$_internal_has_$name$()) {\n" " $msg$clear_$1$();\n" - " $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" + " $msg$$field$ = ::$proto_ns$::Arena::CreateMessage<\n" " ::$proto_ns$::internal::LazyField>(" "$msg$GetArenaForAllocation());\n" " $msg$set_has_$name$();\n" "}\n" - "auto* lazy_field = $msg$$1$_.$name$_;\n", + "auto* lazy_field = $msg$$field$;\n", field->containing_oneof()->name()); } else if (HasHasbit(field)) { format( "_Internal::set_has_$name$(&$has_bits$);\n" - "auto* lazy_field = &$msg$$name$_;\n"); + "auto* lazy_field = &$msg$$field$;\n"); } else { - format("auto* lazy_field = &$msg$$name$_;\n"); + format("auto* lazy_field = &$msg$$field$;\n"); } format( "::$proto_ns$::internal::LazyFieldParseHelper<\n" " ::$proto_ns$::internal::LazyField> parse_helper(\n" " $1$::default_instance(),\n" - " $msg$GetArenaForAllocation(), lazy_field);\n" + " $msg$GetArenaForAllocation(),\n" + " ::google::protobuf::internal::LazyVerifyOption::$2$,\n" + " lazy_field);\n" "ptr = ctx->ParseMessage(&parse_helper, ptr);\n", - FieldMessageTypeName(field, options_)); + FieldMessageTypeName(field, options_), + eager_verify ? "kEager" : "kLazy"); + if (ShouldVerify(descriptor_, options_, scc_analyzer_) && + eager_verify) { + format("ctx->set_lazy_eager_verify_func(nullptr);\n"); + } } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) { if (!field->is_repeated()) { format( @@ -800,7 +1304,7 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, "ptr);\n"); } else { format( - "ptr = ctx->ParseMessage($msg$$name$_.AddWeak(" + "ptr = ctx->ParseMessage($msg$$field$.AddWeak(" "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)" "), ptr);\n", QualifiedDefaultInstanceName(field->message_type(), options_)); @@ -809,7 +1313,7 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, format( "{\n" " auto* default_ = &reinterpret_cast<const Message&>($1$);\n" - " ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage(" + " ptr = ctx->ParseMessage($msg$$weak_field_map$.MutableMessage(" "$2$, default_), ptr);\n" "}\n", QualifiedDefaultInstanceName(field->message_type(), options_), @@ -819,6 +1323,7 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), " "ptr);\n"); } + format("CHK_(ptr);\n"); break; } default: @@ -898,7 +1403,7 @@ void ParseFunctionGenerator::GenerateFieldBody( format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( - "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n" + "$msg$$field$ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n" "CHK_(ptr);\n", zigzag, size); } @@ -917,7 +1422,7 @@ void ParseFunctionGenerator::GenerateFieldBody( format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( - "$msg$$name$_ = " + "$msg$$field$ = " "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n" "ptr += sizeof($primitive_type$);\n"); } @@ -925,7 +1430,6 @@ void ParseFunctionGenerator::GenerateFieldBody( } case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { GenerateLengthDelim(format, field); - format("CHK_(ptr);\n"); break; } case WireFormatLite::WIRETYPE_START_GROUP: { @@ -983,13 +1487,9 @@ static arc_ui32 ExpectedTag(const FieldDescriptor* field, // parse the next tag in the stream. void ParseFunctionGenerator::GenerateParseIterationBody( Formatter& format, const Descriptor* descriptor, - const std::vector<const FieldDescriptor*>& ordered_fields) { - format( - "$uint32$ tag;\n" - "ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n"); - - if (!ordered_fields.empty()) { - GenerateFieldSwitch(format, ordered_fields); + const std::vector<const FieldDescriptor*>& fields) { + if (!fields.empty()) { + GenerateFieldSwitch(format, fields); // Each field `case` only considers field number. Field numbers that are // not defined in the message, or tags with an incompatible wire type, are // considered "unusual" cases. They will be handled by the logic below. @@ -1028,7 +1528,7 @@ void ParseFunctionGenerator::GenerateParseIterationBody( } format( ") {\n" - " ptr = $msg$_extensions_.ParseField(tag, ptr, " + " ptr = $msg$$extensions$.ParseField(tag, ptr, " "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n" " CHK_(ptr != nullptr);\n" " $next_tag$;\n" @@ -1045,12 +1545,12 @@ void ParseFunctionGenerator::GenerateParseIterationBody( } void ParseFunctionGenerator::GenerateFieldSwitch( - Formatter& format, - const std::vector<const FieldDescriptor*>& ordered_fields) { + Formatter& format, const std::vector<const FieldDescriptor*>& fields) { format("switch (tag >> 3) {\n"); format.Indent(); - for (const auto* field : ordered_fields) { + for (const auto* field : fields) { + format.Set("field", FieldMemberName(field)); PrintFieldComment(format, field); format("case $1$:\n", field->number()); format.Indent(); @@ -1104,199 +1604,111 @@ void ParseFunctionGenerator::GenerateFieldSwitch( namespace { -TProtoStringType FieldParseFunctionName(const FieldDescriptor* field, - const Options& options) { - ParseCardinality card = // - field->is_packed() ? ParseCardinality::kPacked - : field->is_repeated() ? ParseCardinality::kRepeated - : field->real_containing_oneof() ? ParseCardinality::kOneof - : ParseCardinality::kSingular; +TProtoStringType FieldParseFunctionName( + const TailCallTableInfo::FieldEntryInfo& entry, const Options& options) { + const FieldDescriptor* field = entry.field; + TProtoStringType name = "::_pbi::TcParser::Fast"; - TypeFormat type_format; switch (field->type()) { - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_DOUBLE: - type_format = TypeFormat::kFixed64; - break; - case FieldDescriptor::TYPE_FIXED32: case FieldDescriptor::TYPE_SFIXED32: case FieldDescriptor::TYPE_FLOAT: - type_format = TypeFormat::kFixed32; + name.append("F32"); break; - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - type_format = TypeFormat::kVar64; + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + case FieldDescriptor::TYPE_DOUBLE: + name.append("F64"); break; + case FieldDescriptor::TYPE_BOOL: + name.append("V8"); + break; case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT32: - type_format = TypeFormat::kVar32; + name.append("V32"); + break; + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + name.append("V64"); break; - case FieldDescriptor::TYPE_SINT64: - type_format = TypeFormat::kSInt64; + case FieldDescriptor::TYPE_ENUM: + if (HasPreservingUnknownEnumSemantics(field)) { + name.append("V32"); + break; + } + if (field->is_repeated() && field->is_packed()) { + GOOGLE_LOG(DFATAL) << "Enum validation not handled: " << field->DebugString(); + return ""; + } + name.append(entry.is_enum_range ? "Er" : "Ev"); break; case FieldDescriptor::TYPE_SINT32: - type_format = TypeFormat::kSInt32; + name.append("Z32"); break; - - case FieldDescriptor::TYPE_BOOL: - type_format = TypeFormat::kBool; + case FieldDescriptor::TYPE_SINT64: + name.append("Z64"); break; case FieldDescriptor::TYPE_BYTES: - type_format = TypeFormat::kBytes; + name.append("B"); + if (IsStringInlined(field, options)) { + name.append("i"); + } break; - case FieldDescriptor::TYPE_STRING: switch (GetUtf8CheckMode(field, options)) { case Utf8CheckMode::kNone: - type_format = TypeFormat::kBytes; - break; - case Utf8CheckMode::kStrict: - type_format = TypeFormat::kString; + name.append("B"); break; case Utf8CheckMode::kVerify: - type_format = TypeFormat::kStringValidateOnly; + name.append("S"); + break; + case Utf8CheckMode::kStrict: + name.append("U"); break; default: GOOGLE_LOG(DFATAL) << "Mode not handled: " << static_cast<int>(GetUtf8CheckMode(field, options)); return ""; } + if (IsStringInlined(field, options)) { + name.append("i"); + } break; - default: - GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString(); - return ""; - } - - return "::" + ProtobufNamespace(options) + "::internal::TcParser::" + - GetTailCallFieldHandlerName(card, type_format, - TagSize(field->number()), options); -} - -} // namespace - -TProtoStringType GetTailCallFieldHandlerName(ParseCardinality card, - TypeFormat type_format, - int tag_length_bytes, - const Options& options) { - TProtoStringType name; - - // The field implementation functions are prefixed by cardinality: - // `Singular` for optional or implicit fields. - // `Repeated` for non-packed repeated. - // `Packed` for packed repeated. - switch (card) { - case ParseCardinality::kSingular: - name.append("Singular"); - break; - case ParseCardinality::kOneof: - name.append("Oneof"); - break; - case ParseCardinality::kRepeated: - name.append("Repeated"); - break; - case ParseCardinality::kPacked: - name.append("Packed"); - break; - } - - // Next in the function name is the TypeFormat-specific name. - switch (type_format) { - case TypeFormat::kFixed64: - case TypeFormat::kFixed32: - name.append("Fixed"); - break; - - case TypeFormat::kVar64: - case TypeFormat::kVar32: - case TypeFormat::kSInt64: - case TypeFormat::kSInt32: - case TypeFormat::kBool: - name.append("Varint"); - break; - - case TypeFormat::kBytes: - case TypeFormat::kString: - case TypeFormat::kStringValidateOnly: - name.append("String"); - break; - - default: - break; - } - - name.append("<"); - - // Determine the numeric layout type for the parser to use, independent of - // the specific parsing logic used. - switch (type_format) { - case TypeFormat::kVar64: - case TypeFormat::kFixed64: - name.append("arc_ui64, "); - break; - - case TypeFormat::kSInt64: - name.append("arc_i64, "); - break; - - case TypeFormat::kVar32: - case TypeFormat::kFixed32: - name.append("arc_ui32, "); - break; - - case TypeFormat::kSInt32: - name.append("arc_i32, "); + case FieldDescriptor::TYPE_MESSAGE: + name.append("M"); break; - - case TypeFormat::kBool: - name.append("bool, "); + case FieldDescriptor::TYPE_GROUP: + name.append("G"); break; default: - break; + GOOGLE_LOG(DFATAL) << "Type not handled: " << field->DebugString(); + return ""; } - name.append(CodedTagType(tag_length_bytes)); - - switch (type_format) { - case TypeFormat::kVar64: - case TypeFormat::kVar32: - case TypeFormat::kBool: - StrAppend(&name, ", ", TcParserName(options), "kNoConversion"); - break; - - case TypeFormat::kSInt64: - case TypeFormat::kSInt32: - StrAppend(&name, ", ", TcParserName(options), "kZigZag"); - break; - - case TypeFormat::kBytes: - StrAppend(&name, ", ", TcParserName(options), "kNoUtf8"); - break; - - case TypeFormat::kString: - StrAppend(&name, ", ", TcParserName(options), "kUtf8"); - break; - - case TypeFormat::kStringValidateOnly: - StrAppend(&name, ", ", TcParserName(options), "kUtf8ValidateOnly"); - break; + // The field implementation functions are prefixed by cardinality: + // `S` for optional or implicit fields. + // `R` for non-packed repeated. + // `P` for packed repeated. + name.append(field->is_packed() ? "P" + : field->is_repeated() ? "R" + : field->real_containing_oneof() ? "O" + : "S"); - default: - break; - } + // Append the tag length. Fast parsing only handles 1- or 2-byte tags. + name.append(TagSize(field->number()) == 1 ? "1" : "2"); - name.append(">"); return name; } +} // namespace + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h index 02460791462..3c8209534a4 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h @@ -35,12 +35,11 @@ #include <string> #include <vector> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/generated_message_tctable_decl.h> #include <google/protobuf/wire_format_lite.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { @@ -50,18 +49,36 @@ namespace cpp { // Helper class for generating tailcall parsing functions. struct TailCallTableInfo { TailCallTableInfo(const Descriptor* descriptor, const Options& options, + const std::vector<const FieldDescriptor*>& ordered_fields, const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, MessageSCCAnalyzer* scc_analyzer); - // Information to generate field entries. - struct FieldInfo { - const FieldDescriptor* field; - google::protobuf::internal::TcFieldData bits; + + // Fields parsed by the table fast-path. + struct FastFieldInfo { TProtoStringType func_name; + const FieldDescriptor* field; + uint16_t coded_tag; + uint8_t hasbit_idx; + uint8_t aux_idx; }; - // Fields parsed by the table fast-path. - std::vector<FieldInfo> fast_path_fields; - // Fields parsed by slow-path fallback. + std::vector<FastFieldInfo> fast_path_fields; + + // Fields parsed by mini parsing routines. + struct FieldEntryInfo { + const FieldDescriptor* field; + int hasbit_idx; + int inlined_string_idx; + uint16_t aux_idx; + // True for enums entirely covered by the start/length fields of FieldAux: + bool is_enum_range; + }; + std::vector<FieldEntryInfo> field_entries; + std::vector<TProtoStringType> aux_entries; + + // Fields parsed by generated fallback function. std::vector<const FieldDescriptor*> fallback_fields; + // Table size. int table_size_log2; // Mask for has-bits of required fields. @@ -110,15 +127,15 @@ class ParseFunctionGenerator { // Generates a fallback function for tailcall table-based parsing. void GenerateTailcallFallbackFunction(Formatter& format); - // Generates functions for parsing this message as a field. - void GenerateTailcallFieldParseFunctions(Formatter& format); - // Generates a looping `_InternalParse` function. void GenerateLoopingParseFunction(Formatter& format); // Generates the tail-call table definition. void GenerateTailCallTable(Formatter& format); - void GenerateFastFieldEntries(Formatter& format, const TProtoStringType& fallback); + void GenerateFastFieldEntries(Formatter& format); + void GenerateFieldEntries(Formatter& format); + int CalculateFieldNamesSize() const; + void GenerateFieldNames(Formatter& format); // Generates parsing code for an `ArenaString` field. void GenerateArenaString(Formatter& format, const FieldDescriptor* field); @@ -139,12 +156,11 @@ class ParseFunctionGenerator { // Generates code to parse the next field from the input stream. void GenerateParseIterationBody( Formatter& format, const Descriptor* descriptor, - const std::vector<const FieldDescriptor*>& ordered_fields); + const std::vector<const FieldDescriptor*>& fields); - // Generates a `switch` statement to parse each of `ordered_fields`. - void GenerateFieldSwitch( - Formatter& format, - const std::vector<const FieldDescriptor*>& ordered_fields); + // Generates a `switch` statement to parse each of `fields`. + void GenerateFieldSwitch(Formatter& format, + const std::vector<const FieldDescriptor*>& fields); const Descriptor* descriptor_; MessageSCCAnalyzer* scc_analyzer_; @@ -152,45 +168,10 @@ class ParseFunctionGenerator { std::map<TProtoStringType, TProtoStringType> variables_; std::unique_ptr<TailCallTableInfo> tc_table_info_; std::vector<int> inlined_string_indices_; + const std::vector<const FieldDescriptor*> ordered_fields_; int num_hasbits_; }; -enum class ParseCardinality { - kSingular, - kOneof, - kRepeated, - kPacked, -}; - -// TypeFormat defines parsing types, which encapsulates the expected wire -// format, conversion or validation, and the in-memory layout. -enum class TypeFormat { - // Fixed types: - kFixed64, // fixed64, sfixed64, double - kFixed32, // fixed32, sfixed32, float - - // Varint types: - kVar64, // int64, uint64 - kVar32, // int32, uint32 - kSInt64, // sint64 - kSInt32, // sint32 - kBool, // bool - - // Length-delimited types: - kBytes, // bytes - kString, // string (proto3/UTF-8 strict) - kStringValidateOnly, // string (proto2/UTF-8 validate only) -}; - -// Returns the name of a field parser function. -// -// These are out-of-line functions generated by -// parse_function_inc_generator_main. -TProtoStringType GetTailCallFieldHandlerName(ParseCardinality card, - TypeFormat type_format, - int tag_length_bytes, - const Options& options); - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 8b37b866aec..910b59a21a7 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -34,10 +34,10 @@ #include <google/protobuf/compiler/cpp/cpp_primitive_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { namespace protobuf { @@ -104,6 +104,9 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type()); (*variables)["default"] = DefaultValue(options, descriptor); + (*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor); + (*variables)["cached_byte_size_field"] = + MakeVarintCachedSizeFieldName(descriptor); (*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor)); int fixed_size = FixedSize(descriptor->type()); if (fixed_size != -1) { @@ -150,7 +153,7 @@ void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( Formatter format(printer, variables_); format( "inline $type$ $classname$::_internal_$name$() const {\n" - " return $name$_;\n" + " return $field$;\n" "}\n" "inline $type$ $classname$::$name$() const {\n" "$annotate_get$" @@ -159,7 +162,7 @@ void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline void $classname$::_internal_set_$name$($type$ value) {\n" " $set_hasbit$\n" - " $name$_ = value;\n" + " $field$ = value;\n" "}\n" "inline void $classname$::set_$name$($type$ value) {\n" " _internal_set_$name$(value);\n" @@ -170,7 +173,7 @@ void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = $default$;\n"); + format("$field$ = $default$;\n"); } void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const { @@ -180,19 +183,19 @@ void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const { void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("swap($name$_, other->$name$_);\n"); + format("swap($field$, other->$field$);\n"); } void PrimitiveFieldGenerator::GenerateConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = $default$;\n"); + format("$field$ = $default$;\n"); } void PrimitiveFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_ = from.$name$_;\n"); + format("$field$ = from.$field$;\n"); } void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -201,7 +204,7 @@ void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( format( "target = stream->EnsureSpace(target);\n" "target = " - "::$proto_ns$::internal::WireFormatLite::Write$declared_type$ToArray(" + "::_pbi::WireFormatLite::Write$declared_type$ToArray(" "$number$, this->_internal_$name$(), target);\n"); } @@ -214,12 +217,12 @@ void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const { // Adding one is very common and it turns out it can be done for // free inside of WireFormatLite, so we can save an instruction here. format( - "total_size += ::$proto_ns$::internal::WireFormatLite::" + "total_size += ::_pbi::WireFormatLite::" "$declared_type$SizePlusOne(this->_internal_$name$());\n"); } else { format( "total_size += $tag_size$ +\n" - " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " ::_pbi::WireFormatLite::$declared_type$Size(\n" " this->_internal_$name$());\n"); } } else { @@ -249,7 +252,7 @@ void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline $type$ $classname$::_internal_$name$() const {\n" " if (_internal_has_$name$()) {\n" - " return $field_member$;\n" + " return $field$;\n" " }\n" " return $default$;\n" "}\n" @@ -258,7 +261,7 @@ void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( " clear_$oneof_name$();\n" " set_has_$name$();\n" " }\n" - " $field_member$ = value;\n" + " $field$ = value;\n" "}\n" "inline $type$ $classname$::$name$() const {\n" "$annotate_get$" @@ -275,7 +278,7 @@ void PrimitiveOneofFieldGenerator::GenerateInlineAccessorDefinitions( void PrimitiveOneofFieldGenerator::GenerateClearingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field_member$ = $default$;\n"); + format("$field$ = $default$;\n"); } void PrimitiveOneofFieldGenerator::GenerateSwappingCode( @@ -286,7 +289,7 @@ void PrimitiveOneofFieldGenerator::GenerateSwappingCode( void PrimitiveOneofFieldGenerator::GenerateConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$ns$::_$classname$_default_instance_.$name$_ = $default$;\n"); + format("$ns$::_$classname$_default_instance_.$field$ = $default$;\n"); } // =================================================================== @@ -313,7 +316,7 @@ void RepeatedPrimitiveFieldGenerator::GeneratePrivateMembers( format("::$proto_ns$::RepeatedField< $type$ > $name$_;\n"); if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && HasGeneratedMethods(descriptor_->file(), options_)) { - format("mutable std::atomic<int> _$name$_cached_byte_size_;\n"); + format("mutable std::atomic<int> $cached_byte_size_name$;\n"); } } @@ -344,7 +347,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( Formatter format(printer, variables_); format( "inline $type$ $classname$::_internal_$name$(int index) const {\n" - " return $name$_.Get(index);\n" + " return $field$.Get(index);\n" "}\n" "inline $type$ $classname$::$name$(int index) const {\n" "$annotate_get$" @@ -353,11 +356,11 @@ void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline void $classname$::set_$name$(int index, $type$ value) {\n" "$annotate_set$" - " $name$_.Set(index, value);\n" + " $field$.Set(index, value);\n" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "inline void $classname$::_internal_add_$name$($type$ value) {\n" - " $name$_.Add(value);\n" + " $field$.Add(value);\n" "}\n" "inline void $classname$::add_$name$($type$ value) {\n" " _internal_add_$name$(value);\n" @@ -366,7 +369,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" "$classname$::_internal_$name$() const {\n" - " return $name$_;\n" + " return $field$;\n" "}\n" "inline const ::$proto_ns$::RepeatedField< $type$ >&\n" "$classname$::$name$() const {\n" @@ -376,7 +379,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline ::$proto_ns$::RepeatedField< $type$ >*\n" "$classname$::_internal_mutable_$name$() {\n" - " return &$name$_;\n" + " return &$field$;\n" "}\n" "inline ::$proto_ns$::RepeatedField< $type$ >*\n" "$classname$::mutable_$name$() {\n" @@ -389,30 +392,19 @@ void RepeatedPrimitiveFieldGenerator::GenerateInlineAccessorDefinitions( void RepeatedPrimitiveFieldGenerator::GenerateClearingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.Clear();\n"); + format("$field$.Clear();\n"); } void RepeatedPrimitiveFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.MergeFrom(from.$name$_);\n"); + format("$field$.MergeFrom(from.$field$);\n"); } void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.InternalSwap(&other->$name$_);\n"); -} - -void RepeatedPrimitiveFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - // Not needed for repeated fields. -} - -void RepeatedPrimitiveFieldGenerator::GenerateCopyConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$name$_.CopyFrom(from.$name$_);\n"); + format("$field$.InternalSwap(&other->$field$);\n"); } void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -423,7 +415,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( format( "{\n" " int byte_size = " - "_$name$_cached_byte_size_.load(std::memory_order_relaxed);\n" + "$cached_byte_size_field$.load(std::memory_order_relaxed);\n" " if (byte_size > 0) {\n" " target = stream->Write$declared_type$Packed(\n" " $number$, _internal_$name$(), byte_size, target);\n" @@ -440,7 +432,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( format( "for (int i = 0, n = this->_internal_$name$_size(); i < n; i++) {\n" " target = stream->EnsureSpace(target);\n" - " target = ::$proto_ns$::internal::WireFormatLite::" + " target = ::_pbi::WireFormatLite::" "Write$declared_type$ToArray($number$, this->_internal_$name$(i), " "target);\n" "}\n"); @@ -455,8 +447,8 @@ void RepeatedPrimitiveFieldGenerator::GenerateByteSize( int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { format( - "size_t data_size = ::$proto_ns$::internal::WireFormatLite::\n" - " $declared_type$Size(this->$name$_);\n"); + "size_t data_size = ::_pbi::WireFormatLite::\n" + " $declared_type$Size(this->$field$);\n"); } else { format( "unsigned int count = static_cast<unsigned " @@ -468,13 +460,12 @@ void RepeatedPrimitiveFieldGenerator::GenerateByteSize( format( "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" - " ::$proto_ns$::internal::WireFormatLite::Int32Size(\n" - " static_cast<$int32$>(data_size));\n" + " ::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" "}\n"); if (FixedSize(descriptor_->type()) == -1) { format( - "int cached_size = ::$proto_ns$::internal::ToCachedSize(data_size);\n" - "_$name$_cached_byte_size_.store(cached_size,\n" + "int cached_size = ::_pbi::ToCachedSize(data_size);\n" + "$cached_byte_size_field$.store(cached_size,\n" " std::memory_order_relaxed);\n"); } format("total_size += data_size;\n"); @@ -482,7 +473,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateByteSize( format( "total_size += $tag_size$ *\n" " " - "::$proto_ns$::internal::FromIntSize(this->_internal_$name$_size());\n" + "::_pbi::FromIntSize(this->_internal_$name$_size());\n" "total_size += data_size;\n"); } format.Outdent(); @@ -495,7 +486,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateConstinitInitializer( format("$name$_()"); if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, _$name$_cached_byte_size_(0)"); + format("\n, $cached_byte_size_name$(0)"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index ff7c208ff29..77ac598e905 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -37,6 +37,7 @@ #include <map> #include <string> + #include <google/protobuf/compiler/cpp/cpp_field.h> namespace google { @@ -48,7 +49,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { public: PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~PrimitiveFieldGenerator(); + ~PrimitiveFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -72,7 +73,7 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~PrimitiveOneofFieldGenerator(); + ~PrimitiveOneofFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -88,7 +89,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { public: RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~RepeatedPrimitiveFieldGenerator(); + ~RepeatedPrimitiveFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -97,8 +98,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const override; void GenerateMergingCode(io::Printer* printer) const override; void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} + void GenerateCopyConstructorCode(io::Printer* printer) const override {} void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc index 944b41ba906..7bf589fa388 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc @@ -33,9 +33,10 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_service.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> + #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h index f510716fedc..d237f9d732e 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h @@ -37,8 +37,9 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_options.h> + #include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/cpp/cpp_options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc index c736ce95272..4d8744976ba 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -33,10 +33,11 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include <google/protobuf/compiler/cpp/cpp_string_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/descriptor.pb.h> + #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/descriptor.pb.h> namespace google { @@ -50,36 +51,30 @@ void SetStringVariables(const FieldDescriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); + + const TProtoStringType kNS = "::" + (*variables)["proto_ns"] + "::internal::"; + const TProtoStringType kArenaStringPtr = kNS + "ArenaStringPtr"; + (*variables)["default"] = DefaultValue(options, descriptor); (*variables)["default_length"] = StrCat(descriptor->default_value_string().length()); - TProtoStringType default_variable_string = MakeDefaultName(descriptor); - (*variables)["default_variable_name"] = default_variable_string; + (*variables)["default_variable_name"] = MakeDefaultName(descriptor); + (*variables)["default_variable_field"] = MakeDefaultFieldName(descriptor); - if (!descriptor->default_value_string().empty()) { + if (descriptor->default_value_string().empty()) { + (*variables)["default_string"] = kNS + "GetEmptyStringAlreadyInited()"; + (*variables)["default_value"] = "&" + (*variables)["default_string"]; + (*variables)["lazy_variable_args"] = ""; + } else { (*variables)["lazy_variable"] = - QualifiedClassName(descriptor->containing_type(), options) + - "::" + default_variable_string; - } - - (*variables)["default_string"] = - descriptor->default_value_string().empty() - ? "::" + (*variables)["proto_ns"] + - "::internal::GetEmptyStringAlreadyInited()" - : (*variables)["lazy_variable"] + ".get()"; - (*variables)["init_value"] = - descriptor->default_value_string().empty() - ? "&::" + (*variables)["proto_ns"] + - "::internal::GetEmptyStringAlreadyInited()" - : "nullptr"; - (*variables)["default_value_tag"] = - "::" + (*variables)["proto_ns"] + "::internal::ArenaStringPtr::" + - (descriptor->default_value_string().empty() ? "Empty" : "NonEmpty") + - "Default{}"; - (*variables)["default_variable_or_tag"] = - (*variables)[descriptor->default_value_string().empty() - ? "default_value_tag" - : "lazy_variable"]; + StrCat(QualifiedClassName(descriptor->containing_type(), options), + "::", MakeDefaultFieldName(descriptor)); + + (*variables)["default_string"] = (*variables)["lazy_variable"] + ".get()"; + (*variables)["default_value"] = "nullptr"; + (*variables)["lazy_variable_args"] = (*variables)["lazy_variable"] + ", "; + } + (*variables)["pointer_type"] = descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; (*variables)["setter"] = @@ -116,9 +111,14 @@ void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { if (!inlined_) { format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); } else { + // Skips the automatic destruction; rather calls it explicitly if + // allocating arena is null. This is required to support message-owned + // arena (go/path-to-arenas) where a root proto is destroyed but + // InlinedStringField may have arena-allocated memory. + // // `_init_inline_xxx` is used for initializing default instances. format( - "::$proto_ns$::internal::InlinedStringField $name$_;\n" + "union { ::$proto_ns$::internal::InlinedStringField $name$_; };\n" "static std::true_type _init_inline_$name$_;\n"); } } @@ -204,8 +204,8 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " // @@protoc_insertion_point(field_get:$full_name$)\n"); if (!descriptor_->default_value_string().empty()) { format( - " if ($name$_.IsDefault(nullptr)) return " - "$default_variable_name$.get();\n"); + " if ($field$.IsDefault()) return " + "$default_variable_field$.get();\n"); } format( " return _internal_$name$();\n" @@ -216,7 +216,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( "inline PROTOBUF_ALWAYS_INLINE\n" "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" " $set_hasbit$\n" - " $name$_.$setter$($default_value_tag$, static_cast<ArgT0 &&>(arg0)," + " $field$.$setter$(static_cast<ArgT0 &&>(arg0)," " args..., GetArenaForAllocation());\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" @@ -227,9 +227,9 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( "inline PROTOBUF_ALWAYS_INLINE\n" "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" " $set_hasbit$\n" - " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0)," + " $field$.$setter$(static_cast<ArgT0 &&>(arg0)," " args..., GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$);\n" + "&$donating_states_word$, $mask_for_undonate$, this);\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" @@ -246,20 +246,20 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " return _s;\n" "}\n" "inline const TProtoStringType& $classname$::_internal_$name$() const {\n" - " return $name$_.Get();\n" + " return $field$.Get();\n" "}\n" "inline void $classname$::_internal_set_$name$(const TProtoStringType& " "value) {\n" " $set_hasbit$\n"); if (!inlined_) { format( - " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n" + " $field$.Set(value, GetArenaForAllocation());\n" "}\n"); } else { format( - " $name$_.Set(nullptr, value, GetArenaForAllocation(),\n" + " $field$.Set(value, GetArenaForAllocation(),\n" " _internal_$name$_donated(), &$donating_states_word$, " - "$mask_for_undonate$);\n" + "$mask_for_undonate$, this);\n" "}\n"); } format( @@ -267,14 +267,14 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " $set_hasbit$\n"); if (!inlined_) { format( - " return $name$_.Mutable($default_variable_or_tag$, " + " return $field$.Mutable($lazy_variable_args$" "GetArenaForAllocation());\n" "}\n"); } else { format( - " return $name$_.Mutable($default_variable_or_tag$, " + " return $field$.Mutable($lazy_variable_args$" "GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$);\n" + "&$donating_states_word$, $mask_for_undonate$, this);\n" "}\n"); } format( @@ -289,26 +289,23 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " }\n" " $clear_hasbit$\n"); if (!inlined_) { - format( - " auto* p = $name$_.ReleaseNonDefault($init_value$, " - "GetArenaForAllocation());\n"); + format(" auto* p = $field$.Release();\n"); if (descriptor_->default_value_string().empty()) { format( "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " if ($name$_.IsDefault($init_value$)) {\n" - " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + " if ($field$.IsDefault()) {\n" + " $field$.Set(\"\", GetArenaForAllocation());\n" " }\n" "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); } format(" return p;\n"); } else { format( - " return $name$_.Release(nullptr, GetArenaForAllocation(), " + " return $field$.Release(GetArenaForAllocation(), " "_internal_$name$_donated());\n"); } } else { - format( - " return $name$_.Release($init_value$, GetArenaForAllocation());\n"); + format(" return $field$.Release();\n"); } format( @@ -320,23 +317,21 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " $clear_hasbit$\n" " }\n"); if (!inlined_) { - format( - " $name$_.SetAllocated($init_value$, $name$,\n" - " GetArenaForAllocation());\n"); + format(" $field$.SetAllocated($name$, GetArenaForAllocation());\n"); if (descriptor_->default_value_string().empty()) { format( "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " if ($name$_.IsDefault($init_value$)) {\n" - " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + " if ($field$.IsDefault()) {\n" + " $field$.Set(\"\", GetArenaForAllocation());\n" " }\n" "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); } } else { // Currently, string fields with default value can't be inlined. format( - " $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), " + " $field$.SetAllocated(nullptr, $name$, GetArenaForAllocation(), " "_internal_$name$_donated(), &$donating_states_word$, " - "$mask_for_undonate$);\n"); + "$mask_for_undonate$, this);\n"); } format( "$annotate_set$" @@ -350,7 +345,7 @@ void StringFieldGenerator::GenerateNonInlineAccessorDefinitions( if (!descriptor_->default_value_string().empty()) { format( "const ::$proto_ns$::internal::LazyString " - "$classname$::$default_variable_name$" + "$classname$::$default_variable_field$" "{{{$default$, $default_length$}}, {nullptr}};\n"); } } @@ -358,11 +353,11 @@ void StringFieldGenerator::GenerateNonInlineAccessorDefinitions( void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const { Formatter format(printer, variables_); if (descriptor_->default_value_string().empty()) { - format("$name$_.ClearToEmpty();\n"); + format("$field$.ClearToEmpty();\n"); } else { GOOGLE_DCHECK(!inlined_); format( - "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n"); + "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n"); } } @@ -388,20 +383,20 @@ void StringFieldGenerator::GenerateMessageClearingCode( // // For non-inlined strings, we distinguish from non-default by comparing // instances, rather than contents. - format("$DCHK$(!$name$_.IsDefault(nullptr));\n"); + format("$DCHK$(!$field$.IsDefault());\n"); } if (descriptor_->default_value_string().empty()) { if (must_be_present) { - format("$name$_.ClearNonDefaultToEmpty();\n"); + format("$field$.ClearNonDefaultToEmpty();\n"); } else { - format("$name$_.ClearToEmpty();\n"); + format("$field$.ClearToEmpty();\n"); } } else { // Clear to a non-empty default is more involved, as we try to use the // Arena if one is present and may need to reallocate the string. format( - "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n "); + "$field$.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n "); } } @@ -416,34 +411,31 @@ void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { if (!inlined_) { format( "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n" - " $init_value$,\n" - " &$name$_, lhs_arena,\n" - " &other->$name$_, rhs_arena\n" + " &$field$, lhs_arena,\n" + " &other->$field$, rhs_arena\n" ");\n"); } else { - // At this point, it's guaranteed that the two fields being swapped are on - // the same arena. format( - "$name$_.Swap(&other->$name$_, nullptr, GetArenaForAllocation(), " - "_internal_$name$_donated(), other->_internal_$name$_donated(), " - "&$donating_states_word$, &(other->$donating_states_word$), " - "$mask_for_undonate$);\n"); + "::$proto_ns$::internal::InlinedStringField::InternalSwap(\n" + " &$field$, lhs_arena, " + "($inlined_string_donated_array$[0] & 0x1u) == 0, this,\n" + " &other->$field$, rhs_arena, " + "(other->$inlined_string_donated_array$[0] & 0x1u) == 0, other);\n"); } } void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { Formatter format(printer, variables_); if (inlined_ && descriptor_->default_value_string().empty()) { - // Automatic initialization will construct the string. return; } GOOGLE_DCHECK(!inlined_); - format("$name$_.UnsafeSetDefault($init_value$);\n"); + format("$field$.InitDefault();\n"); if (IsString(descriptor_, options_) && descriptor_->default_value_string().empty()) { format( "#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n" - " $name$_.Set($init_value$, \"\", GetArenaForAllocation());\n" + " $field$.Set(\"\", GetArenaForAllocation());\n" "#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"); } } @@ -452,6 +444,9 @@ void StringFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); GenerateConstructorCode(printer); + if (inlined_) { + format("new (&$field$) ::_pbi::InlinedStringField();\n"); + } if (HasHasbit(descriptor_)) { format("if (from._internal_has_$name$()) {\n"); @@ -463,13 +458,13 @@ void StringFieldGenerator::GenerateCopyConstructorCode( if (!inlined_) { format( - "$name$_.Set($default_value_tag$, from._internal_$name$(), \n" + "$field$.Set(from._internal_$name$(), \n" " GetArenaForAllocation());\n"); } else { format( - "$name$_.Set(nullptr, from._internal_$name$(),\n" + "$field$.Set(from._internal_$name$(),\n" " GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$);\n"); + "&$donating_states_word$, $mask_for_undonate$, this);\n"); } format.Outdent(); @@ -478,12 +473,30 @@ void StringFieldGenerator::GenerateCopyConstructorCode( void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { Formatter format(printer, variables_); - if (inlined_) { - // The destructor is automatically invoked. + if (!inlined_) { + format("$field$.Destroy();\n"); return; } + // Explicitly calls ~InlinedStringField as its automatic call is disabled. + // Destructor has been implicitly skipped as a union, and even the + // message-owned arena is enabled, arena could still be missing for + // Arena::CreateMessage(nullptr). + format("$field$.~InlinedStringField();\n"); +} - format("$name$_.DestroyNoArena($init_value$);\n"); +ArenaDtorNeeds StringFieldGenerator::NeedsArenaDestructor() const { + return inlined_ ? ArenaDtorNeeds::kOnDemand : ArenaDtorNeeds::kNone; +} + +void StringFieldGenerator::GenerateArenaDestructorCode( + io::Printer* printer) const { + if (!inlined_) return; + Formatter format(printer, variables_); + // _this is the object being destructed (we are inside a static method here). + format( + "if (!_this->_internal_$name$_donated()) {\n" + " _this->$field$.~InlinedStringField();\n" + "}\n"); } void StringFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -517,9 +530,11 @@ void StringFieldGenerator::GenerateConstinitInitializer( return; } if (descriptor_->default_value_string().empty()) { - format("$name$_(&::$proto_ns$::internal::fixed_address_empty_string)"); + format( + "$name$_(&::_pbi::fixed_address_empty_string, " + "::_pbi::ConstantInitialized{})"); } else { - format("$name$_(nullptr)"); + format("$name$_(nullptr, ::_pbi::ConstantInitialized{})"); } } @@ -550,9 +565,9 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( " if (!_internal_has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $field_member$.UnsafeSetDefault($init_value$);\n" + " $field$.InitDefault();\n" " }\n" - " $field_member$.$setter$($default_value_tag$," + " $field$.$setter$(" " static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" @@ -565,7 +580,7 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline const TProtoStringType& $classname$::_internal_$name$() const {\n" " if (_internal_has_$name$()) {\n" - " return $field_member$.Get();\n" + " return $field$.Get();\n" " }\n" " return $default_string$;\n" "}\n" @@ -574,28 +589,26 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( " if (!_internal_has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $field_member$.UnsafeSetDefault($init_value$);\n" + " $field$.InitDefault();\n" " }\n" - " $field_member$.Set($default_value_tag$, value, " - "GetArenaForAllocation());\n" + " $field$.Set(value, GetArenaForAllocation());\n" "}\n"); format( "inline TProtoStringType* $classname$::_internal_mutable_$name$() {\n" " if (!_internal_has_$name$()) {\n" " clear_$oneof_name$();\n" " set_has_$name$();\n" - " $field_member$.UnsafeSetDefault($init_value$);\n" + " $field$.InitDefault();\n" " }\n" - " return $field_member$.Mutable(\n" - " $default_variable_or_tag$, GetArenaForAllocation());\n" + " return $field$.Mutable($lazy_variable_args$" + " GetArenaForAllocation());\n" "}\n" "inline TProtoStringType* $classname$::$release_name$() {\n" "$annotate_release$" " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (_internal_has_$name$()) {\n" " clear_has_$oneof_name$();\n" - " return $field_member$.ReleaseNonDefault($init_value$, " - "GetArenaForAllocation());\n" + " return $field$.Release();\n" " } else {\n" " return nullptr;\n" " }\n" @@ -606,11 +619,7 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( " }\n" " if ($name$ != nullptr) {\n" " set_has_$name$();\n" - " $field_member$.UnsafeSetDefault($name$);\n" - " ::$proto_ns$::Arena* arena = GetArenaForAllocation();\n" - " if (arena != nullptr) {\n" - " arena->Own($name$);\n" - " }\n" + " $field$.InitAllocated($name$, GetArenaForAllocation());\n" " }\n" "$annotate_set$" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" @@ -620,9 +629,7 @@ void StringOneofFieldGenerator::GenerateInlineAccessorDefinitions( void StringOneofFieldGenerator::GenerateClearingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format( - "$field_member$.Destroy($default_value_tag$, " - "GetArenaForAllocation());\n"); + format("$field$.Destroy();\n"); } void StringOneofFieldGenerator::GenerateMessageClearingCode( @@ -737,14 +744,14 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline const TProtoStringType& $classname$::_internal_$name$(int index) " "const {\n" - " return $name$_.InternalCheckedGet(\n" + " return $field$.InternalCheckedGet(\n" " index, ::$proto_ns$::internal::GetEmptyStringAlreadyInited());\n" "}\n"); } else { format( "inline const TProtoStringType& $classname$::_internal_$name$(int index) " "const {\n" - " return $name$_.Get(index);\n" + " return $field$.Get(index);\n" "}\n"); } format( @@ -756,23 +763,23 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( "inline TProtoStringType* $classname$::mutable_$name$(int index) {\n" "$annotate_mutable$" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" - " return $name$_.Mutable(index);\n" + " return $field$.Mutable(index);\n" "}\n" "inline void $classname$::set_$name$(int index, const TProtoStringType& " "value) " "{\n" - " $name$_.Mutable(index)->assign(value);\n" + " $field$.Mutable(index)->assign(value);\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "inline void $classname$::set_$name$(int index, TProtoStringType&& value) {\n" - " $name$_.Mutable(index)->assign(std::move(value));\n" + " $field$.Mutable(index)->assign(std::move(value));\n" "$annotate_set$" " // @@protoc_insertion_point(field_set:$full_name$)\n" "}\n" "inline void $classname$::set_$name$(int index, const char* value) {\n" " $null_check$" - " $name$_.Mutable(index)->assign(value);\n" + " $field$.Mutable(index)->assign(value);\n" "$annotate_set$" " // @@protoc_insertion_point(field_set_char:$full_name$)\n" "}\n"); @@ -780,7 +787,7 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline void " "$classname$::set_$name$(int index, StringPiece value) {\n" - " $name$_.Mutable(index)->assign(value.data(), value.size());\n" + " $field$.Mutable(index)->assign(value.data(), value.size());\n" "$annotate_set$" " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n" "}\n"); @@ -789,34 +796,34 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( "inline void " "$classname$::set_$name$" "(int index, const $pointer_type$* value, size_t size) {\n" - " $name$_.Mutable(index)->assign(\n" + " $field$.Mutable(index)->assign(\n" " reinterpret_cast<const char*>(value), size);\n" "$annotate_set$" " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" "inline TProtoStringType* $classname$::_internal_add_$name$() {\n" - " return $name$_.Add();\n" + " return $field$.Add();\n" "}\n" "inline void $classname$::add_$name$(const TProtoStringType& value) {\n" - " $name$_.Add()->assign(value);\n" + " $field$.Add()->assign(value);\n" "$annotate_add$" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n" "inline void $classname$::add_$name$(TProtoStringType&& value) {\n" - " $name$_.Add(std::move(value));\n" + " $field$.Add(std::move(value));\n" "$annotate_add$" " // @@protoc_insertion_point(field_add:$full_name$)\n" "}\n" "inline void $classname$::add_$name$(const char* value) {\n" " $null_check$" - " $name$_.Add()->assign(value);\n" + " $field$.Add()->assign(value);\n" "$annotate_add$" " // @@protoc_insertion_point(field_add_char:$full_name$)\n" "}\n"); if (!options_.opensource_runtime) { format( "inline void $classname$::add_$name$(StringPiece value) {\n" - " $name$_.Add()->assign(value.data(), value.size());\n" + " $field$.Add()->assign(value.data(), value.size());\n" "$annotate_add$" " // @@protoc_insertion_point(field_add_string_piece:$full_name$)\n" "}\n"); @@ -824,7 +831,7 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline void " "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" - " $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" + " $field$.Add()->assign(reinterpret_cast<const char*>(value), size);\n" "$annotate_add$" " // @@protoc_insertion_point(field_add_pointer:$full_name$)\n" "}\n" @@ -832,43 +839,32 @@ void RepeatedStringFieldGenerator::GenerateInlineAccessorDefinitions( "$classname$::$name$() const {\n" "$annotate_list$" " // @@protoc_insertion_point(field_list:$full_name$)\n" - " return $name$_;\n" + " return $field$;\n" "}\n" "inline ::$proto_ns$::RepeatedPtrField<TProtoStringType>*\n" "$classname$::mutable_$name$() {\n" "$annotate_mutable_list$" " // @@protoc_insertion_point(field_mutable_list:$full_name$)\n" - " return &$name$_;\n" + " return &$field$;\n" "}\n"); } void RepeatedStringFieldGenerator::GenerateClearingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.Clear();\n"); + format("$field$.Clear();\n"); } void RepeatedStringFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.MergeFrom(from.$name$_);\n"); + format("$field$.MergeFrom(from.$field$);\n"); } void RepeatedStringFieldGenerator::GenerateSwappingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_.InternalSwap(&other->$name$_);\n"); -} - -void RepeatedStringFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - // Not needed for repeated fields. -} - -void RepeatedStringFieldGenerator::GenerateCopyConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$name$_.CopyFrom(from.$name$_);"); + format("$field$.InternalSwap(&other->$field$);\n"); } void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -895,11 +891,11 @@ void RepeatedStringFieldGenerator::GenerateByteSize( Formatter format(printer, variables_); format( "total_size += $tag_size$ *\n" - " ::$proto_ns$::internal::FromIntSize($name$_.size());\n" - "for (int i = 0, n = $name$_.size(); i < n; i++) {\n" + " ::$proto_ns$::internal::FromIntSize($field$.size());\n" + "for (int i = 0, n = $field$.size(); i < n; i++) {\n" " total_size += " "::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" - " $name$_.Get(i));\n" + " $field$.Get(i));\n" "}\n"); } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h index 3f05443f582..845bf073a93 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -37,6 +37,7 @@ #include <map> #include <string> + #include <google/protobuf/compiler/cpp/cpp_field.h> namespace google { @@ -48,7 +49,7 @@ class StringFieldGenerator : public FieldGenerator { public: StringFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~StringFieldGenerator(); + ~StringFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -64,11 +65,13 @@ class StringFieldGenerator : public FieldGenerator { void GenerateConstructorCode(io::Printer* printer) const override; void GenerateCopyConstructorCode(io::Printer* printer) const override; void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateArenaDestructorCode(io::Printer* printer) const override; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; void GenerateConstinitInitializer(io::Printer* printer) const override; bool IsInlined() const override { return inlined_; } + ArenaDtorNeeds NeedsArenaDestructor() const override; private: bool inlined_; @@ -79,7 +82,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator { public: StringOneofFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~StringOneofFieldGenerator(); + ~StringOneofFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; @@ -99,7 +102,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator { public: RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, const Options& options); - ~RepeatedStringFieldGenerator(); + ~RepeatedStringFieldGenerator() override; // implements FieldGenerator --------------------------------------- void GeneratePrivateMembers(io::Printer* printer) const override; @@ -108,8 +111,8 @@ class RepeatedStringFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const override; void GenerateMergingCode(io::Printer* printer) const override; void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; - void GenerateCopyConstructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} + void GenerateCopyConstructorCode(io::Printer* printer) const override {} void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; |