diff options
author | heretic <heretic@yandex-team.ru> | 2022-06-14 13:29:31 +0300 |
---|---|---|
committer | heretic <heretic@yandex-team.ru> | 2022-06-14 13:29:31 +0300 |
commit | 16f8be4f481c275c34795233c18f8d078382fcb3 (patch) | |
tree | 2363f1306ce2e17e72c0a48614256acd046990e6 /contrib/libs/protoc/src/google/protobuf/compiler/cpp | |
parent | 647dc68b78e469e5ab416e9b62885c9846fd511d (diff) | |
download | ydb-16f8be4f481c275c34795233c18f8d078382fcb3.tar.gz |
Update protobuf to 3.18.1
ref:4846abb21711ea0dc148d4c5df7b5edd3d1bdc69
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/cpp')
20 files changed, 1651 insertions, 756 deletions
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 3fa64a8640..793ab2d793 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 @@ -50,17 +50,18 @@ class EnumFieldGenerator : public FieldGenerator { ~EnumFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); @@ -73,10 +74,10 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator { ~EnumOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumOneofFieldGenerator); @@ -89,19 +90,20 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { ~RepeatedEnumFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const {} + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateMergeFromCodedStream(io::Printer* printer) const; void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); 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 9b0fcb02da..23ab1bc0bb 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 @@ -57,8 +57,9 @@ TProtoStringType ExtendeeClassName(const FieldDescriptor* descriptor) { } // anonymous namespace ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), options_(options) { + const Options& options, + MessageSCCAnalyzer* scc_analyzer) + : descriptor_(descriptor), options_(options), scc_analyzer_(scc_analyzer) { // Construct type_traits_. if (descriptor_->is_repeated()) { type_traits_ = "Repeated"; @@ -179,6 +180,18 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { " ::$proto_ns$::internal::$type_traits$, $field_type$, $packed$ >\n" " $scoped_name$($constant_name$, $1$);\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_extension.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h index 88c7dafbc3..5a32e84554 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -55,6 +55,8 @@ namespace protobuf { namespace compiler { namespace cpp { +class MessageSCCAnalyzer; + // Generates code for an extension, which may be within the scope of some // message or may be at file scope. This is much simpler than FieldGenerator // since extensions are just simple identifiers with interesting types. @@ -62,7 +64,8 @@ class ExtensionGenerator { public: // See generator.cc for the meaning of dllexport_decl. explicit ExtensionGenerator(const FieldDescriptor* descriptor, - const Options& options); + const Options& options, + MessageSCCAnalyzer* scc_analyzer); ~ExtensionGenerator(); // Header stuff. @@ -77,6 +80,7 @@ class ExtensionGenerator { const FieldDescriptor* descriptor_; TProtoStringType type_traits_; Options options_; + MessageSCCAnalyzer* scc_analyzer_; std::map<TProtoStringType, TProtoStringType> variables_; 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 09261aaddc..22e2a8a4a6 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 @@ -61,37 +61,39 @@ using internal::WireFormat; namespace { -TProtoStringType GenerateAnnotation(StringPiece substitute_template_prefix, - StringPiece prepared_template, - StringPiece substitute_template_suffix, - int field_index, StringPiece lambda_args, - StringPiece access_type) { - return strings::Substitute( - StrCat(substitute_template_prefix, prepared_template, - substitute_template_suffix), - field_index, access_type, lambda_args); +void MaySetAnnotationVariable(const Options& options, + StringPiece annotation_name, + StringPiece substitute_template_prefix, + StringPiece prepared_template, + int field_index, StringPiece access_type, + std::map<TProtoStringType, TProtoStringType>* variables) { + if (options.field_listener_options.forbidden_field_listener_events.count( + TProtoStringType(annotation_name))) + return; + (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( + StrCat(substitute_template_prefix, prepared_template, ");\n"), + field_index, access_type); } TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descriptor, StringPiece proto_ns, StringPiece field_member) { + TProtoStringType field_name = google::protobuf::compiler::cpp::FieldName(descriptor); TProtoStringType field_pointer = descriptor->options().ctype() == google::protobuf::FieldOptions::STRING ? "$0.GetPointer()" : "$0"; if (descriptor->default_value_string().empty()) { - return strings::Substitute( - StrCat("_internal_has_", - google::protobuf::compiler::cpp::FieldName(descriptor), - "()? _listener_->ExtractFieldInfo(", field_pointer, - "): ::", proto_ns, "::FieldAccessListener::AddressInfo()"), - field_member); + return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", + field_pointer, ": nullptr"), + field_member); } if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING_PIECE) { - return StrCat("_listener_->ExtractFieldInfo(_internal_", - google::protobuf::compiler::cpp::FieldName(descriptor), "())"); + return strings::Substitute(StrCat("_internal_has_", field_name, "() ? ", + field_pointer, ": nullptr"), + field_member); } TProtoStringType default_value_pointer = @@ -99,26 +101,24 @@ TProtoStringType GenerateTemplateForOneofString(const FieldDescriptor* descripto ? "&$1.get()" : "&$1"; return strings::Substitute( - StrCat("_listener_->ExtractFieldInfo(_internal_has_", - google::protobuf::compiler::cpp::FieldName(descriptor), "()? ", - field_pointer, " : ", default_value_pointer, ")"), + StrCat("_internal_has_", field_name, "() ? ", field_pointer, " : ", + default_value_pointer), field_member, MakeDefaultName(descriptor)); } TProtoStringType GenerateTemplateForSingleString(const FieldDescriptor* descriptor, StringPiece field_member) { if (descriptor->default_value_string().empty()) { - return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member); + return StrCat("&", field_member); } if (descriptor->options().ctype() == google::protobuf::FieldOptions::STRING) { return strings::Substitute( - "_listener_->ExtractFieldInfo($0.IsDefault(" - "nullptr) ? &$1.get() : $0.GetPointer())", - field_member, MakeDefaultName(descriptor)); + "$0.IsDefault(nullptr) ? &$1.get() : $0.GetPointer()", field_member, + MakeDefaultName(descriptor)); } - return strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member); + return StrCat("&", field_member); } } // namespace @@ -143,7 +143,7 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, " ", FieldName(descriptor), "_AccessedNoStrip = true;\n"); } } - if (!options.inject_field_listener_events) { + if (!options.field_listener_options.inject_field_listener_events) { return; } if (descriptor->file()->options().optimize_for() == @@ -157,50 +157,29 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, field_member = StrCat(oneof_member->name(), "_.", field_member); } const TProtoStringType proto_ns = (*variables)["proto_ns"]; - TProtoStringType lambda_args = "_listener_, this"; - TProtoStringType lambda_flat_args = "_listener_, this"; - const TProtoStringType substitute_template_prefix = StrCat( - " {\n" - " auto _listener_ = ::", - proto_ns, - "::FieldAccessListener::GetListener();\n" - " if (_listener_) _listener_->OnFieldAccess([$2] { return "); - const TProtoStringType substitute_template_suffix = StrCat( - "; }, " - "GetDescriptor()->field($0), " - "::", - proto_ns, - "::FieldAccessListener::FieldAccessType::$1);\n" - " }\n"); + const TProtoStringType substitute_template_prefix = " _tracker_.$1<$0>(this, "; TProtoStringType prepared_template; // Flat template is needed if the prepared one is introspecting the values // inside the returned values, for example, for repeated fields and maps. TProtoStringType prepared_flat_template; TProtoStringType prepared_add_template; - // TODO(jianzhouzh): Fix all forward declared messages and deal with the - // weak fields. + // TODO(b/190614678): Support fields with type Message or Map. if (descriptor->is_repeated() && !descriptor->is_map()) { if (descriptor->type() != FieldDescriptor::TYPE_MESSAGE && descriptor->type() != FieldDescriptor::TYPE_GROUP) { - lambda_args = "_listener_, this, index"; - prepared_template = strings::Substitute( - "_listener_->ExtractFieldInfo(&$0.Get(index))", field_member); - prepared_add_template = strings::Substitute( - "_listener_->ExtractFieldInfo(&$0.Get($0.size() - 1))", field_member); - } else { - prepared_template = - StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()"); + prepared_template = strings::Substitute("&$0.Get(index)", field_member); prepared_add_template = - StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()"); + strings::Substitute("&$0.Get($0.size() - 1)", field_member); + } else { + prepared_template = "nullptr"; + prepared_add_template = "nullptr"; } } else if (descriptor->is_map()) { - prepared_template = - StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()"); + prepared_template = "nullptr"; } else if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE && !descriptor->options().lazy()) { - prepared_template = - StrCat("::", proto_ns, "::FieldAccessListener::AddressInfo()"); + prepared_template = "nullptr"; } else if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { if (oneof_member) { prepared_template = GenerateTemplateForOneofString( @@ -210,56 +189,49 @@ void AddAccessorAnnotations(const FieldDescriptor* descriptor, GenerateTemplateForSingleString(descriptor, field_member); } } else { - prepared_template = - strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member); + prepared_template = StrCat("&", field_member); } if (descriptor->is_repeated() && !descriptor->is_map() && descriptor->type() != FieldDescriptor::TYPE_MESSAGE && descriptor->type() != FieldDescriptor::TYPE_GROUP) { - prepared_flat_template = - strings::Substitute("_listener_->ExtractFieldInfo(&$0)", field_member); + prepared_flat_template = StrCat("&", field_member); } else { prepared_flat_template = prepared_template; } - (*variables)["annotate_get"] = GenerateAnnotation( - substitute_template_prefix, prepared_template, substitute_template_suffix, - descriptor->index(), lambda_args, "kGet"); - (*variables)["annotate_set"] = GenerateAnnotation( - substitute_template_prefix, prepared_template, substitute_template_suffix, - descriptor->index(), lambda_args, "kSet"); - (*variables)["annotate_has"] = GenerateAnnotation( - substitute_template_prefix, prepared_template, substitute_template_suffix, - descriptor->index(), lambda_args, "kHas"); - (*variables)["annotate_mutable"] = GenerateAnnotation( - substitute_template_prefix, prepared_template, substitute_template_suffix, - descriptor->index(), lambda_args, "kMutable"); - (*variables)["annotate_release"] = GenerateAnnotation( - substitute_template_prefix, prepared_template, substitute_template_suffix, - descriptor->index(), lambda_args, "kRelease"); - (*variables)["annotate_clear"] = - GenerateAnnotation(substitute_template_prefix, prepared_flat_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kClear"); - (*variables)["annotate_size"] = - GenerateAnnotation(substitute_template_prefix, prepared_flat_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kSize"); - (*variables)["annotate_list"] = - GenerateAnnotation(substitute_template_prefix, prepared_flat_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kList"); - (*variables)["annotate_mutable_list"] = - GenerateAnnotation(substitute_template_prefix, prepared_flat_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kMutableList"); - (*variables)["annotate_add"] = - GenerateAnnotation(substitute_template_prefix, prepared_add_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kAdd"); - (*variables)["annotate_add_mutable"] = - GenerateAnnotation(substitute_template_prefix, prepared_add_template, - substitute_template_suffix, descriptor->index(), - lambda_flat_args, "kAddMutable"); + + MaySetAnnotationVariable(options, "get", substitute_template_prefix, + prepared_template, descriptor->index(), "OnGet", + variables); + MaySetAnnotationVariable(options, "set", substitute_template_prefix, + prepared_template, descriptor->index(), "OnSet", + variables); + MaySetAnnotationVariable(options, "has", substitute_template_prefix, + prepared_template, descriptor->index(), "OnHas", + variables); + MaySetAnnotationVariable(options, "mutable", substitute_template_prefix, + prepared_template, descriptor->index(), "OnMutable", + variables); + MaySetAnnotationVariable(options, "release", substitute_template_prefix, + prepared_template, descriptor->index(), "OnRelease", + variables); + MaySetAnnotationVariable(options, "clear", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnClear", variables); + MaySetAnnotationVariable(options, "size", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnSize", variables); + MaySetAnnotationVariable(options, "list", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnList", variables); + MaySetAnnotationVariable(options, "mutable_list", substitute_template_prefix, + prepared_flat_template, descriptor->index(), + "OnMutableList", variables); + MaySetAnnotationVariable(options, "add", substitute_template_prefix, + prepared_add_template, descriptor->index(), "OnAdd", + variables); + MaySetAnnotationVariable(options, "add_mutable", substitute_template_prefix, + prepared_add_template, descriptor->index(), + "OnAddMutable", variables); } void SetCommonFieldVariables(const FieldDescriptor* descriptor, @@ -310,6 +282,22 @@ void FieldGenerator::SetHasBitIndex(int32_t has_bit_index) { strings::Hex(1u << (has_bit_index % 32), strings::ZERO_PAD_8), "u;"); } +void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) { + if (!IsStringInlined(descriptor_, options_)) { + GOOGLE_CHECK_EQ(inlined_string_index, -1); + return; + } + variables_["inlined_string_donated"] = StrCat( + "(_inlined_string_donated_[", 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, "]"); + variables_["mask_for_undonate"] = StrCat( + "~0x", strings::Hex(1u << (inlined_string_index % 32), strings::ZERO_PAD_8), + "u"); +} + void SetCommonOneofFieldVariables( const FieldDescriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables) { 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 b05f2d93fa..d263b10e70 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 @@ -181,7 +181,10 @@ class FieldGenerator { // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; + virtual bool IsInlined() const { return false; } + void SetHasBitIndex(int32_t has_bit_index); + void SetInlinedStringIndex(int32_t inlined_string_index); protected: const FieldDescriptor* descriptor_; @@ -207,6 +210,12 @@ class FieldGeneratorMap { } } + void SetInlinedStringIndices(const std::vector<int>& inlined_string_indices) { + for (int i = 0; i < descriptor_->field_count(); ++i) { + field_generators_[i]->SetInlinedStringIndex(inlined_string_indices[i]); + } + } + private: const Descriptor* descriptor_; std::vector<std::unique_ptr<FieldGenerator>> field_generators_; 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 c371a55233..6e3f174c5b 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 @@ -131,7 +131,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) } for (int i = 0; i < file->extension_count(); i++) { extension_generators_.emplace_back( - new ExtensionGenerator(file->extension(i), options)); + new ExtensionGenerator(file->extension(i), options, &scc_analyzer_)); } for (int i = 0; i < file->weak_dependency_count(); ++i) { weak_deps_.insert(file->weak_dependency(i)); @@ -468,6 +468,19 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, DefaultInstanceType(generator->descriptor_, options_), DefaultInstanceName(generator->descriptor_, options_)); + for (int i = 0; i < generator->descriptor_->field_count(); i++) { + const FieldDescriptor* field = generator->descriptor_->field(i); + if (IsStringInlined(field, options_)) { + // Force the initialization of the inlined string in the default instance. + format( + "PROTOBUF_ATTRIBUTE_INIT_PRIORITY std::true_type " + "$1$::_init_inline_$2$_ = " + "($3$._instance.$2$_.Init(), std::true_type{});\n", + ClassName(generator->descriptor_), FieldName(field), + DefaultInstanceName(generator->descriptor_, options_)); + } + } + if (options_.lite_implicit_weak_fields) { format("$1$* $2$ = &$3$;\n", DefaultInstanceType(generator->descriptor_, options_), @@ -583,6 +596,13 @@ void FileGenerator::GenerateSourceForMessage(int idx, io::Printer* printer) { "// @@protoc_insertion_point(global_scope)\n"); } +void FileGenerator::GenerateSourceForExtension(int idx, io::Printer* printer) { + Formatter format(printer, variables_); + GenerateSourceIncludes(printer); + NamespaceOpener ns(Namespace(file_, options_), format); + extension_generators_[idx]->GenerateDefinition(printer); +} + void FileGenerator::GenerateGlobalSource(io::Printer* printer) { Formatter format(printer, variables_); GenerateSourceIncludes(printer); @@ -603,21 +623,6 @@ void FileGenerator::GenerateGlobalSource(io::Printer* printer) { for (int i = 0; i < enum_generators_.size(); i++) { enum_generators_[i]->GenerateMethods(i, printer); } - - // Define extensions. - for (int i = 0; i < extension_generators_.size(); i++) { - extension_generators_[i]->GenerateDefinition(printer); - } - - if (HasGenericServices(file_, options_)) { - // Generate services. - for (int i = 0; i < service_generators_.size(); i++) { - if (i == 0) format("\n"); - format(kThickSeparator); - format("\n"); - service_generators_[i]->GenerateImplementation(printer); - } - } } void FileGenerator::GenerateSource(io::Printer* printer) { @@ -1176,6 +1181,9 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { GOOGLE_CHECK(!options_.opensource_runtime); IncludeFile("net/proto2/public/lazy_field.h", printer); } + if (ShouldVerify(file_, options_, &scc_analyzer_)) { + IncludeFile("net/proto2/public/wire_format_verify.h", printer); + } if (options_.opensource_runtime) { // Verify the protobuf library header version is compatible with the protoc @@ -1203,6 +1211,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { IncludeFile("net/proto2/io/public/coded_stream.h", printer); IncludeFile("net/proto2/public/arena.h", printer); IncludeFile("net/proto2/public/arenastring.h", printer); + if (options_.force_inline_string || options_.profile_driven_inline_string) { + IncludeFile("net/proto2/public/inlined_string_field.h", 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) { 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 41e3907391..984bd26a31 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 @@ -82,9 +82,20 @@ class FileGenerator { void GeneratePBHeader(io::Printer* printer, const TProtoStringType& info_path); void GenerateSource(io::Printer* printer); + // The following member functions are used when the lite_implicit_weak_fields + // option is set. In this mode the code is organized a bit differently to + // promote better linker stripping of unused code. In particular, we generate + // one .cc file per message, one .cc file per extension, and a main pb.cc file + // containing everything else. + int NumMessages() const { return message_generators_.size(); } - // Similar to GenerateSource but generates only one message + int NumExtensions() const { return extension_generators_.size(); } + // Generates the source file for one message. void GenerateSourceForMessage(int idx, io::Printer* printer); + // Generates the source file for one extension. + void GenerateSourceForExtension(int idx, io::Printer* printer); + // Generates a source file containing everything except messages and + // extensions. void GenerateGlobalSource(io::Printer* printer); private: 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 1642299f98..7fe7511d0d 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 @@ -35,6 +35,7 @@ #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <memory> +#include <string> #include <utility> #include <vector> @@ -53,6 +54,12 @@ namespace cpp { CppGenerator::CppGenerator() {} CppGenerator::~CppGenerator() {} +namespace { +TProtoStringType NumberedCcFileName(const TProtoStringType& basename, int number) { + return StrCat(basename, ".out/", number, ".cc"); +} +} // namespace + bool CppGenerator::Generate(const FileDescriptor* file, const TProtoStringType& parameter, GeneratorContext* generator_context, @@ -107,7 +114,19 @@ bool CppGenerator::Generate(const FileDescriptor* file, } else if (options[i].first == "annotate_accessor") { file_options.annotate_accessor = true; } else if (options[i].first == "inject_field_listener_events") { - file_options.inject_field_listener_events = true; + file_options.field_listener_options.inject_field_listener_events = true; + } else if (options[i].first == "forbidden_field_listener_events") { + std::size_t pos = 0; + do { + std::size_t next_pos = options[i].second.find_first_of("+", pos); + if (next_pos == TProtoStringType::npos) { + next_pos = options[i].second.size(); + } + if (next_pos > pos) + file_options.field_listener_options.forbidden_field_listener_events + .insert(options[i].second.substr(pos, next_pos - pos)); + pos = next_pos + 1; + } while (pos < options[i].second.size()); } else if (options[i].first == "eagerly_verified_lazy") { file_options.eagerly_verified_lazy = true; } else if (options[i].first == "force_eagerly_verified_lazy") { @@ -206,24 +225,37 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_generator.GenerateGlobalSource(&printer); } - int num_cc_files = file_generator.NumMessages(); + int num_cc_files = + file_generator.NumMessages() + file_generator.NumExtensions(); // If we're using implicit weak fields then we allow the user to // optionally specify how many files to generate, not counting the global // pb.cc file. If we have more files than messages, then some files will // be generated as empty placeholders. if (file_options.num_cc_files > 0) { - GOOGLE_CHECK_LE(file_generator.NumMessages(), file_options.num_cc_files) - << "There must be at least as many numbered .cc files as messages."; + GOOGLE_CHECK_LE(num_cc_files, file_options.num_cc_files) + << "There must be at least as many numbered .cc files as messages " + "and extensions."; num_cc_files = file_options.num_cc_files; } - for (int i = 0; i < num_cc_files; i++) { - std::unique_ptr<io::ZeroCopyOutputStream> output( - generator_context->Open(StrCat(basename, ".out/", i, ".cc"))); + int cc_file_number = 0; + for (int i = 0; i < file_generator.NumMessages(); i++) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number++))); io::Printer printer(output.get(), '$'); - if (i < file_generator.NumMessages()) { - file_generator.GenerateSourceForMessage(i, &printer); - } + file_generator.GenerateSourceForMessage(i, &printer); + } + for (int i = 0; i < file_generator.NumExtensions(); i++) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number++))); + io::Printer printer(output.get(), '$'); + file_generator.GenerateSourceForExtension(i, &printer); + } + // Create empty placeholder files if necessary to match the expected number + // of files. + for (; cc_file_number < num_cc_files; ++cc_file_number) { + std::unique_ptr<io::ZeroCopyOutputStream> output(generator_context->Open( + NumberedCcFileName(basename, cc_file_number))); } } else { std::unique_ptr<io::ZeroCopyOutputStream> output( 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 0f9660d237..736b73a3ea 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 @@ -169,30 +169,6 @@ static std::unordered_set<TProtoStringType>* MakeKeywordsMap() { static std::unordered_set<TProtoStringType>& kKeywords = *MakeKeywordsMap(); -// Encode [0..63] as 'A'-'Z', 'a'-'z', '0'-'9', '_' -char Base63Char(int value) { - GOOGLE_CHECK_GE(value, 0); - if (value < 26) return 'A' + value; - value -= 26; - if (value < 26) return 'a' + value; - value -= 26; - if (value < 10) return '0' + value; - GOOGLE_CHECK_EQ(value, 10); - return '_'; -} - -// Given a c identifier has 63 legal characters we can't implement base64 -// encoding. So we return the k least significant "digits" in base 63. -template <typename I> -TProtoStringType Base63(I n, int k) { - TProtoStringType res; - while (k-- > 0) { - res += Base63Char(static_cast<int>(n % 63)); - n /= 63; - } - return res; -} - TProtoStringType IntTypeName(const Options& options, const TProtoStringType& type) { if (options.opensource_runtime) { return "::PROTOBUF_NAMESPACE_ID::" + type; @@ -400,7 +376,7 @@ TProtoStringType Namespace(const FileDescriptor* d, const Options& options) { ret = StringReplace(ret, "::google::" "protobuf", - "PROTOBUF_NAMESPACE_ID", false); + "::PROTOBUF_NAMESPACE_ID", false); } return ret; } @@ -454,9 +430,14 @@ TProtoStringType FileDllExport(const FileDescriptor* file, const Options& option TProtoStringType SuperClassName(const Descriptor* descriptor, const Options& options) { - return "::" + ProtobufNamespace(options) + - (HasDescriptorMethods(descriptor->file(), options) ? "::Message" - : "::MessageLite"); + if (!HasDescriptorMethods(descriptor->file(), options)) { + return "::" + ProtobufNamespace(options) + "::MessageLite"; + } + auto simple_base = SimpleBaseClass(descriptor, options); + if (simple_base.empty()) { + return "::" + ProtobufNamespace(options) + "::Message"; + } + return "::" + ProtobufNamespace(options) + "::internal::" + simple_base; } TProtoStringType ResolveKeyword(const TProtoStringType& name) { @@ -796,6 +777,11 @@ TProtoStringType SafeFunctionName(const Descriptor* descriptor, return function_name; } +bool IsStringInlined(const FieldDescriptor* /* descriptor */, + const Options& /* options */) { + return false; +} + static bool HasLazyFields(const Descriptor* descriptor, const Options& options, MessageSCCAnalyzer* scc_analyzer) { for (int field_idx = 0; field_idx < descriptor->field_count(); field_idx++) { @@ -953,6 +939,18 @@ bool HasEnumDefinitions(const FileDescriptor* file) { return false; } +bool ShouldVerify(const Descriptor* /* descriptor */, + const Options& /* options */, + MessageSCCAnalyzer* /* scc_analyzer */) { + return false; +} + +bool ShouldVerify(const FileDescriptor* /* file */, + const Options& /* options */, + MessageSCCAnalyzer* /* scc_analyzer */) { + return false; +} + bool IsStringOrMessage(const FieldDescriptor* field) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -1099,21 +1097,12 @@ void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, "VerifyUTF8CordNamedField", format); } -namespace { - -void Flatten(const Descriptor* descriptor, - std::vector<const Descriptor*>* flatten) { - for (int i = 0; i < descriptor->nested_type_count(); i++) - Flatten(descriptor->nested_type(i), flatten); - flatten->push_back(descriptor); -} - -} // namespace - void FlattenMessagesInFile(const FileDescriptor* file, std::vector<const Descriptor*>* result) { for (int i = 0; i < file->message_type_count(); i++) { - Flatten(file->message_type(i), result); + ForEachMessage(file->message_type(i), [&](const Descriptor* descriptor) { + result->push_back(descriptor); + }); } } @@ -1154,7 +1143,7 @@ bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) { if (analysis_cache_.count(scc)) return analysis_cache_[scc]; - MessageAnalysis result{}; + MessageAnalysis result; if (UsingImplicitWeakFields(scc->GetFile(), options_)) { result.contains_weak = true; } @@ -1481,6 +1470,10 @@ FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, return FileOptions::SPEED; } +bool EnableMessageOwnedArena(const Descriptor* /* desc */) { + return false; +} + } // namespace cpp } // namespace compiler } // namespace protobuf 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 1cc9329c86..8923903452 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 @@ -315,6 +315,8 @@ inline bool IsWeak(const FieldDescriptor* field, const Options& options) { return false; } +bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options); + // For a string field, returns the effective ctype. If the actual ctype is // not supported, returns the default of STRING. FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, @@ -325,6 +327,11 @@ inline bool IsCord(const FieldDescriptor* field, const Options& options) { EffectiveStringCType(field, options) == FieldOptions::CORD; } +inline bool IsString(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING; +} + inline bool IsStringPiece(const FieldDescriptor* field, const Options& options) { return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && @@ -533,6 +540,19 @@ inline std::vector<const Descriptor*> FlattenMessagesInFile( return result; } +template <typename F> +void ForEachMessage(const Descriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->nested_type_count(); i++) + ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func)); + func(descriptor); +} + +template <typename F> +void ForEachMessage(const FileDescriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->message_type_count(); i++) + ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func)); +} + bool HasWeakFields(const Descriptor* desc, const Options& options); bool HasWeakFields(const FileDescriptor* desc, const Options& options); @@ -545,11 +565,11 @@ inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, } struct MessageAnalysis { - bool is_recursive; - bool contains_cord; - bool contains_extension; - bool contains_required; - bool contains_weak; // Implicit weak as well. + bool is_recursive = false; + bool contains_cord = false; + bool contains_extension = false; + bool contains_required = false; + bool contains_weak = false; // Implicit weak as well. }; // This class is used in FileGenerator, to ensure linear instead of @@ -630,6 +650,36 @@ bool UsingImplicitWeakFields(const FileDescriptor* file, bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer); +inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return false; + if (desc->extension_range_count() != 0) return false; + if (desc->field_count() == 0) return true; + // TODO(jorg): Support additional common message types with only one + // or two fields + return false; +} + +inline bool HasSimpleBaseClasses(const FileDescriptor* file, + const Options& options) { + bool v = false; + ForEachMessage(file, [&v, &options](const Descriptor* desc) { + v |= HasSimpleBaseClass(desc, options); + }); + return v; +} + +inline TProtoStringType SimpleBaseClass(const Descriptor* desc, + const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return ""; + if (desc->extension_range_count() != 0) return ""; + if (desc->field_count() == 0) { + return "ZeroFieldsBase"; + } + // TODO(jorg): Support additional common message types with only one + // or two fields + return ""; +} + // Formatter is a functor class which acts as a closure around printer and // the variable map. It's much like printer->Print except it supports both named // variables that are substituted using a key value map and direct arguments. In @@ -884,8 +934,12 @@ inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); -inline bool EnableMessageOwnedArena(const Descriptor* /* desc */ ) { return false; } +bool EnableMessageOwnedArena(const Descriptor* desc); +bool ShouldVerify(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); +bool ShouldVerify(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer); } // namespace cpp } // namespace compiler } // namespace protobuf 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 cb890d5156..7d1535f3b9 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 @@ -43,6 +43,7 @@ #include <utility> #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> @@ -52,6 +53,7 @@ #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> @@ -181,6 +183,10 @@ bool CanBeManipulatedAsRawBytes(const FieldDescriptor* field, return ret; } +bool StrContains(const TProtoStringType& haystack, const TProtoStringType& needle) { + return haystack.find(needle) != TProtoStringType::npos; +} + // Finds runs of fields for which `predicate` is true. // RunMap maps from fields that start each run to the number of fields in that // run. This is optimized for the common case that there are very few runs in @@ -295,15 +301,6 @@ bool ShouldMarkClassAsFinal(const Descriptor* descriptor, return false; } -bool ShouldMarkClearAsFinal(const Descriptor* descriptor, - const Options& options) { - static std::set<TProtoStringType> exclusions{ - }; - - const TProtoStringType name = ClassName(descriptor, true); - return exclusions.find(name) == exclusions.end() || - options.opensource_runtime; -} // Returns true to make the message serialize in order, decided by the following // factors in the order of precedence. @@ -397,6 +394,16 @@ bool IsRequired(const std::vector<const FieldDescriptor*>& v) { return v.front()->is_required(); } +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()) { + return true; + } + } + return false; +} + // Collects neighboring fields based on a given criteria (equivalent predicate). template <typename Predicate> std::vector<std::vector<const FieldDescriptor*>> CollectFields( @@ -553,6 +560,88 @@ bool ColdChunkSkipper::OnEndChunk(int chunk, io::Printer* printer) { return true; } +void MaySetAnnotationVariable(const Options& options, + StringPiece annotation_name, + StringPiece injector_template_prefix, + StringPiece injector_template_suffix, + std::map<TProtoStringType, TProtoStringType>* variables) { + if (options.field_listener_options.forbidden_field_listener_events.count( + TProtoStringType(annotation_name))) + return; + (*variables)[StrCat("annotate_", annotation_name)] = strings::Substitute( + StrCat(injector_template_prefix, injector_template_suffix), + (*variables)["classtype"]); +} + +void GenerateExtensionAnnotations( + const Descriptor* descriptor, const Options& options, + std::map<TProtoStringType, TProtoStringType>* variables) { + const std::map<TProtoStringType, TProtoStringType> accessor_annotations_to_hooks = { + {"annotate_extension_has", "OnHasExtension"}, + {"annotate_extension_clear", "OnClearExtension"}, + {"annotate_extension_repeated_size", "OnExtensionSize"}, + {"annotate_extension_get", "OnGetExtension"}, + {"annotate_extension_mutable", "OnMutableExtension"}, + {"annotate_extension_set", "OnSetExtension"}, + {"annotate_extension_release", "OnReleaseExtension"}, + {"annotate_repeated_extension_get", "OnGetExtension"}, + {"annotate_repeated_extension_mutable", "OnMutableExtension"}, + {"annotate_repeated_extension_set", "OnSetExtension"}, + {"annotate_repeated_extension_add", "OnAddExtension"}, + {"annotate_repeated_extension_add_mutable", "OnAddMutableExtension"}, + {"annotate_repeated_extension_list", "OnListExtension"}, + {"annotate_repeated_extension_list_mutable", "OnMutableListExtension"}, + }; + for (const auto& annotation : accessor_annotations_to_hooks) { + (*variables)[annotation.first] = ""; + } + if (!options.field_listener_options.inject_field_listener_events || + descriptor->file()->options().optimize_for() == + google::protobuf::FileOptions::LITE_RUNTIME) { + return; + } + for (const auto& annotation : accessor_annotations_to_hooks) { + const TProtoStringType& annotation_name = annotation.first; + const TProtoStringType& listener_call = annotation.second; + if (!StrContains(annotation_name, "repeated") && + !StrContains(annotation_name, "size") && + !StrContains(annotation_name, "clear")) { + // 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()));"); + } 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"; + } + (*variables)[annotation_name] = + StrCat(" _tracker_.", listener_call, + "(this, id.number(), " + "_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_));"); + } else { + // Generic accessors such as "clear". + // TODO(b/190614678): Generalize clear from both repeated and non repeated + // calls, currently their underlying memory interfaces are very different. + // Or think of removing clear callback as no usages are needed and no + // memory exist after calling clear(). + } + } +} + } // anonymous namespace // =================================================================== @@ -567,6 +656,7 @@ MessageGenerator::MessageGenerator( options_(options), field_generators_(descriptor, options, scc_analyzer), max_has_bit_index_(0), + max_inlined_string_index_(0), num_weak_fields_(0), scc_analyzer_(scc_analyzer), variables_(vars) { @@ -583,36 +673,31 @@ MessageGenerator::MessageGenerator( variables_["annotate_deserialize"] = ""; variables_["annotate_reflection"] = ""; variables_["annotate_bytesize"] = ""; + variables_["annotate_mergefrom"] = ""; - if (options.inject_field_listener_events && + if (options.field_listener_options.inject_field_listener_events && descriptor->file()->options().optimize_for() != google::protobuf::FileOptions::LITE_RUNTIME) { - const TProtoStringType injector_template = StrCat( - " {\n" - " auto _listener_ = ::", - variables_["proto_ns"], - "::FieldAccessListener::GetListener();\n" - " if (_listener_) "); - - StrAppend(&variables_["annotate_serialize"], injector_template, - "_listener_->OnSerializationAccess(this);\n" - " }\n"); - StrAppend(&variables_["annotate_deserialize"], injector_template, - " _listener_->OnDeserializationAccess(this);\n" - " }\n"); + const TProtoStringType injector_template = " _tracker_."; + + MaySetAnnotationVariable(options, "serialize", injector_template, + "OnSerialize(this);\n", &variables_); + MaySetAnnotationVariable(options, "deserialize", injector_template, + "OnDeserialize(this);\n", &variables_); // TODO(danilak): Ideally annotate_reflection should not exist and we need // to annotate all reflective calls on our own, however, as this is a cause // for side effects, i.e. reading values dynamically, we want the users know // that dynamic access can happen. - StrAppend(&variables_["annotate_reflection"], injector_template, - "_listener_->OnReflectionAccess(default_instance()" - ".GetMetadata().descriptor);\n" - " }\n"); - StrAppend(&variables_["annotate_bytesize"], injector_template, - "_listener_->OnByteSizeAccess(this);\n" - " }\n"); + MaySetAnnotationVariable(options, "reflection", injector_template, + "OnGetMetadata();\n", &variables_); + MaySetAnnotationVariable(options, "bytesize", injector_template, + "OnByteSize(this);\n", &variables_); + MaySetAnnotationVariable(options, "mergefrom", injector_template, + "OnMergeFrom(this, &from);\n", &variables_); } + GenerateExtensionAnnotations(descriptor_, options_, &variables_); + SetUnknownFieldsVariable(descriptor_, options_, &variables_); // Compute optimized field order to be used for layout and initialization @@ -640,12 +725,22 @@ MessageGenerator::MessageGenerator( } has_bit_indices_[field->index()] = max_has_bit_index_++; } + if (IsStringInlined(field, options_)) { + if (inlined_string_indices_.empty()) { + inlined_string_indices_.resize(descriptor_->field_count(), kNoHasbit); + } + inlined_string_indices_[field->index()] = max_inlined_string_index_++; + } } if (!has_bit_indices_.empty()) { field_generators_.SetHasBitIndices(has_bit_indices_); } + if (!inlined_string_indices_.empty()) { + field_generators_.SetInlinedStringIndices(inlined_string_indices_); + } + num_required_fields_ = 0; for (int i = 0; i < descriptor->field_count(); i++) { if (descriptor->field(i)->is_required()) { @@ -656,8 +751,8 @@ MessageGenerator::MessageGenerator( table_driven_ = TableDrivenParsingEnabled(descriptor_, options_, scc_analyzer_); parse_function_generator_.reset(new ParseFunctionGenerator( - descriptor_, max_has_bit_index_, has_bit_indices_, options_, - scc_analyzer_, variables_)); + descriptor_, max_has_bit_index_, has_bit_indices_, + inlined_string_indices_, options_, scc_analyzer_, variables_)); } MessageGenerator::~MessageGenerator() = default; @@ -666,6 +761,10 @@ size_t MessageGenerator::HasBitsSize() const { return (max_has_bit_index_ + 31) / 32; } +size_t MessageGenerator::InlinedStringDonatedSize() const { + return (max_inlined_string_index_ + 31) / 32; +} + int MessageGenerator::HasBitIndex(const FieldDescriptor* field) const { return has_bit_indices_.empty() ? kNoHasbit : has_bit_indices_[field->index()]; @@ -690,8 +789,8 @@ void MessageGenerator::AddGenerators( enum_generators_.push_back(enum_generators->back().get()); } for (int i = 0; i < descriptor_->extension_count(); i++) { - extension_generators->emplace_back( - new ExtensionGenerator(descriptor_->extension(i), options_)); + extension_generators->emplace_back(new ExtensionGenerator( + descriptor_->extension(i), options_, scc_analyzer_)); extension_generators_.push_back(extension_generators->back().get()); } } @@ -777,9 +876,206 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (descriptor_->extension_range_count() > 0) { - // Generate accessors for extensions. We just call a macro located in - // extension_set.h since the accessors about 80 lines of static code. - format("$GOOGLE_PROTOBUF$_EXTENSION_ACCESSORS($classname$)\n"); + // Generate accessors for extensions. + // We use "_proto_TypeTraits" as a type name below because "TypeTraits" + // causes problems if the class has a nested message or enum type with that + // name and "_TypeTraits" is technically reserved for the C++ library since + // it starts with an underscore followed by a capital letter. + // + // For similar reason, we use "_field_type" and "_is_packed" as parameter + // names below, so that "field_type" and "is_packed" can be used as field + // names. + format(R"( +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void ClearExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { + _extensions_.ClearExtension(id.number()); +$annotate_extension_clear$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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_, + id.default_value()); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Singular::MutableType MutableExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_mutable$ + return _proto_TypeTraits::Mutable(id.number(), _field_type, + &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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_); +$annotate_extension_set$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void SetAllocatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::SetAllocated(id.number(), _field_type, value, + &_extensions_); +$annotate_extension_set$ +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void UnsafeArenaSetAllocatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + typename _proto_TypeTraits::Singular::MutableType value) { + _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type, + value, &_extensions_); +$annotate_extension_set$ +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline PROTOBUF_MUST_USE_RESULT + typename _proto_TypeTraits::Singular::MutableType + ReleaseExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_release$ + return _proto_TypeTraits::Release(id.number(), _field_type, + &_extensions_); +} +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Singular::MutableType +UnsafeArenaReleaseExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_extension_release$ + return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type, + &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::ConstType GetExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + int index) const { +$annotate_repeated_extension_get$ + return _proto_TypeTraits::Get(id.number(), _extensions_, index); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::MutableType MutableExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id, + int index) { +$annotate_repeated_extension_mutable$ + return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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_); +$annotate_repeated_extension_set$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +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_); +$annotate_repeated_extension_add_mutable$ + return to_add; +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline void AddExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $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_); +$annotate_repeated_extension_add$ +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline const typename _proto_TypeTraits::Repeated::RepeatedFieldType& +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_); +} + +template <typename _proto_TypeTraits, + ::PROTOBUF_NAMESPACE_ID::internal::FieldType _field_type, + bool _is_packed> +inline typename _proto_TypeTraits::Repeated::RepeatedFieldType* +MutableRepeatedExtension( + const ::PROTOBUF_NAMESPACE_ID::internal::ExtensionIdentifier< + $classname$, _proto_TypeTraits, _field_type, _is_packed>& id) { +$annotate_repeated_extension_list_mutable$ + return _proto_TypeTraits::MutableRepeated(id.number(), _field_type, + _is_packed, &_extensions_); +} + +)"); // Generate MessageSet specific APIs for proto2 MessageSet. // For testing purposes we don't check for bridge.MessageSet, so // we don't use IsProto2MessageSet @@ -1145,8 +1441,10 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { } else { format("inline $classname$() : $classname$(nullptr) {}\n"); } + if (!HasSimpleBaseClass(descriptor_, options_)) { + format("~$classname$() override;\n"); + } format( - "~$classname$() override;\n" "explicit constexpr " "$classname$(::$proto_ns$::internal::ConstantInitialized);\n" "\n" @@ -1162,7 +1460,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "}\n" "inline $classname$& operator=($classname$&& from) noexcept {\n" " if (this == &from) return *this;\n" - " if (GetOwningArena() == from.GetOwningArena()) {\n" + " if (GetOwningArena() == from.GetOwningArena()\n" + "#ifdef PROTOBUF_FORCE_COPY_IN_MOVE\n" + " && GetOwningArena() != nullptr\n" + "#endif // !PROTOBUF_FORCE_COPY_IN_MOVE\n" + " ) {\n" " InternalSwap(&from);\n" " } else {\n" " CopyFrom(from);\n" @@ -1174,7 +1476,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { if (options_.table_driven_serialization) { format( "private:\n" - "const void* InternalGetTable() const;\n" + "const void* InternalGetTable() const override;\n" "public:\n" "\n"); } @@ -1213,7 +1515,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { " return default_instance().GetMetadata().descriptor;\n" "}\n" "static const ::$proto_ns$::Reflection* GetReflection() {\n" - "$annotate_reflection$" " return default_instance().GetMetadata().reflection;\n" "}\n"); } @@ -1362,22 +1663,36 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - // Use Message's built-in MergeFrom and CopyFrom when the passed-in - // argument is a generic Message instance, and only define the custom - // MergeFrom and CopyFrom instances when the source of the merge/copy - // is known to be the same class as the destination. - // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than the - // other way around, to save even more code size. - "using $superclass$::CopyFrom;\n" - "void CopyFrom(const $classname$& from);\n" - "" - "using $superclass$::MergeFrom;\n" - "void MergeFrom(const $classname$& from);\n" - "private:\n" - "static void MergeImpl(::$proto_ns$::Message*to, const " - "::$proto_ns$::Message&from);\n" - "public:\n"); + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + // Use Message's built-in MergeFrom and CopyFrom when the passed-in + // argument is a generic Message instance, and only define the + // custom MergeFrom and CopyFrom instances when the source of the + // merge/copy is known to be the same class as the destination. + // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than + // the other way around, to save even more code size. + "using $superclass$::CopyFrom;\n" + "void CopyFrom(const $classname$& from);\n" + "" + "using $superclass$::MergeFrom;\n" + "void MergeFrom(const $classname$& from);\n" + "private:\n" + "static void MergeImpl(::$proto_ns$::Message* to, const " + "::$proto_ns$::Message& from);\n" + "public:\n"); + } else { + format( + "using $superclass$::CopyFrom;\n" + "inline void CopyFrom(const $classname$& from) {\n" + " $superclass$::CopyImpl(this, from);\n" + "}\n" + "" + "using $superclass$::MergeFrom;\n" + "void MergeFrom(const $classname$& from) {\n" + " $superclass$::MergeImpl(this, from);\n" + "}\n" + "public:\n"); + } } else { format( "void CheckTypeAndMergeFrom(const ::$proto_ns$::MessageLite& from)" @@ -1386,36 +1701,42 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "void MergeFrom(const $classname$& from);\n"); } - format.Set("clear_final", - ShouldMarkClearAsFinal(descriptor_, options_) ? "final" : ""); - - format( - "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear()$ clear_final$;\n" - "bool IsInitialized() const final;\n" - "\n" - "size_t ByteSizeLong() const final;\n"); + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "PROTOBUF_ATTRIBUTE_REINITIALIZES void Clear() final;\n" + "bool IsInitialized() const final;\n" + "\n" + "size_t ByteSizeLong() const final;\n"); - parse_function_generator_->GenerateMethodDecls(printer); + parse_function_generator_->GenerateMethodDecls(printer); - format( - "$uint8$* _InternalSerialize(\n" - " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " - "const final;\n"); - - // DiscardUnknownFields() is implemented in message.cc using reflections. We - // need to implement this function in generated code for messages. - if (!UseUnknownFieldSet(descriptor_->file(), options_)) { - format("void DiscardUnknownFields()$ full_final$;\n"); + format( + "$uint8$* _InternalSerialize(\n" + " $uint8$* target, ::$proto_ns$::io::EpsCopyOutputStream* stream) " + "const final;\n"); + + // DiscardUnknownFields() is implemented in message.cc using reflections. + // We need to implement this function in generated code for messages. + if (!UseUnknownFieldSet(descriptor_->file(), options_)) { + format("void DiscardUnknownFields()$ full_final$;\n"); + } } } - format( - "int GetCachedSize() const final { return _cached_size_.Get(); }" - "\n\nprivate:\n" - "void SharedCtor();\n" - "void SharedDtor();\n" - "void SetCachedSize(int size) const$ full_final$;\n" - "void InternalSwap($classname$* other);\n"); + if (options_.field_listener_options.inject_field_listener_events) { + format("static constexpr int _kInternalFieldNumber = $1$;\n", + descriptor_->field_count()); + } + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "int GetCachedSize() const final { return _cached_size_.Get(); }" + "\n\nprivate:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" + "void SetCachedSize(int size) const$ full_final$;\n" + "void InternalSwap($classname$* other);\n"); + } format( // Friend AnyMetadata so that it can call this FullMessageName() method. @@ -1433,9 +1754,13 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "protected:\n" "explicit $classname$(::$proto_ns$::Arena* arena,\n" " bool is_message_owned = false);\n" - "private:\n" - "static void ArenaDtor(void* object);\n" - "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n"); + "private:\n"); + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "static void ArenaDtor(void* object);\n" + "inline void RegisterArenaDtor(::$proto_ns$::Arena* arena);\n"); + } format( "public:\n" @@ -1562,6 +1887,21 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "\n"); } + if (options_.field_listener_options.inject_field_listener_events && + descriptor_->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME) { + format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n", + ClassName(descriptor_)); + } + + // Generate _inlined_string_donated_ for inlined string type. + // TODO(congliu): To avoid affecting the locality of `_has_bits_`, should this + // be below or above `_has_bits_`? + if (!inlined_string_indices_.empty()) { + format("::$proto_ns$::internal::HasBits<$1$> _inlined_string_donated_;\n", + InlinedStringDonatedSize()); + } + format( "template <typename T> friend class " "::$proto_ns$::Arena::InternalHelper;\n" @@ -1731,8 +2071,17 @@ void MessageGenerator::GenerateSchema(io::Printer* printer, int offset, has_offset = !has_bit_indices_.empty() || IsMapEntryMessage(descriptor_) ? offset + has_offset : -1; + int inlined_string_indices_offset; + if (inlined_string_indices_.empty()) { + inlined_string_indices_offset = -1; + } else { + GOOGLE_DCHECK_NE(has_offset, -1); + GOOGLE_DCHECK(!IsMapEntryMessage(descriptor_)); + inlined_string_indices_offset = has_offset + has_bit_indices_.size(); + } - format("{ $1$, $2$, sizeof($classtype$)},\n", offset, has_offset); + format("{ $1$, $2$, $3$, sizeof($classtype$)},\n", offset, has_offset, + inlined_string_indices_offset); } namespace { @@ -1746,7 +2095,9 @@ uint32_t CalcFieldNum(const FieldGenerator& generator, if (type == FieldDescriptor::TYPE_STRING || type == FieldDescriptor::TYPE_BYTES) { // string field - if (IsCord(field, options)) { + 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; @@ -1956,13 +2307,24 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { " MergeFromInternal(other);\n" "}\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" - " return ::$proto_ns$::internal::AssignDescriptors(\n" - " &$desc_table$_getter, &$desc_table$_once,\n" - " $file_level_metadata$[$1$]);\n" - "}\n", - index_in_file_messages_); + if (!descriptor_->options().map_entry()) { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + "$annotate_reflection$" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } else { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } } return; } @@ -2059,10 +2421,12 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { GenerateClear(printer); format("\n"); - parse_function_generator_->GenerateMethodImpls(printer); - format("\n"); + if (!HasSimpleBaseClass(descriptor_, options_)) { + parse_function_generator_->GenerateMethodImpls(printer); + format("\n"); - parse_function_generator_->GenerateDataDefinitions(printer); + parse_function_generator_->GenerateDataDefinitions(printer); + } GenerateSerializeWithCachedSizesToArray(printer); format("\n"); @@ -2083,6 +2447,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { format("\n"); } + GenerateVerify(printer); + GenerateSwap(printer); format("\n"); @@ -2095,13 +2461,24 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { index_in_file_messages_); } if (HasDescriptorMethods(descriptor_->file(), options_)) { - format( - "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" - " return ::$proto_ns$::internal::AssignDescriptors(\n" - " &$desc_table$_getter, &$desc_table$_once,\n" - " $file_level_metadata$[$1$]);\n" - "}\n", - index_in_file_messages_); + if (!descriptor_->options().map_entry()) { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + "$annotate_reflection$" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } else { + format( + "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n" + " return ::$proto_ns$::internal::AssignDescriptors(\n" + " &$desc_table$_getter, &$desc_table$_once,\n" + " $file_level_metadata$[$1$]);\n" + "}\n", + index_in_file_messages_); + } } else { format( "TProtoStringType $classname$::GetTypeName() const {\n" @@ -2110,6 +2487,14 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { "\n"); } + if (options_.field_listener_options.inject_field_listener_events && + descriptor_->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME) { + format( + "::$proto_ns$::AccessListener<$classtype$> " + "$1$::_tracker_(&FullMessageName);\n", + ClassName(descriptor_)); + } } size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { @@ -2148,9 +2533,13 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { } 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; @@ -2162,6 +2551,9 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { } 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; @@ -2326,7 +2718,12 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( } else { format("~0u, // no _weak_field_map_\n"); } - const int kNumGenericOffsets = 5; // the number of fixed offsets above + if (!inlined_string_indices_.empty()) { + format("PROTOBUF_FIELD_OFFSET($classtype$, _inlined_string_donated_),\n"); + } else { + format("~0u, // no _inlined_string_donated_\n"); + } + const int kNumGenericOffsets = 6; // the number of fixed offsets above const size_t offsets = kNumGenericOffsets + descriptor_->field_count() + descriptor_->real_oneof_decl_count(); size_t entries = offsets; @@ -2345,10 +2742,18 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_)", FieldName(field)); } + // Some information about a field is in the pdproto profile. The profile is + // only available at compile time. So we embed such information in the + // offset of the field, so that the information is available when reflective + // 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"); } else if (IsEagerlyVerifiedLazy(field, options_, scc_analyzer_)) { format(" | 0x1u, // eagerly verified lazy\n"); + } else if (IsStringInlined(field, options_)) { + format(" | 0x1u, // inlined\n"); } else { format(",\n"); } @@ -2374,11 +2779,21 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( format("$1$,\n", index); } } + 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); + } + } return std::make_pair(entries, offsets); } void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); format("void $classname$::SharedCtor() {\n"); @@ -2394,6 +2809,7 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { } void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); format("inline void $classname$::SharedDtor() {\n"); @@ -2424,6 +2840,7 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { } void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); // Generate the ArenaDtor() method. Track whether any fields actually produced @@ -2593,7 +3010,8 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { bool has_arena_constructor = field->is_repeated(); if (!field->real_containing_oneof() && (IsLazy(field, options_, scc_analyzer_) || - IsStringPiece(field, options_))) { + IsStringPiece(field, options_) || + (IsString(field, options_) && IsStringInlined(field, options_)))) { has_arena_constructor = true; } if (has_arena_constructor) { @@ -2620,15 +3038,29 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { format( "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" " bool is_message_owned)\n" - " : $1$ {\n" - " SharedCtor();\n" - " if (!is_message_owned) {\n" - " RegisterArenaDtor(arena);\n" - " }\n" - " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" - "}\n", + " : $1$ {\n", initializer_with_arena); + 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(" }\n"); + } + + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + " SharedCtor();\n" + " if (!is_message_owned) {\n" + " RegisterArenaDtor(arena);\n" + " }\n"); + } + format( + " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" + "}\n"); + std::map<TProtoStringType, TProtoStringType> vars; SetUnknownFieldsVariable(descriptor_, options_, &vars); format.AddMap(vars); @@ -2652,6 +3084,9 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { format.Indent(); format.Indent(); + // Do not copy inlined_string_donated_, because this is not an arena + // constructor. + if (!has_bit_indices_.empty()) { format(",\n_has_bits_(from._has_bits_)"); } @@ -2726,14 +3161,22 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { GenerateSharedConstructorCode(printer); // Generate the destructor. - format( - "$classname$::~$classname$() {\n" - " // @@protoc_insertion_point(destructor:$full_name$)\n" - " if (GetArenaForAllocation() != nullptr) return;\n" - " SharedDtor();\n" - " _internal_metadata_.Delete<$unknown_fields_type$>();\n" - "}\n" - "\n"); + if (!HasSimpleBaseClass(descriptor_, options_)) { + format( + "$classname$::~$classname$() {\n" + " // @@protoc_insertion_point(destructor:$full_name$)\n" + " if (GetArenaForAllocation() != nullptr) return;\n" + " SharedDtor();\n" + " _internal_metadata_.Delete<$unknown_fields_type$>();\n" + "}\n" + "\n"); + } else { + // For messages using simple base classes, having no destructor + // allows our vtable to share the same destructor as every other + // message with a simple base class. This works only as long as + // we have no fields needing destruction, of course. (No strings + // or extensions) + } // Generate the shared destructor code. GenerateSharedDestructorCode(printer); @@ -2741,11 +3184,13 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { // Generate the arena-specific destructor code. GenerateArenaDestructorCode(printer); - // Generate SetCachedSize. - format( - "void $classname$::SetCachedSize(int size) const {\n" - " _cached_size_.Set(size);\n" - "}\n"); + if (!HasSimpleBaseClass(descriptor_, options_)) { + // Generate SetCachedSize. + format( + "void $classname$::SetCachedSize(int size) const {\n" + " _cached_size_.Set(size);\n" + "}\n"); + } } void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { @@ -2759,6 +3204,7 @@ void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { } void MessageGenerator::GenerateClear(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); // The maximum number of bytes we will memset to zero without checking their @@ -2916,6 +3362,8 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { 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"); @@ -2975,6 +3423,7 @@ void MessageGenerator::GenerateOneofClear(io::Printer* printer) { } void MessageGenerator::GenerateSwap(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); format("void $classname$::InternalSwap($classname$* other) {\n"); @@ -2989,6 +3438,11 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { std::map<TProtoStringType, TProtoStringType> vars; SetUnknownFieldsVariable(descriptor_, options_, &vars); format.AddMap(vars); + if (HasSingularString(descriptor_, options_)) { + format( + "auto* lhs_arena = GetArenaForAllocation();\n" + "auto* rhs_arena = other->GetArenaForAllocation();\n"); + } format("_internal_metadata_.InternalSwap(&other->_internal_metadata_);\n"); if (!has_bit_indices_.empty()) { @@ -3056,47 +3510,64 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { Formatter format(printer, variables_); - if (HasDescriptorMethods(descriptor_->file(), options_)) { - // We don't override the generalized MergeFrom (aka that which - // takes in the Message base class as a parameter); instead we just - // let the base Message::MergeFrom take care of it. The base MergeFrom - // knows how to quickly confirm the types exactly match, and if so, will - // use GetClassData() to retrieve the address of MergeImpl, which calls - // the fast MergeFrom overload. Most callers avoid all this by passing - // a "from" message that is the same type as the message being merged - // into, rather than a generic Message. + if (!HasSimpleBaseClass(descriptor_, options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { + // We don't override the generalized MergeFrom (aka that which + // takes in the Message base class as a parameter); instead we just + // let the base Message::MergeFrom take care of it. The base MergeFrom + // knows how to quickly confirm the types exactly match, and if so, will + // use GetClassData() to retrieve the address of MergeImpl, which calls + // the fast MergeFrom overload. Most callers avoid all this by passing + // a "from" message that is the same type as the message being merged + // into, rather than a generic Message. + format( + "const ::$proto_ns$::Message::ClassData " + "$classname$::_class_data_ = {\n" + " ::$proto_ns$::Message::CopyWithSizeCheck,\n" + " $classname$::MergeImpl\n" + "};\n" + "const ::$proto_ns$::Message::ClassData*" + "$classname$::GetClassData() const { return &_class_data_; }\n" + "\n" + "void $classname$::MergeImpl(::$proto_ns$::Message* to,\n" + " const ::$proto_ns$::Message& from) {\n" + " static_cast<$classname$ *>(to)->MergeFrom(\n" + " static_cast<const $classname$ &>(from));\n" + "}\n" + "\n"); + } else { + // Generate CheckTypeAndMergeFrom(). + format( + "void $classname$::CheckTypeAndMergeFrom(\n" + " const ::$proto_ns$::MessageLite& from) {\n" + " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n" + " &from));\n" + "}\n"); + } + } else { + // In the simple case, we just define ClassData that vectors back to the + // simple implementation of Copy and Merge. format( "const ::$proto_ns$::Message::ClassData " "$classname$::_class_data_ = {\n" - " ::$proto_ns$::Message::CopyWithSizeCheck,\n" - " $classname$::MergeImpl\n" + " $superclass$::CopyImpl,\n" + " $superclass$::MergeImpl,\n" "};\n" "const ::$proto_ns$::Message::ClassData*" "$classname$::GetClassData() const { return &_class_data_; }\n" "\n" - "void $classname$::MergeImpl(::$proto_ns$::Message*to,\n" - " const ::$proto_ns$::Message&from) {\n" - " static_cast<$classname$ *>(to)->MergeFrom(\n" - " static_cast<const $classname$ &>(from));\n" - "}\n" "\n"); - } else { - // Generate CheckTypeAndMergeFrom(). - format( - "void $classname$::CheckTypeAndMergeFrom(\n" - " const ::$proto_ns$::MessageLite& from) {\n" - " MergeFrom(*::$proto_ns$::internal::DownCast<const $classname$*>(\n" - " &from));\n" - "}\n"); } } void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. Formatter format(printer, variables_); format( "void $classname$::MergeFrom(const $classname$& from) {\n" + "$annotate_mergefrom$" "// @@protoc_insertion_point(class_specific_merge_from_start:" "$full_name$)\n" " $DCHK$_NE(&from, this);\n"); @@ -3255,6 +3726,7 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { } void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); if (HasDescriptorMethods(descriptor_->file(), options_)) { // We don't override the generalized CopyFrom (aka that which @@ -3301,6 +3773,9 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { format("}\n"); } +void MessageGenerator::GenerateVerify(io::Printer* printer) { +} + void MessageGenerator::GenerateSerializeOneofFields( io::Printer* printer, const std::vector<const FieldDescriptor*>& fields) { Formatter format(printer, variables_); @@ -3376,11 +3851,12 @@ void MessageGenerator::GenerateSerializeOneExtensionRange( format("// Extension range [$start$, $end$)\n"); format( "target = _extensions_._InternalSerialize(\n" - " $start$, $end$, target, stream);\n\n"); + "internal_default_instance(), $start$, $end$, target, stream);\n\n"); } void MessageGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. @@ -3390,7 +3866,8 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( "const {\n" "$annotate_serialize$" " target = _extensions_." - "InternalSerializeMessageSetWithCachedSizesToArray(target, stream);\n"); + "InternalSerializeMessageSetWithCachedSizesToArray(\n" // + "internal_default_instance(), target, stream);\n"); std::map<TProtoStringType, TProtoStringType> vars; SetUnknownFieldsVariable(descriptor_, options_, &vars); format.AddMap(vars); @@ -3443,6 +3920,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesToArray( void MessageGenerator::GenerateSerializeWithCachedSizesBody( io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); // If there are multiple fields in a row from the same oneof then we // coalesce them and emit a switch statement. This is more efficient @@ -3759,6 +4237,7 @@ std::vector<uint32_t> MessageGenerator::RequiredFieldsBitMask() const { } void MessageGenerator::GenerateByteSize(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); if (descriptor_->options().message_set_wire_format()) { @@ -3987,37 +4466,37 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) { format("total_size += _weak_field_map_.ByteSizeLong();\n"); } - format("if (PROTOBUF_PREDICT_FALSE($have_unknown_fields$)) {\n"); if (UseUnknownFieldSet(descriptor_->file(), options_)) { // We go out of our way to put the computation of the uncommon path of // unknown fields in tail position. This allows for better code generation // of this function for simple protos. format( - " return ::$proto_ns$::internal::ComputeUnknownFieldsSize(\n" - " _internal_metadata_, 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"); - } - format("}\n"); + format("}\n"); - // We update _cached_size_ even though this is a const method. Because - // const methods might be called concurrently this needs to be atomic - // operations or the program is undefined. In practice, since any concurrent - // writes will be writing the exact same value, normal writes will work on - // all common processors. We use a dedicated wrapper class to abstract away - // the underlying atomic. This makes it easier on platforms 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" - "SetCachedSize(cached_size);\n" - "return total_size;\n"); + // We update _cached_size_ even though this is a const method. Because + // const methods might be called concurrently this needs to be atomic + // operations or the program is undefined. In practice, since any + // concurrent writes will be writing the exact same value, normal writes + // will work on all common processors. We use a dedicated wrapper class to + // abstract away the underlying atomic. This makes it easier on platforms + // 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" + "SetCachedSize(cached_size);\n" + "return total_size;\n"); + } format.Outdent(); format("}\n"); } void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { + if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); format("bool $classname$::IsInitialized() const {\n"); format.Indent(); 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 904a98acfe..1e4e942d69 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 @@ -134,6 +134,7 @@ class MessageGenerator { // Generate standard Message methods. void GenerateClear(io::Printer* printer); void GenerateOneofClear(io::Printer* printer); + void GenerateVerify(io::Printer* printer); void GenerateSerializeWithCachedSizes(io::Printer* printer); void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); void GenerateSerializeWithCachedSizesBody(io::Printer* printer); @@ -177,6 +178,7 @@ class MessageGenerator { bool copy_constructor) const; size_t HasBitsSize() const; + size_t InlinedStringDonatedSize() const; int HasBitIndex(const FieldDescriptor* a) const; int HasByteIndex(const FieldDescriptor* a) const; int HasWordIndex(const FieldDescriptor* a) const; @@ -196,6 +198,13 @@ class MessageGenerator { std::vector<const FieldDescriptor*> optimized_order_; std::vector<int> has_bit_indices_; int max_has_bit_index_; + + // A map from field index to inlined_string index. For non-inlined-string + // fields, the element is -1. + std::vector<int> inlined_string_indices_; + // The count of inlined_string fields in the message. + int max_inlined_string_index_; + std::vector<const EnumGenerator*> enum_generators_; std::vector<const ExtensionGenerator*> extension_generators_; int num_required_fields_; 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 4b4b8ea59b..712ddbfea1 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 @@ -53,22 +53,25 @@ class MessageFieldGenerator : public FieldGenerator { ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateInternalAccessorDeclarations(io::Printer* printer) const; - void GenerateInternalAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMessageClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateDestructorCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateInternalAccessorDeclarations( + io::Printer* printer) const override; + void GenerateInternalAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateMergingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(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; + void GenerateConstinitInitializer(io::Printer* printer) const override; protected: const bool implicit_weak_field_; @@ -85,16 +88,17 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions( + io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; // MessageFieldGenerator, from which we inherit, overrides this so we need to // override it as well. - void GenerateMessageClearingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateDestructorCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateDestructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageOneofFieldGenerator); @@ -108,17 +112,18 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { ~RepeatedMessageFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const {} - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateSerializeWithCachedSizesToArray( + io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: const bool implicit_weak_field_; 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 ed5cd0b046..bc174c3d6e 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 @@ -33,6 +33,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ +#include <set> #include <string> #include <google/protobuf/stubs/port.h> @@ -50,6 +51,11 @@ enum class EnforceOptimizeMode { kLiteRuntime, }; +struct FieldListenerOptions { + bool inject_field_listener_events = false; + std::set<TProtoStringType> forbidden_field_listener_events; +}; + // Generator options (see generator.cc for a description of each): struct Options { TProtoStringType dllexport_decl; @@ -65,6 +71,8 @@ struct Options { bool opensource_runtime = false; bool annotate_accessor = false; bool unused_field_stripping = false; + bool profile_driven_inline_string = false; + bool force_inline_string = false; TProtoStringType runtime_include_base; int num_cc_files = 0; TProtoStringType annotation_pragma_name; @@ -75,7 +83,7 @@ struct Options { kTCTableGuarded, kTCTableAlways } tctable_mode = kTCTableNever; - bool inject_field_listener_events = false; + FieldListenerOptions field_listener_options; bool eagerly_verified_lazy = false; bool force_eagerly_verified_lazy = false; }; 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 ea146f8992..93d44864c3 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 @@ -30,7 +30,9 @@ #include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> +#include <algorithm> #include <limits> +#include <string> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/wire_format.h> @@ -64,16 +66,6 @@ bool HasInternalAccessors(const FieldOptions::CType ctype) { return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD; } -bool IsTcTableEnabled(const Options& options) { - return options.tctable_mode == Options::kTCTableAlways; -} -bool IsTcTableGuarded(const Options& options) { - return options.tctable_mode == Options::kTCTableGuarded; -} -bool IsTcTableDisabled(const Options& options) { - return options.tctable_mode == Options::kTCTableNever; -} - int TagSize(uint32_t field_number) { if (field_number < 16) return 1; GOOGLE_CHECK_LT(field_number, (1 << 14)) @@ -81,22 +73,38 @@ int TagSize(uint32_t field_number) { return 2; } +const char* CodedTagType(int tag_size) { + return tag_size == 1 ? "uint8_t" : "uint16_t"; +} + const char* TagType(const FieldDescriptor* field) { return CodedTagType(TagSize(field->number())); } -TProtoStringType MessageParseFunctionName(const FieldDescriptor* field, - const Options& options) { - TProtoStringType name = - "::" + ProtobufNamespace(options) + "::internal::TcParserBase::"; - if (field->is_repeated()) { - name.append("Repeated"); - } else { - name.append("Singular"); +TProtoStringType TcParserBaseName(const Options& options) { + return StrCat("::", ProtobufNamespace(options), + "::internal::TcParserBase::"); +} + +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 TcParserBase. + return StrCat(TcParserBaseName(options), + (field->is_repeated() ? "Repeated" : "Singular"), + "ParseMessage<", + QualifiedClassName(field->message_type()), // + ", ", TagType(field), ">"); } - name.append("ParseMessage<" + QualifiedClassName(field->message_type()) + - ", " + TagType(field) + ">"); - return name; + // 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()), ")"); } TProtoStringType FieldParseFunctionName(const FieldDescriptor* field, @@ -105,10 +113,6 @@ TProtoStringType FieldParseFunctionName(const FieldDescriptor* field, } // namespace -const char* CodedTagType(int tag_size) { - return tag_size == 1 ? "uint8_t" : "uint16_t"; -} - TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, const Options& options, const std::vector<int>& has_bit_indices, @@ -139,9 +143,9 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, // Anything difficult slow path: if (field->is_map()) continue; if (field->real_containing_oneof()) continue; - if (field->options().lazy()) 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: @@ -189,7 +193,7 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, switch (field->type()) { case FieldDescriptor::TYPE_MESSAGE: - name = MessageParseFunctionName(field, options); + name = MessageTcParseFunctionName(field, options); break; case FieldDescriptor::TYPE_FIXED64: @@ -210,7 +214,8 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, case FieldDescriptor::TYPE_BYTES: if (field->options().ctype() == FieldOptions::STRING && - field->default_value_string().empty()) { + field->default_value_string().empty() && + !IsStringInlined(field, options)) { name = FieldParseFunctionName(field, options, table_size_log2); } break; @@ -230,16 +235,6 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, fast_path_fields[idx].field = field; } - // Construct a mask of has-bits for required fields numbered <= 32. - has_hasbits_required_mask = 0; - for (auto field : FieldRange(descriptor)) { - if (field->is_required()) { - int idx = has_bit_indices[field->index()]; - if (idx >= 32) continue; - has_hasbits_required_mask |= 1u << idx; - } - } - // 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. @@ -249,15 +244,17 @@ TailCallTableInfo::TailCallTableInfo(const Descriptor* descriptor, ParseFunctionGenerator::ParseFunctionGenerator( const Descriptor* descriptor, int max_has_bit_index, - const std::vector<int>& has_bit_indices, const Options& options, + const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, const Options& options, MessageSCCAnalyzer* scc_analyzer, const std::map<TProtoStringType, TProtoStringType>& vars) : descriptor_(descriptor), scc_analyzer_(scc_analyzer), options_(options), variables_(vars), + inlined_string_indices_(inlined_string_indices), num_hasbits_(max_has_bit_index) { - if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) { + if (should_generate_tctable()) { tc_table_info_.reset(new TailCallTableInfo(descriptor_, options_, has_bit_indices, scc_analyzer)); } @@ -268,28 +265,46 @@ ParseFunctionGenerator::ParseFunctionGenerator( void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) { Formatter format(printer, variables_); - if (IsTcTableGuarded(options_)) { - format.Outdent(); - format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); - format.Indent(); - } - if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) { + 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(); + } + }; + 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( - "static const char* Tct_ParseFallback(\n" - " ::$proto_ns$::MessageLite *msg, const char *ptr,\n" - " ::$proto_ns$::internal::ParseContext *ctx,\n" - " const ::$proto_ns$::internal::TailCallParseTableBase *table,\n" - " uint64_t hasbits, ::$proto_ns$::internal::TcFieldData data);\n" - "inline const char* Tct_FallbackImpl(\n" - " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx,\n" - " const void*, $uint64$ hasbits);\n"); + " private:\n" + " "); + declare_function("Tct_ParseFallback", ""); + format(" public:\n"); + format.Indent(); + } + if (should_generate_guarded_tctable()) { + format.Outdent(); + format("#endif\n"); + format.Indent(); } - } - if (IsTcTableGuarded(options_)) { - format.Outdent(); - format("#endif\n"); - format.Indent(); } format( "const char* _InternalParse(const char* ptr, " @@ -298,8 +313,10 @@ void ParseFunctionGenerator::GenerateMethodDecls(io::Printer* printer) { void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) { Formatter format(printer, variables_); + bool need_parse_function = true; if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. + need_parse_function = false; format( "const char* $classname$::_InternalParse(const char* ptr,\n" " ::$proto_ns$::internal::ParseContext* ctx) {\n" @@ -307,85 +324,157 @@ void ParseFunctionGenerator::GenerateMethodImpls(io::Printer* printer) { " return _extensions_.ParseMessageSet(ptr, \n" " internal_default_instance(), &_internal_metadata_, ctx);\n" "}\n"); + } + if (!should_generate_tctable()) { + if (need_parse_function) { + GenerateLoopingParseFunction(format); + } return; } - if (IsTcTableGuarded(options_)) { + if (should_generate_guarded_tctable()) { format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); } - if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) { - format( - "const char* $classname$::_InternalParse(\n" - " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n" - " return ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n" - " this, ptr, ctx, &_table_.header);\n" - "}\n" - "\n", - tc_table_info_->table_size_log2); - if (tc_table_info_->use_generated_fallback) { - GenerateTailcallFallbackFunction(format); - } - } - if (IsTcTableGuarded(options_)) { - format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); + if (need_parse_function) { + GenerateTailcallParseFunction(format); } - if (IsTcTableGuarded(options_) || IsTcTableDisabled(options_)) { - GenerateLoopingParseFunction(format); + if (tc_table_info_->use_generated_fallback) { + GenerateTailcallFallbackFunction(format); } - if (IsTcTableGuarded(options_)) { + GenerateTailcallFieldParseFunctions(format); + if (should_generate_guarded_tctable()) { + if (need_parse_function) { + format("\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n"); + GenerateLoopingParseFunction(format); + } format("\n#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); } } -void ParseFunctionGenerator::GenerateTailcallFallbackFunction( - Formatter& format) { +bool ParseFunctionGenerator::should_generate_tctable() const { + if (options_.tctable_mode == Options::kTCTableNever) { + return false; + } + return true; +} + +void ParseFunctionGenerator::GenerateTailcallParseFunction(Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); + + // Generate an `_InternalParse` that starts the tail-calling loop. format( - "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n" - " return static_cast<$classname$*>(msg)->Tct_FallbackImpl(ptr, ctx, " - "table, hasbits);\n" + "const char* $classname$::_InternalParse(\n" + " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n" + "$annotate_deserialize$" + " ptr = ::$proto_ns$::internal::TcParser<$1$>::ParseLoop(\n" + " this, ptr, ctx, &_table_.header);\n", + tc_table_info_->table_size_log2); + format( + " return ptr;\n" "}\n\n"); +} +void ParseFunctionGenerator::GenerateTailcallFallbackFunction( + Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); format( - "const char* $classname$::Tct_FallbackImpl(const char* ptr, " - "::$proto_ns$::internal::ParseContext* ctx, const void*, " - "$uint64$ hasbits) {\n" + "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n" "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n"); format.Indent(); + format("auto* typed_msg = static_cast<$classname$*>(msg);\n"); if (num_hasbits_ > 0) { // Sync hasbits - format("_has_bits_[0] = hasbits;\n"); + format("typed_msg->_has_bits_[0] = hasbits;\n"); } - format.Set("has_bits", "_has_bits_"); - format.Set("continue", "goto success"); + format.Set("msg", "typed_msg->"); + format.Set("this", "typed_msg"); + format.Set("has_bits", "typed_msg->_has_bits_"); + format.Set("next_tag", "goto next_tag"); GenerateParseIterationBody(format, descriptor_, tc_table_info_->fallback_fields); format.Outdent(); - format("success:\n"); - format(" return ptr;\n"); format( + "next_tag:\n" + "message_done:\n" + " return ptr;\n" "#undef CHK_\n" "}\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 |= (uint64_t{1} << data.hasbit_idx());\n" + " ::$proto_ns$::internal::TcParserBase::SyncHasbits" + "(msg, hasbits, table);\n" + " auto& field = ::$proto_ns$::internal::TcParserBase::" + "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::TcParserBase::RefAt<" + "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n" + " ::$proto_ns$::internal::TcParserBase::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); + } +} + void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { - if (descriptor_->options().message_set_wire_format()) { + if (!should_generate_tctable()) { return; } Formatter format(printer, variables_); - if (IsTcTableGuarded(options_)) { + if (should_generate_guarded_tctable()) { format.Outdent(); format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); format.Indent(); } - if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) { - format( - "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n" - " _table_;\n", - tc_table_info_->table_size_log2); - } - if (IsTcTableGuarded(options_)) { + format( + "static const ::$proto_ns$::internal::TailCallParseTable<$1$>\n" + " _table_;\n", + tc_table_info_->table_size_log2); + if (should_generate_guarded_tctable()) { format.Outdent(); format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); format.Indent(); @@ -393,17 +482,15 @@ void ParseFunctionGenerator::GenerateDataDecls(io::Printer* printer) { } void ParseFunctionGenerator::GenerateDataDefinitions(io::Printer* printer) { - if (descriptor_->options().message_set_wire_format()) { + if (!should_generate_tctable()) { return; } Formatter format(printer, variables_); - if (IsTcTableGuarded(options_)) { + if (should_generate_guarded_tctable()) { format("#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); } - if (IsTcTableGuarded(options_) || IsTcTableEnabled(options_)) { - GenerateTailCallTable(format); - } - if (IsTcTableGuarded(options_)) { + GenerateTailCallTable(format); + if (should_generate_guarded_tctable()) { format("#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n"); } } @@ -415,6 +502,8 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { "$annotate_deserialize$" "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n"); format.Indent(); + format.Set("msg", ""); + format.Set("this", "this"); int hasbits_size = 0; if (num_hasbits_ > 0) { hasbits_size = (num_hasbits_ + 31) / 32; @@ -427,7 +516,7 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { } else { format.Set("has_bits", "_has_bits_"); } - format.Set("continue", "continue"); + format.Set("next_tag", "continue"); format("while (!ctx->Done(&ptr)) {\n"); format.Indent(); @@ -438,26 +527,26 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format("} // while\n"); format.Outdent(); - format("success:\n"); + format("message_done:\n"); if (hasbits_size) format(" _has_bits_.Or(has_bits);\n"); format( " return ptr;\n" "failure:\n" " ptr = nullptr;\n" - " goto success;\n" + " goto message_done;\n" "#undef CHK_\n" "}\n"); } void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { + GOOGLE_CHECK(should_generate_tctable()); // All entries without a fast-path parsing function need a fallback. TProtoStringType fallback; if (tc_table_info_->use_generated_fallback) { fallback = ClassName(descriptor_) + "::Tct_ParseFallback"; } else { - fallback = "::" + ProtobufNamespace(options_) + - "::internal::TcParserBase::GenericFallback"; + fallback = TcParserBaseName(options_) + "GenericFallback"; if (GetOptimizeFor(descriptor_->file(), options_) == FileOptions::LITE_RUNTIME) { fallback += "Lite"; @@ -493,10 +582,8 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { format("0, 0, 0, // no _extensions_\n"); } format( - "$1$, // has_bits_required_mask\n" - "&$2$._instance,\n" - "$3$ // fallback\n", - tc_table_info_->has_hasbits_required_mask, + "&$1$._instance,\n" + "$2$ // fallback\n", DefaultInstanceName(descriptor_, options_), fallback); format.Outdent(); format("}, {\n"); @@ -536,13 +623,26 @@ void ParseFunctionGenerator::GenerateArenaString(Formatter& format, "::" + MakeDefaultName(field) + ".get()"; format( "if (arena != nullptr) {\n" - " ptr = ctx->ReadArenaString(ptr, &$1$_, arena);\n" + " ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, 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)); + } + format( + ");\n" "} else {\n" " ptr = ::$proto_ns$::internal::InlineGreedyStringParser(" - "$1$_.MutableNoArenaNoDefault(&$2$), ptr, ctx);\n" + "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n" "}\n" - "const TProtoStringType* str = &$1$_.Get(); (void)str;\n", - FieldName(field), default_string); + "const TProtoStringType* str = &$msg$$name$_.Get(); (void)str;\n", + default_string); } void ParseFunctionGenerator::GenerateStrings(Formatter& format, @@ -560,24 +660,24 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, !field->real_containing_oneof() && ctype == FieldOptions::STRING) { GenerateArenaString(format, field); } else { - TProtoStringType name; + TProtoStringType parser_name; switch (ctype) { case FieldOptions::STRING: - name = "GreedyStringParser"; + parser_name = "GreedyStringParser"; break; case FieldOptions::CORD: - name = "CordParser"; + parser_name = "CordParser"; break; case FieldOptions::STRING_PIECE: - name = "StringPieceParser"; + parser_name = "StringPieceParser"; break; } format( - "auto str = $1$$2$_$3$();\n" - "ptr = ::$proto_ns$::internal::Inline$4$(str, ptr, ctx);\n", + "auto str = $msg$$1$$2$_$name$();\n" + "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n", HasInternalAccessors(ctype) ? "_internal_" : "", field->is_repeated() && !field->is_packable() ? "add" : "mutable", - FieldName(field), name); + parser_name); } if (!check_utf8) return; // return if this is a bytes field auto level = GetUtf8CheckMode(field, options_); @@ -614,24 +714,20 @@ void ParseFunctionGenerator::GenerateStrings(Formatter& format, void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, const FieldDescriptor* field) { if (field->is_packable()) { - TProtoStringType enum_validator; if (field->type() == FieldDescriptor::TYPE_ENUM && !HasPreservingUnknownEnumSemantics(field)) { - enum_validator = - StrCat(", ", QualifiedClassName(field->enum_type(), options_), - "_IsValid, &_internal_metadata_, ", field->number()); + TProtoStringType enum_type = QualifiedClassName(field->enum_type(), options_); format( "ptr = " "::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>(" - "_internal_mutable_$2$(), ptr, ctx$3$);\n", - DeclaredTypeMethodName(field->type()), FieldName(field), - enum_validator); + "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, " + "&$msg$_internal_metadata_, $3$);\n", + DeclaredTypeMethodName(field->type()), enum_type, field->number()); } else { format( "ptr = ::$proto_ns$::internal::Packed$1$Parser(" - "_internal_mutable_$2$(), ptr, ctx$3$);\n", - DeclaredTypeMethodName(field->type()), FieldName(field), - enum_validator); + "$msg$_internal_mutable_$name$(), ptr, ctx);\n", + DeclaredTypeMethodName(field->type())); } } else { auto field_type = field->type(); @@ -651,61 +747,59 @@ void ParseFunctionGenerator::GenerateLengthDelim(Formatter& format, !HasPreservingUnknownEnumSemantics(field)) { format( "auto object = " - "::$proto_ns$::internal::InitEnumParseWrapper<$unknown_" - "fields_type$>(" - "&$1$_, $2$_IsValid, $3$, &_internal_metadata_);\n" + "::$proto_ns$::internal::InitEnumParseWrapper<" + "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, " + "$2$, &$msg$_internal_metadata_);\n" "ptr = ctx->ParseMessage(&object, ptr);\n", - FieldName(field), QualifiedClassName(val->enum_type()), + QualifiedClassName(val->enum_type(), options_), field->number()); } else { - format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field)); + format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n"); } } else if (IsLazy(field, options_, scc_analyzer_)) { if (field->real_containing_oneof()) { format( - "if (!_internal_has_$1$()) {\n" - " clear_$2$();\n" - " $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n" + "if (!$msg$_internal_has_$name$()) {\n" + " $msg$clear_$1$();\n" + " $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n" " ::$proto_ns$::internal::LazyField>(" - "GetArenaForAllocation());\n" - " set_has_$1$();\n" + "$msg$GetArenaForAllocation());\n" + " $msg$set_has_$name$();\n" "}\n" - "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n", - FieldName(field), field->containing_oneof()->name()); + "ptr = ctx->ParseMessage($msg$$1$_.$name$_, ptr);\n", + field->containing_oneof()->name()); } else if (HasHasbit(field)) { format( - "_Internal::set_has_$1$(&$has_bits$);\n" - "ptr = ctx->ParseMessage(&$1$_, ptr);\n", - FieldName(field)); + "_Internal::set_has_$name$(&$has_bits$);\n" + "ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n"); } else { - format("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field)); + format("ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n"); } } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) { if (!field->is_repeated()) { format( - "ptr = ctx->ParseMessage(_Internal::mutable_$1$(this), " - "ptr);\n", - FieldName(field)); + "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), " + "ptr);\n"); } else { format( - "ptr = ctx->ParseMessage($1$_.AddWeak(reinterpret_cast<const " - "::$proto_ns$::MessageLite*>($2$::_$3$_default_instance_ptr_)" + "ptr = ctx->ParseMessage($msg$$name$_.AddWeak(" + "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)" "), ptr);\n", - FieldName(field), Namespace(field->message_type(), options_), - ClassName(field->message_type())); + QualifiedDefaultInstanceName(field->message_type(), options_)); } } else if (IsWeak(field, options_)) { format( "{\n" " auto* default_ = &reinterpret_cast<const Message&>($1$);\n" - " ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($2$," - " default_), ptr);\n" + " ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage(" + "$2$, default_), ptr);\n" "}\n", QualifiedDefaultInstanceName(field->message_type(), options_), field->number()); } else { - format("ptr = ctx->ParseMessage(_internal_$1$_$2$(), ptr);\n", - field->is_repeated() ? "add" : "mutable", FieldName(field)); + format( + "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), " + "ptr);\n"); } break; } @@ -728,29 +822,39 @@ static bool ShouldRepeat(const FieldDescriptor* descriptor, void ParseFunctionGenerator::GenerateFieldBody( Formatter& format, WireFormatLite::WireType wiretype, const FieldDescriptor* field) { + Formatter::SaveState formatter_state(&format); + format.AddMap( + {{"name", FieldName(field)}, + {"primitive_type", PrimitiveTypeName(options_, field->cpp_type())}}); + if (field->is_repeated()) { + format.AddMap({{"put_field", StrCat("add_", FieldName(field))}, + {"mutable_field", StrCat("add_", FieldName(field))}}); + } else { + format.AddMap( + {{"put_field", StrCat("set_", FieldName(field))}, + {"mutable_field", StrCat("mutable_", FieldName(field))}}); + } uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype); switch (wiretype) { case WireFormatLite::WIRETYPE_VARINT: { TProtoStringType type = PrimitiveTypeName(options_, field->cpp_type()); - TProtoStringType prefix = field->is_repeated() ? "add" : "set"; if (field->type() == FieldDescriptor::TYPE_ENUM) { + format.Set("enum_type", + QualifiedClassName(field->enum_type(), options_)); format( "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n" "CHK_(ptr);\n"); if (!HasPreservingUnknownEnumSemantics(field)) { - format("if (PROTOBUF_PREDICT_TRUE($1$_IsValid(val))) {\n", - QualifiedClassName(field->enum_type(), options_)); + format("if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n"); format.Indent(); } - format("_internal_$1$_$2$(static_cast<$3$>(val));\n", prefix, - FieldName(field), - QualifiedClassName(field->enum_type(), options_)); + format("$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n"); if (!HasPreservingUnknownEnumSemantics(field)) { format.Outdent(); format( "} else {\n" " ::$proto_ns$::internal::WriteVarint(" - "$1$, val, mutable_unknown_fields());\n" + "$1$, val, $msg$mutable_unknown_fields());\n" "}\n", field->number()); } @@ -765,42 +869,38 @@ void ParseFunctionGenerator::GenerateFieldBody( zigzag = "ZigZag"; } if (field->is_repeated() || field->real_containing_oneof()) { - TProtoStringType prefix = field->is_repeated() ? "add" : "set"; format( - "_internal_$1$_$2$(" - "::$proto_ns$::internal::ReadVarint$3$$4$(&ptr));\n" + "$msg$_internal_$put_field$(" + "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n" "CHK_(ptr);\n", - prefix, FieldName(field), zigzag, size); + zigzag, size); } else { if (HasHasbit(field)) { - format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); + format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( - "$1$_ = ::$proto_ns$::internal::ReadVarint$2$$3$(&ptr);\n" + "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n" "CHK_(ptr);\n", - FieldName(field), zigzag, size); + zigzag, size); } } break; } case WireFormatLite::WIRETYPE_FIXED32: case WireFormatLite::WIRETYPE_FIXED64: { - TProtoStringType type = PrimitiveTypeName(options_, field->cpp_type()); if (field->is_repeated() || field->real_containing_oneof()) { - TProtoStringType prefix = field->is_repeated() ? "add" : "set"; format( - "_internal_$1$_$2$(" - "::$proto_ns$::internal::UnalignedLoad<$3$>(ptr));\n" - "ptr += sizeof($3$);\n", - prefix, FieldName(field), type); + "$msg$_internal_$put_field$(" + "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n" + "ptr += sizeof($primitive_type$);\n"); } else { if (HasHasbit(field)) { - format("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); + format("_Internal::set_has_$name$(&$has_bits$);\n"); } format( - "$1$_ = ::$proto_ns$::internal::UnalignedLoad<$2$>(ptr);\n" - "ptr += sizeof($2$);\n", - FieldName(field), type); + "$msg$$name$_ = " + "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n" + "ptr += sizeof($primitive_type$);\n"); } break; } @@ -811,9 +911,9 @@ void ParseFunctionGenerator::GenerateFieldBody( } case WireFormatLite::WIRETYPE_START_GROUP: { format( - "ptr = ctx->ParseGroup(_internal_$1$_$2$(), ptr, $3$);\n" + "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n" "CHK_(ptr);\n", - field->is_repeated() ? "add" : "mutable", FieldName(field), tag); + tag); break; } case WireFormatLite::WIRETYPE_END_GROUP: { @@ -845,14 +945,90 @@ static uint32_t ExpectedTag(const FieldDescriptor* field, return expected_tag; } +// These variables are used by the generated parse iteration, and must already +// be defined in the generated code: +// - `const char* ptr`: the input buffer. +// - `ParseContext* ctx`: the associated context for `ptr`. +// - implicit `this`: i.e., we must be in a non-static member function. +// +// The macro `CHK_(x)` must be defined. It should return an error condition if +// the macro parameter is false. +// +// Whenever an END_GROUP tag was read, or tag 0 was read, the generated code +// branches to the label `message_done`. +// +// These formatter variables are used: +// - `next_tag`: a single statement to begin parsing the next tag. +// +// At the end of the generated code, the enclosing function should proceed to +// 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()) format("switch (tag >> 3) {\n"); + if (!ordered_fields.empty()) { + GenerateFieldSwitch(format, ordered_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. + format.Outdent(); + format("handle_unusual:\n"); + format.Indent(); + } + + // Unusual/extension/unknown case: + format( + "if ((tag == 0) || ((tag & 7) == 4)) {\n" + " CHK_(ptr);\n" + " ctx->SetLastTag(tag);\n" + " goto message_done;\n" + "}\n"); + if (IsMapEntryMessage(descriptor)) { + format("$next_tag$;\n"); + } else { + if (descriptor->extension_range_count() > 0) { + format("if ("); + for (int i = 0; i < descriptor->extension_range_count(); i++) { + const Descriptor::ExtensionRange* range = + descriptor->extension_range(i); + if (i > 0) format(" ||\n "); + + uint32_t start_tag = WireFormatLite::MakeTag( + range->start, static_cast<WireFormatLite::WireType>(0)); + uint32_t end_tag = WireFormatLite::MakeTag( + range->end, static_cast<WireFormatLite::WireType>(0)); + + if (range->end > FieldDescriptor::kMaxNumber) { + format("($1$u <= tag)", start_tag); + } else { + format("($1$u <= tag && tag < $2$u)", start_tag, end_tag); + } + } + format( + ") {\n" + " ptr = $msg$_extensions_.ParseField(tag, ptr, " + "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n" + " CHK_(ptr != nullptr);\n" + " $next_tag$;\n" + "}\n"); + } + format( + "ptr = UnknownFieldParse(\n" + " tag,\n" + " $msg$_internal_metadata_.mutable_unknown_fields<" + "$unknown_fields_type$>(),\n" + " ptr, ctx);\n" + "CHK_(ptr != nullptr);\n"); + } +} + +void ParseFunctionGenerator::GenerateFieldSwitch( + Formatter& format, + const std::vector<const FieldDescriptor*>& ordered_fields) { + format("switch (tag >> 3) {\n"); format.Indent(); for (const auto* field : ordered_fields) { @@ -893,61 +1069,18 @@ void ParseFunctionGenerator::GenerateParseIterationBody( field); format.Outdent(); } - format.Outdent(); format( - " } else goto handle_unusual;\n" - " $continue$;\n"); + "} else\n" + " goto handle_unusual;\n" + "$next_tag$;\n"); + format.Outdent(); } // for loop over ordered fields - // Default case - if (!ordered_fields.empty()) format("default: {\n"); - if (!ordered_fields.empty()) format("handle_unusual:\n"); format( - " if ((tag == 0) || ((tag & 7) == 4)) {\n" - " CHK_(ptr);\n" - " ctx->SetLastTag(tag);\n" - " goto success;\n" - " }\n"); - if (IsMapEntryMessage(descriptor)) { - format(" $continue$;\n"); - } else { - if (descriptor->extension_range_count() > 0) { - format("if ("); - for (int i = 0; i < descriptor->extension_range_count(); i++) { - const Descriptor::ExtensionRange* range = - descriptor->extension_range(i); - if (i > 0) format(" ||\n "); - - uint32_t start_tag = WireFormatLite::MakeTag( - range->start, static_cast<WireFormatLite::WireType>(0)); - uint32_t end_tag = WireFormatLite::MakeTag( - range->end, static_cast<WireFormatLite::WireType>(0)); - - if (range->end > FieldDescriptor::kMaxNumber) { - format("($1$u <= tag)", start_tag); - } else { - format("($1$u <= tag && tag < $2$u)", start_tag, end_tag); - } - } - format(") {\n"); - format( - " ptr = _extensions_.ParseField(tag, ptr,\n" - " internal_default_instance(), &_internal_metadata_, ctx);\n" - " CHK_(ptr != nullptr);\n" - " $continue$;\n" - "}\n"); - } - format( - " ptr = UnknownFieldParse(tag,\n" - " _internal_metadata_.mutable_unknown_fields<$unknown_" - "fields_type$>(),\n" - " ptr, ctx);\n" - " CHK_(ptr != nullptr);\n" - " $continue$;\n"); - } - if (!ordered_fields.empty()) format("}\n"); // default case + "default:\n" + " goto handle_unusual;\n"); format.Outdent(); - if (!ordered_fields.empty()) format("} // switch\n"); + format("} // switch\n"); } namespace { @@ -1137,31 +1270,30 @@ TProtoStringType GetTailCallFieldHandlerName(ParseCardinality card, name.append(CodedTagType(tag_length_bytes)); - TProtoStringType tcpb = - StrCat(ProtobufNamespace(options), "::internal::TcParserBase"); - switch (type_format) { case TypeFormat::kVar64: case TypeFormat::kVar32: case TypeFormat::kBool: - name.append(StrCat(", ::", tcpb, "::kNoConversion")); + name.append( + StrCat(", ", TcParserBaseName(options), "kNoConversion")); break; case TypeFormat::kSInt64: case TypeFormat::kSInt32: - name.append(StrCat(", ::", tcpb, "::kZigZag")); + name.append(StrCat(", ", TcParserBaseName(options), "kZigZag")); break; case TypeFormat::kBytes: - name.append(StrCat(", ::", tcpb, "::kNoUtf8")); + name.append(StrCat(", ", TcParserBaseName(options), "kNoUtf8")); break; case TypeFormat::kString: - name.append(StrCat(", ::", tcpb, "::kUtf8")); + name.append(StrCat(", ", TcParserBaseName(options), "kUtf8")); break; case TypeFormat::kStringValidateOnly: - name.append(StrCat(", ::", tcpb, "::kUtf8ValidateOnly")); + name.append( + StrCat(", ", TcParserBaseName(options), "kUtf8ValidateOnly")); break; default: 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 b992bb38c8..34c8fc488b 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 @@ -76,6 +76,7 @@ class ParseFunctionGenerator { public: ParseFunctionGenerator(const Descriptor* descriptor, int max_has_bit_index, const std::vector<int>& has_bit_indices, + const std::vector<int>& inlined_string_indices, const Options& options, MessageSCCAnalyzer* scc_analyzer, const std::map<TProtoStringType, TProtoStringType>& vars); @@ -93,9 +94,25 @@ class ParseFunctionGenerator { void GenerateDataDefinitions(io::Printer* printer); private: + // Returns true if tailcall table code should be generated. + bool should_generate_tctable() const; + + // Returns true if tailcall table code should be generated, but inside an + // #ifdef guard. + bool should_generate_guarded_tctable() const { + return should_generate_tctable() && + options_.tctable_mode == Options::kTCTableGuarded; + } + + // Generates a tail-calling `_InternalParse` function. + void GenerateTailcallParseFunction(Formatter& format); + // 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); @@ -123,18 +140,20 @@ class ParseFunctionGenerator { Formatter& format, const Descriptor* descriptor, const std::vector<const FieldDescriptor*>& ordered_fields); + // Generates a `switch` statement to parse each of `ordered_fields`. + void GenerateFieldSwitch( + Formatter& format, + const std::vector<const FieldDescriptor*>& ordered_fields); + const Descriptor* descriptor_; MessageSCCAnalyzer* scc_analyzer_; const Options& options_; std::map<TProtoStringType, TProtoStringType> variables_; std::unique_ptr<TailCallTableInfo> tc_table_info_; + std::vector<int> inlined_string_indices_; int num_hasbits_; }; -// Returns the integer type that holds a tag of the given length (in bytes) when -// wire-encoded. -const char* CodedTagType(int tag_size); - enum class ParseCardinality { kSingular, kOneof, 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 da229ce3c4..8b37b866ae 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 @@ -209,10 +209,19 @@ void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const { Formatter format(printer, variables_); int fixed_size = FixedSize(descriptor_->type()); if (fixed_size == -1) { - format( - "total_size += $tag_size$ +\n" - " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" - " this->_internal_$name$());\n"); + if (internal::WireFormat::TagSize(descriptor_->number(), + descriptor_->type()) == 1) { + // 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::" + "$declared_type$SizePlusOne(this->_internal_$name$());\n"); + } else { + format( + "total_size += $tag_size$ +\n" + " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n" + " this->_internal_$name$());\n"); + } } else { format("total_size += $tag_size$ + $fixed_size$;\n"); } 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 394b304770..ce0f97d930 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 @@ -51,17 +51,17 @@ class PrimitiveFieldGenerator : public FieldGenerator { ~PrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); @@ -74,10 +74,10 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { ~PrimitiveOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveOneofFieldGenerator); @@ -90,17 +90,17 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { ~RepeatedPrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); 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 12faeaf7a0..0adde4e777 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 @@ -104,7 +104,8 @@ void SetStringVariables(const FieldDescriptor* descriptor, StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, const Options& options) - : FieldGenerator(descriptor, options) { + : FieldGenerator(descriptor, options), + inlined_(IsStringInlined(descriptor, options)) { SetStringVariables(descriptor, &variables_, options); } @@ -112,7 +113,14 @@ StringFieldGenerator::~StringFieldGenerator() {} void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const { Formatter format(printer, variables_); - format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); + if (!inlined_) { + format("::$proto_ns$::internal::ArenaStringPtr $name$_;\n"); + } else { + // `_init_inline_xxx` is used for initializing default instances. + format( + "::$proto_ns$::internal::InlinedStringField $name$_;\n" + "static std::true_type _init_inline_$name$_;\n"); + } } void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const { @@ -172,8 +180,13 @@ void StringFieldGenerator::GenerateAccessorDeclarations( "const TProtoStringType& _internal_$name$() const;\n" "inline PROTOBUF_ALWAYS_INLINE void " "_internal_set_$name$(const TProtoStringType& value);\n" - "TProtoStringType* _internal_mutable_$name$();\n" - "public:\n"); + "TProtoStringType* _internal_mutable_$name$();\n"); + if (inlined_) { + format( + "inline PROTOBUF_ALWAYS_INLINE bool _internal_$name$_donated() " + "const;\n"); + } + format("public:\n"); if (unknown_ctype) { format.Outdent(); @@ -196,16 +209,36 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( } format( " return _internal_$name$();\n" - "}\n" - "template <typename ArgT0, typename... ArgT>\n" - "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)," - " args..., GetArenaForAllocation());\n" - "$annotate_set$" - " // @@protoc_insertion_point(field_set:$full_name$)\n" - "}\n" + "}\n"); + if (!inlined_) { + format( + "template <typename ArgT0, typename... ArgT>\n" + "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)," + " args..., GetArenaForAllocation());\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n"); + } else { + format( + "template <typename ArgT0, typename... ArgT>\n" + "inline PROTOBUF_ALWAYS_INLINE\n" + "void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n" + " $set_hasbit$\n" + " $name$_.$setter$(nullptr, static_cast<ArgT0 &&>(arg0)," + " args..., GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n" + "$annotate_set$" + " // @@protoc_insertion_point(field_set:$full_name$)\n" + "}\n" + "inline bool $classname$::_internal_$name$_donated() const {\n" + " bool value = $inlined_string_donated$\n" + " return value;\n" + "}\n"); + } + format( "inline TProtoStringType* $classname$::mutable_$name$() {\n" " TProtoStringType* _s = _internal_mutable_$name$();\n" "$annotate_mutable$" @@ -217,15 +250,34 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( "}\n" "inline void $classname$::_internal_set_$name$(const TProtoStringType& " "value) {\n" - " $set_hasbit$\n" - " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n" - "}\n"); + " $set_hasbit$\n"); + if (!inlined_) { + format( + " $name$_.Set($default_value_tag$, value, GetArenaForAllocation());\n" + "}\n"); + } else { + format( + " $name$_.Set(nullptr, value, GetArenaForAllocation(),\n" + " _internal_$name$_donated(), &$donating_states_word$, " + "$mask_for_undonate$);\n" + "}\n"); + } format( "inline TProtoStringType* $classname$::_internal_mutable_$name$() {\n" - " $set_hasbit$\n" - " return $name$_.Mutable($default_variable_or_tag$, " - "GetArenaForAllocation());\n" - "}\n" + " $set_hasbit$\n"); + if (!inlined_) { + format( + " return $name$_.Mutable($default_variable_or_tag$, " + "GetArenaForAllocation());\n" + "}\n"); + } else { + format( + " return $name$_.Mutable($default_variable_or_tag$, " + "GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n" + "}\n"); + } + format( "inline TProtoStringType* $classname$::$release_name$() {\n" "$annotate_release$" " // @@protoc_insertion_point(field_release:$full_name$)\n"); @@ -235,9 +287,16 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " if (!_internal_has_$name$()) {\n" " return nullptr;\n" " }\n" - " $clear_hasbit$\n" - " return $name$_.ReleaseNonDefault($init_value$, " - "GetArenaForAllocation());\n"); + " $clear_hasbit$\n"); + if (!inlined_) { + format( + " return $name$_.ReleaseNonDefault($init_value$, " + "GetArenaForAllocation());\n"); + } else { + format( + " return $name$_.Release(nullptr, GetArenaForAllocation(), " + "_internal_$name$_donated());\n"); + } } else { format( " return $name$_.Release($init_value$, GetArenaForAllocation());\n"); @@ -250,9 +309,19 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( " $set_hasbit$\n" " } else {\n" " $clear_hasbit$\n" - " }\n" - " $name$_.SetAllocated($init_value$, $name$,\n" - " GetArenaForAllocation());\n" + " }\n"); + if (!inlined_) { + format( + " $name$_.SetAllocated($init_value$, $name$,\n" + " GetArenaForAllocation());\n"); + } else { + // Currently, string fields with default value can't be inlined. + format( + " $name$_.SetAllocated(nullptr, $name$, GetArenaForAllocation(), " + "_internal_$name$_donated(), &$donating_states_word$, " + "$mask_for_undonate$);\n"); + } + format( "$annotate_set$" " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n"); @@ -274,6 +343,7 @@ void StringFieldGenerator::GenerateClearingCode(io::Printer* printer) const { if (descriptor_->default_value_string().empty()) { format("$name$_.ClearToEmpty();\n"); } else { + GOOGLE_DCHECK(!inlined_); format( "$name$_.ClearToDefault($lazy_variable$, GetArenaForAllocation());\n"); } @@ -292,6 +362,18 @@ void StringFieldGenerator::GenerateMessageClearingCode( // checks against the default variable. const bool must_be_present = HasHasbit(descriptor_); + if (inlined_ && must_be_present) { + // Calling mutable_$name$() gives us a string reference and sets the has bit + // for $name$ (in proto2). We may get here when the string field is inlined + // but the string's contents have not been changed by the user, so we cannot + // make an assertion about the contents of the string and could never make + // an assertion about the string instance. + // + // For non-inlined strings, we distinguish from non-default by comparing + // instances, rather than contents. + format("$DCHK$(!$name$_.IsDefault(nullptr));\n"); + } + if (descriptor_->default_value_string().empty()) { if (must_be_present) { format("$name$_.ClearNonDefaultToEmpty();\n"); @@ -314,16 +396,31 @@ void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const { void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format( - "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n" - " $init_value$,\n" - " &$name$_, GetArenaForAllocation(),\n" - " &other->$name$_, other->GetArenaForAllocation()\n" - ");\n"); + if (!inlined_) { + format( + "::$proto_ns$::internal::ArenaStringPtr::InternalSwap(\n" + " $init_value$,\n" + " &$name$_, lhs_arena,\n" + " &other->$name$_, 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"); + } } 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"); } @@ -340,10 +437,16 @@ void StringFieldGenerator::GenerateCopyConstructorCode( format.Indent(); - // TODO(gpike): improve this - format( - "$name$_.Set($default_value_tag$, from._internal_$name$(), \n" - " GetArenaForAllocation());\n"); + if (!inlined_) { + format( + "$name$_.Set($default_value_tag$, from._internal_$name$(), \n" + " GetArenaForAllocation());\n"); + } else { + format( + "$name$_.Set(nullptr, from._internal_$name$(),\n" + " GetArenaForAllocation(), _internal_$name$_donated(), " + "&$donating_states_word$, $mask_for_undonate$);\n"); + } format.Outdent(); format("}\n"); @@ -351,6 +454,11 @@ void StringFieldGenerator::GenerateCopyConstructorCode( void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const { Formatter format(printer, variables_); + if (inlined_) { + // The destructor is automatically invoked. + return; + } + format("$name$_.DestroyNoArena($init_value$);\n"); } @@ -380,6 +488,10 @@ void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const { void StringFieldGenerator::GenerateConstinitInitializer( io::Printer* printer) const { Formatter format(printer, variables_); + if (inlined_) { + format("$name$_(nullptr, false)"); + return; + } if (descriptor_->default_value_string().empty()) { format("$name$_(&::$proto_ns$::internal::fixed_address_empty_string)"); } else { 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 213f13465d..85689bbec8 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 @@ -51,23 +51,25 @@ class StringFieldGenerator : public FieldGenerator { ~StringFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateStaticMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMessageClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateDestructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateStaticMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; + void GenerateMessageClearingCode(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 GenerateDestructorCode(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_; } private: + bool inlined_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); }; @@ -78,14 +80,14 @@ class StringOneofFieldGenerator : public StringFieldGenerator { ~StringOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + void GenerateClearingCode(io::Printer* printer) const override; // StringFieldGenerator, from which we inherit, overrides this so we need to // override it as well. - void GenerateMessageClearingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; + void GenerateMessageClearingCode(io::Printer* printer) const override; + void GenerateSwappingCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator); @@ -98,17 +100,17 @@ class RepeatedStringFieldGenerator : public FieldGenerator { ~RepeatedStringFieldGenerator(); // implements FieldGenerator --------------------------------------- - void GeneratePrivateMembers(io::Printer* printer) const; - void GenerateAccessorDeclarations(io::Printer* printer) const; - void GenerateInlineAccessorDefinitions(io::Printer* printer) const; - void GenerateClearingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; - void GenerateSwappingCode(io::Printer* printer) const; - void GenerateConstructorCode(io::Printer* printer) const; - void GenerateCopyConstructorCode(io::Printer* printer) const; - void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; - void GenerateByteSize(io::Printer* printer) const; - void GenerateConstinitInitializer(io::Printer* printer) const; + void GeneratePrivateMembers(io::Printer* printer) const override; + void GenerateAccessorDeclarations(io::Printer* printer) const override; + void GenerateInlineAccessorDefinitions(io::Printer* printer) const override; + 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 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const override; + void GenerateByteSize(io::Printer* printer) const override; + void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); |