diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc index 083b75aa9348e..9fed9de99def4 100644 --- a/src/google/protobuf/compiler/cpp/field.cc +++ b/src/google/protobuf/compiler/cpp/field.cc @@ -22,7 +22,6 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "absl/types/span.h" #include "google/protobuf/compiler/cpp/field_generators/generators.h" #include "google/protobuf/compiler/cpp/field_layout.h" @@ -44,8 +43,9 @@ namespace cpp { using ::google::protobuf::internal::WireFormat; using Sub = ::google::protobuf::io::Printer::Sub; -std::vector FieldVars(const FieldDescriptor* field, const Options& opts) { - bool split = ShouldSplit(field, opts); +std::vector FieldVars(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) { + bool split = field_layout.IsSplit(field); std::vector vars = { // This will eventually be renamed to "field", once the existing "field" // variable is replaced with "field_" everywhere. @@ -110,10 +110,11 @@ std::vector FieldVars(const FieldDescriptor* field, const Options& opts) { } FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* field, - const Options& options) - : field_(field), options_(options) { + const Options& options, + const FieldLayout& field_layout) + : field_(field), options_(options), field_layout_(field_layout) { bool is_repeated_or_map = field->is_repeated(); - should_split_ = ShouldSplit(field, options); + should_split_ = field_layout_.IsSplit(field); is_oneof_ = field->real_containing_oneof() != nullptr; switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_ENUM: @@ -165,7 +166,7 @@ void FieldGeneratorBase::GenerateMemberConstexprConstructor( void FieldGeneratorBase::GenerateMemberConstructor(io::Printer* p) const { ABSL_CHECK(!field_->is_extension()); if (field_->is_repeated() || field_->is_map()) { - if (ShouldSplit(field_, options_)) { + if (field_layout_.IsSplit(field_)) { ABSL_CHECK(!field_->is_map()); p->Emit("$name$_{}"); // RawPtr } else { @@ -202,7 +203,7 @@ void FieldGeneratorBase::GenerateOneofCopyConstruct(io::Printer* p) const { } void FieldGeneratorBase::GenerateAggregateInitializer(io::Printer* p) const { - if (ShouldSplit(field_, options_)) { + if (field_layout_.IsSplit(field_)) { p->Emit(R"cc( decltype(Impl_::Split::$name$_){arena}, )cc"); @@ -255,68 +256,70 @@ Sub FieldGeneratorBase::InternalMetadataOffsetSub(io::Printer* p) { } namespace { -std::unique_ptr MakeGenerator(const FieldDescriptor* field, - const Options& options) { +std::unique_ptr MakeGenerator( + const FieldDescriptor* field, const Options& options, + const FieldLayout& field_layout) { if (field->is_map()) { ABSL_CHECK( !(field->options().lazy() || field->options().unverified_lazy())); - return MakeMapGenerator(field, options); + return MakeMapGenerator(field, options, field_layout); } if (field->is_repeated()) { ABSL_CHECK(!field->options().unverified_lazy()); switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return MakeRepeatedMessageGenerator(field, options); + return MakeRepeatedMessageGenerator(field, options, field_layout); case FieldDescriptor::CPPTYPE_STRING: { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kView) { - return MakeRepeatedStringViewGenerator(field, options); + return MakeRepeatedStringViewGenerator(field, options, field_layout); } else { - return MakeRepeatedStringGenerator(field, options); + return MakeRepeatedStringGenerator(field, options, field_layout); } } case FieldDescriptor::CPPTYPE_ENUM: - return MakeRepeatedEnumGenerator(field, options); + return MakeRepeatedEnumGenerator(field, options, field_layout); default: - return MakeRepeatedPrimitiveGenerator(field, options); + return MakeRepeatedPrimitiveGenerator(field, options, field_layout); } } if (field->real_containing_oneof() && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - return MakeOneofMessageGenerator(field, options); + return MakeOneofMessageGenerator(field, options, field_layout); } switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_MESSAGE: - return MakeSinguarMessageGenerator(field, options); + return MakeSinguarMessageGenerator(field, options, field_layout); case FieldDescriptor::CPPTYPE_ENUM: - return MakeSinguarEnumGenerator(field, options); + return MakeSinguarEnumGenerator(field, options, field_layout); case FieldDescriptor::CPPTYPE_STRING: { switch (field->cpp_string_type()) { case FieldDescriptor::CppStringType::kView: - return MakeSingularStringViewGenerator(field, options); + return MakeSingularStringViewGenerator(field, options, field_layout); case FieldDescriptor::CppStringType::kCord: if (field->type() == FieldDescriptor::TYPE_BYTES) { if (field->real_containing_oneof()) { - return MakeOneofCordGenerator(field, options); + return MakeOneofCordGenerator(field, options, field_layout); } else { - return MakeSingularCordGenerator(field, options); + return MakeSingularCordGenerator(field, options, field_layout); } } ABSL_FALLTHROUGH_INTENDED; default: - return MakeSinguarStringGenerator(field, options); + return MakeSinguarStringGenerator(field, options, field_layout); } } default: - return MakeSinguarPrimitiveGenerator(field, options); + return MakeSinguarPrimitiveGenerator(field, options, field_layout); } } void HasBitVars(const FieldDescriptor* field, const Options& opts, - absl::optional idx, std::vector& vars) { + const FieldLayout& field_layout, std::vector& vars) { + const auto idx = field_layout.GetHasBitIndex(field); if (!idx.has_value()) { vars.emplace_back(Sub("set_hasbit", "").WithSuffix(";")); vars.emplace_back(Sub("clear_hasbit", "").WithSuffix(";")); @@ -350,12 +353,12 @@ void HasBitVars(const FieldDescriptor* field, const Options& opts, FieldGenerator::FieldGenerator(const FieldDescriptor* field, const Options& options, - absl::optional hasbit_index) - : impl_(MakeGenerator(field, options)), - field_vars_(FieldVars(field, options)), - tracker_vars_(MakeTrackerCalls(field, options)), + const FieldLayout& field_layout) + : impl_(MakeGenerator(field, options, field_layout)), + field_vars_(FieldVars(field, options, field_layout)), + tracker_vars_(MakeTrackerCalls(field, options, field_layout)), per_generator_vars_(impl_->MakeVars()) { - HasBitVars(field, options, hasbit_index, field_vars_); + HasBitVars(field, options, field_layout, field_vars_); } void FieldGeneratorTable::Build(const Options& options, @@ -363,8 +366,7 @@ void FieldGeneratorTable::Build(const Options& options, // Construct all the FieldGenerators. fields_.reserve(static_cast(descriptor_->field_count())); for (const auto* field : internal::FieldRange(descriptor_)) { - fields_.push_back( - FieldGenerator(field, options, field_layout.GetHasBitIndex(field))); + fields_.push_back(FieldGenerator(field, options, field_layout)); } } diff --git a/src/google/protobuf/compiler/cpp/field.h b/src/google/protobuf/compiler/cpp/field.h index 8f93625510755..17625dfed9186 100644 --- a/src/google/protobuf/compiler/cpp/field.h +++ b/src/google/protobuf/compiler/cpp/field.h @@ -13,7 +13,6 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ #include -#include #include #include #include @@ -21,7 +20,6 @@ #include "absl/container/flat_hash_map.h" #include "absl/log/absl_check.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "absl/types/span.h" #include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" @@ -52,7 +50,8 @@ class FieldGeneratorBase { // variable instead of calling GetArena()' enum class GeneratorFunction { kMergeFrom }; - FieldGeneratorBase(const FieldDescriptor* field, const Options& options); + FieldGeneratorBase(const FieldDescriptor* field, const Options& options, + const FieldLayout& field_layout); FieldGeneratorBase(const FieldGeneratorBase&) = delete; FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete; @@ -198,6 +197,8 @@ class FieldGeneratorBase { } protected: + const FieldLayout& field_layout() const { return field_layout_; } + const FieldDescriptor* field_; const Options& options_; absl::flat_hash_map variables_; @@ -207,6 +208,8 @@ class FieldGeneratorBase { static io::Printer::Sub InternalMetadataOffsetSub(io::Printer* p); private: + const FieldLayout& field_layout_; + bool should_split_ = false; bool is_trivial_ = false; bool has_trivial_value_ = false; @@ -499,7 +502,7 @@ class FieldGenerator { private: friend class FieldGeneratorTable; FieldGenerator(const FieldDescriptor* field, const Options& options, - absl::optional hasbit_index); + const FieldLayout& field_layout); std::unique_ptr impl_; std::vector field_vars_; @@ -533,7 +536,8 @@ class FieldGeneratorTable { // // TODO: Make this function .cc-private. std::vector FieldVars(const FieldDescriptor* field, - const Options& opts); + const Options& opts, + const FieldLayout& field_layout); } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/field_chunk.h b/src/google/protobuf/compiler/cpp/field_chunk.h index b8f5be25cdf85..8b2635360ba1d 100644 --- a/src/google/protobuf/compiler/cpp/field_chunk.h +++ b/src/google/protobuf/compiler/cpp/field_chunk.h @@ -52,7 +52,8 @@ struct AlwaysTruePred { template std::vector CollectFields( absl::Span fields, const Options& options, - const Predicate& equivalent, const Filter filter = {}) { + const SplitMap& split_map, const Predicate& equivalent, + const Filter filter = {}) { std::vector chunks; bool force_new_chunk = true; for (auto field : fields) { @@ -66,7 +67,7 @@ std::vector CollectFields( force_new_chunk = false; chunks.emplace_back(HasHasbit(field, options), IsRarelyPresent(field, options), - ShouldSplit(field, options)); + split_map.IsSplit(field)); } chunks.back().fields.push_back(field); } diff --git a/src/google/protobuf/compiler/cpp/field_chunk_test.cc b/src/google/protobuf/compiler/cpp/field_chunk_test.cc index cabf676e6d0b9..f13bcae72d21b 100644 --- a/src/google/protobuf/compiler/cpp/field_chunk_test.cc +++ b/src/google/protobuf/compiler/cpp/field_chunk_test.cc @@ -38,7 +38,8 @@ std::vector CreateFieldArray( template std::vector CreateAndCollectFields( absl::Span field_names, PredT&& predicate) { - return CollectFields(CreateFieldArray(field_names), {}, predicate); + return CollectFields(CreateFieldArray(field_names), /*options=*/{}, + /*split_map=*/{}, predicate); } TEST(CollectFieldsTest, SingleChunk) { @@ -70,10 +71,11 @@ TEST(CollectFieldsTest, RepeatedAndSingular) { "optional_int64"}; auto fields = CreateFieldArray(field_names); - auto chunks = CollectFields( - fields, {}, [](const FieldDescriptor* lhs, const FieldDescriptor* rhs) { - return lhs->is_repeated() == rhs->is_repeated(); - }); + auto chunks = + CollectFields(fields, /*options=*/{}, /*split_map=*/{}, + [](const FieldDescriptor* lhs, const FieldDescriptor* rhs) { + return lhs->is_repeated() == rhs->is_repeated(); + }); ASSERT_EQ(chunks.size(), 2); diff --git a/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc b/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc index 51bbb82adbece..88e88ab725961 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc @@ -11,7 +11,6 @@ #include #include -#include #include "absl/container/flat_hash_map.h" #include "absl/log/absl_check.h" @@ -21,7 +20,7 @@ #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -61,7 +60,8 @@ void SetCordVariables( class CordFieldGenerator : public FieldGeneratorBase { public: - CordFieldGenerator(const FieldDescriptor* descriptor, const Options& options); + CordFieldGenerator(const FieldDescriptor* descriptor, const Options& options, + const FieldLayout& field_layout); ~CordFieldGenerator() override = default; void GeneratePrivateMembers(io::Printer* p) const override; @@ -84,7 +84,7 @@ class CordFieldGenerator : public FieldGeneratorBase { if (field_->default_value_string().empty()) { p->Emit(R"cc($name$_ {})cc"); } else { - p->Emit({{"Split", ShouldSplit(field_, options_) ? "Split::" : ""}}, + p->Emit({{"Split", field_layout().IsSplit(field_) ? "Split::" : ""}}, R"cc( $name$_ { ::absl::strings_internal::MakeStringConstant( @@ -120,7 +120,8 @@ class CordFieldGenerator : public FieldGeneratorBase { class CordOneofFieldGenerator : public CordFieldGenerator { public: CordOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + const Options& options, + const FieldLayout& field_layout); ~CordOneofFieldGenerator() override = default; void GeneratePrivateMembers(io::Printer* p) const override; @@ -140,8 +141,9 @@ class CordOneofFieldGenerator : public CordFieldGenerator { CordFieldGenerator::CordFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : FieldGeneratorBase(descriptor, options) { + const Options& options, + const FieldLayout& field_layout) + : FieldGeneratorBase(descriptor, options, field_layout) { SetCordVariables(descriptor, &variables_, options); } @@ -334,8 +336,9 @@ void CordFieldGenerator::GenerateAggregateInitializer(io::Printer* p) const { // =================================================================== CordOneofFieldGenerator::CordOneofFieldGenerator( - const FieldDescriptor* descriptor, const Options& options) - : CordFieldGenerator(descriptor, options) {} + const FieldDescriptor* descriptor, const Options& options, + const FieldLayout& field_layout) + : CordFieldGenerator(descriptor, options, field_layout) {} void CordOneofFieldGenerator::GeneratePrivateMembers(io::Printer* p) const { auto v = p->WithVars(variables_); @@ -469,14 +472,16 @@ void CordOneofFieldGenerator::GenerateMergingCode(io::Printer* p) const { } // namespace std::unique_ptr MakeSingularCordGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeOneofCordGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc index 242ee8de841ec..fea7b71bcae17 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc @@ -18,7 +18,7 @@ #include "absl/memory/memory.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -36,9 +36,10 @@ namespace { using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic; using Sub = ::google::protobuf::io::Printer::Sub; -std::vector Vars(const FieldDescriptor* field, const Options& opts) { +std::vector Vars(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) { const EnumValueDescriptor* default_value = field->default_value_enum(); - bool split = ShouldSplit(field, opts); + bool split = field_layout.IsSplit(field); bool is_open = internal::cpp::HasPreservingUnknownEnumSemantics(field); auto enum_name = QualifiedClassName(field->enum_type(), opts); return { @@ -60,11 +61,14 @@ std::vector Vars(const FieldDescriptor* field, const Options& opts) { class SingularEnum : public FieldGeneratorBase { public: - SingularEnum(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), opts_(&opts) {} + SingularEnum(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts) {} ~SingularEnum() override = default; - std::vector MakeVars() const override { return Vars(field_, *opts_); } + std::vector MakeVars() const override { + return Vars(field_, *opts_, field_layout()); + } void GeneratePrivateMembers(io::Printer* p) const override { p->Emit(R"cc( @@ -222,8 +226,9 @@ void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const { class RepeatedEnum : public FieldGeneratorBase { public: - RepeatedEnum(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + RepeatedEnum(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), has_cached_size_(field_->is_packed() && HasGeneratedMethods(field_->file(), opts) && @@ -231,7 +236,9 @@ class RepeatedEnum : public FieldGeneratorBase { cpp_repeated_type_(CalculateFieldDescriptorRepeatedType(field)) {} ~RepeatedEnum() override = default; - std::vector MakeVars() const override { return Vars(field_, *opts_); } + std::vector MakeVars() const override { + return Vars(field_, *opts_, field_layout()); + } void GeneratePrivateMembers(io::Printer* p) const override { if (should_split()) { @@ -621,13 +628,15 @@ void RepeatedEnum::GenerateByteSize(io::Printer* p) const { } // namespace std::unique_ptr MakeSinguarEnumGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeRepeatedEnumGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/generators.h b/src/google/protobuf/compiler/cpp/field_generators/generators.h index b063deabf4a2c..5d35c5c3f8420 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/generators.h +++ b/src/google/protobuf/compiler/cpp/field_generators/generators.h @@ -11,7 +11,7 @@ #include #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -31,46 +31,60 @@ namespace protobuf { namespace compiler { namespace cpp { std::unique_ptr MakeSinguarPrimitiveGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeRepeatedPrimitiveGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeSinguarEnumGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeRepeatedEnumGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeSinguarStringGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeRepeatedStringGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeSingularStringViewGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeRepeatedStringViewGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeSinguarMessageGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeRepeatedMessageGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeOneofMessageGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeMapGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeSingularCordGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); std::unique_ptr MakeOneofCordGenerator( - const FieldDescriptor* desc, const Options& options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout); } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc index 15a124989c8d3..9f3be38a47a95 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc @@ -5,23 +5,20 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd -#include #include #include #include -#include "absl/log/absl_check.h" #include "absl/strings/ascii.h" #include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" -#include "google/protobuf/port.h" // Must be included last. #include "google/protobuf/port_def.inc" @@ -81,8 +78,9 @@ void EmitFuncs(const FieldDescriptor* field, io::Printer* p) { class Map : public FieldGeneratorBase { public: - Map(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + Map(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), key_(field->message_type()->map_key()), val_(field->message_type()->map_value()), opts_(&opts), @@ -324,8 +322,9 @@ void Map::GenerateByteSize(io::Printer* p) const { } // namespace std::unique_ptr MakeMapGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc index 77d77ed241012..4025270ac239b 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc @@ -19,7 +19,7 @@ #include "absl/strings/string_view.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -39,8 +39,9 @@ using ::google::protobuf::io::AnnotationCollector; using Sub = ::google::protobuf::io::Printer::Sub; std::vector Vars(const FieldDescriptor* field, const Options& opts, - bool is_weak, bool use_base_class) { - bool split = ShouldSplit(field, opts); + const FieldLayout& field_layout, bool is_weak, + bool use_base_class) { + bool split = field_layout.IsSplit(field); bool is_foreign = IsCrossFileMessage(field); std::string field_name = FieldMemberName(field, split); std::string qualified_type = FieldMessageTypeName(field, opts); @@ -81,8 +82,9 @@ std::vector Vars(const FieldDescriptor* field, const Options& opts, class SingularMessage : public FieldGeneratorBase { public: - SingularMessage(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + SingularMessage(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), has_required_( opts.scc_analyzer->HasRequiredFields(field->message_type())), @@ -91,7 +93,7 @@ class SingularMessage : public FieldGeneratorBase { ~SingularMessage() override = default; std::vector MakeVars() const override { - return Vars(field_, *opts_, is_weak(), is_weak()); + return Vars(field_, *opts_, field_layout(), is_weak(), is_weak()); } void GeneratePrivateMembers(io::Printer* p) const override { @@ -459,8 +461,9 @@ void SingularMessage::GenerateAggregateInitializer(io::Printer* p) const { class OneofMessage : public SingularMessage { public: - OneofMessage(const FieldDescriptor* descriptor, const Options& options) - : SingularMessage(descriptor, options) { + OneofMessage(const FieldDescriptor* descriptor, const Options& options, + const FieldLayout& field_layout) + : SingularMessage(descriptor, options, field_layout) { auto* oneof = descriptor->containing_oneof(); num_message_fields_in_oneof_ = 0; for (int i = 0; i < oneof->field_count(); ++i) { @@ -495,7 +498,7 @@ class OneofMessage : public SingularMessage { } std::vector MakeVars() const override { - return Vars(field_, *opts_, is_weak(), use_base_class()); + return Vars(field_, *opts_, field_layout(), is_weak(), use_base_class()); } void GenerateInlineAccessorDefinitions(io::Printer* p) const override; @@ -703,8 +706,9 @@ bool OneofMessage::RequiresArena(GeneratorFunction func) const { class RepeatedMessage : public FieldGeneratorBase { public: - RepeatedMessage(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + RepeatedMessage(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), has_required_( opts.scc_analyzer->HasRequiredFields(field->message_type())), @@ -713,7 +717,7 @@ class RepeatedMessage : public FieldGeneratorBase { ~RepeatedMessage() override = default; std::vector MakeVars() const override { - return Vars(field_, *opts_, is_weak(), is_weak()); + return Vars(field_, *opts_, field_layout(), is_weak(), is_weak()); } void GeneratePrivateMembers(io::Printer* p) const override; @@ -1112,18 +1116,21 @@ bool RepeatedMessage::RequiresArena(GeneratorFunction func) const { } // namespace std::unique_ptr MakeSinguarMessageGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeRepeatedMessageGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeOneofMessageGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc index df489725a0898..849386bebe195 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc @@ -11,7 +11,6 @@ #include #include -#include #include #include "absl/log/absl_check.h" @@ -20,7 +19,7 @@ #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -81,8 +80,9 @@ absl::optional FixedSize(FieldDescriptor::Type type) { return absl::nullopt; } -std::vector Vars(const FieldDescriptor* field, const Options& options) { - bool cold = ShouldSplit(field, options); +std::vector Vars(const FieldDescriptor* field, const Options& options, + const FieldLayout& field_layout) { + bool cold = field_layout.IsSplit(field); return { {"Type", PrimitiveTypeName(options, field->cpp_type())}, {"kDefault", DefaultValue(options, field)}, @@ -92,11 +92,14 @@ std::vector Vars(const FieldDescriptor* field, const Options& options) { class SingularPrimitive final : public FieldGeneratorBase { public: - SingularPrimitive(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), opts_(&opts) {} + SingularPrimitive(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts) {} ~SingularPrimitive() override = default; - std::vector MakeVars() const override { return Vars(field_, *opts_); } + std::vector MakeVars() const override { + return Vars(field_, *opts_, field_layout()); + } void GeneratePrivateMembers(io::Printer* p) const override { p->Emit(R"cc( @@ -288,13 +291,16 @@ void SingularPrimitive::GenerateByteSize(io::Printer* p) const { class RepeatedPrimitive final : public FieldGeneratorBase { public: - RepeatedPrimitive(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + RepeatedPrimitive(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), cpp_repeated_type_(CalculateFieldDescriptorRepeatedType(field)) {} ~RepeatedPrimitive() override = default; - std::vector MakeVars() const override { return Vars(field_, *opts_); } + std::vector MakeVars() const override { + return Vars(field_, *opts_, field_layout()); + } void GenerateMessageClearingCode(io::Printer* p) const override { if (should_split()) { @@ -714,13 +720,15 @@ void RepeatedPrimitive::GenerateByteSize(io::Printer* p) const { } // namespace std::unique_ptr MakeSinguarPrimitiveGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeRepeatedPrimitiveGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc index 4dd53b577c708..1fa7fddb8dcbf 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/string_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/string_field.cc @@ -18,7 +18,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "google/protobuf/compiler/cpp/field.h" -#include "google/protobuf/compiler/cpp/field_generators/generators.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -68,8 +68,9 @@ std::vector Vars(const FieldDescriptor* field, const Options& opts) { class SingularString : public FieldGeneratorBase { public: - SingularString(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), opts_(&opts) {} + SingularString(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts) {} ~SingularString() override = default; std::vector MakeVars() const override { return Vars(field_, *opts_); } @@ -651,8 +652,9 @@ void SingularString::GenerateAggregateInitializer(io::Printer* p) const { class RepeatedString : public FieldGeneratorBase { public: - RepeatedString(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + RepeatedString(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), cpp_repeated_type_(CalculateFieldDescriptorRepeatedType(field)) {} ~RepeatedString() override = default; @@ -985,13 +987,15 @@ void RepeatedString::GenerateSerializeWithCachedSizesToArray( } // namespace std::unique_ptr MakeSinguarStringGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeRepeatedStringGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc b/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc index b0dae01676d85..f0b82166c52e3 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc @@ -17,6 +17,7 @@ #include "absl/memory/memory.h" #include "absl/strings/str_cat.h" #include "google/protobuf/compiler/cpp/field.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -71,8 +72,9 @@ std::vector Vars(const FieldDescriptor* field, const Options& opts) { class SingularStringView : public FieldGeneratorBase { public: - SingularStringView(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + SingularStringView(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), use_micro_string_(IsMicroString(field, opts)), opts_(&opts) {} ~SingularStringView() override = default; @@ -542,8 +544,9 @@ void SingularStringView::GenerateAggregateInitializer(io::Printer* p) const { class RepeatedStringView : public FieldGeneratorBase { public: - RepeatedStringView(const FieldDescriptor* field, const Options& opts) - : FieldGeneratorBase(field, opts), + RepeatedStringView(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) + : FieldGeneratorBase(field, opts, field_layout), opts_(&opts), cpp_repeated_type_(CalculateFieldDescriptorRepeatedType(field)) {} ~RepeatedStringView() override = default; @@ -852,13 +855,15 @@ void RepeatedStringView::GenerateSerializeWithCachedSizesToArray( } // namespace std::unique_ptr MakeSingularStringViewGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } std::unique_ptr MakeRepeatedStringViewGenerator( - const FieldDescriptor* desc, const Options& options) { - return std::make_unique(desc, options); + const FieldDescriptor* desc, const Options& options, + const FieldLayout& field_layout) { + return std::make_unique(desc, options, field_layout); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/field_layout.cc b/src/google/protobuf/compiler/cpp/field_layout.cc index 3eea1c959f522..fc0d7197892c6 100644 --- a/src/google/protobuf/compiler/cpp/field_layout.cc +++ b/src/google/protobuf/compiler/cpp/field_layout.cc @@ -7,6 +7,7 @@ #include #include +#include "google/protobuf/compiler/split_map.h" #include "absl/algorithm/container.h" #include "absl/base/nullability.h" #include "absl/log/absl_check.h" @@ -17,6 +18,7 @@ #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/compiler/cpp/padding_optimizer.h" #include "google/protobuf/descriptor.h" +#include "google/protobuf/generated_message_reflection.h" #include "google/protobuf/has_bits.h" @@ -42,22 +44,18 @@ FieldLayout FieldLayout::BuildOptimizedLayout( std::vector has_bit_indices; int max_has_bit_index = 0; + SplitMap split_map; + // Compute optimized field order to be used for layout and initialization // purposes. CollectFieldsExcludingOneof(descriptor, options, optimized_order); const size_t initial_size = optimized_order.size(); auto message_layout_helper = CreateMessageLayoutHelper(descriptor, options); - optimized_order = - message_layout_helper->OptimizeLayout(optimized_order, options); + optimized_order = message_layout_helper->OptimizeLayout(optimized_order, + options, split_map); ABSL_CHECK_EQ(initial_size, optimized_order.size()); - // Verify that all split fields are placed at the end in the optimized order. - ABSL_CHECK(absl::c_is_partitioned( - optimized_order, [&options](const FieldDescriptor* absl_nonnull field) { - return !ShouldSplit(field, options); - })); - // This message has hasbits iff one or more fields need one. for (const FieldDescriptor* field : optimized_order) { if (HasHasbit(field, options)) { @@ -71,7 +69,7 @@ FieldLayout FieldLayout::BuildOptimizedLayout( } return FieldLayout(std::move(has_bit_indices), max_has_bit_index, - std::move(optimized_order)); + std::move(optimized_order), std::move(split_map)); } FieldLayout FieldLayout::BuildForTesting( @@ -81,7 +79,7 @@ FieldLayout FieldLayout::BuildForTesting( int max_has_bit_index = max_it != has_bit_indices.end() ? std::max(*max_it, 0) : 0; return FieldLayout(std::move(has_bit_indices), max_has_bit_index, - std::move(fields)); + std::move(fields), /*split_map=*/{}); } bool FieldLayout::HasHasbits() const { return !has_bit_indices_.empty(); } @@ -129,12 +127,24 @@ void FieldLayout::PrintHasBitIndicesForSchema(io::Printer* absl_nonnull p, } } +bool FieldLayout::IsSplit(const FieldDescriptor* absl_nonnull field) const { + return split_map_.IsSplit(field); +} + FieldLayout::FieldLayout( std::vector has_bit_indices, int max_has_bit_index, - std::vector fields) + std::vector fields, + SplitMap&& split_map) : has_bit_indices_(std::move(has_bit_indices)), max_has_bit_index_(max_has_bit_index), - fields_(std::move(fields)) {} + fields_(std::move(fields)), + split_map_(std::move(split_map)) { + // Verify that all split fields are placed at the end in the optimized order. + ABSL_CHECK(absl::c_is_partitioned( + fields_, [this](const FieldDescriptor* absl_nonnull field) { + return !IsSplit(field); + })); +} } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/field_layout.h b/src/google/protobuf/compiler/cpp/field_layout.h index 539a5c267bfd4..df580566af7d6 100644 --- a/src/google/protobuf/compiler/cpp/field_layout.h +++ b/src/google/protobuf/compiler/cpp/field_layout.h @@ -4,6 +4,7 @@ #include #include +#include "google/protobuf/compiler/split_map.h" #include "absl/base/nullability.h" #include "absl/types/optional.h" #include "absl/types/span.h" @@ -61,14 +62,24 @@ class FieldLayout { void PrintHasBitIndicesForSchema(io::Printer* absl_nonnull p, size_t& entries) const; + const SplitMap& split_map() const { return split_map_; } + + bool HasSplitFields() const { return split_map_.HasSplitFields(); } + + // Returns true if the given field is part of the split object. + bool IsSplit(const FieldDescriptor* absl_nonnull field) const; + private: FieldLayout(std::vector has_bit_indices, int max_has_bit_index, - std::vector fields); + std::vector fields, + SplitMap&& split_map); std::vector has_bit_indices_; int max_has_bit_index_; std::vector fields_; + + SplitMap split_map_; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc index dfd58f07f5564..ffd7344e7e99b 100644 --- a/src/google/protobuf/compiler/cpp/file.cc +++ b/src/google/protobuf/compiler/cpp/file.cc @@ -33,6 +33,7 @@ #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/cpp/enum.h" #include "google/protobuf/compiler/cpp/extension.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/message.h" #include "google/protobuf/compiler/cpp/names.h" @@ -1491,8 +1492,9 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* p) { } for (const auto& mg : message_generators_) { const Descriptor* d = mg->descriptor(); + const FieldLayout& field_layout = mg->field_layout(); if (d != nullptr && public_set.count(d->file()) == 0u && - ShouldSplit(mg->descriptor(), options_)) + field_layout.HasSplitFields()) decls[Namespace(d)].AddSplit(d); } diff --git a/src/google/protobuf/compiler/cpp/generator.cc b/src/google/protobuf/compiler/cpp/generator.cc index 99d1e7f7e171a..32a950f32f145 100644 --- a/src/google/protobuf/compiler/cpp/generator.cc +++ b/src/google/protobuf/compiler/cpp/generator.cc @@ -427,7 +427,6 @@ bool CppGenerator::GenerateAll(const std::vector& files, } } - if (!GenerateImpl(file, parameter, generator_context, error, file_options)) { *error = absl::StrCat(file->name(), ": ", *error); diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc index 99ed4be0fe191..2b6907cf3d851 100644 --- a/src/google/protobuf/compiler/cpp/helpers.cc +++ b/src/google/protobuf/compiler/cpp/helpers.cc @@ -58,7 +58,6 @@ #include "google/protobuf/io/printer.h" #include "google/protobuf/io/strtod.h" #include "google/protobuf/map.h" -#include "google/protobuf/port.h" #include "google/protobuf/repeated_ptr_field.h" #include "google/protobuf/wire_format.h" #include "google/protobuf/wire_format_lite.h" @@ -1209,8 +1208,6 @@ VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) { return VerifySimpleType::kCustom; } -bool ShouldSplit(const Descriptor*, const Options&) { return false; } -bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; } bool ShouldForceAllocationOnConstruction(const Descriptor* desc, const Options& options) { diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h index c326776fe78f7..4e595dfbf00fe 100644 --- a/src/google/protobuf/compiler/cpp/helpers.h +++ b/src/google/protobuf/compiler/cpp/helpers.h @@ -12,7 +12,6 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ -#include #include #include #include @@ -481,13 +480,6 @@ enum class VerifySimpleType { VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor); -// Is the given message being split (go/pdsplit)? -PROTOC_EXPORT bool ShouldSplit(const Descriptor* desc, const Options& options); - -// Is the given field being split out? -PROTOC_EXPORT bool ShouldSplit(const FieldDescriptor* field, - const Options& options); - // Should we generate code that force creating an allocation in the constructor // of the given message? bool ShouldForceAllocationOnConstruction(const Descriptor* desc, diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc index 0611024645deb..40ac69e6c037f 100644 --- a/src/google/protobuf/compiler/cpp/message.cc +++ b/src/google/protobuf/compiler/cpp/message.cc @@ -469,10 +469,11 @@ bool IsCrossFileMaybeMap(const FieldDescriptor* field) { return IsCrossFileMessage(field); } -bool HasNonSplitOptionalString(const Descriptor* desc, const Options& options) { +bool HasNonSplitOptionalString(const Descriptor* desc, + const FieldLayout& field_layout) { for (const auto* field : internal::FieldRange(desc)) { if (IsString(field) && !field->is_repeated() && - !field->real_containing_oneof() && !ShouldSplit(field, options)) { + !field->real_containing_oneof() && !field_layout.IsSplit(field)) { return true; } } @@ -638,7 +639,7 @@ MessageGenerator::MessageGenerator( parse_function_generator_ = std::make_unique( descriptor_, field_layout_.HasHasbits(), get_has_bit_index, options_, - variables_, index_in_file_messages_); + field_layout_.split_map(), variables_, index_in_file_messages_); } bool MessageGenerator::ShouldGenerateEnclosingIf( @@ -703,7 +704,8 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* p) { "kFields", [&] { for (auto field : ordered_fields) { - auto v = p->WithVars(FieldVars(field, options_)); + auto v = + p->WithVars(FieldVars(field, options_, field_layout_)); p->Emit({Sub("kField", FieldConstantName(field)) .AnnotatedAs(field)}, R"cc( @@ -721,8 +723,8 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* p) { for (auto field : ordered_fields) { auto name = FieldName(field); - auto v = p->WithVars(FieldVars(field, options_)); - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto v = p->WithVars(FieldVars(field, options_, field_layout_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); p->Emit({{"field_comment", FieldComment(field, options_)}, Sub("const_impl", "const;").WithSuffix(";"), Sub("impl", ";").WithSuffix(";"), @@ -1063,7 +1065,7 @@ void MessageGenerator::GenerateFieldAccessorDeclarations(io::Printer* p) { void MessageGenerator::GenerateSingularFieldHasBits( const FieldDescriptor* field, io::Printer* p) { - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); if (GetFieldHasbitMode(field, options_) == HasbitMode::kTrueHasbit) { auto v = p->WithVars(HasBitVars(field)); @@ -1119,7 +1121,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, // has_$name$() methods, but oneofs still have set_has_$name$(). // Oneofs also have private _internal_has_$name$() a helper method. if (field->has_presence()) { - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); p->Emit(R"cc( inline bool $Msg$::has_$name$() const { $WeakDescriptorSelfPin$; @@ -1146,7 +1148,7 @@ void MessageGenerator::GenerateOneofMemberHasBits(const FieldDescriptor* field, void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, bool is_inline, io::Printer* p) { - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); p->Emit({{"inline", is_inline ? "inline" : ""}, {"body", [&] { @@ -1166,7 +1168,7 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field, )cc"); } else { // TODO: figure out if early return breaks tracking - if (ShouldSplit(field, options_)) { + if (field_layout_.IsSplit(field)) { p->Emit(R"cc( if (ABSL_PREDICT_TRUE(IsSplitMessageDefault())) return; @@ -1342,8 +1344,8 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* p) { PrintFieldComment(Formatter{p}, field, options_); - auto v = p->WithVars(FieldVars(field, options_)); - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto v = p->WithVars(FieldVars(field, options_, field_layout_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); if (field->is_repeated()) { p->Emit(R"cc( PROTOBUF_ALWAYS_INLINE_NODEBUG int @@ -1499,7 +1501,7 @@ void MessageGenerator::GenerateImplDefinition(io::Printer* p) { // Emit some private and static members for (auto field : field_layout_.optimized_order()) { field_generators_.get(field).GenerateStaticMembers(p); - if (!ShouldSplit(field, options_)) { + if (!field_layout_.IsSplit(field)) { field_generators_.get(field).GeneratePrivateMembers(p); } } @@ -1507,18 +1509,18 @@ void MessageGenerator::GenerateImplDefinition(io::Printer* p) { {"secondary_field_members", [&] { for (auto field : field_layout_.optimized_order()) { - if (!ShouldSplit(field, options_)) { + if (!field_layout_.IsSplit(field)) { field_generators_.get(field).GenerateSecondaryPrivateMembers(p); } } }}, {"decl_split", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit({{"split_field", [&] { for (auto field : field_layout_.optimized_order()) { - if (!ShouldSplit(field, options_)) continue; + if (!field_layout_.IsSplit(field)) continue; field_generators_.get(field).GeneratePrivateMembers(p); } }}}, @@ -2007,7 +2009,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) { }}, {"decl_split_methods", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit({{"split_default", SplitDefaultInstanceName(descriptor_, options_)}}, R"cc( @@ -2104,7 +2106,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) { {"msg_globals", MsgGlobalsInstanceName(descriptor_, options_)}, {"split_friend", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit({{"split_default", SplitDefaultInstanceType(descriptor_, options_)}}, @@ -2374,8 +2376,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* p) { } // Generate non-inline field definitions. for (auto field : internal::FieldRange(descriptor_)) { - auto v = p->WithVars(FieldVars(field, options_)); - auto t = p->WithVars(MakeTrackerCalls(field, options_)); + auto v = p->WithVars(FieldVars(field, options_, field_layout_)); + auto t = p->WithVars(MakeTrackerCalls(field, options_, field_layout_)); field_generators_.get(field).GenerateNonInlineAccessorDefinitions(p); if (IsCrossFileMaybeMap(field)) { GenerateFieldClear(field, false, p); @@ -2413,7 +2415,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* p) { p->Emit("\n"); } - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { p->Emit({{"split_default", SplitDefaultInstanceName(descriptor_, options_)}, {"globals", MsgGlobalsInstanceName(descriptor_, options_)}}, R"cc( @@ -2512,7 +2514,7 @@ size_t MessageGenerator::GenerateOffsets(io::Printer* p) { // NOTE: We can cleanup three bits from old logic. const bool has_weak_fields = false; const bool has_inline_strings = false; - const bool has_split = ShouldSplit(descriptor_, options_); + const bool has_split = field_layout_.HasSplitFields(); format("$1$, // bitmap\n", // These conditions have to match exactly the order done below @@ -2551,8 +2553,8 @@ size_t MessageGenerator::GenerateOffsets(io::Printer* p) { field->real_containing_oneof()->name()); } else { format("PROTOBUF_FIELD_OFFSET($classtype$$1$, $2$)", - ShouldSplit(field, options_) ? "::Impl_::Split" : "", - ShouldSplit(field, options_) + field_layout_.IsSplit(field) ? "::Impl_::Split" : "", + field_layout_.IsSplit(field) ? absl::StrCat(FieldName(field), "_") : FieldMemberName(field, /*split=*/false)); } @@ -2566,7 +2568,7 @@ size_t MessageGenerator::GenerateOffsets(io::Printer* p) { // the field is eagerly verified lazy or inlined string to the LSB of the // offset. - if (ShouldSplit(field, options_)) { + if (field_layout_.IsSplit(field)) { format(" | ::_pbi::kSplitFieldOffsetTag"); } if (IsEagerlyVerifiedLazy(field, options_)) { @@ -2631,7 +2633,7 @@ void MessageGenerator::GenerateZeroInitFields(io::Printer* p) const { const auto optimized_order = field_layout_.optimized_order(); auto it = optimized_order.begin(); auto end = optimized_order.end(); - for (; it != end && !ShouldSplit(*it, options_); ++it) { + for (; it != end && !field_layout_.IsSplit(*it); ++it) { auto const& generator = field_generators_.get(*it); if (generator.has_trivial_zero_default()) { if (first == nullptr) first = *it; @@ -2698,7 +2700,7 @@ void MessageGenerator::GenerateImplMemberInit(io::Printer* p, auto init_fields = [&] { for (auto* field : field_layout_.optimized_order()) { - if (ShouldSplit(field, options_)) continue; + if (field_layout_.IsSplit(field)) continue; auto const& generator = field_generators_.get(field); switch (init_type) { @@ -2723,7 +2725,7 @@ void MessageGenerator::GenerateImplMemberInit(io::Printer* p, }; auto init_split = [&] { - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { separator(); p->Emit({{"name", SplitDefaultInstanceName(descriptor_, options_)}}, "_split_{const_cast(&$name$._instance)}"); @@ -2784,13 +2786,13 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* p) { } void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* p) { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; auto v = p->WithVars(ClassVars(descriptor_, options_)); auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_)); p->Emit("\n"); for (const auto* field : field_layout_.optimized_order()) { - if (ShouldSplit(field, options_)) { + if (field_layout_.IsSplit(field)) { field_generators_.get(field).GenerateConstexprAggregateInitializer(p); } } @@ -2807,13 +2809,13 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* p) { // Write the destructors for each field except oneof members. // optimized_order_ does not contain oneof fields. for (const auto* field : field_layout_.optimized_order()) { - if (ShouldSplit(field, options_)) continue; + if (field_layout_.IsSplit(field)) continue; field_generators_.get(field).GenerateDestructorCode(p); } }}, {"split_field_dtors", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit( R"cc( if (ABSL_PREDICT_FALSE(!this_.IsSplitMessageDefault())) { @@ -2866,13 +2868,13 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { // Write the destructors for each field except oneof members. // optimized_order_ does not contain oneof fields. for (const auto* field : field_layout_.optimized_order()) { - if (ShouldSplit(field, options_) != split_fields) continue; + if (field_layout_.IsSplit(field) != split_fields) continue; field_generators_.get(field).GenerateArenaDestructorCode(p); } }; bool needs_arena_dtor_split = false; for (const auto* field : field_layout_.optimized_order()) { - if (!ShouldSplit(field, options_)) continue; + if (!field_layout_.IsSplit(field)) continue; if (field_generators_.get(field).NeedsArenaDestructor() > ArenaDtorNeeds::kNone) { needs_arena_dtor_split = true; @@ -2889,7 +2891,7 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* p) { {"field_dtors", [&] { emit_field_dtors(/* split_fields= */ false); }}, {"split_field_dtors", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; if (!needs_arena_dtor_split) { return; } @@ -2977,7 +2979,7 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* p) { } bool MessageGenerator::CanUseTrivialCopy() const { - if (ShouldSplit(descriptor_, options_)) return false; + if (field_layout_.HasSplitFields()) return false; if (HasSimpleBaseClass(descriptor_, options_)) return false; if (descriptor_->extension_range_count() > 0) return false; @@ -3058,7 +3060,7 @@ void MessageGenerator::GenerateCopyInitFields(io::Printer* p) const { for (auto it = begin; it != end; ++it) { const auto* field = *it; const auto& gen = field_generators_.get(field); - auto v = p->WithVars(FieldVars(field, options_)); + auto v = p->WithVars(FieldVars(field, options_, field_layout_)); // Non trivial field values are copy constructed if (!gen.has_trivial_value() || gen.should_split()) { @@ -3122,7 +3124,7 @@ void MessageGenerator::GenerateCopyInitFields(io::Printer* p) const { $copy_oneof_fields$; )cc"); - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { p->Emit(R"cc( if (ABSL_PREDICT_FALSE(!from.IsSplitMessageDefault())) { _Internal::MergeSplit(this, from); @@ -3339,7 +3341,7 @@ void MessageGenerator::EmitClearChunks(io::Printer* p, bool is_split) { int chunk_count = 0; std::vector chunks = CollectFields( - field_layout_.optimized_order(), options_, + field_layout_.optimized_order(), options_, field_layout_.split_map(), [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { chunk_count++; // This predicate guarantees that there is only a single zero-init @@ -3353,7 +3355,7 @@ void MessageGenerator::EmitClearChunks(io::Printer* p, bool is_split) { if (!same) chunk_count = 0; return same; }, - [&](auto* f) { return ShouldSplit(f, options_) == is_split; }); + [&](auto* f) { return field_layout_.IsSplit(f) == is_split; }); auto it = chunks.begin(); auto end = chunks.end(); @@ -3517,7 +3519,7 @@ void MessageGenerator::GenerateClear(io::Printer* p) { {"clear_fields", [&] { EmitClearChunks(p, /* is_split= */ false); - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { p->Emit(R"cc( if (ABSL_PREDICT_FALSE(!this_.IsSplitMessageDefault())) { _Internal::ClearSplit(this_); @@ -3628,7 +3630,7 @@ void MessageGenerator::GenerateSwap(io::Printer* p) { "\n"); } - if (HasNonSplitOptionalString(descriptor_, options_)) { + if (HasNonSplitOptionalString(descriptor_, field_layout_)) { p->Emit(R"cc( auto* arena = GetArena(); ABSL_DCHECK_EQ(arena, other->GetArena()); @@ -3644,16 +3646,16 @@ void MessageGenerator::GenerateSwap(io::Printer* p) { } // If possible, we swap several fields at once, including padding. - const RunMap runs = FindRuns( - field_layout_.optimized_order(), [this](const FieldDescriptor* field) { - return !ShouldSplit(field, options_) && - HasTrivialSwap(field, options_); - }); + const RunMap runs = FindRuns(field_layout_.optimized_order(), + [this](const FieldDescriptor* field) { + return !field_layout_.IsSplit(field) && + HasTrivialSwap(field, options_); + }); const auto optimized_order = field_layout_.optimized_order(); for (size_t i = 0; i < optimized_order.size(); ++i) { const FieldDescriptor* field = optimized_order[i]; - if (ShouldSplit(field, options_)) { + if (field_layout_.IsSplit(field)) { continue; } const auto it = runs.find(field); @@ -3688,7 +3690,7 @@ void MessageGenerator::GenerateSwap(io::Printer* p) { field_generators_.get(field).GenerateSwappingCode(p); } } - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { format("swap($split$, other->$split$);\n"); } @@ -3727,7 +3729,7 @@ MessageGenerator::NewOpRequirements MessageGenerator::GetNewOp() const { } for (const FieldDescriptor* field : internal::FieldRange(descriptor_)) { - if (ShouldSplit(field, options_)) { + if (field_layout_.IsSplit(field)) { op.needs_memcpy = true; } else if (field->real_containing_oneof() != nullptr) { /* nothing to do */ @@ -4170,13 +4172,13 @@ bool MessageGenerator::EmitMergeChunks(io::Printer* p, bool is_split) { }; std::vector chunks = CollectFields( - field_layout_.optimized_order(), options_, + field_layout_.optimized_order(), options_, field_layout_.split_map(), [&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool { return field_layout_.GetHasByteIndex(a) == field_layout_.GetHasByteIndex(b) && IsLikelyPresent(a, options_) == IsLikelyPresent(b, options_); }, - [&](const auto* f) { return ShouldSplit(f, options_) == is_split; }); + [&](const auto* f) { return field_layout_.IsSplit(f) == is_split; }); auto it = chunks.begin(); auto end = chunks.end(); @@ -4231,7 +4233,7 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* p) { }}, {"merge_split", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit(R"cc( if (ABSL_PREDICT_FALSE(!from.IsSplitMessageDefault())) { _Internal::MergeSplit(_this, from); @@ -4449,7 +4451,7 @@ void MessageGenerator::GenerateSerializeOneofFields( void MessageGenerator::GenerateSerializeOneField(io::Printer* p, const FieldDescriptor* field, int cached_has_bits_index) { - auto v = p->WithVars(FieldVars(field, options_)); + auto v = p->WithVars(FieldVars(field, options_, field_layout_)); auto emit_body = [&] { field_generators_.get(field).GenerateSerializeWithCachedSizesToArray(p); }; @@ -4604,7 +4606,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody(io::Printer* p) { if (field->real_containing_oneof()) { v_.push_back(field); } else { - if (ShouldSplit(field, options_)) { + if (mg_->field_layout().IsSplit(field)) { OpenSplit(); } else { CloseSplit(); @@ -4616,7 +4618,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody(io::Printer* p) { // if it is for only one field. Deferring non-oneof emitting would // allow us to determine whether this is going to be useful. int has_word_index = - mg_->field_layout_.GetHasWordIndex(field).value(); + mg_->field_layout().GetHasWordIndex(field).value(); if (cached_has_bit_index_ != has_word_index) { // Reload. int new_index = has_word_index; @@ -4740,7 +4742,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody(io::Printer* p) { { {"serialize_split_var", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit(R"cc( //~ const bool serialize_split_fields = !this_.IsSplitMessageDefault(); @@ -4934,7 +4936,7 @@ void MessageGenerator::EmitByteSizeChunks(io::Printer* p, bool is_split) { std::vector fixed; std::vector rest; for (auto* f : field_layout_.optimized_order()) { - if (ShouldSplit(f, options_) != is_split) continue; + if (field_layout_.IsSplit(f) != is_split) continue; if (FixedSize(f).has_value()) { fixed.push_back(f); } else { @@ -4952,12 +4954,14 @@ void MessageGenerator::EmitByteSizeChunks(io::Printer* p, bool is_split) { absl::c_sort( fixed, [&](auto* a, auto* b) { return fixed_tuple(a) < fixed_tuple(b); }); std::vector fixed_chunks = - CollectFields(fixed, options_, [&](const auto* a, const auto* b) { - return fixed_tuple(a) == fixed_tuple(b); - }); + CollectFields(fixed, options_, field_layout_.split_map(), + [&](const auto* a, const auto* b) { + return fixed_tuple(a) == fixed_tuple(b); + }); - std::vector chunks = - CollectFields(rest, options_, [&](const auto* a, const auto* b) { + std::vector chunks = CollectFields( + rest, options_, field_layout_.split_map(), + [&](const auto* a, const auto* b) { return a->is_required() == b->is_required() && field_layout_.GetHasByteIndex(a) == field_layout_.GetHasByteIndex(b) && @@ -5146,7 +5150,7 @@ void MessageGenerator::GenerateByteSize(io::Printer* p) { {"handle_fields", [&] { EmitByteSizeChunks(p, /* is_split= */ false); - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { p->Emit(R"cc( if (ABSL_PREDICT_FALSE(!this_.IsSplitMessageDefault())) { total_size += _Internal::ByteSizeSplit(this_); @@ -5444,13 +5448,13 @@ void MessageGenerator::GenerateSourceDefaultInstance(io::Printer* p) { }}, {"split", [&] { - if (!ShouldSplit(descriptor_, options_)) return; + if (!field_layout_.HasSplitFields()) return; p->Emit( {{"destroy_fields", [&] { for (const auto* field : field_layout_.optimized_order()) { - if (!ShouldSplit(field, options_)) continue; + if (!field_layout_.IsSplit(field)) continue; field_generators_.get(field).GenerateDestructorCode(p); } }}, @@ -5505,12 +5509,13 @@ void MessageGenerator::GenerateSourceDefaultInstance(io::Printer* p) { p->Emit("\n"); } - parse_function_generator_->GenerateParseTableHelperDefinition(p); + parse_function_generator_->GenerateParseTableHelperDefinition( + p, field_layout_.split_map()); p->Emit("\n"); // Generate the split instance first because it's needed in the constexpr // constructor. - if (ShouldSplit(descriptor_, options_)) { + if (field_layout_.HasSplitFields()) { // Use a union to disable the destructor of the _instance member. // We can constant initialize, but the object will still have a non-trivial // destructor that we need to elide. diff --git a/src/google/protobuf/compiler/cpp/message.h b/src/google/protobuf/compiler/cpp/message.h index be4fa900edf4a..164e7c1901a03 100644 --- a/src/google/protobuf/compiler/cpp/message.h +++ b/src/google/protobuf/compiler/cpp/message.h @@ -86,6 +86,8 @@ class MessageGenerator { const Descriptor* descriptor() const { return descriptor_; } + const FieldLayout& field_layout() const { return field_layout_; } + private: using GeneratorFunction = FieldGeneratorBase::GeneratorFunction; enum class InitType { kConstexpr, kArena, kArenaCopy }; diff --git a/src/google/protobuf/compiler/cpp/message_layout_helper.cc b/src/google/protobuf/compiler/cpp/message_layout_helper.cc index fd77e8b0a67f1..e8f5955b5ff10 100644 --- a/src/google/protobuf/compiler/cpp/message_layout_helper.cc +++ b/src/google/protobuf/compiler/cpp/message_layout_helper.cc @@ -67,8 +67,10 @@ bool FieldGroup::UpdatePreferredLocationAndInsertOtherFields( } MessageLayoutHelper::FieldVector MessageLayoutHelper::DoOptimizeLayout( - const FieldVector& fields, const Options& options) const { - auto field_alignment_groups = BuildFieldAlignmentGroups(fields, options); + const FieldVector& fields, const Options& options, + const SplitMap& split_map) const { + auto field_alignment_groups = + BuildFieldAlignmentGroups(fields, options, split_map); auto field_groups = MergeFieldAlignmentGroups(std::move(field_alignment_groups)); auto ordered_fields = @@ -83,9 +85,10 @@ constexpr size_t MessageLayoutHelper::FieldHotnessIndex(FieldHotness hotness) { } MessageLayoutHelper::FieldFamily MessageLayoutHelper::GetFieldFamily( - const FieldDescriptor* field, const Options& options) { + const FieldDescriptor* field, const Options& options, + const SplitMap& split_map) { if (field->is_repeated()) { - return ShouldSplit(field, options) ? OTHER : REPEATED; + return split_map.IsSplit(field) ? OTHER : REPEATED; } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { return STRING; } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { @@ -98,7 +101,8 @@ MessageLayoutHelper::FieldFamily MessageLayoutHelper::GetFieldFamily( } std::vector -MessageLayoutHelper::BuildFastParseTable(const Options& options) const { +MessageLayoutHelper::BuildFastParseTable(const Options& options, + const SplitMap& split_map) const { FieldVector ordered_fields; for (const auto* field : GetOrderedFields(descriptor_)) { if (IsLayoutOptimized(field, options)) { @@ -107,7 +111,8 @@ MessageLayoutHelper::BuildFastParseTable(const Options& options) const { } auto field_options = ParseFunctionGenerator::BuildFieldOptions( descriptor_, ordered_fields, - /*get_has_bit_index=*/[](const auto*) { return absl::nullopt; }, options); + /*get_has_bit_index=*/[](const auto*) { return absl::nullopt; }, options, + split_map); auto table_info = ParseFunctionGenerator::BuildTcTableInfoFromDescriptor( descriptor_, options, field_options); return table_info.fast_path_fields; @@ -138,16 +143,17 @@ bool MessageLayoutHelper::ShouldPromoteToFastParse( } MessageLayoutHelper::FieldAlignmentGroups -MessageLayoutHelper::BuildFieldAlignmentGroups(const FieldVector& fields, - const Options& options) const { +MessageLayoutHelper::BuildFieldAlignmentGroups( + const FieldVector& fields, const Options& options, + const SplitMap& split_map) const { FieldAlignmentGroups field_alignment_groups; - const auto fast_path_fields = BuildFastParseTable(options); + const auto fast_path_fields = BuildFastParseTable(options, split_map); for (const auto* field : fields) { - FieldFamily f = GetFieldFamily(field, options); + FieldFamily f = GetFieldFamily(field, options, split_map); FieldHotness hotness; - if (ShouldSplit(field, options)) { + if (split_map.IsSplit(field)) { hotness = FieldHotness::kSplit; } else if (field->is_repeated()) { hotness = FieldHotness::kRepeated; diff --git a/src/google/protobuf/compiler/cpp/message_layout_helper.h b/src/google/protobuf/compiler/cpp/message_layout_helper.h index 4a26ea5d40c08..6f4c6d2053455 100644 --- a/src/google/protobuf/compiler/cpp/message_layout_helper.h +++ b/src/google/protobuf/compiler/cpp/message_layout_helper.h @@ -17,6 +17,7 @@ #include #include +#include "google/protobuf/compiler/split_map.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -89,8 +90,9 @@ class MessageLayoutHelper { const Descriptor* descriptor() const { return descriptor_; } virtual FieldVector OptimizeLayout(const FieldVector& fields, - const Options& options) const { - return DoOptimizeLayout(fields, options); + const Options& options, + const SplitMap& split_map) const { + return DoOptimizeLayout(fields, options, split_map); } protected: @@ -148,7 +150,8 @@ class MessageLayoutHelper { // order within split fields follows the same rule, aka classify and order by // "family". FieldVector DoOptimizeLayout(const FieldVector& fields, - const Options& options) const; + const Options& options, + const SplitMap& split_map) const; private: enum FieldFamily { @@ -180,14 +183,15 @@ class MessageLayoutHelper { virtual FieldGroup SingleFieldGroup(const FieldDescriptor* field) const = 0; static FieldFamily GetFieldFamily(const FieldDescriptor* field, - const Options& options); + const Options& options, + const SplitMap& split_map); // Constructs the fast parse table for the message as it would be generated, // ignoring hasbits/inlined string indices as those have not been assigned // yet. This is used to determine which fields to prioritize for the fast // parse hotness class, which guarantees fast-parse eligibility. std::vector BuildFastParseTable( - const Options& options) const; + const Options& options, const SplitMap& split_map) const; static bool IsFastPathField( const FieldDescriptor* field, @@ -202,8 +206,9 @@ class MessageLayoutHelper { // Groups fields into alignment equivalence classes (1, 4, and 8). Within // each alignment equivalence class, fields are partitioned by `FieldFamily` // and `FieldHotness`. - FieldAlignmentGroups BuildFieldAlignmentGroups(const FieldVector& fields, - const Options& options) const; + FieldAlignmentGroups BuildFieldAlignmentGroups( + const FieldVector& fields, const Options& options, + const SplitMap& split_map) const; // Consolidates all fields into a single array of field groups, partitioned by // `FieldFamily` and `FieldHotness`. Within each partition, fields are diff --git a/src/google/protobuf/compiler/cpp/options.h b/src/google/protobuf/compiler/cpp/options.h index 86d652f656514..7228e16a143c4 100644 --- a/src/google/protobuf/compiler/cpp/options.h +++ b/src/google/protobuf/compiler/cpp/options.h @@ -41,7 +41,6 @@ struct FieldListenerOptions { // Generator options (see generator.cc for a description of each): struct Options { const AccessInfoMap* access_info_map = nullptr; - const SplitMap* split_map = nullptr; cpp::MessageSCCAnalyzer* scc_analyzer = nullptr; std::string dllexport_decl; std::string runtime_include_base; diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc index 778999306fcea..9662155bc2ca2 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -55,6 +55,7 @@ std::vector GetOrderedFields( ParseFunctionGenerator::ParseFunctionGenerator( const Descriptor* descriptor, bool has_hasbits, GetHasBitIndex get_has_bit_index, const Options& options, + const SplitMap& split_map, const absl::flat_hash_map& vars, int index_in_file_messages) : descriptor_(descriptor), @@ -64,7 +65,7 @@ ParseFunctionGenerator::ParseFunctionGenerator( has_hasbits_(has_hasbits), index_in_file_messages_(index_in_file_messages) { auto fields = BuildFieldOptions(descriptor_, ordered_fields_, - get_has_bit_index, options_); + get_has_bit_index, options_, split_map); tc_table_info_ = std::make_unique( BuildTcTableInfoFromDescriptor(descriptor_, options_, fields)); SetCommonMessageDataVariables(descriptor_, &variables_); @@ -75,7 +76,8 @@ std::vector ParseFunctionGenerator::BuildFieldOptions( const Descriptor* descriptor, absl::Span ordered_fields, - GetHasBitIndex get_has_bit_index, const Options& options) { + GetHasBitIndex get_has_bit_index, const Options& options, + const SplitMap& split_map) { using FieldOptions = TailCallTableInfo::FieldOptions; std::vector fields; fields.reserve(ordered_fields.size()); @@ -106,7 +108,7 @@ ParseFunctionGenerator::BuildFieldOptions( GetLazyStyle(field, options), IsImplicitWeakField(field, options), /* use_direct_tcparser_table */ true, - ShouldSplit(field, options), + split_map.IsSplit(field), str_options(), }); } @@ -209,7 +211,7 @@ static std::string TcParseFunctionName(internal::TcParseFunction func) { } void ParseFunctionGenerator::GenerateParseTableHelperDefinition( - io::Printer* p) { + io::Printer* p, const SplitMap& split_map) { auto v = p->WithVars(variables_); // For simplicity and speed, the table is not covering all proto // configurations. This model uses a fallback to cover all situations that @@ -424,7 +426,7 @@ void ParseFunctionGenerator::GenerateParseTableHelperDefinition( ? "constexpr" : "PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1\nconst"}, {"table_base", GenerateTableBase}, - {"fast_entries", [&] { GenerateFastFieldEntries(p); }}, + {"fast_entries", [&] { GenerateFastFieldEntries(p, split_map); }}, {"field_lookup_table", [&] { for (const auto& entry_block : field_num_to_entry_table.blocks) { @@ -462,7 +464,8 @@ void ParseFunctionGenerator::GenerateParseTableHelperDefinition( p->Emit( { - {"field_entries", [&] { GenerateFieldEntries(p); }}, + {"field_entries", + [&] { GenerateFieldEntries(p, split_map); }}, {"aux_entries", [&] { if (tc_table_info_->aux_entries.empty()) { @@ -521,7 +524,8 @@ constexpr $Msg$::ParseTableT_ $Msg$::InternalGenerateParseTable_(const ::_pbi::C ); } -void ParseFunctionGenerator::GenerateFastFieldEntries(io::Printer* p) { +void ParseFunctionGenerator::GenerateFastFieldEntries( + io::Printer* p, const SplitMap& split_map) { for (const auto& info : tc_table_info_->fast_path_fields) { if (auto* nonfield = info.AsNonField()) { // Fast slot that is not associated with a field. Eg end group tags. @@ -554,7 +558,7 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(io::Printer* p) { Formatter format(p, variables_); PrintFieldComment(format, as_field->field, options_); } - ABSL_CHECK(!ShouldSplit(as_field->field, options_)); + ABSL_CHECK(!split_map.IsSplit(as_field->field)); std::string func_name = TcParseFunctionName(as_field->func); if (GetOptimizeFor(as_field->field->file(), options_) == @@ -602,7 +606,8 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(io::Printer* p) { } } -void ParseFunctionGenerator::GenerateFieldEntries(io::Printer* p) { +void ParseFunctionGenerator::GenerateFieldEntries(io::Printer* p, + const SplitMap& split_map) { for (const auto& entry : tc_table_info_->field_entries) { const FieldDescriptor* field = entry.field; // TODO: refactor this to use Emit. @@ -610,7 +615,7 @@ void ParseFunctionGenerator::GenerateFieldEntries(io::Printer* p) { PrintFieldComment(format, field, options_); bool weak = IsWeak(field, options_); - bool split = ShouldSplit(field, options_); + bool split = split_map.IsSplit(field); const OneofDescriptor* oneof = field->real_containing_oneof(); auto v = p->WithVars( diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.h b/src/google/protobuf/compiler/cpp/parse_function_generator.h index 715716cc54007..4038ed5e4c47e 100644 --- a/src/google/protobuf/compiler/cpp/parse_function_generator.h +++ b/src/google/protobuf/compiler/cpp/parse_function_generator.h @@ -12,6 +12,7 @@ #include #include +#include "google/protobuf/compiler/split_map.h" #include "absl/container/flat_hash_map.h" #include "absl/functional/function_ref.h" #include "absl/strings/string_view.h" @@ -50,23 +51,26 @@ class ParseFunctionGenerator { ParseFunctionGenerator( const Descriptor* descriptor, bool has_hasbits, GetHasBitIndex get_has_bit_index, const Options& options, + const SplitMap& split_map, const absl::flat_hash_map& vars, int index_in_file_messages); // Construct a ParseFunctionGenerator ignoring the effect of hasbits. ParseFunctionGenerator( const Descriptor* descriptor, const Options& options, + const SplitMap& split_map, const absl::flat_hash_map& vars, int index_in_file_messages) : ParseFunctionGenerator( descriptor, /*has_hasbits=*/false, - [](const FieldDescriptor*) { return absl::nullopt; }, options, vars, - index_in_file_messages) {} + [](const FieldDescriptor*) { return absl::nullopt; }, options, + split_map, vars, index_in_file_messages) {} static std::vector BuildFieldOptions(const Descriptor* descriptor, absl::Span ordered_fields, - GetHasBitIndex get_has_bit_index, const Options& options); + GetHasBitIndex get_has_bit_index, const Options& options, + const SplitMap& split_map); static internal::TailCallTableInfo BuildTcTableInfoFromDescriptor( const Descriptor* descriptor, const Options& options, @@ -83,7 +87,8 @@ class ParseFunctionGenerator { void GenerateDataDefinitions(io::Printer* printer); // Emits the helper function definition to `printer`: - void GenerateParseTableHelperDefinition(io::Printer* printer); + void GenerateParseTableHelperDefinition(io::Printer* printer, + const SplitMap& split_map); private: friend class TailCallTableInfoTest; @@ -92,8 +97,9 @@ class ParseFunctionGenerator { // Generates the tail-call table definition. void GenerateTailCallTable(io::Printer* printer); - void GenerateFastFieldEntries(io::Printer* printer); - void GenerateFieldEntries(io::Printer* p); + void GenerateFastFieldEntries(io::Printer* printer, + const SplitMap& split_map); + void GenerateFieldEntries(io::Printer* p, const SplitMap& split_map); void GenerateFieldNames(Formatter& format); const Descriptor* descriptor_; diff --git a/src/google/protobuf/compiler/cpp/tools/analyze_profile_proto.cc b/src/google/protobuf/compiler/cpp/tools/analyze_profile_proto.cc index c2bab97d84da1..8c8f0a4da0396 100644 --- a/src/google/protobuf/compiler/cpp/tools/analyze_profile_proto.cc +++ b/src/google/protobuf/compiler/cpp/tools/analyze_profile_proto.cc @@ -29,6 +29,7 @@ #include "google/protobuf/compiler/split_map.h" #include "google/protobuf/compiler/profile_bootstrap.pb.h" #include "google/protobuf/descriptor.pb.h" +#include "absl/container/flat_hash_map.h" #include "absl/log/absl_log.h" #include "absl/log/log.h" #include "absl/status/status.h" @@ -49,6 +50,7 @@ #include "third_party/gloop/util/status/status_macros.h" #include "google/protobuf/compiler/cpp/cpp_access_info_parse_helper.h" #include "google/protobuf/compiler/cpp/helpers.h" +#include "google/protobuf/compiler/cpp/message.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" #include "third_party/re2/re2.h" @@ -116,12 +118,12 @@ class PDProtoAnalyzer { options_.scc_analyzer = scc_analyzer_.get(); } - void SetFile(const FileDescriptor* file) { - if (current_file_ != file) { - split_map_ = cpp::CreateSplitMap(file, options_); - options_.split_map = &split_map_; - current_file_ = file; - } + void SetDescriptor(const Descriptor* descriptor) { + current_file_ = descriptor->file(); + + absl::flat_hash_map vars; + message_generator_ = std::make_unique( + descriptor, /*ignored=*/vars, /*index_in_file_messages=*/0, options_); } bool HasProfile(const Descriptor* descriptor) const { @@ -171,7 +173,7 @@ class PDProtoAnalyzer { return PDProtoOptimization::kLazy; } - if (cpp::ShouldSplit(field, options_)) { + if (message_generator_->field_layout().IsSplit(field)) { return PDProtoOptimization::kSplit; } @@ -213,6 +215,7 @@ class PDProtoAnalyzer { AccessInfoMap info_map_; SplitMap split_map_; std::unique_ptr scc_analyzer_; + std::unique_ptr message_generator_; const FileDescriptor* current_file_ = nullptr; }; @@ -464,7 +467,7 @@ static absl::StatusOr AnalyzeProfileProto( if (descriptor == nullptr) continue; - analyzer.SetFile(descriptor->file()); + analyzer.SetDescriptor(descriptor); if (analyzer.HasProfile(descriptor)) { bool message_header = false; for (int i = 0; i < descriptor->field_count(); ++i) { diff --git a/src/google/protobuf/compiler/cpp/tracker.cc b/src/google/protobuf/compiler/cpp/tracker.cc index b8b65f3959e32..a137b185caf18 100644 --- a/src/google/protobuf/compiler/cpp/tracker.cc +++ b/src/google/protobuf/compiler/cpp/tracker.cc @@ -17,6 +17,7 @@ #include "absl/strings/substitute.h" #include "absl/types/optional.h" #include "absl/types/span.h" +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" @@ -218,8 +219,9 @@ Getters RepeatedFieldGetters(const FieldDescriptor* field, return getters; } -Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) { - std::string member = FieldMemberName(field, ShouldSplit(field, opts)); +Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) { + std::string member = FieldMemberName(field, field_layout.IsSplit(field)); Getters getters; if (IsArenaStringPtr(field, opts) && !field->default_value_string().empty()) { @@ -235,10 +237,11 @@ Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) { } Getters StringOneofGetters(const FieldDescriptor* field, - const OneofDescriptor* oneof, const Options& opts) { + const OneofDescriptor* oneof, const Options& opts, + const FieldLayout& field_layout) { ABSL_CHECK(oneof != nullptr); - std::string member = FieldMemberName(field, ShouldSplit(field, opts)); + std::string member = FieldMemberName(field, field_layout.IsSplit(field)); std::string field_ptr = member; if (IsArenaStringPtr(field, opts)) { @@ -269,9 +272,9 @@ Getters StringOneofGetters(const FieldDescriptor* field, return getters; } -Getters SingularFieldGetters(const FieldDescriptor* field, - const Options& opts) { - std::string member = FieldMemberName(field, ShouldSplit(field, opts)); +Getters SingularFieldGetters(const FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout) { + std::string member = FieldMemberName(field, field_layout.IsSplit(field)); Getters getters; getters.base = absl::StrCat("&", member); @@ -283,20 +286,21 @@ Getters SingularFieldGetters(const FieldDescriptor* field, } // namespace std::vector MakeTrackerCalls(const FieldDescriptor* field, - const Options& opts) { + const Options& opts, + const FieldLayout& field_layout) { Getters getters; if (field->is_repeated()) { getters = RepeatedFieldGetters(field, opts); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { const auto* oneof = field->real_containing_oneof(); if (oneof != nullptr) { - getters = StringOneofGetters(field, oneof, opts); + getters = StringOneofGetters(field, oneof, opts, field_layout); } else { - getters = StringFieldGetters(field, opts); + getters = StringFieldGetters(field, opts, field_layout); } } else if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE || IsExplicitLazy(field)) { - getters = SingularFieldGetters(field, opts); + getters = SingularFieldGetters(field, opts, field_layout); } auto index = field->index(); diff --git a/src/google/protobuf/compiler/cpp/tracker.h b/src/google/protobuf/compiler/cpp/tracker.h index 734620d921ba0..4989e7e98e969 100644 --- a/src/google/protobuf/compiler/cpp/tracker.h +++ b/src/google/protobuf/compiler/cpp/tracker.h @@ -10,6 +10,7 @@ #include +#include "google/protobuf/compiler/cpp/field_layout.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" @@ -25,7 +26,8 @@ std::vector MakeTrackerCalls( // Generates printer substitutions for field-specific tracker callbacks. std::vector MakeTrackerCalls( - const google::protobuf::FieldDescriptor* field, const Options& opts); + const google::protobuf::FieldDescriptor* field, const Options& opts, + const FieldLayout& field_layout); } // namespace cpp } // namespace compiler