diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_message.cc')
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_message.cc | 1194 |
1 files changed, 562 insertions, 632 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 60467598..778fc406 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -38,9 +38,6 @@ #include <google/protobuf/stubs/hash.h> #include <map> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <utility> #include <vector> @@ -49,9 +46,9 @@ #include <google/protobuf/compiler/cpp/cpp_field.h> #include <google/protobuf/compiler/cpp/cpp_helpers.h> #include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> +#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/io/coded_stream.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.pb.h> #include <google/protobuf/generated_message_table_driven.h> #include <google/protobuf/generated_message_util.h> #include <google/protobuf/map_entry_lite.h> @@ -60,6 +57,7 @@ #include <google/protobuf/stubs/substitute.h> + namespace google { namespace protobuf { namespace compiler { @@ -113,16 +111,16 @@ struct ExtensionRangeSorter { bool IsPOD(const FieldDescriptor* field) { if (field->is_repeated() || field->is_extension()) return false; switch (field->cpp_type()) { - case internal::WireFormatLite::CPPTYPE_ENUM: - case internal::WireFormatLite::CPPTYPE_INT32: - case internal::WireFormatLite::CPPTYPE_INT64: - case internal::WireFormatLite::CPPTYPE_UINT32: - case internal::WireFormatLite::CPPTYPE_UINT64: - case internal::WireFormatLite::CPPTYPE_FLOAT: - case internal::WireFormatLite::CPPTYPE_DOUBLE: - case internal::WireFormatLite::CPPTYPE_BOOL: + case FieldDescriptor::CPPTYPE_ENUM: + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_UINT64: + case FieldDescriptor::CPPTYPE_FLOAT: + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_BOOL: return true; - case internal::WireFormatLite::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: return false; default: return false; @@ -325,6 +323,109 @@ bool IsCrossFileMaybeMap(const FieldDescriptor* field) { return IsCrossFileMessage(field); } +bool IsRequired(const std::vector<const FieldDescriptor*>& v) { + return v.front()->is_required(); +} + +// Allows chunking repeated fields together and non-repeated fields if the +// fields share the same has_byte index. +// TODO(seongkim): use lambda with capture instead of functor. +class MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByte(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : has_bit_indices_(*has_bit_indices), + has_field_presence_(has_field_presence) {} + + // Returns true if the following conditions are met: + // --both fields are repeated fields + // --both fields are non-repeated fields with either has_field_presence is + // false or have the same has_byte index. + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return a->is_repeated() == b->is_repeated() && + (!has_field_presence_ || a->is_repeated() || + has_bit_indices_[a->index()] / 8 == + has_bit_indices_[b->index()] / 8); + } + + private: + const std::vector<int>& has_bit_indices_; + const bool has_field_presence_; +}; + +// Allows chunking required fields separately after chunking with +// MatchRepeatedAndHasByte. +class MatchRepeatedAndHasByteAndRequired : public MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByteAndRequired(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {} + + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return MatchRepeatedAndHasByte::operator()(a, b) && + a->is_required() == b->is_required(); + } +}; + +// Allows chunking zero-initializable fields separately after chunking with +// MatchRepeatedAndHasByte. +class MatchRepeatedAndHasByteAndZeroInits : public MatchRepeatedAndHasByte { + public: + MatchRepeatedAndHasByteAndZeroInits(const std::vector<int>* has_bit_indices, + bool has_field_presence) + : MatchRepeatedAndHasByte(has_bit_indices, has_field_presence) {} + + bool operator()(const FieldDescriptor* a, const FieldDescriptor* b) const { + return MatchRepeatedAndHasByte::operator()(a, b) && + CanInitializeByZeroing(a) == CanInitializeByZeroing(b); + } +}; + +// Collects neighboring fields based on a given criteria (equivalent predicate). +template <typename Predicate> +std::vector<std::vector<const FieldDescriptor*> > CollectFields( + const std::vector<const FieldDescriptor*>& fields, + const Predicate& equivalent) { + std::vector<std::vector<const FieldDescriptor*> > chunks; + if (fields.empty()) { + return chunks; + } + + const FieldDescriptor* last_field = fields.front(); + std::vector<const FieldDescriptor*> chunk; + for (int i = 0; i < fields.size(); i++) { + if (!equivalent(last_field, fields[i]) && !chunk.empty()) { + chunks.push_back(chunk); + chunk.clear(); + } + chunk.push_back(fields[i]); + last_field = fields[i]; + } + if (!chunk.empty()) { + chunks.push_back(chunk); + } + return chunks; +} + +// Returns a bit mask based on has_bit index of "fields" that are typically on +// the same chunk. It is used in a group presence check where _has_bits_ is +// masked to tell if any thing in "fields" is present. +uint32 GenChunkMask(const std::vector<const FieldDescriptor*>& fields, + const std::vector<int>& has_bit_indices) { + GOOGLE_CHECK(!fields.empty()); + int first_index_offset = has_bit_indices[fields.front()->index()] / 32; + uint32 chunk_mask = 0; + for (int i = 0; i < fields.size(); i++) { + const FieldDescriptor* field = fields[i]; + // "index" defines where in the _has_bits_ the field appears. + int index = has_bit_indices[field->index()]; + GOOGLE_CHECK_EQ(first_index_offset, index / 32); + chunk_mask |= static_cast<uint32>(1) << (index % 32); + } + GOOGLE_CHECK_NE(0, chunk_mask); + return chunk_mask; +} + } // anonymous namespace // =================================================================== @@ -337,13 +438,12 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, index_in_file_messages_(index_in_file_messages), classname_(ClassName(descriptor, false)), options_(options), - field_generators_(descriptor, options), + field_generators_(descriptor, options, scc_analyzer), max_has_bit_index_(0), enum_generators_( - new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]), - extension_generators_(new google::protobuf::scoped_ptr< + new std::unique_ptr<EnumGenerator>[descriptor->enum_type_count()]), + extension_generators_(new std::unique_ptr< ExtensionGenerator>[descriptor->extension_count()]), - use_dependent_base_(false), num_weak_fields_(0), message_layout_helper_(new PaddingOptimizer()), scc_analyzer_(scc_analyzer) { @@ -389,13 +489,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, if (descriptor->field(i)->is_required()) { ++num_required_fields_; } - if (options.proto_h && IsFieldDependent(descriptor->field(i))) { - use_dependent_base_ = true; - } - } - if (options.proto_h && descriptor->oneof_decl_count() > 0) { - // Always make oneofs dependent. - use_dependent_base_ = true; } table_driven_ = TableDrivenParsingEnabled(descriptor_, options_); @@ -436,22 +529,6 @@ void MessageGenerator::FillMessageForwardDeclarations( } void MessageGenerator:: -GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - PrintFieldComment(printer, field); - - std::map<string, string> vars; - SetCommonFieldVariables(field, &vars, options_); - - // Generate type-specific accessor declarations. - field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); - printer->Print("\n"); - } -} - -void MessageGenerator:: GenerateFieldAccessorDeclarations(io::Printer* printer) { // optimized_fields_ does not contain fields where // field->containing_oneof() != NULL @@ -482,21 +559,6 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { SetCommonFieldVariables(field, &vars, options_); vars["constant_name"] = FieldConstantName(field); - bool dependent_field = use_dependent_base_ && IsFieldDependent(field); - if (dependent_field && - field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !field->is_map()) { - // If this field is dependent, the dependent base class determines - // the message type from the derived class (which is a template - // parameter). This typedef is for that: - printer->Print( - "private:\n" - "typedef $field_type$ $dependent_type$;\n" - "public:\n", - "field_type", FieldMessageTypeName(field), - "dependent_type", DependentTypeName(field)); - } - if (field->is_repeated()) { printer->Print(vars, "$deprecated_attr$int ${$$name$_size$}$() const;\n"); printer->Annotate("{", "}", field); @@ -534,6 +596,7 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( + "void clear_$oneof_name$();\n" "$camel_oneof_name$Case $oneof_name$_case() const;\n", "camel_oneof_name", UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true), @@ -542,32 +605,6 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } void MessageGenerator:: -GenerateDependentFieldAccessorDefinitions(io::Printer* printer) { - if (!use_dependent_base_) return; - - printer->Print("// $classname$\n\n", "classname", - DependentBaseClassTemplateName(descriptor_)); - - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - - if (field->options().weak()) continue; - - PrintFieldComment(printer, field); - // Generate type-specific accessors. - field_generators_.get(field) - .GenerateDependentInlineAccessorDefinitions(printer); - - printer->Print("\n"); - } - - // Generate has_$name$() and clear_has_$name$() functions for oneofs - // Similar to other has-bits, these must always be in the header if we - // are using a dependent base class. - GenerateOneofHasBits(printer); -} - -void MessageGenerator:: GenerateSingularFieldHasBits(const FieldDescriptor* field, std::map<string, string> vars, io::Printer* printer) { @@ -709,18 +746,6 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { std::map<string, string> vars; SetCommonFieldVariables(field, &vars, options_); - if (use_dependent_base_ && IsFieldDependent(field)) { - vars["tmpl"] = "template<class T>\n"; - vars["dependent_classname"] = - DependentBaseClassTemplateName(descriptor_) + "<T>"; - vars["this_message"] = "reinterpret_cast<T*>(this)->"; - vars["this_const_message"] = "reinterpret_cast<const T*>(this)->"; - } else { - vars["tmpl"] = ""; - vars["dependent_classname"] = vars["classname"]; - vars["this_message"] = ""; - vars["this_const_message"] = ""; - } // Generate has_$name$() or $name$_size(). if (field->is_repeated()) { @@ -748,42 +773,8 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { printer->Print("\n"); } - if (!use_dependent_base_) { - // Generate has_$name$() and clear_has_$name$() functions for oneofs - // If we aren't using a dependent base, they can be with the other functions - // that are #ifdef-guarded. - GenerateOneofHasBits(printer); - } -} - -void MessageGenerator:: -GenerateDependentBaseClassDefinition(io::Printer* printer) { - if (!use_dependent_base_) { - return; - } - - std::map<string, string> vars; - vars["classname"] = DependentBaseClassTemplateName(descriptor_); - vars["full_name"] = descriptor_->full_name(); - vars["superclass"] = SuperClassName(descriptor_, options_); - - printer->Print(vars, - "template <class T>\n" - "class $classname$ : public $superclass$ " - "/* @@protoc_insertion_point(dep_base_class_definition:$full_name$) */ {\n" - " public:\n"); - printer->Indent(); - - printer->Print(vars, - "$classname$() {}\n" - "virtual ~$classname$() {}\n" - "\n"); - - // Generate dependent accessor methods for all fields. - GenerateDependentFieldAccessorDeclarations(printer); - - printer->Outdent(); - printer->Print("};\n"); + // Generate has_$name$() and clear_has_$name$() functions for oneofs. + GenerateOneofHasBits(printer); } void MessageGenerator:: @@ -816,7 +807,7 @@ GenerateClassDefinition(io::Printer* printer) { "$classname$*>(&_$classname$_default_instance_); }\n"); if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - " void MergeFrom(const ::google::protobuf::Message& other) PROTOBUF_FINAL;\n" + " void MergeFrom(const ::google::protobuf::Message& other) final;\n" " ::google::protobuf::Metadata GetMetadata() const;\n" "};\n"); } else { @@ -824,10 +815,6 @@ GenerateClassDefinition(io::Printer* printer) { } return; } - if (use_dependent_base_) { - GenerateDependentBaseClassDefinition(printer); - printer->Print("\n"); - } std::map<string, string> vars; vars["classname"] = classname_; @@ -839,20 +826,12 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = options_.dllexport_decl + " "; } - if (use_dependent_base_) { - vars["superclass"] = - DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; - } else { - vars["superclass"] = SuperClassName(descriptor_, options_); - } + vars["superclass"] = SuperClassName(descriptor_, options_); printer->Print(vars, "class $dllexport$$classname$ : public $superclass$ " "/* @@protoc_insertion_point(class_definition:$full_name$) */ " "{\n"); printer->Annotate("classname", descriptor_); - if (use_dependent_base_) { - printer->Print(vars, " friend class $superclass$;\n"); - } printer->Print(" public:\n"); printer->Indent(); @@ -913,10 +892,10 @@ GenerateClassDefinition(io::Printer* printer) { // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a // MessageLite* (e.g., in RepeatedField::AddAllocated()). printer->Print( - "inline ::google::protobuf::Arena* GetArena() const PROTOBUF_FINAL {\n" + "inline ::google::protobuf::Arena* GetArena() const final {\n" " return GetArenaNoVirtual();\n" "}\n" - "inline void* GetMaybeArenaPointer() const PROTOBUF_FINAL {\n" + "inline void* GetMaybeArenaPointer() const final {\n" " return MaybeArenaPtr();\n" "}\n"); } @@ -968,7 +947,7 @@ GenerateClassDefinition(io::Printer* printer) { " return reinterpret_cast<const $classname$*>(\n" " &_$classname$_default_instance_);\n" "}\n" - "static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =\n" + "static constexpr int kIndexInFileMessages =\n" " $message_index$;\n" "\n"); @@ -988,10 +967,12 @@ GenerateClassDefinition(io::Printer* printer) { "template<typename T> bool Is() const {\n" " return _any_metadata_.Is<T>();\n" "}\n" + "static bool ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name);\n" "\n"); } - vars["new_final"] = " PROTOBUF_FINAL"; + vars["new_final"] = " final"; printer->Print(vars, "void Swap($classname$* other);\n" @@ -1001,29 +982,33 @@ GenerateClassDefinition(io::Printer* printer) { "\n" "// implements Message ----------------------------------------------\n" "\n" - "inline $classname$* New() const$new_final$ { return New(NULL); }\n" + "inline $classname$* New() const$new_final$ {\n" + " return CreateMaybeMessage<$classname$>(NULL);\n" + "}\n" "\n" - "$classname$* New(::google::protobuf::Arena* arena) const$new_final$;\n"); + "$classname$* New(::google::protobuf::Arena* arena) const$new_final$ {\n" + " return CreateMaybeMessage<$classname$>(arena);\n" + "}\n"); // For instances that derive from Message (rather than MessageLite), some // methods are virtual and should be marked as final. string use_final = HasDescriptorMethods(descriptor_->file(), options_) ? - " PROTOBUF_FINAL" : ""; + " final" : ""; if (HasGeneratedMethods(descriptor_->file(), options_)) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, - "void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n" - "void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;\n"); + "void CopyFrom(const ::google::protobuf::Message& from) final;\n" + "void MergeFrom(const ::google::protobuf::Message& from) final;\n"); } else { printer->Print(vars, "void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from)\n" - " PROTOBUF_FINAL;\n"); + " final;\n"); } - vars["clear_final"] = " PROTOBUF_FINAL"; - vars["is_initialized_final"] = " PROTOBUF_FINAL"; - vars["merge_partial_final"] = " PROTOBUF_FINAL"; + vars["clear_final"] = " final"; + vars["is_initialized_final"] = " final"; + vars["merge_partial_final"] = " final"; printer->Print( vars, @@ -1032,7 +1017,7 @@ GenerateClassDefinition(io::Printer* printer) { "void Clear()$clear_final$;\n" "bool IsInitialized() const$is_initialized_final$;\n" "\n" - "size_t ByteSizeLong() const PROTOBUF_FINAL;\n" + "size_t ByteSizeLong() const final;\n" "bool MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input)$merge_partial_final$;\n"); if (!options_.table_driven_serialization || @@ -1040,7 +1025,7 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print( "void SerializeWithCachedSizes(\n" " ::google::protobuf::io::CodedOutputStream* output) const " - "PROTOBUF_FINAL;\n"); + "final;\n"); } // DiscardUnknownFields() is implemented in message.cc using reflections. We // need to implement this function in generated code for messages. @@ -1052,19 +1037,18 @@ GenerateClassDefinition(io::Printer* printer) { if (HasFastArraySerialization(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n" - " bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;\n"); + " bool deterministic, ::google::protobuf::uint8* target) const final;\n"); } } printer->Print( - "int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }\n" - "private:\n" - "void SharedCtor();\n" - "void SharedDtor();\n" - "void SetCachedSize(int size) const$final$;\n" - "void InternalSwap($classname$* other);\n", - "classname", classname_, - "final", use_final); + "int GetCachedSize() const final { return _cached_size_.Get(); }" + "\n\nprivate:\n" + "void SharedCtor();\n" + "void SharedDtor();\n" + "void SetCachedSize(int size) const$final$;\n" + "void InternalSwap($classname$* other);\n", + "classname", classname_, "final", use_final); if (SupportsArenas(descriptor_)) { printer->Print( // TODO(gerbens) Make this private! Currently people are deriving from @@ -1104,11 +1088,11 @@ GenerateClassDefinition(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( - "::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;\n" + "::google::protobuf::Metadata GetMetadata() const final;\n" "\n"); } else { printer->Print( - "::std::string GetTypeName() const PROTOBUF_FINAL;\n" + "::std::string GetTypeName() const final;\n" "\n"); } @@ -1187,7 +1171,6 @@ GenerateClassDefinition(io::Printer* printer) { for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( "inline bool has_$oneof_name$() const;\n" - "void clear_$oneof_name$();\n" "inline void clear_has_$oneof_name$();\n\n", "oneof_name", descriptor_->oneof_decl(i)->name()); } @@ -1205,7 +1188,8 @@ GenerateClassDefinition(io::Printer* printer) { bool need_to_emit_cached_size = true; // TODO(kenton): Make _cached_size_ an atomic<int> when C++ supports it. - const string cached_size_decl = "mutable int _cached_size_;\n"; + const string cached_size_decl = + "mutable ::google::protobuf::internal::CachedSize _cached_size_;\n"; const size_t sizeof_has_bits = HasBitsSize(); const string has_bits_decl = sizeof_has_bits == 0 ? "" : @@ -1315,13 +1299,10 @@ GenerateClassDefinition(io::Printer* printer) { // The TableStruct struct needs access to the private parts, in order to // construct the offsets of all members. - // TODO(gerbens) Remove the friend for InitDefaults. - printer->Print( - "friend struct ::$file_namespace$::TableStruct;\n" - "friend void ::$file_namespace$::InitDefaults$scc_name$Impl();\n", - // Vars. - "scc_name", scc_name_, "file_namespace", - FileLevelNamespace(descriptor_)); + printer->Print("friend struct ::$file_namespace$::TableStruct;\n", + // Vars. + "scc_name", scc_name_, "file_namespace", + FileLevelNamespace(descriptor_)); printer->Outdent(); printer->Print("};"); @@ -1329,18 +1310,6 @@ GenerateClassDefinition(io::Printer* printer) { } void MessageGenerator:: -GenerateDependentInlineMethods(io::Printer* printer) { - if (IsMapEntryMessage(descriptor_)) return; - for (int i = 0; i < descriptor_->field_count(); i++) { - if (descriptor_->field(i)->options().weak()) { - field_generators_.get(descriptor_->field(i)) - .GenerateDependentInlineAccessorDefinitions(printer); - } - } - GenerateDependentFieldAccessorDefinitions(printer); -} - -void MessageGenerator:: GenerateInlineMethods(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) return; GenerateFieldAccessorDefinitions(printer); @@ -1495,7 +1464,8 @@ uint32 CalculateType(uint32 type, uint32 type_class) { return (type - 1) + type_class * 20; } -uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { +uint32 CalcFieldNum(const FieldGenerator&, const FieldDescriptor* field, + const Options& options) { bool is_a_map = IsMapEntryMessage(field->containing_type()); int type = field->type(); if (field->containing_oneof()) { @@ -1516,9 +1486,16 @@ uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { #else // We need to calculate for each field what function the table driven code // should use to serialize it. This returns the index in a lookup table. -uint32 CalcFieldNum(const FieldDescriptor* field, const Options& options) { +uint32 CalcFieldNum(const FieldGenerator& generator, + const FieldDescriptor* field, const Options& options) { bool is_a_map = IsMapEntryMessage(field->containing_type()); int type = field->type(); + if (type == FieldDescriptor::TYPE_STRING || + type == FieldDescriptor::TYPE_BYTES) { + if (generator.IsInlined()) { + type = internal::FieldMetadata::kInlinedType; + } + } if (field->containing_oneof()) { return internal::FieldMetadata::CalculateType( type, internal::FieldMetadata::kOneOf); @@ -1560,6 +1537,8 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { if (IsMapEntryMessage(descriptor_)) { for (int i = 0; i < 2; i++) { const FieldDescriptor* field = sorted[i]; + const FieldGenerator& generator = field_generators_.get(field); + uint32 tag = internal::WireFormatLite::MakeTag( field->number(), WireFormat::WireTypeForFieldType(field->type())); @@ -1568,7 +1547,7 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { vars["field_name"] = FieldName(field); vars["tag"] = SimpleItoa(tag); vars["hasbit"] = SimpleItoa(i); - vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); vars["ptr"] = "NULL"; if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { GOOGLE_CHECK(!IsMapEntryMessage(field->message_type())); @@ -1657,7 +1636,9 @@ int MessageGenerator::GenerateFieldMetadata(io::Printer* printer) { SimpleItoa(FindMessageIndexInFile(field->message_type())); } } - vars["type"] = SimpleItoa(CalcFieldNum(field, options_)); + + const FieldGenerator& generator = field_generators_.get(field); + vars["type"] = SimpleItoa(CalcFieldNum(generator, field, options_)); if (field->options().weak()) { @@ -1804,6 +1785,11 @@ GenerateClassMethods(io::Printer* printer) { "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" " return _any_metadata_.UnpackTo(message);\n" "}\n" + "bool $classname$::ParseAnyTypeUrl(const string& type_url,\n" + " string* full_type_name) {\n" + " return ::google::protobuf::internal::ParseAnyTypeUrl(type_url,\n" + " full_type_name);\n" + "}\n" "\n", "classname", classname_); } @@ -1941,16 +1927,26 @@ 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)) { case FieldOptions::STRING: - default: + default: { + if (generator.IsInlined()) { + processing_type = internal::TYPE_STRING_INLINED; + break; + } break; + } } } else if (field->type() == FieldDescriptor::TYPE_BYTES) { switch (EffectiveStringCType(field)) { case FieldOptions::STRING: default: + if (generator.IsInlined()) { + processing_type = internal::TYPE_BYTES_INLINED; + break; + } break; } } @@ -1985,7 +1981,7 @@ size_t MessageGenerator::GenerateParseOffsets(io::Printer* printer) { "{\n" " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(\n" " $classname$, $name$_),\n" - " static_cast< ::google::protobuf::uint32>($presence$),\n" + " static_cast<::google::protobuf::uint32>($presence$),\n" " $nwtype$, $pwtype$, $ptype$, $tag_size$\n" "},\n"); } @@ -2042,20 +2038,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { printer->Print( vars, "{::google::protobuf::internal::AuxillaryParseTableField::message_aux{\n" - " &$ns$::_$classname$_default_instance_,\n"); - - bool dont_emit_table = - !TableDrivenParsingEnabled(field->message_type(), options_); - - if (dont_emit_table) { - printer->Print(" NULL,\n"); - } else { - printer->Print(vars, - " ::$file_namespace$::TableStruct::schema +\n" - " $ns$::$classname$::kIndexInFileMessages,\n"); - } - - printer->Print("}},\n"); + " &$ns$::_$classname$_default_instance_}},\n"); last_field_number++; break; } @@ -2066,7 +2049,7 @@ size_t MessageGenerator::GenerateParseAuxTable(io::Printer* printer) { field->default_value_string().empty() ? "&::google::protobuf::internal::fixed_address_empty_string" : "&" + Namespace(field) + " ::" + classname_ + - "::_default_" + FieldName(field) + "_"; + "::" + MakeDefaultName(field); break; case FieldOptions::CORD: case FieldOptions::STRING_PIECE: @@ -2137,14 +2120,20 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->containing_oneof() || field->options().weak()) { - printer->Print("offsetof($classname$DefaultTypeInternal, $name$_),\n", + printer->Print("offsetof($classname$DefaultTypeInternal, $name$_)", "classname", full_classname, "name", FieldName(field)); } else { printer->Print( - "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, " - "$name$_),\n", + "GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, $name$_)", "classname", full_classname, "name", FieldName(field)); } + + uint32 tag = field_generators_.get(field).CalculateFieldTag(); + if (tag != 0) { + printer->Print(" | $tag$", "tag", SimpleItoa(tag)); + } + + printer->Print(",\n"); } for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { @@ -2178,15 +2167,6 @@ GenerateSharedConstructorCode(io::Printer* printer) { "classname", classname_); printer->Indent(); - bool need_to_clear_cached_size = true; - // We reproduce the logic used for laying out _cached_sized_ in the class - // definition, as to initialize it in-order. - if (HasFieldPresence(descriptor_->file()) && - (HasBitsSize() % 8) != 0) { - printer->Print("_cached_size_ = 0;\n"); - need_to_clear_cached_size = false; - } - std::vector<bool> processed(optimized_order_.size(), false); GenerateConstructorBody(printer, processed, false); @@ -2196,10 +2176,6 @@ GenerateSharedConstructorCode(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - if (need_to_clear_cached_size) { - printer->Print("_cached_size_ = 0;\n"); - } - printer->Outdent(); printer->Print("}\n\n"); } @@ -2304,7 +2280,7 @@ GenerateArenaDestructorCode(io::Printer* printer) { "classname", classname_); } else { printer->Print( - "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n" + "void $classname$::RegisterArenaDtor(::google::protobuf::Arena*) {\n" "}\n", "classname", classname_); } @@ -2383,12 +2359,7 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, void MessageGenerator:: GenerateStructors(io::Printer* printer) { string superclass; - if (use_dependent_base_) { - superclass = - DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; - } else { - superclass = SuperClassName(descriptor_, options_); - } + superclass = SuperClassName(descriptor_, options_); string initializer_with_arena = superclass + "()"; if (descriptor_->extension_range_count() > 0) { @@ -2420,15 +2391,14 @@ GenerateStructors(io::Printer* printer) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; } if (num_weak_fields_ > 0) { - initializer_null += ", _weak_field_map_(NULL)"; + initializer_null += ", _weak_field_map_(nullptr)"; } printer->Print( "$classname$::$classname$()\n" " : $initializer$ {\n" - " if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" - " }\n" + " ::google::protobuf::internal::InitSCC(\n" + " &$file_namespace$::scc_info_$scc_name$.base);\n" " SharedCtor();\n" " // @@protoc_insertion_point(constructor:$full_name$)\n" "}\n", @@ -2440,7 +2410,9 @@ GenerateStructors(io::Printer* printer) { printer->Print( "$classname$::$classname$(::google::protobuf::Arena* arena)\n" " : $initializer$ {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" + " " + "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$." + "base);\n" " SharedCtor();\n" " RegisterArenaDtor(arena);\n" " // @@protoc_insertion_point(arena_constructor:$full_name$)\n" @@ -2452,112 +2424,110 @@ GenerateStructors(io::Printer* printer) { } // Generate the copy constructor. - printer->Print( - "$classname$::$classname$(const $classname$& from)\n" - " : $superclass$()", - "classname", classname_, - "superclass", superclass, - "full_name", descriptor_->full_name()); - printer->Indent(); - printer->Indent(); - printer->Indent(); + if (UsingImplicitWeakFields(descriptor_->file(), options_)) { + // If we are in lite mode and using implicit weak fields, we generate a + // one-liner copy constructor that delegates to MergeFrom. This saves some + // code size and also cuts down on the complexity of implicit weak fields. + // We might eventually want to do this for all lite protos. + printer->Print( + "$classname$::$classname$(const $classname$& from)\n" + " : $classname$() {\n" + " MergeFrom(from);\n" + "}\n", + "classname", classname_); + } else { + printer->Print( + "$classname$::$classname$(const $classname$& from)\n" + " : $superclass$()", + "classname", classname_, + "superclass", superclass, + "full_name", descriptor_->full_name()); + printer->Indent(); + printer->Indent(); + printer->Indent(); - printer->Print( - ",\n_internal_metadata_(NULL)"); + printer->Print( + ",\n_internal_metadata_(NULL)"); - if (HasFieldPresence(descriptor_->file())) { - printer->Print(",\n_has_bits_(from._has_bits_)"); - } + if (HasFieldPresence(descriptor_->file())) { + printer->Print(",\n_has_bits_(from._has_bits_)"); + } - bool need_to_emit_cached_size = true; - const string cached_size_decl = ",\n_cached_size_(0)"; - // We reproduce the logic used for laying out _cached_sized_ in the class - // definition, as to initialize it in-order. - if (HasFieldPresence(descriptor_->file()) && - (HasBitsSize() % 8) != 0) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; - } + std::vector<bool> processed(optimized_order_.size(), false); + for (int i = 0; i < optimized_order_.size(); ++i) { + const FieldDescriptor* field = optimized_order_[i]; - std::vector<bool> processed(optimized_order_.size(), false); - for (int i = 0; i < optimized_order_.size(); ++i) { - const FieldDescriptor* field = optimized_order_[i]; + if (!(field->is_repeated() && !(field->is_map())) + ) { + continue; + } - if (!(field->is_repeated() && !(field->is_map())) - ) { - continue; + processed[i] = true; + printer->Print(",\n$name$_(from.$name$_)", + "name", FieldName(field)); } - processed[i] = true; - printer->Print(",\n$name$_(from.$name$_)", - "name", FieldName(field)); - } - - if (need_to_emit_cached_size) { - printer->Print(cached_size_decl.c_str()); - need_to_emit_cached_size = false; - } - - if (IsAnyMessage(descriptor_)) { - printer->Print(",\n_any_metadata_(&type_url_, &value_)"); - } - if (num_weak_fields_ > 0) { - printer->Print(",\n_weak_field_map_(from._weak_field_map_)"); - } + if (IsAnyMessage(descriptor_)) { + printer->Print(",\n_any_metadata_(&type_url_, &value_)"); + } + if (num_weak_fields_ > 0) { + printer->Print(",\n_weak_field_map_(from._weak_field_map_)"); + } - printer->Outdent(); - printer->Outdent(); - printer->Print(" {\n"); + printer->Outdent(); + printer->Outdent(); + printer->Print(" {\n"); - printer->Print( - "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); + printer->Print( + "_internal_metadata_.MergeFrom(from._internal_metadata_);\n"); - if (descriptor_->extension_range_count() > 0) { - printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); - } + if (descriptor_->extension_range_count() > 0) { + printer->Print("_extensions_.MergeFrom(from._extensions_);\n"); + } - GenerateConstructorBody(printer, processed, true); + GenerateConstructorBody(printer, processed, true); - // Copy oneof fields. Oneof field requires oneof case check. - for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { - printer->Print( - "clear_has_$oneofname$();\n" - "switch (from.$oneofname$_case()) {\n", - "oneofname", descriptor_->oneof_decl(i)->name()); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + // Copy oneof fields. Oneof field requires oneof case check. + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { printer->Print( - "case k$field_name$: {\n", - "field_name", UnderscoresToCamelCase(field->name(), true)); + "clear_has_$oneofname$();\n" + "switch (from.$oneofname$_case()) {\n", + "oneofname", descriptor_->oneof_decl(i)->name()); printer->Indent(); - field_generators_.get(field).GenerateMergingCode(printer); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case k$field_name$: {\n", + "field_name", UnderscoresToCamelCase(field->name(), true)); + printer->Indent(); + field_generators_.get(field).GenerateMergingCode(printer); + printer->Print( + "break;\n"); + printer->Outdent(); + printer->Print( + "}\n"); + } printer->Print( - "break;\n"); + "case $cap_oneof_name$_NOT_SET: {\n" + " break;\n" + "}\n", + "oneof_index", + SimpleItoa(descriptor_->oneof_decl(i)->index()), + "cap_oneof_name", + ToUpper(descriptor_->oneof_decl(i)->name())); printer->Outdent(); printer->Print( "}\n"); } - printer->Print( - "case $cap_oneof_name$_NOT_SET: {\n" - " break;\n" - "}\n", - "oneof_index", - SimpleItoa(descriptor_->oneof_decl(i)->index()), - "cap_oneof_name", - ToUpper(descriptor_->oneof_decl(i)->name())); + printer->Outdent(); printer->Print( - "}\n"); + " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" + "}\n" + "\n", + "full_name", descriptor_->full_name()); } - printer->Outdent(); - printer->Print( - " // @@protoc_insertion_point(copy_constructor:$full_name$)\n" - "}\n" - "\n", - "full_name", descriptor_->full_name()); - // Generate the shared constructor code. GenerateSharedConstructorCode(printer); @@ -2581,12 +2551,10 @@ GenerateStructors(io::Printer* printer) { // Generate SetCachedSize. printer->Print( - "void $classname$::SetCachedSize(int size) const {\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - " _cached_size_ = size;\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "}\n", - "classname", classname_); + "void $classname$::SetCachedSize(int size) const {\n" + " _cached_size_.Set(size);\n" + "}\n", + "classname", classname_); // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file(), options_) && @@ -2605,29 +2573,24 @@ GenerateStructors(io::Printer* printer) { printer->Print( "const $classname$& $classname$::default_instance() {\n" - " ::$file_namespace$::InitDefaults$scc_name$();\n" + " " + "::google::protobuf::internal::InitSCC(&$file_namespace$::scc_info_$scc_name$.base)" + ";\n" " return *internal_default_instance();\n" "}\n\n", "classname", classname_, "scc_name", scc_name_, "file_namespace", FileLevelNamespace(descriptor_)); +} - if (SupportsArenas(descriptor_)) { - printer->Print( - "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" - " return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n" - "}\n", - "classname", classname_); - } else { - printer->Print( - "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n" - " $classname$* n = new $classname$;\n" - " if (arena != NULL) {\n" - " arena->Own(n);\n" - " }\n" - " return n;\n" +void MessageGenerator::GenerateSourceInProto2Namespace(io::Printer* printer) { + printer->Print( + "template<> " + "GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE " + "$classname$* Arena::CreateMaybeMessage< $classname$ >(Arena* arena) {\n" + " return Arena::$create_func$Internal< $classname$ >(arena);\n" "}\n", - "classname", classname_); - } + "classname", QualifiedClassName(descriptor_), + "create_func", MessageCreateFunction(descriptor_)); } // Return the number of bits set in n, a non-negative integer. @@ -2681,7 +2644,6 @@ GenerateClear(io::Printer* printer) { printer->Print("_extensions_.Clear();\n"); } - int last_i = -1; int unconditional_budget = kMaxUnconditionalPrimitiveBytesClear; for (int i = 0; i < optimized_order_.size(); i++) { const FieldDescriptor* field = optimized_order_[i]; @@ -2693,197 +2655,162 @@ GenerateClear(io::Printer* printer) { unconditional_budget -= EstimateAlignmentSize(field); } - for (int i = 0; i < optimized_order_.size(); ) { - // Detect infinite loops. - GOOGLE_CHECK_NE(i, last_i); - last_i = i; + std::vector<std::vector<const FieldDescriptor*> > chunks_frag = CollectFields( + optimized_order_, + MatchRepeatedAndHasByteAndZeroInits( + &has_bit_indices_, HasFieldPresence(descriptor_->file()))); + + // Merge next non-zero initializable chunk if it has the same has_byte index + // and not meeting unconditional clear condition. + std::vector<std::vector<const FieldDescriptor*> > chunks; + if (!HasFieldPresence(descriptor_->file())) { + // Don't bother with merging without has_bit field. + chunks = chunks_frag; + } else { + // Note that only the next chunk is considered for merging. + for (int i = 0; i < chunks_frag.size(); i++) { + chunks.push_back(chunks_frag[i]); + const FieldDescriptor* field = chunks_frag[i].front(); + const FieldDescriptor* next_field = + (i + 1) < chunks_frag.size() ? chunks_frag[i + 1].front() : nullptr; + if (CanInitializeByZeroing(field) && + (chunks_frag[i].size() == 1 || unconditional_budget < 0) && + next_field != nullptr && + has_bit_indices_[field->index()] / 8 == + has_bit_indices_[next_field->index()] / 8) { + GOOGLE_CHECK(!CanInitializeByZeroing(next_field)); + // Insert next chunk to the current one and skip next chunk. + chunks.back().insert(chunks.back().end(), chunks_frag[i + 1].begin(), + chunks_frag[i + 1].end()); + i++; + } + } + } + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + GOOGLE_CHECK(!chunk.empty()); // Step 2: Repeated fields don't use _has_bits_; emit code to clear them // here. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - const FieldGenerator& generator = field_generators_.get(field); + if (chunk.front()->is_repeated()) { + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; + const FieldGenerator& generator = field_generators_.get(field); - if (!field->is_repeated()) { - break; + generator.GenerateMessageClearingCode(printer); } - - generator.GenerateMessageClearingCode(printer); + continue; } - // Step 3: Greedily seek runs of fields that can be cleared by - // memset-to-0. - int last_chunk = -1; - int last_chunk_start = -1; - int last_chunk_end = -1; - uint32 last_chunk_mask = 0; - + // Step 3: Non-repeated fields that can be cleared by memset-to-0, then + // non-repeated, non-zero initializable fields. + int last_chunk = HasFieldPresence(descriptor_->file()) + ? has_bit_indices_[chunk.front()->index()] / 8 + : 0; + int last_chunk_start = 0; int memset_run_start = -1; int memset_run_end = -1; - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - - if (!CanInitializeByZeroing(field)) { - break; - } - - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; - - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; - } - if (memset_run_start == -1) { - memset_run_start = i; + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; + if (CanInitializeByZeroing(field)) { + if (memset_run_start == -1) { + memset_run_start = i; + } + memset_run_end = i; } - - memset_run_end = i; - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); } - if (memset_run_start != memset_run_end && unconditional_budget >= 0) { - // Flush the memset fields. - goto flush; - } + const bool have_outer_if = + HasFieldPresence(descriptor_->file()) && chunk.size() > 1 && + (memset_run_end != chunk.size() - 1 || unconditional_budget < 0); - // Step 4: Non-repeated, non-zero initializable fields. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field->is_repeated() || CanInitializeByZeroing(field)) { - break; - } + if (have_outer_if) { + uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_); + const int count = popcnt(last_chunk_mask); - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; + if (cached_has_bit_index != last_chunk / 4) { + cached_has_bit_index = last_chunk / 4; + printer->Print("cached_has_bits = _has_bits_[$idx$];\n", "idx", + SimpleItoa(cached_has_bit_index)); } - - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); + printer->Print("if (cached_has_bits & $mask$u) {\n", "mask", + SimpleItoa(last_chunk_mask)); + printer->Indent(); } -flush: - - if (last_chunk != -1) { - GOOGLE_DCHECK_NE(-1, last_chunk_start); - GOOGLE_DCHECK_NE(-1, last_chunk_end); - GOOGLE_DCHECK_NE(0, last_chunk_mask); - - const int count = popcnt(last_chunk_mask); - const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end) && - (memset_run_start != last_chunk_start || - memset_run_end != last_chunk_end || - unconditional_budget < 0); - - if (have_outer_if) { - // Check (up to) 8 has_bits at a time if we have more than one field in - // this chunk. Due to field layout ordering, we may check - // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, count); - GOOGLE_DCHECK_GE(8, count); + if (memset_run_start != -1) { + if (memset_run_start == memset_run_end) { + // For clarity, do not memset a single field. + const FieldGenerator& generator = + field_generators_.get(chunk[memset_run_start]); + generator.GenerateMessageClearingCode(printer); + } else { + const string first_field_name = FieldName(chunk[memset_run_start]); + const string last_field_name = FieldName(chunk[memset_run_end]); - if (cached_has_bit_index != last_chunk / 4) { - cached_has_bit_index = last_chunk / 4; - printer->Print( - "cached_has_bits = _has_bits_[$idx$];\n", - "idx", SimpleItoa(cached_has_bit_index)); - } printer->Print( - "if (cached_has_bits & $mask$u) {\n", - "mask", SimpleItoa(last_chunk_mask)); - printer->Indent(); - } - - if (memset_run_start != -1) { - if (memset_run_start == memset_run_end) { - // For clarity, do not memset a single field. - const FieldGenerator& generator = - field_generators_.get(optimized_order_[memset_run_start]); - generator.GenerateMessageClearingCode(printer); - } else { - const string first_field_name = - FieldName(optimized_order_[memset_run_start]); - const string last_field_name = - FieldName(optimized_order_[memset_run_end]); - - printer->Print( "::memset(&$first$_, 0, static_cast<size_t>(\n" " reinterpret_cast<char*>(&$last$_) -\n" " reinterpret_cast<char*>(&$first$_)) + sizeof($last$_));\n", - "first", first_field_name, - "last", last_field_name); - } - - // Advance last_chunk_start to skip over the fields we zeroed/memset. - last_chunk_start = memset_run_end + 1; + "first", first_field_name, "last", last_field_name); } - // Go back and emit clears for each of the fields we processed. - for (int j = last_chunk_start; j <= last_chunk_end; j++) { - const FieldDescriptor* field = optimized_order_[j]; - const string fieldname = FieldName(field); - const FieldGenerator& generator = field_generators_.get(field); + // Advance last_chunk_start to skip over the fields we zeroed/memset. + last_chunk_start = memset_run_end + 1; + } + + // Go back and emit clears for each of the fields we processed. + for (int j = last_chunk_start; j < chunk.size(); j++) { + const FieldDescriptor* field = chunk[j]; + const string fieldname = FieldName(field); + const FieldGenerator& generator = field_generators_.get(field); - // It's faster to just overwrite primitive types, but we should only - // clear strings and messages if they were set. - // - // TODO(kenton): Let the CppFieldGenerator decide this somehow. - bool should_check_bit = + // It's faster to just overwrite primitive types, but we should only + // clear strings and messages if they were set. + // + // TODO(kenton): Let the CppFieldGenerator decide this somehow. + bool should_check_bit = field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || field->cpp_type() == FieldDescriptor::CPPTYPE_STRING; - bool have_enclosing_if = false; - if (should_check_bit && - // If no field presence, then always clear strings/messages as well. - HasFieldPresence(descriptor_->file())) { - if (!field->options().weak() && - cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) { - cached_has_bit_index = (has_bit_indices_[field->index()] / 32); - printer->Print("cached_has_bits = _has_bits_[$new_index$];\n", - "new_index", SimpleItoa(cached_has_bit_index)); - } - if (!MaybeGenerateOptionalFieldCondition(printer, field, - cached_has_bit_index)) { - printer->Print( - "if (has_$name$()) {\n", - "name", fieldname); - } - printer->Indent(); - have_enclosing_if = true; + bool have_enclosing_if = false; + if (should_check_bit && + // If no field presence, then always clear strings/messages as well. + HasFieldPresence(descriptor_->file())) { + if (!field->options().weak() && + cached_has_bit_index != (has_bit_indices_[field->index()] / 32)) { + cached_has_bit_index = (has_bit_indices_[field->index()] / 32); + printer->Print("cached_has_bits = _has_bits_[$new_index$];\n", + "new_index", SimpleItoa(cached_has_bit_index)); } - - generator.GenerateMessageClearingCode(printer); - - if (have_enclosing_if) { - printer->Outdent(); - printer->Print("}\n"); + if (!MaybeGenerateOptionalFieldCondition(printer, field, + cached_has_bit_index)) { + printer->Print("if (has_$name$()) {\n", "name", fieldname); } + printer->Indent(); + have_enclosing_if = true; } - if (have_outer_if) { + generator.GenerateMessageClearingCode(printer); + + if (have_enclosing_if) { printer->Outdent(); printer->Print("}\n"); } } + + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); + } } // Step 4: Unions. @@ -3033,7 +2960,6 @@ GenerateSwap(io::Printer* printer) { printer->Print("_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - printer->Print("swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Swap(&other->_extensions_);\n"); } @@ -3349,7 +3275,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "}\n"); return; } - std::vector<const FieldDescriptor*> ordered_fields = SortFieldsByNumber(descriptor_); @@ -3379,9 +3304,22 @@ GenerateMergeFromCodedStream(io::Printer* printer) { return; } + if (SupportsArenas(descriptor_)) { + for (int i = 0; i < ordered_fields.size(); i++) { + const FieldDescriptor* field = ordered_fields[i]; + const FieldGenerator& field_generator = field_generators_.get(field); + if (field_generator.MergeFromCodedStreamNeedsArena()) { + printer->Print( + " ::google::protobuf::Arena* arena = GetArenaNoVirtual();\n"); + break; + } + } + } + printer->Print( - "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n" - " ::google::protobuf::uint32 tag;\n"); + "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto " + "failure\n" + " ::google::protobuf::uint32 tag;\n"); if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( @@ -3402,8 +3340,12 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print("for (;;) {\n"); printer->Indent(); - uint32 maxtag = descriptor_->field_count() == 0 ? 0 : - WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]); + // To calculate the maximum tag to expect, we look at the highest-numbered + // field. We need to be prepared to handle more than one wire type if that + // field is a packable repeated field, so to simplify things we assume the + // highest possible wire type of 5. + uint32 maxtag = + ordered_fields.empty() ? 0 : ordered_fields.back()->number() * 8 + 5; const int kCutoff0 = 127; // fits in 1-byte varint const int kCutoff1 = (127 << 7) + 127; // fits in 2-byte varint @@ -3421,6 +3363,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { break; } } + + for (int i = 0; i < parent->extension_count(); i++) { + const FieldDescriptor* field = parent->extension(i); + if (field->type() == FieldDescriptor::TYPE_GROUP && + field->message_type() == descriptor_) { + capture_last_tag = true; + break; + } + } } for (int i = 0; i < descriptor_->file()->extension_count(); i++) { @@ -3432,7 +3383,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } } - printer->Print("::std::pair< ::google::protobuf::uint32, bool> p = " + printer->Print("::std::pair<::google::protobuf::uint32, bool> p = " "input->ReadTagWithCutoffNoLastTag($max$u);\n" "tag = p.first;\n" "if (!p.second) goto handle_unusual;\n", @@ -3531,7 +3482,6 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Outdent(); printer->Print("}\n\n"); } - printer->Print("default: {\n"); printer->Indent(); } @@ -3922,7 +3872,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { // Merge the fields and the extension ranges, both sorted by field number. { LazySerializerEmitter e(this, printer, to_array); - const FieldDescriptor* last_weak_field = NULL; + const FieldDescriptor* last_weak_field = nullptr; int i, j; for (i = 0, j = 0; i < ordered_fields.size() || j < sorted_extensions.size();) { @@ -3934,16 +3884,16 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { last_weak_field = field; PrintFieldComment(printer, field); } else { - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); - last_weak_field = NULL; + last_weak_field = nullptr; } e.Emit(field); } } else { - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); - last_weak_field = NULL; + last_weak_field = nullptr; } e.Flush(); GenerateSerializeOneExtensionRange(printer, @@ -3951,7 +3901,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { to_array); } } - if (last_weak_field != NULL) { + if (last_weak_field != nullptr) { e.Emit(last_weak_field); } } @@ -4013,8 +3963,9 @@ static string ConditionalToCheckBitmasks(const std::vector<uint32>& masks) { } GOOGLE_CHECK(!parts.empty()); // If we have multiple parts, each expected to be 0, then bitwise-or them. - string result = parts.size() == 1 ? parts[0] : - StrCat("(", Join(parts, "\n | "), ")"); + string result = parts.size() == 1 + ? parts[0] + : StrCat("(", Join(parts, "\n | "), ")"); return result + " == 0"; } @@ -4027,20 +3978,19 @@ GenerateByteSize(io::Printer* printer) { SetUnknkownFieldsVariable(descriptor_, options_, &vars); vars["classname"] = classname_; vars["full_name"] = descriptor_->full_name(); - printer->Print(vars, - "size_t $classname$::ByteSizeLong() const {\n" - "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" - " size_t total_size = _extensions_.MessageSetByteSize();\n" - " if ($have_unknown_fields$) {\n" - " total_size += ::google::protobuf::internal::WireFormat::\n" - " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" - " }\n" - " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - " _cached_size_ = cached_size;\n" - " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - " return total_size;\n" - "}\n"); + printer->Print( + vars, + "size_t $classname$::ByteSizeLong() const {\n" + "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" + " size_t total_size = _extensions_.MessageSetByteSize();\n" + " if ($have_unknown_fields$) {\n" + " total_size += ::google::protobuf::internal::WireFormat::\n" + " ComputeUnknownMessageSetItemsSize($unknown_fields$);\n" + " }\n" + " int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + " SetCachedSize(cached_size);\n" + " return total_size;\n" + "}\n"); return; } @@ -4141,28 +4091,30 @@ GenerateByteSize(io::Printer* printer) { } } - int last_i = -1; - for (int i = 0; i < optimized_order_.size(); ) { - // Detect infinite loops. - GOOGLE_CHECK_NE(i, last_i); - last_i = i; + std::vector<std::vector<const FieldDescriptor*> > chunks = CollectFields( + optimized_order_, + MatchRepeatedAndHasByteAndRequired( + &has_bit_indices_, HasFieldPresence(descriptor_->file()))); - // Skip required fields. - for (; i < optimized_order_.size() && - optimized_order_[i]->is_required(); i++) { - } + // Remove chunks with required fields. + chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired), + chunks.end()); + + for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { + const std::vector<const FieldDescriptor*>& chunk = chunks[chunk_index]; + GOOGLE_CHECK(!chunk.empty()); // Handle repeated fields. - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (!field->is_repeated()) { - break; - } + if (chunk.front()->is_repeated()) { + for (int i = 0; i < chunk.size(); i++) { + const FieldDescriptor* field = chunk[i]; - PrintFieldComment(printer, field); - const FieldGenerator& generator = field_generators_.get(field); - generator.GenerateByteSize(printer); - printer->Print("\n"); + PrintFieldComment(printer, field); + const FieldGenerator& generator = field_generators_.get(field); + generator.GenerateByteSize(printer); + printer->Print("\n"); + } + continue; } // Handle optional (non-repeated/oneof) fields. @@ -4174,92 +4126,62 @@ GenerateByteSize(io::Printer* printer) { // descriptor_->field(8), descriptor_->field(9), ... // descriptor_->field(15), // etc. - int last_chunk = -1; - int last_chunk_start = -1; - int last_chunk_end = -1; - uint32 last_chunk_mask = 0; - for (; i < optimized_order_.size(); i++) { - const FieldDescriptor* field = optimized_order_[i]; - if (field->is_repeated() || field->is_required()) { - break; - } + int last_chunk = HasFieldPresence(descriptor_->file()) + ? has_bit_indices_[chunk.front()->index()] / 8 + : 0; + GOOGLE_DCHECK_NE(-1, last_chunk); - // "index" defines where in the _has_bits_ the field appears. - // "i" is our loop counter within optimized_order_. - int index = HasFieldPresence(descriptor_->file()) ? - has_bit_indices_[field->index()] : 0; - int chunk = index / 8; + const bool have_outer_if = + HasFieldPresence(descriptor_->file()) && chunk.size() > 1; - if (last_chunk == -1) { - last_chunk = chunk; - last_chunk_start = i; - } else if (chunk != last_chunk) { - // Emit the fields for this chunk so far. - break; - } + if (have_outer_if) { + uint32 last_chunk_mask = GenChunkMask(chunk, has_bit_indices_); + const int count = popcnt(last_chunk_mask); - last_chunk_end = i; - last_chunk_mask |= static_cast<uint32>(1) << (index % 32); - } + // Check (up to) 8 has_bits at a time if we have more than one field in + // this chunk. Due to field layout ordering, we may check + // _has_bits_[last_chunk * 8 / 32] multiple times. + GOOGLE_DCHECK_LE(2, count); + GOOGLE_DCHECK_GE(8, count); - if (last_chunk != -1) { - GOOGLE_DCHECK_NE(-1, last_chunk_start); - GOOGLE_DCHECK_NE(-1, last_chunk_end); - GOOGLE_DCHECK_NE(0, last_chunk_mask); + printer->Print("if (_has_bits_[$index$ / 32] & $mask$u) {\n", "index", + SimpleItoa(last_chunk * 8), "mask", + SimpleItoa(last_chunk_mask)); + printer->Indent(); + } - const int count = popcnt(last_chunk_mask); - const bool have_outer_if = HasFieldPresence(descriptor_->file()) && - (last_chunk_start != last_chunk_end); + // Go back and emit checks for each of the fields we processed. + for (int j = 0; j < chunk.size(); j++) { + const FieldDescriptor* field = chunk[j]; + const FieldGenerator& generator = field_generators_.get(field); - if (have_outer_if) { - // Check (up to) 8 has_bits at a time if we have more than one field in - // this chunk. Due to field layout ordering, we may check - // _has_bits_[last_chunk * 8 / 32] multiple times. - GOOGLE_DCHECK_LE(2, count); - GOOGLE_DCHECK_GE(8, count); + PrintFieldComment(printer, field); - printer->Print( - "if (_has_bits_[$index$ / 32] & $mask$u) {\n", - "index", SimpleItoa(last_chunk * 8), - "mask", SimpleItoa(last_chunk_mask)); + bool have_enclosing_if = false; + if (HasFieldPresence(descriptor_->file())) { + printer->Print("if (has_$name$()) {\n", "name", FieldName(field)); printer->Indent(); + have_enclosing_if = true; + } else { + // Without field presence: field is serialized only if it has a + // non-default value. + have_enclosing_if = + EmitFieldNonDefaultCondition(printer, "this->", field); } - // Go back and emit checks for each of the fields we processed. - for (int j = last_chunk_start; j <= last_chunk_end; j++) { - const FieldDescriptor* field = optimized_order_[j]; - const FieldGenerator& generator = field_generators_.get(field); - - PrintFieldComment(printer, field); - - bool have_enclosing_if = false; - if (HasFieldPresence(descriptor_->file())) { - printer->Print( - "if (has_$name$()) {\n", - "name", FieldName(field)); - printer->Indent(); - have_enclosing_if = true; - } else { - // Without field presence: field is serialized only if it has a - // non-default value. - have_enclosing_if = EmitFieldNonDefaultCondition( - printer, "this->", field); - } - - generator.GenerateByteSize(printer); + generator.GenerateByteSize(printer); - if (have_enclosing_if) { - printer->Outdent(); - printer->Print( + if (have_enclosing_if) { + printer->Outdent(); + printer->Print( "}\n" "\n"); - } } + } - if (have_outer_if) { - printer->Outdent(); - printer->Print("}\n"); - } + if (have_outer_if) { + printer->Outdent(); + printer->Print("}\n"); } } @@ -4300,17 +4222,18 @@ GenerateByteSize(io::Printer* printer) { printer->Print("total_size += _weak_field_map_.ByteSizeLong();\n"); } - // We update _cached_size_ even though this is a const method. In theory, - // this is not thread-compatible, because concurrent writes have undefined - // results. In practice, since any concurrent writes will be writing the - // exact same value, it works on all common processors. In a future version - // of C++, _cached_size_ should be made into an atomic<int>. + // 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. printer->Print( - "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" - "_cached_size_ = cached_size;\n" - "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" - "return total_size;\n"); + "int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);\n" + "SetCachedSize(cached_size);\n" + "return total_size;\n"); printer->Outdent(); printer->Print("}\n"); @@ -4359,10 +4282,17 @@ GenerateIsInitialized(io::Printer* printer) { !ShouldIgnoreRequiredFieldCheck(field, options_) && scc_analyzer_->HasRequiredFields(field->message_type())) { if (field->is_repeated()) { - printer->Print( - "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" - " return false;\n", - "name", FieldName(field)); + if (IsImplicitWeakField(field, options_, scc_analyzer_)) { + printer->Print( + "if (!::google::protobuf::internal::AllAreInitializedWeak(this->$name$_))" + " return false;\n", + "name", FieldName(field)); + } else { + printer->Print( + "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" + " return false;\n", + "name", FieldName(field)); + } } else if (field->options().weak()) { continue; } else { |