Skip to content

Commit

Permalink
Merge pull request protocolbuffers#9912 from acozzette/sync-stage
Browse files Browse the repository at this point in the history
Integrate from Piper for C++, Java, and Python
  • Loading branch information
acozzette authored May 5, 2022
2 parents 67823fe + df00695 commit 1522492
Show file tree
Hide file tree
Showing 19 changed files with 637 additions and 78 deletions.
2 changes: 1 addition & 1 deletion cmake/libprotoc.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ set(libprotoc_files
set(libprotoc_headers
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/helpers.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/names.h
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ nobase_include_HEADERS = \
google/protobuf/arenaz_sampler.h \
google/protobuf/compiler/code_generator.h \
google/protobuf/compiler/command_line_interface.h \
google/protobuf/compiler/cpp/file.h \
google/protobuf/compiler/cpp/cpp_generator.h \
google/protobuf/compiler/cpp/file.h \
google/protobuf/compiler/cpp/generator.h \
google/protobuf/compiler/cpp/helpers.h \
google/protobuf/compiler/cpp/names.h \
Expand Down
9 changes: 8 additions & 1 deletion src/google/protobuf/compiler/cpp/enum_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/compiler/cpp/field.h>
#include <google/protobuf/compiler/cpp/helpers.h>

namespace google {
Expand All @@ -55,8 +56,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["default"] = Int32ToString(default_value->number());
(*variables)["full_name"] = descriptor->full_name();
(*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
bool cold = ShouldSplit(descriptor, options);
(*variables)["cached_byte_size_field"] =
MakeVarintCachedSizeFieldName(descriptor);
MakeVarintCachedSizeFieldName(descriptor, cold);
}

} // namespace
Expand Down Expand Up @@ -110,6 +112,7 @@ void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
" $field$ = value;\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n"
"$maybe_prepare_split_message$"
" _internal_set_$name$(value);\n"
"$annotate_set$"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
Expand Down Expand Up @@ -162,6 +165,10 @@ void EnumFieldGenerator::GenerateConstexprAggregateInitializer(
void EnumFieldGenerator::GenerateAggregateInitializer(
io::Printer* printer) const {
Formatter format(printer, variables_);
if (ShouldSplit(descriptor_, options_)) {
format("decltype(Impl_::Split::$name$_){$default$}");
return;
}
format("decltype($field$){$default$}");
}

Expand Down
4 changes: 3 additions & 1 deletion src/google/protobuf/compiler/cpp/enum_field.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const override;
void GenerateSwappingCode(io::Printer* printer) const override;
void GenerateConstructorCode(io::Printer* printer) const override;
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
}
void GenerateDestructorCode(io::Printer* printer) const override;
void GenerateSerializeWithCachedSizesToArray(
io::Printer* printer) const override;
Expand Down
18 changes: 17 additions & 1 deletion src/google/protobuf/compiler/cpp/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -244,14 +244,17 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
(*variables)["number"] = StrCat(descriptor->number());
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
(*variables)["field"] = FieldMemberName(descriptor);
bool split = ShouldSplit(descriptor, options);
(*variables)["field"] = FieldMemberName(descriptor, split);

(*variables)["tag_size"] = StrCat(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecated_attr"] = DeprecatedAttribute(options, descriptor);

(*variables)["set_hasbit"] = "";
(*variables)["clear_hasbit"] = "";
(*variables)["maybe_prepare_split_message"] =
split ? " PrepareSplitMessageForWrite();\n" : "";

AddAccessorAnnotations(descriptor, options, variables);

Expand Down Expand Up @@ -299,6 +302,10 @@ void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {

void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
Formatter format(printer, variables_);
if (ShouldSplit(descriptor_, options_)) {
format("decltype(Impl_::Split::$name$_){arena}");
return;
}
format("decltype($field$){arena}");
}

Expand All @@ -314,6 +321,15 @@ void FieldGenerator::GenerateCopyAggregateInitializer(
format("decltype($field$){from.$field$}");
}

void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
if (ShouldSplit(descriptor_, options_)) {
// There is no copy constructor for the `Split` struct, so we need to copy
// the value here.
Formatter format(printer, variables_);
format("$field$ = from.$field$;\n");
}
}

void SetCommonOneofFieldVariables(
const FieldDescriptor* descriptor,
std::map<std::string, std::string>* variables) {
Expand Down
5 changes: 4 additions & 1 deletion src/google/protobuf/compiler/cpp/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class FieldGenerator {
virtual void GenerateMergingCode(io::Printer* printer) const = 0;

// Generates a copy constructor
virtual void GenerateCopyConstructorCode(io::Printer* printer) const = 0;
virtual void GenerateCopyConstructorCode(io::Printer* printer) const;

// Generate lines of code (statements, not declarations) which swaps
// this field and the corresponding field of another message, which
Expand All @@ -150,6 +150,9 @@ class FieldGenerator {
// method, invoked by each of the generated constructors.
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;

// Generate initialization code for private members in the cold struct.
virtual void GenerateCreateSplitMessageCode(io::Printer* printer) const {}

// Generate any code that needs to go in the class's SharedDtor() method,
// invoked by the destructor.
// Most field types don't need this, so the default implementation is empty.
Expand Down
67 changes: 55 additions & 12 deletions src/google/protobuf/compiler/cpp/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,40 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
io::Printer* printer) {
Formatter format(printer, variables_);
MessageGenerator* generator = message_generators_[idx].get();
// Generate the split instance first because it's needed in the constexpr
// constructor.
if (ShouldSplit(generator->descriptor_, options_)) {
// 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.
format(
"struct $1$ {\n"
" PROTOBUF_CONSTEXPR $1$()\n"
" : _instance{",
DefaultInstanceType(generator->descriptor_, options_,
/*split=*/true));
generator->GenerateInitDefaultSplitInstance(printer);
format(
"} {}\n"
" ~$1$() {}\n"
" union {\n"
" $2$ _instance;\n"
" };\n"
"};\n",
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
StrCat(generator->classname_, "::Impl_::Split"));
// NO_DESTROY is not necessary for correctness. The empty destructor is
// enough. However, the empty destructor fails to be elided in some
// configurations (like non-opt or with certain sanitizers). NO_DESTROY is
// there just to improve performance and binary size in these builds.
format(
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
DefaultInstanceName(generator->descriptor_, options_, /*split=*/true));
}

generator->GenerateConstexprConstructor(printer);
// 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.
format(
"struct $1$ {\n"
" PROTOBUF_CONSTEXPR $1$()\n"
Expand All @@ -495,14 +525,11 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
"};\n",
DefaultInstanceType(generator->descriptor_, options_),
generator->classname_);
// NO_DESTROY is not necessary for correctness. The empty destructor is
// enough. However, the empty destructor fails to be elided in some
// configurations (like non-opt or with certain sanitizers). NO_DESTROY is
// there just to improve performance and binary size in these builds.
format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
DefaultInstanceType(generator->descriptor_, options_),
DefaultInstanceName(generator->descriptor_, options_));
format(
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
DefaultInstanceType(generator->descriptor_, options_),
DefaultInstanceName(generator->descriptor_, options_));

for (int i = 0; i < generator->descriptor_->field_count(); i++) {
const FieldDescriptor* field = generator->descriptor_->field(i);
Expand All @@ -514,7 +541,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
"($3$._instance.$4$.Init(), std::true_type{});\n",
ClassName(generator->descriptor_), FieldName(field),
DefaultInstanceName(generator->descriptor_, options_),
FieldMemberName(field));
FieldMemberName(field, ShouldSplit(field, options_)));
}
}

Expand Down Expand Up @@ -947,6 +974,7 @@ class FileGenerator::ForwardDeclarations {
public:
void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; }
void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; }
void AddSplit(const Descriptor* d) { splits_[ClassName(d)] = d; }

void Print(const Formatter& format, const Options& options) const {
for (const auto& p : enums_) {
Expand All @@ -967,6 +995,14 @@ class FileGenerator::ForwardDeclarations {
class_desc, classname, DefaultInstanceType(class_desc, options),
DefaultInstanceName(class_desc, options));
}
for (const auto& p : splits_) {
const Descriptor* class_desc = p.second;
format(
"struct $1$;\n"
"$dllexport_decl $extern $1$ $2$;\n",
DefaultInstanceType(class_desc, options, /*split=*/true),
DefaultInstanceName(class_desc, options, /*split=*/true));
}
}

void PrintTopLevelDecl(const Formatter& format,
Expand All @@ -982,6 +1018,7 @@ class FileGenerator::ForwardDeclarations {
private:
std::map<std::string, const Descriptor*> classes_;
std::map<std::string, const EnumDescriptor*> enums_;
std::map<std::string, const Descriptor*> splits_;
};

static void PublicImportDFS(const FileDescriptor* fd,
Expand Down Expand Up @@ -1027,6 +1064,12 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
if (d && !public_set.count(d->file()))
decls[Namespace(d, options_)].AddEnum(d);
}
for (const auto& mg : message_generators_) {
const Descriptor* d = mg->descriptor_;
if ((d != nullptr) && (public_set.count(d->file()) == 0u) &&
ShouldSplit(mg->descriptor_, options_))
decls[Namespace(d, options_)].AddSplit(d);
}

{
NamespaceOpener ns(format);
Expand Down
57 changes: 43 additions & 14 deletions src/google/protobuf/compiler/cpp/helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <functional>
#include <limits>
#include <map>
#include <memory>
#include <queue>
#include <unordered_set>
#include <vector>
Expand Down Expand Up @@ -185,6 +186,23 @@ bool AllocExpected(const Descriptor* descriptor) {
return false;
}

// Describes different approaches to detect non-canonical int32 encoding. Only
// kNever or kAlways is eligible for *simple* verification methods.
enum class VerifyInt32Type {
kCustom, // Only check if field number matches.
kNever, // Do not check.
kAlways, // Always check.
};

inline VerifySimpleType VerifyInt32TypeToVerifyCustom(VerifyInt32Type t) {
static VerifySimpleType kCustomTypes[] = {
VerifySimpleType::kCustom, VerifySimpleType::kCustomInt32Never,
VerifySimpleType::kCustomInt32Always};
return kCustomTypes[static_cast<int32_t>(t) -
static_cast<int32_t>(VerifyInt32Type::kCustom)];
}


} // namespace

bool IsLazy(const FieldDescriptor* field, const Options& options,
Expand Down Expand Up @@ -261,6 +279,8 @@ void SetCommonMessageDataVariables(
(*variables)["oneof_case"] = prefix + "_oneof_case_";
(*variables)["tracker"] = "Impl_::_tracker_";
(*variables)["weak_field_map"] = prefix + "_weak_field_map_";
(*variables)["split"] = prefix + "_split_";
(*variables)["cached_split_ptr"] = "cached_split_ptr";
}

void SetUnknownFieldsVariable(const Descriptor* descriptor,
Expand Down Expand Up @@ -425,29 +445,32 @@ std::string Namespace(const EnumDescriptor* d, const Options& options) {
}

std::string DefaultInstanceType(const Descriptor* descriptor,
const Options& options) {
return ClassName(descriptor) + "DefaultTypeInternal";
const Options& /*options*/, bool split) {
return ClassName(descriptor) + (split ? "__Impl_Split" : "") +
"DefaultTypeInternal";
}

std::string DefaultInstanceName(const Descriptor* descriptor,
const Options& options) {
return "_" + ClassName(descriptor, false) + "_default_instance_";
const Options& /*options*/, bool split) {
return "_" + ClassName(descriptor, false) + (split ? "__Impl_Split" : "") +
"_default_instance_";
}

std::string DefaultInstancePtr(const Descriptor* descriptor,
const Options& options) {
return DefaultInstanceName(descriptor, options) + "ptr_";
const Options& options, bool split) {
return DefaultInstanceName(descriptor, options, split) + "ptr_";
}

std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
const Options& options) {
const Options& options, bool split) {
return QualifiedFileLevelSymbol(
descriptor->file(), DefaultInstanceName(descriptor, options), options);
descriptor->file(), DefaultInstanceName(descriptor, options, split),
options);
}

std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
const Options& options) {
return QualifiedDefaultInstanceName(descriptor, options) + "ptr_";
const Options& options, bool split) {
return QualifiedDefaultInstanceName(descriptor, options, split) + "ptr_";
}

std::string DescriptorTableName(const FileDescriptor* file,
Expand Down Expand Up @@ -487,12 +510,15 @@ std::string FieldName(const FieldDescriptor* field) {
return result;
}

std::string FieldMemberName(const FieldDescriptor* field) {
std::string FieldMemberName(const FieldDescriptor* field, bool split) {
StringPiece prefix =
IsMapEntryMessage(field->containing_type()) ? "" : "_impl_.";
StringPiece split_prefix = split ? "_split_->" : "";
if (field->real_containing_oneof() == nullptr) {
return StrCat(prefix, FieldName(field), "_");
return StrCat(prefix, split_prefix, FieldName(field), "_");
}
// Oneof fields are never split.
GOOGLE_CHECK(!split);
return StrCat(prefix, field->containing_oneof()->name(), "_.",
FieldName(field), "_");
}
Expand Down Expand Up @@ -875,6 +901,9 @@ bool HasLazyFields(const FileDescriptor* file, const Options& options,
return false;
}

bool ShouldSplit(const Descriptor*, const Options&) { return false; }
bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; }

static bool HasRepeatedFields(const Descriptor* descriptor) {
for (int i = 0; i < descriptor->field_count(); ++i) {
if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) {
Expand Down Expand Up @@ -1016,9 +1045,9 @@ bool IsUtf8String(const FieldDescriptor* field) {
field->type() == FieldDescriptor::TYPE_STRING;
}

bool ShouldVerifySimple(const Descriptor* descriptor) {
VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) {
(void)descriptor;
return false;
return VerifySimpleType::kCustom;
}

bool IsStringOrMessage(const FieldDescriptor* field) {
Expand Down
Loading

0 comments on commit 1522492

Please sign in to comment.