Use monomorphic static dispatch for Java Protobuf submessage parsing

PiperOrigin-RevId: 970550003
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index 033187a..0189b8e 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -609,7 +609,7 @@
   @CanIgnoreReturnValue
   public abstract int pushLimit(int byteLimit) throws InvalidProtocolBufferException;
 
-  final int pushLimitBeforeMessage() throws IOException {
+  public final int pushLimitBeforeMessage() throws IOException {
     final int length = readRawVarint32();
     checkRecursionLimit();
     final int oldLimit = pushLimit(length);
@@ -624,7 +624,7 @@
    */
   public abstract void popLimit(final int oldLimit);
 
-  final void popLimitAfterMessage(int oldLimit) throws IOException {
+  public final void popLimitAfterMessage(int oldLimit) throws IOException {
     checkLastTagWas(0);
     --messageDepth;
     if (getBytesUntilLimit() != 0) {
diff --git a/src/google/protobuf/compiler/java/full/message_field.cc b/src/google/protobuf/compiler/java/full/message_field.cc
index 1ca8782..26cb67a 100644
--- a/src/google/protobuf/compiler/java/full/message_field.cc
+++ b/src/google/protobuf/compiler/java/full/message_field.cc
@@ -11,6 +11,7 @@
 
 #include "google/protobuf/compiler/java/full/message_field.h"
 
+#include <cstdint>
 #include <string>
 
 #include "absl/log/absl_check.h"
@@ -85,6 +86,8 @@
   (*variables)["get_has_field_bit_from_local"] =
       GenerateGetBitFromLocal(bit_index);
 
+  (*variables)["tag"] = absl::StrCat(
+      static_cast<int32_t>(internal::WireFormat::MakeTag(descriptor)));
   (*variables)["tag_size"] = absl::StrCat(
       internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
 }
@@ -181,6 +184,29 @@
   GenerateHasMethod(printer);
   GenerateGetMethod(printer);
   GenerateGetOrBuilderMethod(printer);
+  GenerateWriteFieldMethod(printer);
+}
+
+void ImmutableMessageFieldGenerator::GenerateWriteFieldMethod(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  output.writeGroup($number$, get$capitalized_name$());\n"
+                   "}\n");
+  } else {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  $type$ tmp = get$capitalized_name$();\n"
+                   "  output.writeUInt32NoTag($tag$);\n"
+                   "  output.writeUInt32NoTag(tmp.getSerializedSize());\n"
+                   "  tmp.writeTo(output);\n"
+                   "}\n");
+  }
 }
 
 void ImmutableMessageFieldGenerator::PrintNestedBuilderCondition(
@@ -394,14 +420,15 @@
   } else {
     printer->Print(
         variables_,
+        "final int oldLimit = input.pushLimitBeforeMessage();\n"
         "if ($name$_ != null || $name$Builder_ != null) {\n"
-        "  input.readMessage(\n"
-        "      "
-        "internalGet$capitalized_name$FieldBuilder().getBuilder(),\n"
-        "      extensionRegistry);\n"
+        "  internalGet$capitalized_name$FieldBuilder().getBuilder()\n"
+        "      .mergeFrom(input, extensionRegistry);\n"
         "} else {\n"
-        "  $name$_ = input.readMessage($type$.parser(), extensionRegistry);\n"
+        "  $name$_ = $type$.parser().parsePartialFrom(input, "
+        "extensionRegistry);\n"
         "}\n"
+        "input.popLimitAfterMessage(oldLimit);\n"
         "$set_has_field_bit$\n");
   }
   printer->Outdent();
@@ -482,11 +509,10 @@
 
 void ImmutableMessageFieldGenerator::GenerateSerializationCode(
     io::Printer* printer) const {
-  printer->Print(
-      variables_,
-      "if ($is_field_present$) {\n"
-      "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
-      "}\n");
+  printer->Print(variables_,
+                 "if ($is_field_present$) {\n"
+                 "  write$capitalized_name$Field(output);\n"
+                 "}\n");
 }
 
 void ImmutableMessageFieldGenerator::GenerateSerializedSizeCode(
@@ -578,6 +604,29 @@
   GenerateHasMethod(printer);
   GenerateGetMethod(printer);
   GenerateGetOrBuilderMethod(printer);
+  GenerateWriteFieldMethod(printer);
+}
+
+void ImmutableMessageOneofFieldGenerator::GenerateWriteFieldMethod(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  output.writeGroup($number$, ($type$) $oneof_name$_);\n"
+                   "}\n");
+  } else {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  $type$ tmp = ($type$) $oneof_name$_;\n"
+                   "  output.writeUInt32NoTag($tag$);\n"
+                   "  output.writeUInt32NoTag(tmp.getSerializedSize());\n"
+                   "  tmp.writeTo(output);\n"
+                   "}\n");
+  }
 }
 
 void ImmutableMessageOneofFieldGenerator::GenerateBuilderHasMethod(
@@ -826,11 +875,10 @@
 
 void ImmutableMessageOneofFieldGenerator::GenerateSerializationCode(
     io::Printer* printer) const {
-  printer->Print(
-      variables_,
-      "if ($has_oneof_case_message$) {\n"
-      "  output.write$group_or_message$($number$, ($type$) $oneof_name$_);\n"
-      "}\n");
+  printer->Print(variables_,
+                 "if ($has_oneof_case_message$) {\n"
+                 "  write$capitalized_name$Field(output);\n"
+                 "}\n");
 }
 
 void ImmutableMessageOneofFieldGenerator::GenerateSerializedSizeCode(
@@ -982,6 +1030,33 @@
   GenerateGetCountMethod(printer);
   GenerateGetMethod(printer);
   GenerateGetOrBuilderMethod(printer);
+  GenerateWriteFieldMethod(printer);
+}
+
+void RepeatedImmutableMessageFieldGenerator::GenerateWriteFieldMethod(
+    io::Printer* printer) const {
+  if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  for (int i = 0; i < $name$_.size(); i++) {\n"
+                   "    output.writeGroup($number$, $name$_.get(i));\n"
+                   "  }\n"
+                   "}\n");
+  } else {
+    printer->Print(variables_,
+                   "private void write$capitalized_name$Field(\n"
+                   "    com.google.protobuf.CodedOutputStream output)\n"
+                   "    throws java.io.IOException {\n"
+                   "  for (int i = 0; i < $name$_.size(); i++) {\n"
+                   "    $type$ tmp = $name$_.get(i);\n"
+                   "    output.writeUInt32NoTag($tag$);\n"
+                   "    output.writeUInt32NoTag(tmp.getSerializedSize());\n"
+                   "    tmp.writeTo(output);\n"
+                   "  }\n"
+                   "}\n");
+  }
 }
 
 void RepeatedImmutableMessageFieldGenerator::GenerateEnsureIsMutableMethod(
@@ -1436,10 +1511,10 @@
                    "        extensionRegistry);\n");
   } else {
     printer->Print(variables_,
-                   "$type$ m =\n"
-                   "    input.readMessage(\n"
-                   "        $type$.$get_parser$,\n"
-                   "        extensionRegistry);\n");
+                   "final int oldLimit = input.pushLimitBeforeMessage();\n"
+                   "$type$ m = $type$.parser().parsePartialFrom(input, "
+                   "extensionRegistry);\n"
+                   "input.popLimitAfterMessage(oldLimit);\n");
   }
   PrintNestedBuilderCondition(printer,
                               "ensure$capitalized_name$IsMutable();\n"
@@ -1451,10 +1526,7 @@
 
 void RepeatedImmutableMessageFieldGenerator::GenerateSerializationCode(
     io::Printer* printer) const {
-  printer->Print(variables_,
-                 "for (int i = 0; i < $name$_.size(); i++) {\n"
-                 "  output.write$group_or_message$($number$, $name$_.get(i));\n"
-                 "}\n");
+  printer->Print(variables_, "write$capitalized_name$Field(output);\n");
 }
 
 void RepeatedImmutableMessageFieldGenerator::GenerateSerializedSizeCode(
diff --git a/src/google/protobuf/compiler/java/full/message_field.h b/src/google/protobuf/compiler/java/full/message_field.h
index dd00288..c14b32e 100644
--- a/src/google/protobuf/compiler/java/full/message_field.h
+++ b/src/google/protobuf/compiler/java/full/message_field.h
@@ -83,6 +83,7 @@
   void GenerateHasMethod(io::Printer* printer) const;
   void GenerateGetMethod(io::Printer* printer) const;
   void GenerateGetOrBuilderMethod(io::Printer* printer) const;
+  void GenerateWriteFieldMethod(io::Printer* printer) const;
 
   void GenerateBuilderHasMethod(io::Printer* printer) const;
   void GenerateBuilderGetMethod(io::Printer* printer) const;
@@ -120,6 +121,7 @@
   void GenerateHasMethod(io::Printer* printer) const;
   void GenerateGetMethod(io::Printer* printer) const;
   void GenerateGetOrBuilderMethod(io::Printer* printer) const;
+  void GenerateWriteFieldMethod(io::Printer* printer) const;
 
   void GenerateBuilderHasMethod(io::Printer* printer) const;
   void GenerateBuilderGetMethod(io::Printer* printer) const;
@@ -173,6 +175,7 @@
   void GenerateGetMethod(io::Printer* printer) const;
   void GenerateGetOrBuilderListMethod(io::Printer* printer) const;
   void GenerateGetOrBuilderMethod(io::Printer* printer) const;
+  void GenerateWriteFieldMethod(io::Printer* printer) const;
 
   void GenerateEnsureIsMutableMethod(io::Printer* printer) const;
   void GenerateBuilderGetListMethod(io::Printer* printer) const;