Use ProtobufArrayList for repeated bytes field. Presize primitive arrays for fixed-length primitives.

PiperOrigin-RevId: 542353392
pull/13111/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent bcc464686e
commit b0b926a141
  1. 1
      src/google/protobuf/compiler/java/message_builder.cc
  2. 185
      src/google/protobuf/compiler/java/primitive_field.cc

@ -87,7 +87,6 @@ bool BitfieldTracksMutability(const FieldDescriptor* const descriptor) {
case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_ENUM: case FieldDescriptor::TYPE_ENUM:
case FieldDescriptor::TYPE_BYTES:
return true; return true;
default: default:
return false; return false;

@ -44,6 +44,7 @@
#include "google/protobuf/compiler/java/doc_comment.h" #include "google/protobuf/compiler/java/doc_comment.h"
#include "google/protobuf/compiler/java/helpers.h" #include "google/protobuf/compiler/java/helpers.h"
#include "google/protobuf/compiler/java/name_resolver.h" #include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/printer.h" #include "google/protobuf/io/printer.h"
#include "google/protobuf/wire_format.h" #include "google/protobuf/wire_format.h"
@ -71,6 +72,7 @@ void SetPrimitiveVariables(
variables->insert({"field_type", (*variables)["type"]}); variables->insert({"field_type", (*variables)["type"]});
std::string name = (*variables)["name"]; std::string name = (*variables)["name"];
(*variables)["name_make_immutable"] = absl::StrCat(name, "_.makeImmutable()");
if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE || if (javaType == JAVATYPE_BOOLEAN || javaType == JAVATYPE_DOUBLE ||
javaType == JAVATYPE_FLOAT || javaType == JAVATYPE_INT || javaType == JAVATYPE_FLOAT || javaType == JAVATYPE_INT ||
javaType == JAVATYPE_LONG) { javaType == JAVATYPE_LONG) {
@ -80,12 +82,6 @@ void SetPrimitiveVariables(
absl::StrCat("com.google.protobuf.Internal.", capitalized_type, "List"); absl::StrCat("com.google.protobuf.Internal.", capitalized_type, "List");
(*variables)["empty_list"] = (*variables)["empty_list"] =
absl::StrCat("empty", capitalized_type, "List()"); absl::StrCat("empty", capitalized_type, "List()");
(*variables)["create_list"] =
absl::StrCat("new", capitalized_type, "List()");
(*variables)["mutable_copy_list"] =
absl::StrCat("mutableCopy(", name, "_)");
(*variables)["name_make_immutable"] =
absl::StrCat(name, "_.makeImmutable()");
(*variables)["repeated_get"] = (*variables)["repeated_get"] =
absl::StrCat(name, "_.get", capitalized_type); absl::StrCat(name, "_.get", capitalized_type);
(*variables)["repeated_add"] = (*variables)["repeated_add"] =
@ -93,16 +89,11 @@ void SetPrimitiveVariables(
(*variables)["repeated_set"] = (*variables)["repeated_set"] =
absl::StrCat(name, "_.set", capitalized_type); absl::StrCat(name, "_.set", capitalized_type);
} else { } else {
std::string boxed_type = (*variables)["boxed_type"];
(*variables)["field_list_type"] = (*variables)["field_list_type"] =
absl::StrCat("java.util.List<", boxed_type, ">"); "com.google.protobuf.Internal.ProtobufList<com.google.protobuf."
(*variables)["create_list"] = "ByteString>";
absl::StrCat("new java.util.ArrayList<", boxed_type, ">()"); (*variables)["empty_list"] =
(*variables)["mutable_copy_list"] = "emptyList(com.google.protobuf.ByteString.class)";
absl::StrCat("new java.util.ArrayList<", boxed_type, ">(", name, "_)");
(*variables)["empty_list"] = "java.util.Collections.emptyList()";
(*variables)["name_make_immutable"] = absl::StrCat(
name, "_ = java.util.Collections.unmodifiableList(", name, "_)");
(*variables)["repeated_get"] = absl::StrCat(name, "_.get"); (*variables)["repeated_get"] = absl::StrCat(name, "_.get");
(*variables)["repeated_add"] = absl::StrCat(name, "_.add"); (*variables)["repeated_add"] = absl::StrCat(name, "_.add");
(*variables)["repeated_set"] = absl::StrCat(name, "_.set"); (*variables)["repeated_set"] = absl::StrCat(name, "_.set");
@ -171,13 +162,6 @@ void SetPrimitiveVariables(
break; break;
} }
} }
// For repeated bytes builders, one bit is used for whether the array is
// mutable.
// TODO(b/255468704): migrate bytes field to ProtobufList so that we can
// use the bit field to track their presence instead of mutability.
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex);
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex);
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex);
// Always track the presence of a field explicitly in the builder, regardless // Always track the presence of a field explicitly in the builder, regardless
// of syntax. // of syntax.
@ -731,34 +715,29 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMembers(
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers( void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const { io::Printer* printer) const {
// One field is the list and the bit field keeps track of whether the // We use a ProtobufArrayList because it starts as a mutable list that can be
// list is immutable. If it's immutable, the invariant is that it must // switched to immutable when references are handed out. This allows copy-free
// either an instance of Collections.emptyList() or it's an ArrayList // sharing. A bit in the bitfield tracks whether there are any items in the
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has // list. The presence bit allows us to skip work on blocks of 32 fields by
// a reference to the underlying ArrayList. This invariant allows us to // by checking if the entire bit-field int == 0 (none of the fields are
// share instances of lists between protocol buffers avoiding expensive // present).
// 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_, printer->Print(variables_,
"private $field_list_type$ $name$_ = $empty_list$;\n"); "private $field_list_type$ $name$_ = $empty_list$;\n"
"private void ensure$capitalized_name$IsMutable() {\n"
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { " if (!$name$_.isModifiable()) {\n"
printer->Print(variables_, " $name$_ = makeMutableCopy($name$_);\n"
"private void ensure$capitalized_name$IsMutable() {\n" " }\n"
" if (!$get_mutable_bit_builder$) {\n" " $set_has_field_bit_builder$\n"
" $name$_ = $mutable_copy_list$;\n" "}\n");
" $set_mutable_bit_builder$;\n" if (FixedSize(GetType(descriptor_)) != -1) {
" }\n" printer->Print(
"}\n"); variables_,
} else { "private void ensure$capitalized_name$IsMutable(int capacity) {\n"
printer->Print(variables_, " if (!$name$_.isModifiable()) {\n"
"private void ensure$capitalized_name$IsMutable() {\n" " $name$_ = makeMutableCopy($name$_, capacity);\n"
" if (!$name$_.isModifiable()) {\n" " }\n"
" $name$_ = $mutable_copy_list$;\n" " $set_has_field_bit_builder$\n"
" }\n" "}\n");
" $set_has_field_bit_builder$\n"
"}\n");
} }
// Note: We return an unmodifiable list because otherwise the caller // Note: We return an unmodifiable list because otherwise the caller
@ -766,22 +745,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
// has been built, thus mutating the message which is supposed to be // has been built, thus mutating the message which is supposed to be
// immutable. // immutable.
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER); WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER);
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { printer->Print(variables_,
printer->Print(variables_, "$deprecation$public java.util.List<$boxed_type$>\n"
"$deprecation$public java.util.List<$boxed_type$>\n" " ${$get$capitalized_name$List$}$() {\n"
" ${$get$capitalized_name$List$}$() {\n" " $name$_.makeImmutable();\n"
" return $get_mutable_bit_builder$ ?\n" " return $name$_;\n"
" java.util.Collections.unmodifiableList($name$_) " "}\n");
": $name$_;\n"
"}\n");
} else {
printer->Print(variables_,
"$deprecation$public java.util.List<$boxed_type$>\n"
" ${$get$capitalized_name$List$}$() {\n"
" $name$_.makeImmutable();\n"
" return $name$_;\n"
"}\n");
}
printer->Annotate("{", "}", descriptor_); printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT); WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT);
printer->Print( printer->Print(
@ -804,15 +773,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" int index, $type$ value) {\n" " int index, $type$ value) {\n"
" $null_check$\n" " $null_check$\n"
" ensure$capitalized_name$IsMutable();\n" " ensure$capitalized_name$IsMutable();\n"
" $repeated_set$(index, value);\n"); " $repeated_set$(index, value);\n"
printer->Annotate("{", "}", descriptor_, Semantic::kSet); " $set_has_field_bit_builder$\n"
if (descriptor_->type() != FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_, " $set_has_field_bit_builder$\n");
}
printer->Print(variables_,
" $on_changed$\n" " $on_changed$\n"
" return this;\n" " return this;\n"
"}\n"); "}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER, WriteFieldAccessorDocComment(printer, descriptor_, LIST_ADDER,
/* builder */ true); /* builder */ true);
printer->Print(variables_, printer->Print(variables_,
@ -820,15 +786,12 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
"${$add$capitalized_name$$}$($type$ value) {\n" "${$add$capitalized_name$$}$($type$ value) {\n"
" $null_check$\n" " $null_check$\n"
" ensure$capitalized_name$IsMutable();\n" " ensure$capitalized_name$IsMutable();\n"
" $repeated_add$(value);\n"); " $repeated_add$(value);\n"
printer->Annotate("{", "}", descriptor_, Semantic::kSet); " $set_has_field_bit_builder$\n"
if (descriptor_->type() != FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_, " $set_has_field_bit_builder$\n");
}
printer->Print(variables_,
" $on_changed$\n" " $on_changed$\n"
" return this;\n" " return this;\n"
"}\n"); "}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER, WriteFieldAccessorDocComment(printer, descriptor_, LIST_MULTI_ADDER,
/* builder */ true); /* builder */ true);
printer->Print(variables_, printer->Print(variables_,
@ -836,22 +799,19 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderMembers(
" java.lang.Iterable<? extends $boxed_type$> values) {\n" " java.lang.Iterable<? extends $boxed_type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n" " ensure$capitalized_name$IsMutable();\n"
" com.google.protobuf.AbstractMessageLite.Builder.addAll(\n" " com.google.protobuf.AbstractMessageLite.Builder.addAll(\n"
" values, $name$_);\n"); " values, $name$_);\n"
printer->Annotate("{", "}", descriptor_, Semantic::kSet); " $set_has_field_bit_builder$\n"
if (descriptor_->type() != FieldDescriptor::TYPE_BYTES) {
printer->Print(variables_, " $set_has_field_bit_builder$\n");
}
printer->Print(variables_,
" $on_changed$\n" " $on_changed$\n"
" return this;\n" " return this;\n"
"}\n"); "}\n");
printer->Annotate("{", "}", descriptor_, Semantic::kSet);
WriteFieldAccessorDocComment(printer, descriptor_, CLEARER, WriteFieldAccessorDocComment(printer, descriptor_, CLEARER,
/* builder */ true); /* builder */ true);
printer->Print( printer->Print(
variables_, variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n" "$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $name$_ = $empty_list$;\n" " $name$_ = $empty_list$;\n"
" $clear_mutable_bit_builder$;\n" " $clear_has_field_bit_builder$\n"
" $on_changed$\n" " $on_changed$\n"
" return this;\n" " return this;\n"
"}\n"); "}\n");
@ -977,14 +937,9 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateMergingCode(
printer->Print(variables_, printer->Print(variables_,
"if (!other.$name$_.isEmpty()) {\n" "if (!other.$name$_.isEmpty()) {\n"
" if ($name$_.isEmpty()) {\n" " if ($name$_.isEmpty()) {\n"
" $name$_ = other.$name$_;\n"); " $name$_ = other.$name$_;\n"
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { " $name_make_immutable$;\n"
printer->Print(variables_, " $clear_mutable_bit_builder$;\n"); " $set_has_field_bit_builder$\n");
} else {
printer->Print(variables_,
" $name$_.makeImmutable();\n"
" $set_has_field_bit_builder$\n");
}
printer->Print(variables_, printer->Print(variables_,
" } else {\n" " } else {\n"
" ensure$capitalized_name$IsMutable();\n" " ensure$capitalized_name$IsMutable();\n"
@ -998,20 +953,11 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuildingCode(
io::Printer* printer) const { io::Printer* printer) const {
// The code below ensures that the result has an immutable list. If our // The code below ensures that the result has an immutable list. If our
// list is immutable, we can just reuse it. If not, we make it immutable. // list is immutable, we can just reuse it. If not, we make it immutable.
if (descriptor_->type() == FieldDescriptor::TYPE_BYTES) { printer->Print(variables_,
printer->Print(variables_, "if ($get_has_field_bit_from_local$) {\n"
"if ($get_mutable_bit_builder$) {\n" " $name_make_immutable$;\n"
" $name_make_immutable$;\n" " result.$name$_ = $name$_;\n"
" $clear_mutable_bit_builder$;\n" "}\n");
"}\n"
"result.$name$_ = $name$_;\n");
} else {
printer->Print(variables_,
"if ($get_has_field_bit_from_local$) {\n"
" $name_make_immutable$;\n"
" result.$name$_ = $name$_;\n"
"}\n");
}
} }
void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode( void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
@ -1024,14 +970,25 @@ void RepeatedImmutablePrimitiveFieldGenerator::GenerateBuilderParsingCode(
void RepeatedImmutablePrimitiveFieldGenerator:: void RepeatedImmutablePrimitiveFieldGenerator::
GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const { GenerateBuilderParsingCodeFromPacked(io::Printer* printer) const {
printer->Print(variables_, if (FixedSize(GetType(descriptor_)) != -1) {
"int length = input.readRawVarint32();\n" printer->Print(variables_,
"int limit = input.pushLimit(length);\n" "int length = input.readRawVarint32();\n"
"ensure$capitalized_name$IsMutable();\n" "int limit = input.pushLimit(length);\n"
"while (input.getBytesUntilLimit() > 0) {\n" "ensure$capitalized_name$IsMutable(length / $fixed_size$);\n"
" $repeated_add$(input.read$capitalized_type$());\n" "while (input.getBytesUntilLimit() > 0) {\n"
"}\n" " $repeated_add$(input.read$capitalized_type$());\n"
"input.popLimit(limit);\n"); "}\n"
"input.popLimit(limit);\n");
} else {
printer->Print(variables_,
"int length = input.readRawVarint32();\n"
"int limit = input.pushLimit(length);\n"
"ensure$capitalized_name$IsMutable();\n"
"while (input.getBytesUntilLimit() > 0) {\n"
" $repeated_add$(input.read$capitalized_type$());\n"
"}\n"
"input.popLimit(limit);\n");
}
} }
void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializationCode( void RepeatedImmutablePrimitiveFieldGenerator::GenerateSerializationCode(

Loading…
Cancel
Save