Skip to content

Commit

Permalink
Proto java full runtime: avoid allocating Integers accessing enum lists
Browse files Browse the repository at this point in the history
Previously, we would allocate a boxed Integer when accessing repeated enums, because we used ArrayList<Integer>, which must box the int.

Use IntArrayList and the primitive "int getInt()" method instead.

PiperOrigin-RevId: 630229119
  • Loading branch information
mhansen authored and copybara-github committed May 3, 2024
1 parent d6c2833 commit cc79f77
Showing 1 changed file with 48 additions and 51 deletions.
99 changes: 48 additions & 51 deletions src/google/protobuf/compiler/java/immutable/enum_field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -687,28 +687,27 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
printer->Print(
variables_,
"@SuppressWarnings(\"serial\")\n"
"private java.util.List<java.lang.Integer> $name$_;\n"
"private com.google.protobuf.Internal.IntList $name$_;\n"
"private static final "
"com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$> $name$_converter_ =\n"
" new com.google.protobuf.Internal.ListAdapter.Converter<\n"
" java.lang.Integer, $type$>() {\n"
" public $type$ convert(java.lang.Integer from) {\n"
"com.google.protobuf.Internal.IntListAdapter.IntConverter<\n"
" $type$> $name$_converter_ =\n"
" new com.google.protobuf.Internal.IntListAdapter.IntConverter<\n"
" $type$>() {\n"
" public $type$ convert(int from) {\n"
" $type$ result = $type$.forNumber(from);\n"
" return result == null ? $unknown$ : result;\n"
" }\n"
" };\n");
PrintExtraFieldInfo(variables_, printer);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_GETTER,
context_->options());
printer->Print(
variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.ListAdapter<\n"
" java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Print(variables_,
"@java.lang.Override\n"
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.IntListAdapter<\n"
" $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
context_->options());
Expand All @@ -725,7 +724,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
variables_,
"@java.lang.Override\n"
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $name$_converter_.convert($name$_.get(index));\n"
" return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
if (SupportUnknownEnumValue(descriptor_)) {
Expand All @@ -744,7 +743,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateMembers(
"@java.lang.Override\n"
"$deprecation$public int "
"${$get$capitalized_name$Value$}$(int index) {\n"
" return $name$_.get(index);\n"
" return $name$_.getInt(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
}
Expand All @@ -760,19 +759,18 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
variables_,
// 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.
"private java.util.List<java.lang.Integer> $name$_ =\n"
" java.util.Collections.emptyList();\n"
// either an instance of emptyIntList() or it's an immutable IntArrayList
// 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.
"private com.google.protobuf.Internal.IntList $name$_ =\n"
" emptyIntList();\n"

"private void ensure$capitalized_name$IsMutable() {\n"
" if (!$get_mutable_bit_builder$) {\n"
" $name$_ = new java.util.ArrayList<java.lang.Integer>($name$_);\n"
" $name$_ = makeMutableCopy($name$_);\n"
" $set_mutable_bit_builder$;\n"
" }\n"
"}\n");
Expand All @@ -787,8 +785,8 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
// immutable.
"$deprecation$public java.util.List<$type$> "
"${$get$capitalized_name$List$}$() {\n"
" return new com.google.protobuf.Internal.ListAdapter<\n"
" java.lang.Integer, $type$>($name$_, $name$_converter_);\n"
" return new com.google.protobuf.Internal.IntListAdapter<\n"
" $type$>($name$_, $name$_converter_);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_COUNT,
Expand All @@ -804,7 +802,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
printer->Print(
variables_,
"$deprecation$public $type$ ${$get$capitalized_name$$}$(int index) {\n"
" return $name$_converter_.convert($name$_.get(index));\n"
" return $name$_converter_.convert($name$_.getInt(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_SETTER,
Expand All @@ -817,7 +815,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" throw new NullPointerException();\n"
" }\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.set(index, value.getNumber());\n"
" $name$_.setInt(index, value.getNumber());\n"
" onChanged();\n"
" return this;\n"
"}\n");
Expand All @@ -832,7 +830,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" throw new NullPointerException();\n"
" }\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value.getNumber());\n"
" $name$_.addInt(value.getNumber());\n"
" onChanged();\n"
" return this;\n"
"}\n");
Expand All @@ -845,7 +843,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" java.lang.Iterable<? extends $type$> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" for ($type$ value : values) {\n"
" $name$_.add(value.getNumber());\n"
" $name$_.addInt(value.getNumber());\n"
" }\n"
" onChanged();\n"
" return this;\n"
Expand All @@ -857,7 +855,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
printer->Print(
variables_,
"$deprecation$public Builder ${$clear$capitalized_name$$}$() {\n"
" $name$_ = java.util.Collections.emptyList();\n"
" $name$_ = emptyIntList();\n"
" $clear_mutable_bit_builder$;\n"
" onChanged();\n"
" return this;\n"
Expand All @@ -878,7 +876,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
printer->Print(variables_,
"$deprecation$public int "
"${$get$capitalized_name$Value$}$(int index) {\n"
" return $name$_.get(index);\n"
" return $name$_.getInt(index);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
WriteFieldEnumValueAccessorDocComment(
Expand All @@ -889,7 +887,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
"$deprecation$public Builder ${$set$capitalized_name$Value$}$(\n"
" int index, int value) {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.set(index, value);\n"
" $name$_.setInt(index, value);\n"
" onChanged();\n"
" return this;\n"
"}\n");
Expand All @@ -901,7 +899,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
"$deprecation$public Builder "
"${$add$capitalized_name$Value$}$(int value) {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(value);\n"
" $name$_.addInt(value);\n"
" onChanged();\n"
" return this;\n"
"}\n");
Expand All @@ -915,7 +913,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderMembers(
" java.lang.Iterable<java.lang.Integer> values) {\n"
" ensure$capitalized_name$IsMutable();\n"
" for (int value : values) {\n"
" $name$_.add(value);\n"
" $name$_.addInt(value);\n"
" }\n"
" onChanged();\n"
" return this;\n"
Expand All @@ -931,13 +929,13 @@ void RepeatedImmutableEnumFieldGenerator::

void RepeatedImmutableEnumFieldGenerator::GenerateInitializationCode(
io::Printer* printer) const {
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n");
printer->Print(variables_, "$name$_ = emptyIntList();\n");
}

void RepeatedImmutableEnumFieldGenerator::GenerateBuilderClearCode(
io::Printer* printer) const {
printer->Print(variables_,
"$name$_ = java.util.Collections.emptyList();\n"
"$name$_ = emptyIntList();\n"
"$clear_mutable_bit_builder$;\n");
}

Expand Down Expand Up @@ -965,13 +963,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuildingCode(
io::Printer* printer) const {
// 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.
printer->Print(
variables_,
"if ($get_mutable_bit_builder$) {\n"
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n"
" $clear_mutable_bit_builder$;\n"
"}\n"
"result.$name$_ = $name$_;\n");
printer->Print(variables_,
"if ($get_mutable_bit_builder$) {\n"
" $name$_.makeImmutable();\n"
" $clear_mutable_bit_builder$;\n"
"}\n"
"result.$name$_ = $name$_;\n");
}

void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
Expand All @@ -981,7 +978,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
printer->Print(variables_,
"int tmpRaw = input.readEnum();\n"
"ensure$capitalized_name$IsMutable();\n"
"$name$_.add(tmpRaw);\n");
"$name$_.addInt(tmpRaw);\n");
} else {
printer->Print(variables_,
"int tmpRaw = input.readEnum();\n"
Expand All @@ -991,7 +988,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
" mergeUnknownVarintField($number$, tmpRaw);\n"
"} else {\n"
" ensure$capitalized_name$IsMutable();\n"
" $name$_.add(tmpRaw);\n"
" $name$_.addInt(tmpRaw);\n"
"}\n");
}
}
Expand Down Expand Up @@ -1022,12 +1019,12 @@ void RepeatedImmutableEnumFieldGenerator::GenerateSerializationCode(
" output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
"}\n"
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.writeEnumNoTag($name$_.get(i));\n"
" output.writeEnumNoTag($name$_.getInt(i));\n"
"}\n");
} else {
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
" output.writeEnum($number$, $name$_.get(i));\n"
" output.writeEnum($number$, $name$_.getInt(i));\n"
"}\n");
}
}
Expand All @@ -1042,7 +1039,7 @@ void RepeatedImmutableEnumFieldGenerator::GenerateSerializedSizeCode(
printer->Print(variables_,
"for (int i = 0; i < $name$_.size(); i++) {\n"
" dataSize += com.google.protobuf.CodedOutputStream\n"
" .computeEnumSizeNoTag($name$_.get(i));\n"
" .computeEnumSizeNoTag($name$_.getInt(i));\n"
"}\n");
printer->Print("size += dataSize;\n");
if (descriptor_->is_packed()) {
Expand Down

0 comments on commit cc79f77

Please sign in to comment.