Internal change. PiperOrigin-RevId: 970073736
diff --git a/src/google/protobuf/compiler/java/full/message_builder.cc b/src/google/protobuf/compiler/java/full/message_builder.cc index e546e22..6781472 100644 --- a/src/google/protobuf/compiler/java/full/message_builder.cc +++ b/src/google/protobuf/compiler/java/full/message_builder.cc
@@ -77,24 +77,6 @@ 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 @@ } // 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 @@ 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 @@ "\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 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
diff --git a/src/google/protobuf/compiler/java/full/message_field.cc b/src/google/protobuf/compiler/java/full/message_field.cc index 5a2c949..1ca8782 100644 --- a/src/google/protobuf/compiler/java/full/message_field.cc +++ b/src/google/protobuf/compiler/java/full/message_field.cc
@@ -49,6 +49,9 @@ (*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 @@ " isClean());\n" " $name$_ = null;\n" " }\n" + " $set_has_field_bit$\n" " return $name$Builder_;\n" "}\n"); } @@ -968,9 +972,10 @@ 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::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 @@ "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 @@ "$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 @@ "$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 @@ "$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 @@ 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 @@ "$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 @@ " 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:: 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 @@ 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 @@ "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 @@ 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::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 @@ "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 @@ " $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 @@ // 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 @@ 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(