Extend the weak descriptor message feature to include extensions.
An extension declaration now allows both messages to be weak and will create
the prototype on the fly.
PiperOrigin-RevId: 588811002
diff --git a/src/google/protobuf/compiler/cpp/extension.cc b/src/google/protobuf/compiler/cpp/extension.cc
index a62f694..a06128b 100644
--- a/src/google/protobuf/compiler/cpp/extension.cc
+++ b/src/google/protobuf/compiler/cpp/extension.cc
@@ -12,6 +12,7 @@
#include "google/protobuf/compiler/cpp/extension.h"
#include <string>
+#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_replace.h"
@@ -188,35 +189,58 @@
$repeated$, $packed$, $enum_name$_IsValid),
)cc");
break;
- case FieldDescriptor::CPPTYPE_MESSAGE:
- p->Emit({{"verify",
- [&] {
- const bool should_verify =
- // Only verify msgs.
- descriptor_->cpp_type() ==
- FieldDescriptor::CPPTYPE_MESSAGE &&
- // Options say to verify.
- ShouldVerify(descriptor_->message_type(), options_,
- scc_analyzer_) &&
- ShouldVerify(descriptor_->containing_type(), options_,
- scc_analyzer_);
- if (should_verify) {
- p->Emit("&$message_type$::InternalVerify,");
- } else {
- p->Emit("nullptr,");
- }
- }},
- {"message_type", FieldMessageTypeName(descriptor_, options_)},
- {"lazy", descriptor_->options().has_lazy()
- ? descriptor_->options().lazy() ? "kLazy" : "kEager"
- : "kUndefined"}},
- R"cc(
- ::_pbi::ExtensionSet::RegisterMessageExtension(
- &$extendee$::default_instance(), $number$, $field_type$,
- $repeated$, $packed$, &$message_type$::default_instance(),
- $verify$, ::_pbi::LazyAnnotation::$lazy$),
- )cc");
+ case FieldDescriptor::CPPTYPE_MESSAGE: {
+ const bool should_verify =
+ // Only verify msgs.
+ descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+ // Options say to verify.
+ ShouldVerify(descriptor_->message_type(), options_, scc_analyzer_) &&
+ ShouldVerify(descriptor_->containing_type(), options_, scc_analyzer_);
+ const auto message_type = FieldMessageTypeName(descriptor_, options_);
+ auto v = p->WithVars(
+ {{"verify", should_verify
+ ? absl::StrCat("&", message_type, "::InternalVerify")
+ : "nullptr"},
+ {"message_type", message_type},
+ {"lazy", descriptor_->options().has_lazy()
+ ? descriptor_->options().lazy() ? "kLazy" : "kEager"
+ : "kUndefined"}});
+ if (UsingImplicitWeakDescriptor(descriptor_->file(), options_)) {
+ const auto find_index = [](auto* desc) {
+ const std::vector<const Descriptor*> msgs =
+ FlattenMessagesInFile(desc->file());
+ return absl::c_find(msgs, desc) - msgs.begin();
+ };
+ p->Emit(
+ {
+ {"extendee_table",
+ DescriptorTableName(descriptor_->containing_type()->file(),
+ options_)},
+ {"extendee_index", find_index(descriptor_->containing_type())},
+ {"extension_table",
+ DescriptorTableName(descriptor_->message_type()->file(),
+ options_)},
+ {"extension_index", find_index(descriptor_->message_type())},
+ },
+ R"cc(
+ ::_pbi::ExtensionSet::RegisterMessageExtension(
+ ::_pbi::GetPrototypeForWeakDescriptor(&$extendee_table$,
+ $extendee_index$),
+ $number$, $field_type$, $repeated$, $packed$,
+ ::_pbi::GetPrototypeForWeakDescriptor(&$extension_table$,
+ $extension_index$),
+ $verify$, ::_pbi::LazyAnnotation::$lazy$),
+ )cc");
+ } else {
+ p->Emit(R"cc(
+ ::_pbi::ExtensionSet::RegisterMessageExtension(
+ &$extendee$::default_instance(), $number$, $field_type$,
+ $repeated$, $packed$, &$message_type$::default_instance(),
+ $verify$, ::_pbi::LazyAnnotation::$lazy$),
+ )cc");
+ }
break;
+ }
default:
p->Emit(
R"cc(
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h
index 5815b4a..64e2a82 100644
--- a/src/google/protobuf/compiler/cpp/helpers.h
+++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -772,9 +772,13 @@
// 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 extensions, the identifiers currently pin the extendee. The extended is
+// assumed to by pinned elsewhere since we already have an instance of it when
+// we call `.GetExtension` et al. The extension identifier itself is not
+// automatically pinned, so it has to be used to participate in the graph.
+// Registration of the extensions do not pin the extended or the extendee. At
+// registration time we will eagerly create a prototype object if one is
+// missing to insert in the extension table in ExtensionSet.
//
// For services, the TU unconditionally pins the request/response objects.
// This is the status quo for simplicitly to avoid modifying the RPC layer. It
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 563d518..288d60f 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -39,6 +39,7 @@
#include "google/protobuf/inlined_string_field.h"
#include "google/protobuf/map_field.h"
#include "google/protobuf/map_field_inl.h"
+#include "google/protobuf/message.h"
#include "google/protobuf/raw_ptr.h"
#include "google/protobuf/repeated_field.h"
#include "google/protobuf/unknown_field_set.h"
@@ -3819,6 +3820,24 @@
return field->is_repeated();
}
+const Message* GetPrototypeForWeakDescriptor(const DescriptorTable* table,
+ int index) {
+ // First, make sure we inject the surviving default instances.
+ InitProtobufDefaults();
+
+ // Now check if the table has it. If so, return it.
+ if (const auto* msg = table->default_instances[index]) {
+ return msg;
+ }
+
+ // Fallback to dynamic messages.
+ // Register the dep and generate the prototype via the generated pool.
+ AssignDescriptors(table);
+ ABSL_CHECK(table->file_level_metadata[index].descriptor != nullptr);
+ return MessageFactory::generated_factory()->GetPrototype(
+ table->file_level_metadata[index].descriptor);
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h
index 6138a21..7b42813 100644
--- a/src/google/protobuf/generated_message_reflection.h
+++ b/src/google/protobuf/generated_message_reflection.h
@@ -344,6 +344,11 @@
explicit AddDescriptorsRunner(const DescriptorTable* table);
};
+// Retrieves the existing prototype out of a descriptor table.
+// If it doesn't exist, asks the generated message factory for one.
+const Message* GetPrototypeForWeakDescriptor(const DescriptorTable* table,
+ int index);
+
struct DenseEnumCacheInfo {
std::atomic<const std::string**> cache;
int min_val;