Change Reflection::GetDefaultMessageInstance to Reflection::GetMessageClassData.

`Reflection::GetMessageClassData` now has to call `GetClassData` on the prototype returned from the message factory, as the `MessageFactory` interface only has a `GetPrototype` method. We could add a `GetClassData` method to the generated message factory, but we already cache the `ClassData` pointer in the `FieldDescriptor` for fields from the generated factory. We couldn't add a `GetClassData` to dynamic factories, as `ClassData` is `internal` and dynamic factories have a public interface that users can override.

This cl includes a refactor of `LazyField::InternalWrite` to accept `ClassData` instead of a `MessageLite` prototype, and changes the cached prototype to `ClassData` in `FieldDescriptor`.

PiperOrigin-RevId: 963758127
This commit is contained in:
Clayton Knittel 2026-08-12 17:47:46 -07:00 committed by Copybara-Service
parent 7b59c75e36
commit d0be1f2cb0
8 changed files with 41 additions and 26 deletions

View file

@ -6437,7 +6437,7 @@ void internal::DescriptorBuilder::BuildFieldOrExtension(
DescriptorPool::ErrorCollector::DEFAULT_VALUE,
"Messages can't have default values.");
result->has_default_value_ = false;
result->default_generated_instance_ = nullptr;
result->generated_class_data_ = nullptr;
break;
}
@ -6485,7 +6485,7 @@ void internal::DescriptorBuilder::BuildFieldOrExtension(
result->default_value_string_ = &internal::GetEmptyString();
break;
case FieldDescriptor::CPPTYPE_MESSAGE:
result->default_generated_instance_ = nullptr;
result->generated_class_data_ = nullptr;
break;
}
}

View file

@ -56,6 +56,7 @@
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "google/protobuf/class_data.h"
#include "google/protobuf/descriptor_lite.h" // IWYU pragma: export
#include "google/protobuf/extension_set.h"
#include "google/protobuf/offset_ptr.h"
@ -1363,7 +1364,7 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
mutable const EnumValueDescriptor* default_value_enum_;
const std::string* default_value_string_;
mutable std::atomic<const Message*> default_generated_instance_;
mutable std::atomic<const internal::ClassData*> generated_class_data_;
};
static const CppType kTypeToCppTypeMap[MAX_TYPE + 1];

View file

@ -393,7 +393,7 @@ size_t ExtensionSet::GetMessageByteSizeLong(int number) const {
}
uint8_t* ExtensionSet::InternalSerializeMessage(
int number, const MessageLite* prototype, uint8_t* target,
int number, const ClassData* class_data, uint8_t* target,
io::EpsCopyOutputStream* stream) const {
const Extension* extension = FindOrNull(number);
ABSL_CHECK(extension != nullptr) << "not present";
@ -1846,7 +1846,7 @@ uint8_t* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
return target;
}
const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
const ClassData* ExtensionSet::GetClassDataForLazyMessage(
const MessageLite* extendee, int number) {
GeneratedExtensionFinder finder(extendee);
bool was_packed_on_wire = false;
@ -1856,7 +1856,7 @@ const MessageLite* ExtensionSet::GetPrototypeForLazyMessage(
&extension_info, &was_packed_on_wire)) {
return nullptr;
}
return extension_info.message_info.GetPrototype();
return extension_info.message_info.GetClassData();
}
uint8_t*

View file

@ -696,7 +696,7 @@ class PROTOBUF_EXPORT ExtensionSet {
static bool FieldTypeIsPointer(FieldType type);
size_t GetMessageByteSizeLong(int number) const;
uint8_t* InternalSerializeMessage(int number, const MessageLite* prototype,
uint8_t* InternalSerializeMessage(int number, const ClassData* class_data,
uint8_t* target,
io::EpsCopyOutputStream* stream) const;
@ -1158,9 +1158,9 @@ class PROTOBUF_EXPORT ExtensionSet {
return expected_wire_type == wire_type;
}
// Find the prototype for a LazyMessage from the extension registry. Returns
// null if the extension is not found.
static const MessageLite* GetPrototypeForLazyMessage(
// Returns the ClassData for a LazyMessage from the extension registry.
// Returns null if the extension is not found.
static const ClassData* GetClassDataForLazyMessage(
const MessageLite* extendee, int number);
// Returns true if extension is present and lazy.

View file

@ -2574,7 +2574,7 @@ void Reflection::AddEnumValueInternal(Message* message,
// -------------------------------------------------------------------
const Message* Reflection::GetDefaultMessageInstance(
const internal::ClassData* Reflection::GetMessageClassData(
const FieldDescriptor* field) const {
// If we are using the generated factory, we cache the prototype in the field
// descriptor for faster access.
@ -2582,11 +2582,13 @@ const Message* Reflection::GetDefaultMessageInstance(
// means they contain null pointers on their message fields and can't be used
// to get the default of submessages.
if (message_factory_ == MessageFactory::generated_factory()) {
auto& ptr = field->default_generated_instance_;
auto& ptr = field->generated_class_data_;
auto* res = ptr.load(std::memory_order_acquire);
if (res == nullptr) {
// First time asking for this field's default. Load it and cache it.
res = message_factory_->GetPrototype(field->message_type());
const MessageLite* prototype =
message_factory_->GetPrototype(field->message_type());
res = internal::GetClassData(*prototype);
ptr.store(res, std::memory_order_release);
}
return res;
@ -2602,12 +2604,13 @@ const Message* Reflection::GetDefaultMessageInstance(
PROTOBUF_IGNORE_DEPRECATION_STOP
if (!field->is_extension() && !field->is_repeated() && !field_is_weak &&
!IsLazyField(field) && !schema_.InRealOneof(field)) {
auto* res = DefaultRaw<const Message*>(field);
ABSL_DCHECK_NE(res, nullptr);
return res;
const Message* prototype = DefaultRaw<const Message*>(field);
ABSL_DCHECK_NE(prototype, nullptr);
return internal::GetClassData(*prototype);
}
// Otherwise, just go to the factory.
return message_factory_->GetPrototype(field->message_type());
return internal::GetClassData(
*message_factory_->GetPrototype(field->message_type()));
}
const Message& Reflection::GetMessage(const Message& message,
@ -2622,11 +2625,13 @@ const Message& Reflection::GetMessage(const Message& message,
message.GetArena(), field->number(), field->message_type(), factory));
} else {
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return *GetDefaultMessageInstance(field);
return *DownCastMessage<Message>(
GetMessageClassData(field)->default_instance());
}
const Message* result = GetRaw<const Message*>(message, field);
if (result == nullptr) {
result = GetDefaultMessageInstance(field);
result = DownCastMessage<Message>(
GetMessageClassData(field)->default_instance());
}
return *result;
}
@ -2652,16 +2657,16 @@ Message* Reflection::MutableMessage(Message* message,
if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof());
result_holder = MutableField<Message*>(message, field);
const Message* default_message = GetDefaultMessageInstance(field);
*result_holder = default_message->New(arena);
*result_holder =
DownCastMessage<Message>(GetMessageClassData(field)->New(arena));
}
} else {
SetHasBit(message, field);
}
if (*result_holder == nullptr) {
const Message* default_message = GetDefaultMessageInstance(field);
*result_holder = default_message->New(arena);
*result_holder =
DownCastMessage<Message>(GetMessageClassData(field)->New(arena));
}
result = *result_holder;
return result;
@ -3759,8 +3764,7 @@ void Reflection::PopulateTcParseFieldAux(
field_aux++->offset = schema_.SizeofSplit();
break;
case internal::TailCallTableInfo::kClassData:
field_aux++->class_data_p =
internal::GetClassData(*GetDefaultMessageInstance(aux_entry.field));
field_aux++->class_data_p = GetMessageClassData(aux_entry.field);
break;
case internal::TailCallTableInfo::kClassDataWeak:
case internal::TailCallTableInfo::kMessageVerifyFunc:

View file

@ -1345,7 +1345,8 @@ class PROTOBUF_EXPORT Reflection final {
template <typename Type>
const Type& DefaultRaw(const FieldDescriptor* field) const;
const Message* GetDefaultMessageInstance(const FieldDescriptor* field) const;
const internal::ClassData* GetMessageClassData(
const FieldDescriptor* field) const;
const uint32_t* GetHasBits(const Message& message) const;
inline uint32_t* MutableHasBits(Message* message) const;

View file

@ -258,6 +258,10 @@ struct MessageGlobalsBase {
const void* default_instance) {
return reinterpret_cast<const MessageGlobalsBase*>(default_instance);
}
static const MessageGlobalsBase* FromClassData(const ClassData* class_data) {
return FromDefaultInstance(class_data->default_instance());
}
};
template <const auto* kDefault, const auto* kClassData>
@ -302,6 +306,10 @@ struct MessageGlobalsBase {
}
constexpr const ClassData* GetClassData() const { return class_data.base(); }
static const MessageGlobalsBase* FromClassData(const void* class_data) {
return reinterpret_cast<const MessageGlobalsBase*>(class_data);
}
explicit constexpr MessageGlobalsBase(ClassDataFull class_data)
: class_data(class_data) {}

View file

@ -24,6 +24,7 @@
#include "absl/log/absl_log.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "google/protobuf/class_data.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/dynamic_message.h"