New feature: weak descriptor based types.

This feature allows for tree shaking within a single .proto file, dropping
unused types while still allowing reflection to work for them via the generated
DescriptorPool.

PiperOrigin-RevId: 587066283
diff --git a/src/google/protobuf/compiler/cpp/file.cc b/src/google/protobuf/compiler/cpp/file.cc
index 0ef0e64..df46703 100644
--- a/src/google/protobuf/compiler/cpp/file.cc
+++ b/src/google/protobuf/compiler/cpp/file.cc
@@ -922,6 +922,26 @@
   IncludeFile("third_party/protobuf/port_undef.inc", p);
 }
 
+static std::vector<const Descriptor*>
+GetMessagesToPinGloballyForWeakDescriptors(const FileDescriptor* file) {
+  std::vector<const Descriptor*> out;
+
+  // For simplicity we force pin request/response messages for all
+  // services. The current implementation of services might not do
+  // the pin itself, so it is simpler.
+  // This is a place for improvement in the future.
+  for (int i = 0; i < file->service_count(); ++i) {
+    auto* service = file->service(i);
+    for (int j = 0; j < service->method_count(); ++j) {
+      auto* method = service->method(j);
+      out.push_back(method->input_type());
+      out.push_back(method->output_type());
+    }
+  }
+
+  return out;
+}
+
 void FileGenerator::GenerateReflectionInitializationCode(io::Printer* p) {
   if (!message_generators_.empty()) {
     p->Emit({{"len", message_generators_.size()}}, R"cc(
@@ -955,6 +975,8 @@
   if (!message_generators_.empty()) {
     std::vector<std::pair<size_t, size_t>> offsets;
     offsets.reserve(message_generators_.size());
+    bool has_implicit_weak_descriptors =
+        UsingImplicitWeakDescriptor(file_, options_);
 
     p->Emit(
         {
@@ -973,19 +995,50 @@
                  offset += offsets[i].first;
                }
              }},
-            {"defaults",
+            {"weak_defaults",
              [&] {
+               if (!has_implicit_weak_descriptors) return;
+               int index = 0;
                for (auto& gen : message_generators_) {
                  p->Emit(
                      {
+                         {"index", index++},
                          {"ns", Namespace(gen->descriptor(), options_)},
                          {"class", ClassName(gen->descriptor())},
+                         {"section", WeakDefaultWriterSection(gen->descriptor(),
+                                                              options_)},
                      },
                      R"cc(
-                       &$ns$::_$class$_default_instance_._instance,
+                       constexpr ::_pbi::WeakDefaultWriter pb_$index$_weak_
+                           __attribute__((__nodebug__))
+                           __attribute__((section("$section$"))) = {
+                               file_default_instances + $index$,
+                               &$ns$::_$class$_default_instance_._instance};
                      )cc");
                }
              }},
+            {"defaults",
+             [&] {
+               for (auto& gen : message_generators_) {
+                 if (has_implicit_weak_descriptors) {
+                   p->Emit(R"cc(
+                     nullptr,
+                   )cc");
+                 } else {
+                   p->Emit(
+                       {
+                           {"ns", Namespace(gen->descriptor(), options_)},
+                           {"class", ClassName(gen->descriptor())},
+                       },
+                       R"cc(
+                         &$ns$::_$class$_default_instance_._instance,
+                       )cc");
+                 }
+               }
+             }},
+            // When we have implicit weak descriptors we make the array mutable
+            // for dynamic initialization.
+            {"const", has_implicit_weak_descriptors ? "" : "const"},
         },
         R"cc(
           const ::uint32_t
@@ -999,9 +1052,10 @@
                   $schemas$,
           };
 
-          static const ::_pb::Message* const file_default_instances[] = {
+          static const ::_pb::Message* $const $file_default_instances[] = {
               $defaults$,
           };
+          $weak_defaults$;
         )cc");
   } else {
     // Ee still need these symbols to exist.
@@ -1169,12 +1223,41 @@
   // pull in a lot of unnecessary code that can't be stripped by --gc-sections.
   // Descriptor initialization will still be performed lazily when it's needed.
   if (!IsLazilyInitializedFile(file_->name())) {
-    p->Emit({{"dummy", UniqueName("dynamic_init_dummy", file_, options_)}},
-            R"cc(
-              // Force running AddDescriptors() at dynamic initialization time.
-              PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
-              static ::_pbi::AddDescriptorsRunner $dummy$(&$desc_table$);
-            )cc");
+    p->Emit(
+        {
+            {"dummy", UniqueName("dynamic_init_dummy", file_, options_)},
+            {"desc_table_expr",
+             [&] {
+               std::vector<const Descriptor*> pinned_messages;
+               if (UsingImplicitWeakDescriptor(file_, options_)) {
+                 pinned_messages =
+                     GetMessagesToPinGloballyForWeakDescriptors(file_);
+               }
+               if (pinned_messages.empty()) {
+                 p->Emit("&$desc_table$");
+               } else {
+                 p->Emit({{"pinned",
+                           [&] {
+                             for (const auto* pinned : pinned_messages) {
+                               p->Emit(
+                                   {
+                                       {"default", QualifiedDefaultInstanceName(
+                                                       pinned, options_)},
+                                   },
+                                   R"cc(
+                                     ::_pbi::StrongPointer(&$default$),
+                                   )cc");
+                             }
+                           }}},
+                         "($pinned$, &$desc_table$)");
+               }
+             }},
+        },
+        R"cc(
+          // Force running AddDescriptors() at dynamic initialization time.
+          PROTOBUF_ATTRIBUTE_INIT_PRIORITY2
+          static ::_pbi::AddDescriptorsRunner $dummy$($desc_table_expr$);
+        )cc");
   }
 
   // However, we must provide a way to force initialize the default instances
diff --git a/src/google/protobuf/compiler/cpp/generator.cc b/src/google/protobuf/compiler/cpp/generator.cc
index cc0f8af..32d2a2c 100644
--- a/src/google/protobuf/compiler/cpp/generator.cc
+++ b/src/google/protobuf/compiler/cpp/generator.cc
@@ -139,6 +139,8 @@
       if (!value.empty()) {
         file_options.num_cc_files = std::strtol(value.c_str(), nullptr, 10);
       }
+    } else if (key == "descriptor_implicit_weak_messages") {
+      file_options.descriptor_implicit_weak_messages = true;
     } else if (key == "proto_h") {
       file_options.proto_h = true;
     } else if (key == "proto_static_reflection_h") {
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index 7428660..79d4768 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -1480,6 +1480,32 @@
   return false;
 }
 
+bool UsingImplicitWeakDescriptor(const FileDescriptor* file,
+                                 const Options& options) {
+  return HasDescriptorMethods(file, options) &&
+         !IsBootstrapProto(options, file) &&
+         options.descriptor_implicit_weak_messages &&
+         !options.opensource_runtime;
+}
+
+std::string WeakDefaultWriterSection(const Descriptor* descriptor,
+                                     const Options& options) {
+  const auto* file = descriptor->file();
+
+  // To make a compact name we use the index of the object in its parent instead
+  // of its name, recursively until we reach the root.
+  // So the name could be `pb_def_1_2_1_0_HASH` instead of
+  // `pd_def_VeryLongClassName_WithNesting_AndMoreNames_HASH`
+  // We need a know common prefix to merge the sections later on.
+  std::string prefix = "pb_def";
+  do {
+    absl::StrAppend(&prefix, "_", descriptor->index());
+    descriptor = descriptor->containing_type();
+  } while (descriptor != nullptr);
+
+  return UniqueName(prefix, file, options);
+}
+
 bool UsingImplicitWeakFields(const FileDescriptor* file,
                              const Options& options) {
   return options.lite_implicit_weak_fields &&
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h
index e3e7bf6..5815b4a 100644
--- a/src/google/protobuf/compiler/cpp/helpers.h
+++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -734,6 +734,60 @@
 void ListAllTypesForServices(const FileDescriptor* fd,
                              std::vector<const Descriptor*>* types);
 
+// Whether this type should use the implicit weak feature for descriptor based
+// objects.
+//
+// This feature allows tree shaking within a single translation unit by
+// decoupling the messages from the TU-wide `file_default_instances` array.
+// This way there are no static initializers in the TU pointing to any part of
+// the generated classes and they can be GC'd by the linker.
+// Instead, we inject the surviving messages by having `WeakDefaultWriter`
+// objects in a special `pb_defaults` section. The runtime will iterate this
+// section to see the list of all live objects and put them back into the
+// `file_default_instances` array.
+//
+// Any object that gets GC'd will have a `nullptr` in the respective slot in the
+// `file_default_instances` array. The runtime will recognize this and will
+// dynamically generate the object if needed. This logic is in the
+// `GeneratedMessageFactory::GetPrototype`.  It will fall back to a
+// `DynamicMessage` for the missing objects.
+// This allows all of reflection to keep working normally, even for types that
+// were dropped. Note that dropping the _classes_ will not drop the descriptor
+// information. The messages are still going to be registered in the generated
+// `DescriptorPool` and will be available via normal `FindMessageTypeByName` and
+// friends.
+//
+// A "pin" is adding dependency edge in the graph for the GC.
+// The `WeakDefaultWriter`, the default instance, and vtable of a message all
+// pin each other. If anyone lives, they all do. This is important.
+// The `WeakDefaultWriter` pins the default instance of the message by using it.
+// The default instance of the message pins the vtable trivially by using it.
+// The vtable pins the `WeakDefaultWriter` by having a StrongPointer into it
+// from any of the virtual functions.
+//
+// All parent messages pin their children.
+// SPEED messages do this implicitly via the TcParseTable, which contain
+// pointers to the submessages.
+// CODE_SIZE messages explicitly add a pin via `StrongPointer` somewhere in
+// their codegen.
+// LITE messages do not participate at all in this feature.
+//
+// For extensions, the identifiers currently pin both the extended and extendee
+// messages. This is the status quo, but not the desired end state which should
+// change in a future update to the feature.
+//
+// For services, the TU unconditionally pins the request/response objects.
+// This is the status quo for simplicitly to avoid modifying the RPC layer. It
+// might be improved in the future.
+bool UsingImplicitWeakDescriptor(const FileDescriptor* file,
+                                 const Options& options);
+
+// Section name to be used for the DefaultWriter object for implicit weak
+// descriptor objects.
+// See `UsingImplicitWeakDescriptor` above.
+std::string WeakDefaultWriterSection(const Descriptor* descriptor,
+                                     const Options& options);
+
 // Indicates whether we should use implicit weak fields for this file.
 bool UsingImplicitWeakFields(const FileDescriptor* file,
                              const Options& options);
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index e78326f..d5fb7af 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -2057,30 +2057,50 @@
   auto v = p->WithVars(ClassVars(descriptor_, options_));
   auto t = p->WithVars(MakeTrackerCalls(descriptor_, options_));
   Formatter format(p);
+
+  const auto pin_weak_writer = [&] {
+    if (!UsingImplicitWeakDescriptor(descriptor_->file(), options_)) return;
+    p->Emit({{"index", index_in_file_messages_}},
+            R"cc(
+              ::_pbi::StrongPointer(&pb_$index$_weak_);
+            )cc");
+
+    // For CODE_SIZE types, we need to pin the submessages too.
+    // SPEED types will pin them via the TcParse table automatically.
+    if (HasGeneratedMethods(descriptor_->file(), options_)) return;
+    for (int i = 0; i < descriptor_->field_count(); ++i) {
+      auto* field = descriptor_->field(i);
+      if (field->type() != field->TYPE_MESSAGE) continue;
+      p->Emit(
+          {
+              {"sub_default_name",
+               QualifiedDefaultInstanceName(field->message_type(), options_)},
+          },
+          R"cc(
+            ::_pbi::StrongPointer(&$sub_default_name$);
+          )cc");
+    }
+  };
+
   if (IsMapEntryMessage(descriptor_)) {
     format(
         "$classname$::$classname$() {}\n"
         "$classname$::$classname$(::$proto_ns$::Arena* arena)\n"
         "    : SuperType(arena) {}\n");
     if (HasDescriptorMethods(descriptor_->file(), options_)) {
-      if (!descriptor_->options().map_entry()) {
-        format(
-            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-            "$annotate_reflection$"
-            "  return ::_pbi::AssignDescriptors(\n"
-            "      &$desc_table$_getter, &$desc_table$_once,\n"
-            "      $file_level_metadata$[$1$]);\n"
-            "}\n",
-            index_in_file_messages_);
-      } else {
-        format(
-            "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-            "  return ::_pbi::AssignDescriptors(\n"
-            "      &$desc_table$_getter, &$desc_table$_once,\n"
-            "      $file_level_metadata$[$1$]);\n"
-            "}\n",
-            index_in_file_messages_);
-      }
+      p->Emit(
+          {
+              {"pin_weak_writer", pin_weak_writer},
+              {"index", index_in_file_messages_},
+          },
+          R"cc(
+            ::$proto_ns$::Metadata $classname$::GetMetadata() const {
+              $pin_weak_writer$;
+              return ::_pbi::AssignDescriptors(&$desc_table$_getter,
+                                               &$desc_table$_once,
+                                               $file_level_metadata$[$index$]);
+            }
+          )cc");
     }
     return;
   }
@@ -2203,24 +2223,20 @@
   format("\n");
 
   if (HasDescriptorMethods(descriptor_->file(), options_)) {
-    if (!descriptor_->options().map_entry()) {
-      format(
-          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-          "$annotate_reflection$"
-          "  return ::_pbi::AssignDescriptors(\n"
-          "      &$desc_table$_getter, &$desc_table$_once,\n"
-          "      $file_level_metadata$[$1$]);\n"
-          "}\n",
-          index_in_file_messages_);
-    } else {
-      format(
-          "::$proto_ns$::Metadata $classname$::GetMetadata() const {\n"
-          "  return ::_pbi::AssignDescriptors(\n"
-          "      &$desc_table$_getter, &$desc_table$_once,\n"
-          "      $file_level_metadata$[$1$]);\n"
-          "}\n",
-          index_in_file_messages_);
-    }
+    p->Emit(
+        {
+            {"pin_weak_writer", pin_weak_writer},
+            {"index", index_in_file_messages_},
+        },
+        R"cc(
+          ::$proto_ns$::Metadata $classname$::GetMetadata() const {
+            $annotate_reflection$;
+            $pin_weak_writer$;
+            return ::_pbi::AssignDescriptors(&$desc_table$_getter,
+                                             &$desc_table$_once,
+                                             $file_level_metadata$[$index$]);
+          }
+        )cc");
   }
 
   if (HasTracker(descriptor_, options_)) {
diff --git a/src/google/protobuf/compiler/cpp/options.h b/src/google/protobuf/compiler/cpp/options.h
index 30be9c0..4d60063 100644
--- a/src/google/protobuf/compiler/cpp/options.h
+++ b/src/google/protobuf/compiler/cpp/options.h
@@ -50,6 +50,7 @@
   bool transitive_pb_h = true;
   bool annotate_headers = false;
   bool lite_implicit_weak_fields = false;
+  bool descriptor_implicit_weak_messages = false;
   bool bootstrap = false;
   bool opensource_runtime = false;
   bool annotate_accessor = false;
diff --git a/src/google/protobuf/compiler/java/java_features.pb.cc b/src/google/protobuf/compiler/java/java_features.pb.cc
index 9c2c10c..7f940e8 100644
--- a/src/google/protobuf/compiler/java/java_features.pb.cc
+++ b/src/google/protobuf/compiler/java/java_features.pb.cc
@@ -367,9 +367,9 @@
 }
 
 ::google::protobuf::Metadata JavaFeatures::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto[0]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto[0]);
 }
 PROTOC_EXPORT PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::_pbi::
     ExtensionIdentifier<::google::protobuf::FeatureSet, ::_pbi::MessageTypeTraits< ::pb::JavaFeatures >,
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index 12f13d0..a782fcc 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -608,9 +608,9 @@
 }
 
 ::google::protobuf::Metadata Version::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[0]);
 }
 // ===================================================================
 
@@ -953,9 +953,9 @@
 }
 
 ::google::protobuf::Metadata CodeGeneratorRequest::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[1]);
 }
 // ===================================================================
 
@@ -1272,9 +1272,9 @@
 }
 
 ::google::protobuf::Metadata CodeGeneratorResponse_File::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[2]);
 }
 // ===================================================================
 
@@ -1602,9 +1602,9 @@
 }
 
 ::google::protobuf::Metadata CodeGeneratorResponse::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcompiler_2fplugin_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcompiler_2fplugin_2eproto[3]);
 }
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace compiler
diff --git a/src/google/protobuf/cpp_features.pb.cc b/src/google/protobuf/cpp_features.pb.cc
index 0052cf1..b0f7f30 100644
--- a/src/google/protobuf/cpp_features.pb.cc
+++ b/src/google/protobuf/cpp_features.pb.cc
@@ -295,9 +295,9 @@
 }
 
 ::google::protobuf::Metadata CppFeatures::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fcpp_5ffeatures_2eproto_getter, &descriptor_table_google_2fprotobuf_2fcpp_5ffeatures_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fcpp_5ffeatures_2eproto[0]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fcpp_5ffeatures_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fcpp_5ffeatures_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fcpp_5ffeatures_2eproto[0]);
 }
 PROTOBUF_CONSTINIT PROTOBUF_EXPORT
     PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 ::_pbi::
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index ea59753..269a8dc 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -2534,9 +2534,9 @@
 }
 
 ::google::protobuf::Metadata FileDescriptorSet::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[0]);
 }
 // ===================================================================
 
@@ -3122,9 +3122,9 @@
 }
 
 ::google::protobuf::Metadata FileDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[1]);
 }
 // ===================================================================
 
@@ -3406,9 +3406,9 @@
 }
 
 ::google::protobuf::Metadata DescriptorProto_ExtensionRange::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[2]);
 }
 // ===================================================================
 
@@ -3629,9 +3629,9 @@
 }
 
 ::google::protobuf::Metadata DescriptorProto_ReservedRange::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[3]);
 }
 // ===================================================================
 
@@ -4116,9 +4116,9 @@
 }
 
 ::google::protobuf::Metadata DescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[4]);
 }
 // ===================================================================
 
@@ -4450,9 +4450,9 @@
 }
 
 ::google::protobuf::Metadata ExtensionRangeOptions_Declaration::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[5]);
 }
 // ===================================================================
 
@@ -4775,9 +4775,9 @@
 }
 
 ::google::protobuf::Metadata ExtensionRangeOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[6]);
 }
 // ===================================================================
 
@@ -5300,9 +5300,9 @@
 }
 
 ::google::protobuf::Metadata FieldDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[7]);
 }
 // ===================================================================
 
@@ -5554,9 +5554,9 @@
 }
 
 ::google::protobuf::Metadata OneofDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[8]);
 }
 // ===================================================================
 
@@ -5777,9 +5777,9 @@
 }
 
 ::google::protobuf::Metadata EnumDescriptorProto_EnumReservedRange::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[9]);
 }
 // ===================================================================
 
@@ -6116,9 +6116,9 @@
 }
 
 ::google::protobuf::Metadata EnumDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[10]);
 }
 // ===================================================================
 
@@ -6405,9 +6405,9 @@
 }
 
 ::google::protobuf::Metadata EnumValueDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[11]);
 }
 // ===================================================================
 
@@ -6689,9 +6689,9 @@
 }
 
 ::google::protobuf::Metadata ServiceDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[12]);
 }
 // ===================================================================
 
@@ -7069,9 +7069,9 @@
 }
 
 ::google::protobuf::Metadata MethodDescriptorProto::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[13]);
 }
 // ===================================================================
 
@@ -7903,9 +7903,9 @@
 }
 
 ::google::protobuf::Metadata FileOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[14]);
 }
 // ===================================================================
 
@@ -8289,9 +8289,9 @@
 }
 
 ::google::protobuf::Metadata MessageOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[15]);
 }
 // ===================================================================
 
@@ -8525,9 +8525,9 @@
 }
 
 ::google::protobuf::Metadata FieldOptions_EditionDefault::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[16]);
 }
 // ===================================================================
 
@@ -9069,9 +9069,9 @@
 }
 
 ::google::protobuf::Metadata FieldOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[17]);
 }
 // ===================================================================
 
@@ -9329,9 +9329,9 @@
 }
 
 ::google::protobuf::Metadata OneofOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[18]);
 }
 // ===================================================================
 
@@ -9675,9 +9675,9 @@
 }
 
 ::google::protobuf::Metadata EnumOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[19]);
 }
 // ===================================================================
 
@@ -10003,9 +10003,9 @@
 }
 
 ::google::protobuf::Metadata EnumValueOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[20]);
 }
 // ===================================================================
 
@@ -10300,9 +10300,9 @@
 }
 
 ::google::protobuf::Metadata ServiceOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[21]);
 }
 // ===================================================================
 
@@ -10633,9 +10633,9 @@
 }
 
 ::google::protobuf::Metadata MethodOptions::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[22]);
 }
 // ===================================================================
 
@@ -10874,9 +10874,9 @@
 }
 
 ::google::protobuf::Metadata UninterpretedOption_NamePart::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[23]);
 }
 // ===================================================================
 
@@ -11263,9 +11263,9 @@
 }
 
 ::google::protobuf::Metadata UninterpretedOption::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[24]);
 }
 // ===================================================================
 
@@ -11615,9 +11615,9 @@
 }
 
 ::google::protobuf::Metadata FeatureSet::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[25]);
 }
 // ===================================================================
 
@@ -11867,9 +11867,9 @@
 }
 
 ::google::protobuf::Metadata FeatureSetDefaults_FeatureSetEditionDefault::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[26]);
 }
 // ===================================================================
 
@@ -12137,9 +12137,9 @@
 }
 
 ::google::protobuf::Metadata FeatureSetDefaults::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[27]);
 }
 // ===================================================================
 
@@ -12479,9 +12479,9 @@
 }
 
 ::google::protobuf::Metadata SourceCodeInfo_Location::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[28]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[28]);
 }
 // ===================================================================
 
@@ -12665,9 +12665,9 @@
 }
 
 ::google::protobuf::Metadata SourceCodeInfo::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[29]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[29]);
 }
 // ===================================================================
 
@@ -13003,9 +13003,9 @@
 }
 
 ::google::protobuf::Metadata GeneratedCodeInfo_Annotation::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[30]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[30]);
 }
 // ===================================================================
 
@@ -13189,9 +13189,9 @@
 }
 
 ::google::protobuf::Metadata GeneratedCodeInfo::GetMetadata() const {
-  return ::_pbi::AssignDescriptors(
-      &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter, &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
-      file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[31]);
+  return ::_pbi::AssignDescriptors(&descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_getter,
+                                   &descriptor_table_google_2fprotobuf_2fdescriptor_2eproto_once,
+                                   file_level_metadata_google_2fprotobuf_2fdescriptor_2eproto[31]);
 }
 // @@protoc_insertion_point(namespace_scope)
 }  // namespace protobuf
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 7872866..1dcbe30 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -627,7 +627,9 @@
     const Descriptor* type) {
   if (delegate_to_generated_factory_ &&
       type->file()->pool() == DescriptorPool::generated_pool()) {
-    return MessageFactory::generated_factory()->GetPrototype(type);
+    const Message* result = MessageFactory::TryGetGeneratedPrototype(type);
+    if (result != nullptr) return result;
+    // Otherwise, we will create it dynamically so keep going.
   }
 
   const TypeInfo** target = &prototypes_[type];
diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc
index 4893ca8..1bad594 100644
--- a/src/google/protobuf/generated_message_util.cc
+++ b/src/google/protobuf/generated_message_util.cc
@@ -21,6 +21,7 @@
 #include "google/protobuf/io/zero_copy_stream_impl_lite.h"
 #include "google/protobuf/message_lite.h"
 #include "google/protobuf/metadata_lite.h"
+#include "google/protobuf/port.h"
 #include "google/protobuf/repeated_field.h"
 #include "google/protobuf/wire_format_lite.h"
 
@@ -48,10 +49,32 @@
 
 PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT const EmptyCord empty_cord_;
 
+#if defined(PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED)
+extern "C" {
+// We add a single dummy writer to guarantee the section is never empty.
+WeakDefaultWriter dummy_writer
+    __attribute__((section("pb_defaults"))) = {&dummy_writer.source, nullptr};
+// When using --descriptor_implicit_weak_messages we expect the writer objects
+// to live in the `pb_defaults` section. We load them all using the
+// __start/__end symbols provided by the linker.
+extern const WeakDefaultWriter __start_pb_defaults;
+extern const WeakDefaultWriter __stop_pb_defaults;
+}
+static void InitWeakDefaults() {
+  StrongPointer(&dummy_writer);  // force link the dummy writer.
+  for (auto it = &__start_pb_defaults; it != &__stop_pb_defaults; ++it) {
+    *it->destination = it->source;
+  }
+}
+#else
+void InitWeakDefaults() {}
+#endif
+
 PROTOBUF_CONSTINIT std::atomic<bool> init_protobuf_defaults_state{false};
 static bool InitProtobufDefaultsImpl() {
   fixed_address_empty_string.DefaultConstruct();
   OnShutdownDestroyString(fixed_address_empty_string.get_mutable());
+  InitWeakDefaults();
 
 
   init_protobuf_defaults_state.store(true, std::memory_order_release);
diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h
index 72e6649..4c1258f 100644
--- a/src/google/protobuf/generated_message_util.h
+++ b/src/google/protobuf/generated_message_util.h
@@ -316,6 +316,13 @@
   std::unique_ptr<storage_type[]> items_;
 };
 
+// Single message link for implicit weak descriptor messages.
+// The runtime will register all the instances that are linked in.
+struct WeakDefaultWriter {
+  const Message** destination;
+  const Message* source;
+};
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index 1b8b329..91f770c 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -22,8 +22,10 @@
 #include "absl/strings/str_join.h"
 #include "absl/strings/string_view.h"
 #include "absl/synchronization/mutex.h"
+#include "absl/types/optional.h"
 #include "google/protobuf/descriptor.h"
 #include "google/protobuf/descriptor.pb.h"
+#include "google/protobuf/dynamic_message.h"
 #include "google/protobuf/generated_message_reflection.h"
 #include "google/protobuf/generated_message_tctable_impl.h"
 #include "google/protobuf/generated_message_util.h"
@@ -218,15 +220,21 @@
   void RegisterFile(const google::protobuf::internal::DescriptorTable* table);
   void RegisterType(const Descriptor* descriptor, const Message* prototype);
 
+  const Message* TryGetPrototype(const Descriptor* type);
+
   // implements MessageFactory ---------------------------------------
   const Message* GetPrototype(const Descriptor* type) override;
 
  private:
-  const Message* FindInTypeMap(const Descriptor* type)
+  GeneratedMessageFactory() {
+    dropped_defaults_factory_.SetDelegateToGeneratedFactory(true);
+  }
+
+  absl::optional<const Message*> FindInTypeMap(const Descriptor* type)
       ABSL_SHARED_LOCKS_REQUIRED(mutex_)
   {
     auto it = type_map_.find(type);
-    if (it == type_map_.end()) return nullptr;
+    if (it == type_map_.end()) return absl::nullopt;
     return it->second;
   }
 
@@ -270,6 +278,7 @@
   absl::flat_hash_set<const google::protobuf::internal::DescriptorTable*,
                       DescriptorByNameHash, DescriptorByNameEq>
       files_;
+  DynamicMessageFactory dropped_defaults_factory_;
 
   absl::Mutex mutex_;
   absl::flat_hash_map<const Descriptor*, const Message*> type_map_
@@ -307,10 +316,36 @@
 
 
 const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
+  const Message* result = TryGetPrototype(type);
+  if (result == nullptr &&
+      type->file()->pool() == DescriptorPool::generated_pool()) {
+    // We registered this descriptor with a null pointer.
+    // In this case we need to create the prototype from the dynamic factory.
+    // We _must_ do this outside the lock because the dynamic factory will call
+    // back into the generated factory for cross linking.
+    result = dropped_defaults_factory_.GetPrototype(type);
+
+    {
+      absl::WriterMutexLock lock(&mutex_);
+      // And update the main map to make the next lookup faster.
+      // We don't need to recheck here. Even if someone raced us here the result
+      // is the same, so we can just write it.
+      type_map_[type] = result;
+    }
+  }
+
+  return result;
+}
+
+const Message* GeneratedMessageFactory::TryGetPrototype(
+    const Descriptor* type) {
+  absl::optional<const Message*> result;
   {
     absl::ReaderMutexLock lock(&mutex_);
-    const Message* result = FindInTypeMap(type);
-    if (result != nullptr) return result;
+    result = FindInTypeMap(type);
+    if (result.has_value() && *result != nullptr) {
+      return *result;
+    }
   }
 
   // If the type is not in the generated pool, then we can't possibly handle
@@ -327,27 +362,30 @@
     return nullptr;
   }
 
-  absl::WriterMutexLock lock(&mutex_);
+  {
+    absl::WriterMutexLock lock(&mutex_);
 
-  // Check if another thread preempted us.
-  const Message* result = FindInTypeMap(type);
-  if (result == nullptr) {
-    // Nope.  OK, register everything.
-    internal::RegisterFileLevelMetadata(registration_data);
-    // Should be here now.
+    // Check if another thread preempted us.
     result = FindInTypeMap(type);
+    if (!result.has_value()) {
+      // Nope.  OK, register everything.
+      internal::RegisterFileLevelMetadata(registration_data);
+      // Should be here now.
+      result = FindInTypeMap(type);
+      ABSL_DCHECK(result.has_value());
+    }
   }
 
-  if (result == nullptr) {
-    ABSL_DLOG(FATAL) << "Type appears to be in generated pool but wasn't "
-                     << "registered: " << type->full_name();
-  }
-
-  return result;
+  return *result;
 }
 
 }  // namespace
 
+const Message* MessageFactory::TryGetGeneratedPrototype(
+    const Descriptor* type) {
+  return GeneratedMessageFactory::singleton()->TryGetPrototype(type);
+}
+
 MessageFactory* MessageFactory::generated_factory() {
   return GeneratedMessageFactory::singleton();
 }
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index c3b41a0..6f206a3 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -1347,6 +1347,10 @@
   static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
                                                const Message* prototype);
 
+
+ private:
+  friend class DynamicMessageFactory;
+  static const Message* TryGetGeneratedPrototype(const Descriptor* type);
 };
 
 #define DECLARE_GET_REPEATED_FIELD(TYPE)                           \
@@ -1389,6 +1393,7 @@
   (void)unused;
 
 #if PROTOBUF_RTTI
+  internal::StrongReference(T::default_instance());
   return dynamic_cast<const T*>(from);
 #else
   bool ok = from != nullptr &&
@@ -1427,11 +1432,7 @@
 // instance T and T is a type derived from base Message class.
 template <typename T>
 const T* DownCastToGenerated(const Message* from) {
-  // Compile-time assert that T is a generated type that has a
-  // default_instance() accessor, but avoid actually calling it.
-  const T& (*get_default_instance)() = &T::default_instance;
-  (void)get_default_instance;
-
+  internal::StrongReference(T::default_instance());
   ABSL_DCHECK(DynamicCastToGenerated<T>(from) == from)
       << "Cannot downcast " << from->GetTypeName() << " to "
       << T::default_instance().GetTypeName();
diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h
index 9aee882..da59316 100644
--- a/src/google/protobuf/port.h
+++ b/src/google/protobuf/port.h
@@ -39,6 +39,12 @@
 namespace internal {
 
 
+template <typename T>
+void StrongPointer(T* var) {
+  auto volatile unused = var;
+  (void)&unused;  // Use address to avoid an extra load of "unused".
+}
+
 // See comments on `AllocateAtLeast` for information on size returning new.
 struct SizedPtr {
   void* p;
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index dfd3f88..235644a 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -782,6 +782,15 @@
 #define PROTOBUF_BUILTIN_CONSTANT_P(x) false
 #endif
 
+// Determines the platforms where descriptor weak messages can be used.
+#ifdef PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED
+#error PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED was previously defined
+#endif
+#if defined(__GNUC__) && defined(__clang__) && !defined(__APPLE__) && \
+    !defined(_MSC_VER)
+#define PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED
+#endif
+
 
 // TODO: Enable the feature by default and remove this flag.
 #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index 277971f..70fca1c 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -78,6 +78,7 @@
 #undef PROTOBUF_TSAN_WRITE
 #undef PROTOBUF_USE_TABLE_PARSER_ON_REFLECTION
 #undef PROTOBUF_BUILTIN_CONSTANT_P
+#undef PROTOBUF_DESCRIPTOR_WEAK_MESSAGES_ALLOWED
 #undef PROTOBUF_PREFETCH_PARSE_TABLE
 #undef PROTOBUF_TC_PARAM_DECL
 #undef PROTOBUF_DEBUG