Internal change.

PiperOrigin-RevId: 972290345
diff --git a/src/google/protobuf/compiler/java/full/field_generator.cc b/src/google/protobuf/compiler/java/full/field_generator.cc
index a72b7be..bf830ee 100644
--- a/src/google/protobuf/compiler/java/full/field_generator.cc
+++ b/src/google/protobuf/compiler/java/full/field_generator.cc
@@ -1,6 +1,7 @@
 #include "google/protobuf/compiler/java/full/field_generator.h"
 
 #include "google/protobuf/compiler/java/context.h"
+#include "google/protobuf/compiler/java/helpers.h"
 #include "google/protobuf/compiler/java/name_resolver.h"
 
 namespace google {
@@ -15,6 +16,14 @@
       context_(context),
       name_resolver_(context->GetNameResolver()) {}
 
+bool ImmutableFieldGenerator::HasHasbit() const {
+  return ::google::protobuf::compiler::java::HasHasbit(descriptor_);
+}
+
+bool ImmutableFieldGenerator::IsRealOneof() const {
+  return ::google::protobuf::compiler::java::IsRealOneof(descriptor_);
+}
+
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/full/field_generator.h b/src/google/protobuf/compiler/java/full/field_generator.h
index fddc8d5..193acb8 100644
--- a/src/google/protobuf/compiler/java/full/field_generator.h
+++ b/src/google/protobuf/compiler/java/full/field_generator.h
@@ -23,6 +23,9 @@
   ImmutableFieldGenerator& operator=(const ImmutableFieldGenerator&) = delete;
   ~ImmutableFieldGenerator() override = default;
 
+  bool HasHasbit() const;
+  bool IsRealOneof() const;
+
   int GetBitIndex() const { return bit_index_; }
   constexpr int GetNumBits() const { return 1; }
   virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0;
diff --git a/src/google/protobuf/compiler/java/full/make_field_gens.cc b/src/google/protobuf/compiler/java/full/make_field_gens.cc
index e88deb6..0c11451 100644
--- a/src/google/protobuf/compiler/java/full/make_field_gens.cc
+++ b/src/google/protobuf/compiler/java/full/make_field_gens.cc
@@ -86,7 +86,13 @@
     }
   }
 }
-
+bool HasExplicitPresence(const FieldDescriptor* field) {
+  return HasHasbit(field);
+}
+bool HasNoPresence(const FieldDescriptor* field) { return IsRealOneof(field); }
+bool HasHintBitFields(const FieldDescriptor* field) {
+  return !HasExplicitPresence(field) && !HasNoPresence(field);
+}
 }  // namespace
 
 FieldGeneratorMap<ImmutableFieldGenerator> MakeImmutableFieldGenerators(
@@ -95,11 +101,35 @@
   // bit fields.
   int bit_index = 0;
   FieldGeneratorMap<ImmutableFieldGenerator> ret(descriptor);
+
+  // First pass: fields with real presence bits.
   for (int i = 0; i < descriptor->field_count(); i++) {
     const FieldDescriptor* field = descriptor->field(i);
-    auto generator = MakeImmutableGenerator(field, bit_index, context);
-    bit_index += generator->GetNumBits();
-    ret.Add(field, std::move(generator));
+    if (HasExplicitPresence(field)) {
+      auto generator = MakeImmutableGenerator(field, bit_index, context);
+      bit_index += generator->GetNumBits();
+      ret.Add(field, std::move(generator));
+    }
+  }
+
+  // Second pass: fields with hint presence bits.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (HasHintBitFields(field)) {
+      auto generator = MakeImmutableGenerator(field, bit_index, context);
+      bit_index += generator->GetNumBits();
+      ret.Add(field, std::move(generator));
+    }
+  }
+
+  // Third pass: fields with no presence tracking.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    const FieldDescriptor* field = descriptor->field(i);
+    if (HasNoPresence(field)) {
+      auto generator = MakeImmutableGenerator(field, bit_index, context);
+      bit_index += generator->GetNumBits();
+      ret.Add(field, std::move(generator));
+    }
   }
   return ret;
 }
diff --git a/src/google/protobuf/compiler/java/full/message_builder.cc b/src/google/protobuf/compiler/java/full/message_builder.cc
index 6781472..801e67f 100644
--- a/src/google/protobuf/compiler/java/full/message_builder.cc
+++ b/src/google/protobuf/compiler/java/full/message_builder.cc
@@ -18,10 +18,7 @@
 #include <vector>
 
 #include "absl/container/btree_map.h"
-#include "absl/container/btree_set.h"
-#include "absl/container/flat_hash_map.h"
 #include "absl/log/absl_check.h"
-#include "absl/strings/ascii.h"
 #include "absl/strings/str_cat.h"
 #include "absl/strings/str_replace.h"
 #include "absl/strings/string_view.h"
@@ -30,7 +27,7 @@
 #include "google/protobuf/compiler/java/context.h"
 #include "google/protobuf/compiler/java/doc_comment.h"
 #include "google/protobuf/compiler/java/field_common.h"
-#include "google/protobuf/compiler/java/generator_factory.h"
+#include "google/protobuf/compiler/java/generator_common.h"
 #include "google/protobuf/compiler/java/helpers.h"
 #include "google/protobuf/compiler/java/full/enum.h"
 #include "google/protobuf/compiler/java/full/extension.h"
@@ -584,9 +581,8 @@
       "classname", name_resolver_->GetImmutableClassName(descriptor_));
 
   // Build all fields in shards organized by bitfield membership.
-  int start_field = 0;
   for (int i = 0; i < totalInts; i++) {
-    start_field = GenerateBuildPartialShard(printer, i, start_field);
+    GenerateBuildPartialShard(printer, i);
   }
 
   // Build Oneofs
@@ -603,50 +599,35 @@
   }
 }
 
-int MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
-                                                       int shard,
-                                                       int first_field) {
+void MessageBuilderGenerator::GenerateBuildPartialShard(io::Printer* printer,
+                                                        int shard) {
   printer->Print(
       "private void buildPartial_autosplit_$shard$($classname$ result) {\n"
-      "  int from_$bit_field_name$ = $bit_field_name$;\n",
+      "  int from_$bit_field_name$ = $bit_field_name$;\n"
+      "  int to_$bit_field_name$ = 0;\n",
       "classname", name_resolver_->GetImmutableClassName(descriptor_), "shard",
       absl::StrCat(shard), "bit_field_name", GetBitFieldName(shard));
   printer->Indent();
-  absl::btree_set<int> declared_to_bitfields;
-
-  int bit = 0;
-  int next = first_field;
-  for (; bit < 32 && next < descriptor_->field_count(); ++next, ++bit) {
+  int i = shard * 32;
+  int shard_end = std::min(i + 32, static_cast<int>(field_generators_.size()));
+  for (; i < shard_end; ++i) {
     const ImmutableFieldGenerator& field =
-        field_generators_.get(descriptor_->field(next));
+        field_generators_.getInInsertOrder(i);
 
-    // Skip oneof fields that are handled separately
-    if (IsRealOneof(descriptor_->field(next))) {
+    // Currently oneofs are not built in shards.
+    if (field.IsRealOneof()) {
       continue;
     }
-
-    // Track message bits if necessary
-    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
     field.GenerateBuildingCode(printer);
   }
+  printer->Outdent();
 
   // Copy the bit field results to the generated message
-  for (int to_bitfield : declared_to_bitfields) {
-    printer->Print("result.$bit_field_name$ |= to_$bit_field_name$;\n",
-                   "bit_field_name", GetBitFieldName(to_bitfield));
-  }
-
-  printer->Outdent();
-  printer->Print("}\n\n");
-
-  return next;
+  printer->Print(
+      "  result.$bit_field_name$ |= to_$bit_field_name$;\n"
+      "}\n\n",
+      "bit_field_name", GetBitFieldName(shard));
 }
 
 // ===================================================================
diff --git a/src/google/protobuf/compiler/java/full/message_builder.h b/src/google/protobuf/compiler/java/full/message_builder.h
index e793fe3..b338f90 100644
--- a/src/google/protobuf/compiler/java/full/message_builder.h
+++ b/src/google/protobuf/compiler/java/full/message_builder.h
@@ -14,11 +14,11 @@
 
 #include <memory>
 #include <string>
-#include <vector>
 
 #include "absl/container/btree_map.h"
 #include "absl/strings/string_view.h"
 #include "absl/types/span.h"
+#include "google/protobuf/compiler/java/generator_common.h"
 #include "google/protobuf/compiler/java/full/field_generator.h"
 #include "google/protobuf/compiler/java/full/oneof_generator.h"
 #include "google/protobuf/descriptor.h"
@@ -67,8 +67,7 @@
       io::Printer* printer, absl::Span<const std::string> merging_code_blocks,
       absl::string_view method_suffix);
   void GenerateBuildPartial(io::Printer* printer);
-  int GenerateBuildPartialShard(io::Printer* printer, int shard,
-                                int first_field);
+  void GenerateBuildPartialShard(io::Printer* printer, int shard);
   void GenerateDescriptorMethods(io::Printer* printer);
   void GenerateBuilderParsingMethods(io::Printer* printer);
   void GenerateBuilderFieldParsingCases(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/generator_common.h b/src/google/protobuf/compiler/java/generator_common.h
index 7ec12c1..0ff66d9 100644
--- a/src/google/protobuf/compiler/java/generator_common.h
+++ b/src/google/protobuf/compiler/java/generator_common.h
@@ -30,11 +30,12 @@
  public:
   explicit FieldGeneratorMap(const Descriptor* descriptor)
       : descriptor_(descriptor) {
-    field_generators_.reserve(static_cast<size_t>(descriptor->field_count()));
+    insert_order_.reserve(static_cast<size_t>(descriptor->field_count()));
+    index_order_.resize(static_cast<size_t>(descriptor->field_count()));
   }
 
   ~FieldGeneratorMap() {
-    for (const auto* g : field_generators_) {
+    for (const auto* g : insert_order_) {
       delete g;
     }
   }
@@ -45,21 +46,28 @@
   FieldGeneratorMap(const FieldGeneratorMap&) = delete;
   FieldGeneratorMap& operator=(const FieldGeneratorMap&) = delete;
 
+  size_t size() const { return insert_order_.size(); }
+
   void Add(const FieldDescriptor* field,
            std::unique_ptr<FieldGeneratorType> field_generator) {
     ABSL_CHECK_EQ(field->containing_type(), descriptor_);
-    field_generators_.push_back(field_generator.release());
+    insert_order_.push_back(field_generator.release());
+    index_order_[static_cast<size_t>(field->index())] = insert_order_.back();
   }
 
   const FieldGeneratorType& get(const FieldDescriptor* field) const {
     ABSL_CHECK_EQ(field->containing_type(), descriptor_);
-    return *field_generators_[static_cast<size_t>(field->index())];
+    return *index_order_[static_cast<size_t>(field->index())];
+  }
+
+  const FieldGeneratorType& getInInsertOrder(int index) const {
+    return *insert_order_[static_cast<size_t>(index)];
   }
 
   std::vector<const FieldGenerator*> field_generators() const {
     std::vector<const FieldGenerator*> field_generators;
-    field_generators.reserve(field_generators_.size());
-    for (const auto* g : field_generators_) {
+    field_generators.reserve(index_order_.size());
+    for (const auto* g : index_order_) {
       field_generators.push_back(g);
     }
     return field_generators;
@@ -67,7 +75,8 @@
 
  private:
   const Descriptor* descriptor_;
-  std::vector<const FieldGeneratorType*> field_generators_;
+  std::vector<const FieldGeneratorType*> insert_order_;
+  std::vector<const FieldGeneratorType*> index_order_;
 };
 
 inline void ReportUnexpectedPackedFieldsCall() {