Internal change.

PiperOrigin-RevId: 970073736
This commit is contained in:
Protobuf Team Bot 2026-08-24 14:14:21 -07:00 committed by Copybara-Service
parent dee117a787
commit 4d20214ca8
2 changed files with 91 additions and 138 deletions

View file

@ -77,24 +77,6 @@ std::string MapValueImmutableClassdName(const Descriptor* descriptor,
ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, value_field->type());
return name_resolver->GetImmutableClassName(value_field->message_type());
}
bool BitfieldTracksMutability(const FieldDescriptor* const descriptor) {
if (!descriptor->is_repeated() || IsMapField(descriptor)) {
return false;
}
// TODO: update this to migrate repeated fields to use
// ProtobufList (which tracks immutability internally). That allows us to use
// the presence bit to skip work on the repeated field if it is not populated.
// Once all repeated fields are held in ProtobufLists, this method shouldn't
// be needed.
switch (descriptor->type()) {
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
return true;
default:
return false;
}
}
} // namespace
MessageBuilderGenerator::MessageBuilderGenerator(
@ -150,11 +132,7 @@ void MessageBuilderGenerator::Generate(io::Printer* printer) {
}
// Integers for bit fields.
int totalBits = 0;
for (int i = 0; i < descriptor_->field_count(); i++) {
totalBits += field_generators_.get(descriptor_->field(i)).GetNumBits();
}
int totalInts = (totalBits + 31) / 32;
int totalInts = (descriptor_->field_count() + 31) / 32;
for (int i = 0; i < totalInts; i++) {
printer->Print("private int $bit_field_name$;\n", "bit_field_name",
GetBitFieldName(i));
@ -582,20 +560,10 @@ void MessageBuilderGenerator::GenerateBuildPartial(io::Printer* printer) {
printer->Indent();
// Handle the repeated fields first so that the "mutable bits" are cleared.
bool has_repeated_fields = false;
for (int i = 0; i < descriptor_->field_count(); ++i) {
if (BitfieldTracksMutability(descriptor_->field(i))) {
has_repeated_fields = true;
printer->Print("buildPartialRepeatedFields(result);\n");
break;
}
}
// One buildPartial_autosplit_#() per from_bit_field
int totalBuilderInts = (descriptor_->field_count() + 31) / 32;
if (totalBuilderInts > 0) {
for (int i = 0; i < totalBuilderInts; ++i) {
int totalInts = (descriptor_->field_count() + 31) / 32;
if (totalInts > 0) {
for (int i = 0; i < totalInts; ++i) {
printer->Print(
"if ($bit_field_name$ != 0) { "
"buildPartial_autosplit_$shard$(result); }\n",
@ -615,26 +583,9 @@ void MessageBuilderGenerator::GenerateBuildPartial(io::Printer* printer) {
"\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
// Build Repeated Fields
if (has_repeated_fields) {
printer->Print(
"private void buildPartialRepeatedFields($classname$ result) {\n",
"classname", name_resolver_->GetImmutableClassName(descriptor_));
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); ++i) {
if (BitfieldTracksMutability(descriptor_->field(i))) {
const ImmutableFieldGenerator& field =
field_generators_.get(descriptor_->field(i));
field.GenerateBuildingCode(printer);
}
}
printer->Outdent();
printer->Print("}\n\n");
}
// Build all fields in shards organized by bitfield membership.
int start_field = 0;
for (int i = 0; i < totalBuilderInts; i++) {
for (int i = 0; i < totalInts; i++) {
start_field = GenerateBuildPartialShard(printer, i, start_field);
}
@ -665,34 +616,21 @@ int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
int bit = 0;
int next = first_field;
for (; bit < 32 && next < descriptor_->field_count(); ++next) {
for (; bit < 32 && next < descriptor_->field_count(); ++next, ++bit) {
const ImmutableFieldGenerator& field =
field_generators_.get(descriptor_->field(next));
bit += field.GetNumBits();
// Skip oneof fields that are handled separately
if (IsRealOneof(descriptor_->field(next))) {
continue;
}
// Skip repeated fields because they are currently handled
// in separate buildPartial sub-methods.
if (BitfieldTracksMutability(descriptor_->field(next))) {
continue;
}
// Skip fields without presence bits in the builder
if (field.GetNumBits() == 0) {
continue;
}
// Track message bits if necessary
if (field.GetNumBits() > 0) {
int to_bitfield = field.GetBitIndex() / 32;
if (declared_to_bitfields.count(to_bitfield) == 0) {
printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name",
GetBitFieldName(to_bitfield));
declared_to_bitfields.insert(to_bitfield);
}
int to_bitfield = field.GetBitIndex() / 32;
if (declared_to_bitfields.count(to_bitfield) == 0) {
printer->Print("int to_$bit_field_name$ = 0;\n", "bit_field_name",
GetBitFieldName(to_bitfield));
declared_to_bitfields.insert(to_bitfield);
}
// Copy the field from the builder to the message

View file

@ -49,6 +49,9 @@ void SetMessageVariables(
(*variables)["group_or_message"] =
(GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group"
: "Message";
(*variables)["empty_list"] =
absl::StrCat("emptyList(", (*variables)["type"], ".class)");
// TODO: Add @deprecated javadoc when generating javadoc is supported
// by the proto compiler
(*variables)["deprecation"] =
@ -359,6 +362,7 @@ void ImmutableMessageFieldGenerator::
" isClean());\n"
" $name$_ = null;\n"
" }\n"
" $set_has_field_bit$\n"
" return $name$Builder_;\n"
"}\n");
}
@ -968,9 +972,10 @@ void RepeatedImmutableMessageFieldGenerator::GenerateGetOrBuilderMethod(
void RepeatedImmutableMessageFieldGenerator::GenerateMembers(
io::Printer* printer) const {
printer->Print(variables_,
"@SuppressWarnings(\"serial\")\n"
"private java.util.List<$type$> $name$_;\n");
printer->Print(
variables_,
"private com.google.protobuf.Internal.ProtobufList<$type$> $name$_ =\n"
" $empty_list$;\n");
PrintExtraFieldInfo(variables_, printer);
GenerateGetListMethod(printer);
GenerateGetOrBuilderListMethod(printer);
@ -981,30 +986,29 @@ void RepeatedImmutableMessageFieldGenerator::GenerateMembers(
void RepeatedImmutableMessageFieldGenerator::GenerateEnsureIsMutableMethod(
io::Printer* printer) const {
printer->Print(
variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$get_mutable_bit_builder$) {\n"
" $name$_ = new java.util.ArrayList<$type$>($name$_);\n"
" $set_mutable_bit_builder$;\n"
" }\n"
"}\n"
"\n");
printer->Print(variables_,
"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$name$_.isModifiable()) {\n"
" $name$_ = makeMutableCopy($name$_);\n"
" }\n"
" $set_has_field_bit$\n"
"}\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderGetListMethod(
io::Printer* printer) const {
// List<Field> getRepeatedFieldList()
WriteFieldDocComment(printer, descriptor_, context_->options());
PrintNestedBuilderFunction(
printer,
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$()",
PrintNestedBuilderFunction(printer,
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$()",
"return java.util.Collections.unmodifiableList($name$_);\n",
"return $name$Builder_.getMessageList();\n",
"$name$_.makeImmutable();\n"
"return $name$_;\n",
nullptr);
"return $name$Builder_.getMessageList();\n",
nullptr);
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderGetCountMethod(
@ -1046,8 +1050,9 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderSetMethod(
"ensure$capitalized_name$IsMutable();\n"
"$name$_.set(index, value);\n"
"$on_changed$\n",
"$name$Builder_.setMessage(index, value);\n", "return this;\n",
Semantic::kSet);
"$name$Builder_.setMessage(index, "
"value);\n$set_has_field_bit$\n$on_changed$\n",
"return this;\n", Semantic::kSet);
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderSetBuilderMethod(
@ -1078,7 +1083,9 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderAddMethod(
"$on_changed$\n",
"$name$Builder_.addMessage(value);\n",
"$name$Builder_.addMessage(value);\n"
"$set_has_field_bit$\n"
"$on_changed$\n",
"return this;\n", Semantic::kSet);
}
@ -1097,7 +1104,9 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderAddAtIndexMethod(
"$name$_.add(index, value);\n"
"$on_changed$\n",
"$name$Builder_.addMessage(index, value);\n",
"$name$Builder_.addMessage(index, value);\n"
"$set_has_field_bit$\n"
"$on_changed$\n",
"return this;\n", Semantic::kSet);
}
@ -1138,14 +1147,17 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderAddAllMethod(
"$deprecation$public Builder ${$addAll$capitalized_name$$}$(\n"
" java.lang.Iterable<? extends $type$> values)",
"ensure$capitalized_name$IsMutable();\n"
"com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
" values, $name$_);\n"
"$on_changed$\n",
"$name$_ = com.google.protobuf.Internal.ProtobufList.concatenate(\n"
" $name$_, values);\n",
"$name$Builder_.addAllMessages(values);\n",
"return this;\n", Semantic::kSet);
"if (get$capitalized_name$Count() > 0) {\n"
" $set_has_field_bit$;\n"
"}\n"
"$on_changed$\n"
"return this;\n",
Semantic::kSet);
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearMethod(
@ -1155,13 +1167,14 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearMethod(
PrintNestedBuilderFunction(
printer, "$deprecation$public Builder ${$clear$capitalized_name$$}$()",
"$name$_ = java.util.Collections.emptyList();\n"
"$clear_mutable_bit_builder$;\n"
"$on_changed$\n",
"$name$_ = $empty_list$;\n",
"$name$Builder_.clear();\n",
"return this;\n", Semantic::kSet);
"$clear_has_field_bit$\n"
"$on_changed$\n"
"return this;\n",
Semantic::kSet);
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderRemoveMethod(
@ -1173,12 +1186,16 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderRemoveMethod(
"$deprecation$public Builder ${$remove$capitalized_name$$}$(int index)",
"ensure$capitalized_name$IsMutable();\n"
"$name$_.remove(index);\n"
"$on_changed$\n",
"$name$_.remove(index);\n",
"$name$Builder_.remove(index);\n",
"return this;\n", Semantic::kSet);
"if (get$capitalized_name$Count() == 0) {\n"
" $clear_has_field_bit$;\n"
"}\n"
"$on_changed$\n"
"return this;\n",
Semantic::kSet);
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderGetBuilderMethod(
@ -1224,7 +1241,8 @@ void RepeatedImmutableMessageFieldGenerator::
" if ($name$Builder_ != null) {\n"
" return $name$Builder_.getMessageOrBuilderList();\n"
" } else {\n"
" return java.util.Collections.unmodifiableList($name$_);\n"
" $name$_.makeImmutable();\n"
" return $name$_;\n"
" }\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
@ -1232,11 +1250,13 @@ void RepeatedImmutableMessageFieldGenerator::
void RepeatedImmutableMessageFieldGenerator::
GenerateBuilderAddBuilderNoArgsMethod(io::Printer* printer) const {
// Field.Builder addRepeatedField()
// Field.Builder addRepeatedFieldBuilder()
WriteFieldDocComment(printer, descriptor_, context_->options());
printer->Print(variables_,
"$deprecation$public $type$.Builder "
"${$add$capitalized_name$Builder$}$() {\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return "
"internalGet$capitalized_name$FieldBuilder().addBuilder(\n"
" $type$.getDefaultInstance());\n"
@ -1252,6 +1272,8 @@ void RepeatedImmutableMessageFieldGenerator::
variables_,
"$deprecation$public $type$.Builder ${$add$capitalized_name$Builder$}$(\n"
" int index) {\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return "
"internalGet$capitalized_name$FieldBuilder().addBuilder(\n"
" index, $type$.getDefaultInstance());\n"
@ -1284,30 +1306,23 @@ void RepeatedImmutableMessageFieldGenerator::
"com.google.protobuf.RepeatedFieldBuilder<\n"
" $type$, $type$.Builder, $type$OrBuilder>(\n"
" $name$_,\n"
" $get_mutable_bit_builder$,\n"
" $name$_.isModifiable(),\n"
" getParentForChildren(),\n"
" isClean());\n"
" $name$_ = null;\n"
" }\n"
" $set_has_field_bit$\n"
" $on_changed$\n"
" return $name$Builder_;\n"
"}\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
// Used when the builder is null.
// One field is the list and the other field keeps track of whether the
// list is immutable. If it's immutable, the invariant is that it must
// either an instance of Collections.emptyList() or it's an ArrayList
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
// a reference to the underlying ArrayList. This invariant allows us to
// share instances of lists between protocol buffers avoiding expensive
// memory allocations. Note, immutable is a strong guarantee here -- not
// just that the list cannot be modified via the reference but that the
// list can never be modified.
printer->Print(variables_,
"private java.util.List<$type$> $name$_ =\n"
" java.util.Collections.emptyList();\n");
printer->Print(
variables_,
"private com.google.protobuf.Internal.ProtobufList<$type$> $name$_ =\n"
" emptyList($type$.class);\n");
GenerateEnsureIsMutableMethod(printer);
@ -1339,7 +1354,6 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderMembers(
GenerateBuilderGetBuilderListMethod(printer);
GenerateBuilderInternalGetFieldBuilderMethod(printer);
}
void RepeatedImmutableMessageFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
printer->Print(variables_, "internalGet$capitalized_name$FieldBuilder();\n");
@ -1347,18 +1361,16 @@ void RepeatedImmutableMessageFieldGenerator::
void RepeatedImmutableMessageFieldGenerator::GenerateInitializationCode(
io::Printer* printer) const {
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
printer->Print(variables_, "$name$_ = $empty_list$;\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderClearCode(
io::Printer* printer) const {
PrintNestedBuilderCondition(printer,
"$name$_ = java.util.Collections.emptyList();\n",
PrintNestedBuilderCondition(printer, "$name$_ = $empty_list$;\n",
"$name$_ = null;\n"
"$name$Builder_.clear();\n");
printer->Print(variables_, "$clear_mutable_bit_builder$;\n");
printer->Print(variables_, "$clear_has_field_bit$;\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateMergingCode(
@ -1373,7 +1385,7 @@ void RepeatedImmutableMessageFieldGenerator::GenerateMergingCode(
"if (!other.$name$_.isEmpty()) {\n"
" if ($name$_.isEmpty()) {\n"
" $name$_ = other.$name$_;\n"
" $clear_mutable_bit_builder$;\n"
" $set_has_field_bit$\n"
" } else {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.addAll(other.$name$_);\n"
@ -1386,14 +1398,16 @@ void RepeatedImmutableMessageFieldGenerator::GenerateMergingCode(
" $name$Builder_.dispose();\n"
" $name$Builder_ = null;\n"
" $name$_ = other.$name$_;\n"
" $clear_mutable_bit_builder$;\n"
" $set_has_field_bit$\n"
" $name$Builder_ = \n"
" com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders "
"?\n"
" internalGet$capitalized_name$FieldBuilder() : null;\n"
" } else {\n"
" $name$Builder_.addAllMessages(other.$name$_);\n"
" $set_has_field_bit$\n"
" }\n"
" $on_changed$\n"
"}\n");
}
@ -1402,15 +1416,14 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuildingCode(
// The code below (non-nested builder case) ensures that the result has an
// immutable list. If our list is immutable, we can just reuse it. If not,
// we make it immutable.
printer->Print(variables_, "if ($get_has_field_bit_from_local$) {\n");
PrintNestedBuilderCondition(
printer,
"if ($get_mutable_bit_builder$) {\n"
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
" $clear_mutable_bit_builder$;\n"
"}\n"
"$name$_.makeImmutable();\n"
"result.$name$_ = $name$_;\n",
"result.$name$_ = $name$Builder_.build();\n");
"result.$name$_ = $name$Builder_.buildProtobufList();\n");
printer->Print("}\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
@ -1431,7 +1444,9 @@ void RepeatedImmutableMessageFieldGenerator::GenerateBuilderParsingCode(
PrintNestedBuilderCondition(printer,
"ensure$capitalized_name$IsMutable();\n"
"$name$_.add(m);\n",
"$name$Builder_.addMessage(m);\n");
"$name$Builder_.addMessage(m);\n"
"$set_has_field_bit$\n"
"$on_changed$\n");
}
void RepeatedImmutableMessageFieldGenerator::GenerateSerializationCode(