From 6ccf130bc2c5a1d0b15d588eca57f6a758b3469f Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Fri, 17 Apr 2026 22:13:34 -0700 Subject: [PATCH] Use globals #ifdef PROTOBUF_MESSAGE_GLOBALS for MessageInfo. With "globals", we can directly get class data from globals rather than dependent loads. DynamicMessage needs to update ClassData as the parse table is created lazily. PiperOrigin-RevId: 901621493 --- src/google/protobuf/extension_set.cc | 8 +++- src/google/protobuf/extension_set.h | 42 +++++++++++++++++-- src/google/protobuf/extension_set_heavy.cc | 11 ++--- src/google/protobuf/extension_set_inl.h | 8 ++-- .../protobuf/generated_message_reflection.cc | 11 +++++ src/google/protobuf/generated_message_util.h | 5 +++ src/google/protobuf/message_lite.h | 11 +++++ 7 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index eb30fb0186456..b1f7c811a5286 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -167,6 +167,7 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee, type == WireFormatLite::TYPE_GROUP); ExtensionInfo info(extendee, number, type, is_repeated, is_packed, verify_func, is_lazy); +#ifndef PROTOBUF_MESSAGE_GLOBALS info.message_info = {prototype, #if defined(PROTOBUF_CONSTINIT_DEFAULT_INSTANCES) prototype->GetTcParseTable() @@ -174,6 +175,11 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee, nullptr #endif }; +#else // PROTOBUF_MESSAGE_GLOBALS + ABSL_DCHECK_NE(prototype, nullptr); + info.message_info = { + internal::MessageGlobalsBase::FromDefaultInstance(prototype)}; +#endif // PROTOBUF_MESSAGE_GLOBALS Register(info); } @@ -1830,7 +1836,7 @@ const MessageLite* ExtensionSet::GetPrototypeForLazyMessage( &extension_info, &was_packed_on_wire)) { return nullptr; } - return extension_info.message_info.prototype; + return extension_info.message_info.GetPrototype(); } uint8_t* diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index f90343c4acee9..eb89110a0e5b8 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -29,6 +29,7 @@ #include #include "absl/log/absl_log.h" +#include "google/protobuf/generated_message_util.h" #include "google/protobuf/stubs/common.h" #include "absl/base/casts.h" @@ -167,18 +168,53 @@ struct ExtensionInfo { }; struct MessageInfo { +#ifdef PROTOBUF_MESSAGE_GLOBALS + const internal::MessageGlobalsBase* globals = nullptr; +#else const MessageLite* prototype = nullptr; - // The TcParse table used for this object. - // Never null. (except in platforms that don't constant initialize default - // instances) + // The TcParse table used for this object. Never null. (except in platforms + // that don't constant initialize default instances) const internal::TcParseTableBase* tc_table = nullptr; +#endif + + // Create from prototype + static MessageInfo Create(const MessageLite* prototype) { + const internal::TcParseTableBase* tc_table = + internal::PrivateAccess::GetTcParseTable(prototype); +#ifdef PROTOBUF_MESSAGE_GLOBALS + ABSL_DCHECK_NE(tc_table, nullptr); + return {internal::MessageGlobalsBase::FromDefaultInstance(prototype)}; +#else + return {prototype, tc_table}; +#endif + } + + const MessageLite* GetPrototype() const { +#ifdef PROTOBUF_MESSAGE_GLOBALS + return internal::MessageGlobalsBase::ToDefaultInstance(globals); +#else + return prototype; +#endif + } + + const internal::TcParseTableBase* GetTcTable() const { +#ifdef PROTOBUF_MESSAGE_GLOBALS + return internal::MessageGlobalsBase::ToParseTableBase(globals); +#else + return tc_table; +#endif + } const ClassData* GetClassData() const { +#ifdef PROTOBUF_MESSAGE_GLOBALS + return internal::MessageGlobalsBase::GetClassData(globals); +#else // !PROTOBUF_MESSAGE_GLOBALS #ifdef PROTOBUF_CONSTINIT_DEFAULT_INSTANCES return tc_table->class_data; #else return google::protobuf::internal::GetClassData(*prototype); #endif +#endif // !PROTOBUF_MESSAGE_GLOBALS } }; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index a339f0980df33..fdbc8f7680c6d 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -258,13 +258,14 @@ bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) { output->is_packed = extension->is_packed(); output->descriptor = extension; if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - output->message_info.prototype = - factory_->GetPrototype(extension->message_type()); - output->message_info.tc_table = - output->message_info.prototype->GetTcParseTable(); - ABSL_CHECK(output->message_info.prototype != nullptr) + output->message_info = ExtensionInfo::MessageInfo::Create( + factory_->GetPrototype(extension->message_type())); + ABSL_CHECK_NE(output->message_info.GetPrototype(), nullptr) << "Extension factory's GetPrototype() returned nullptr; extension: " << extension->full_name(); + ABSL_CHECK_NE(output->message_info.GetTcTable(), nullptr) + << "Extension factory's GetTcTable() returned nullptr; extension: " + << extension->full_name(); } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { output->enum_validity_check.func = ValidateEnumUsingDescriptor; diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h index 20e4497fde193..bcb71a53c52cb 100644 --- a/src/google/protobuf/extension_set_inl.h +++ b/src/google/protobuf/extension_set_inl.h @@ -169,7 +169,8 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo( ? AddMessage(arena, number, WireFormatLite::TYPE_GROUP, info.message_info.GetClassData(), info.descriptor) : MutableMessage(arena, number, WireFormatLite::TYPE_GROUP, - *info.message_info.prototype, info.descriptor); + *info.message_info.GetPrototype(), + info.descriptor); uint32_t tag = (number << 3) + WireFormatLite::WIRETYPE_START_GROUP; return ctx->ParseGroup(value, ptr, tag); } @@ -180,7 +181,8 @@ const char* ExtensionSet::ParseFieldWithExtensionInfo( ? AddMessage(arena, number, WireFormatLite::TYPE_MESSAGE, info.message_info.GetClassData(), info.descriptor) : MutableMessage(arena, number, WireFormatLite::TYPE_MESSAGE, - *info.message_info.prototype, info.descriptor); + *info.message_info.GetPrototype(), + info.descriptor); return ctx->ParseMessage(value, ptr); } } @@ -224,7 +226,7 @@ const char* ExtensionSet::ParseMessageSetItemTmpl( extension.message_info.GetClassData(), extension.descriptor) : MutableMessage(arena, type_id, WireFormatLite::TYPE_MESSAGE, - *extension.message_info.prototype, + *extension.message_info.GetPrototype(), extension.descriptor); const char* p; diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 29e15259d42f7..9c1822d3d9078 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -3823,6 +3823,17 @@ const internal::TcParseTableBase* Reflection::CreateTcParseTable() const { byte_size) << "message = " << descriptor_->full_name(); +#ifdef PROTOBUF_MESSAGE_GLOBALS + // DynamicMessage's parse table is lazily created and its class data should be + // updated to point to the parse table. + ABSL_CHECK_NE(message_factory_, nullptr); + const MessageLite* prototype = message_factory_->GetPrototype(descriptor_); + // const_cast is unfortunate but acceptable as we own the type. + auto* mutable_globals = MessageGlobalsBase::FromDefaultInstance( + const_cast(prototype)); + ABSL_DCHECK(!mutable_globals->GetClassData()->full().is_lite); + mutable_globals->SetTcParseTableForDynamicMessage(res); +#endif return res; } diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 57c657ea1d9fc..4fb99fc4fcecc 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -425,6 +425,11 @@ struct PrivateAccess { return T::InternalGenerateParseTable_(class_data); } + inline static const internal::TcParseTableBase* GetTcParseTable( + const MessageLite* msg) { + return msg->GetTcParseTable(); + } + static internal::ExtensionSet* GetExtensionSet(MessageLite* msg); static const internal::ExtensionSet* GetExtensionSet(const MessageLite* msg); diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index ac44bb6995146..643f5293b47b2 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -574,6 +574,7 @@ struct PROTOBUF_EXPORT ClassDataFull : ClassData { } constexpr const ClassData* base() const { return this; } + ClassData* mutable_base() { return this; } // Accessors for reflection related data (ClassDataFull only). const Reflection* reflection() const { return reflection_data()->reflection; } @@ -664,6 +665,11 @@ struct MessageGlobalsBase { reinterpret_cast(default_instance) - OffsetToDefault()); } + static MessageGlobalsBase* FromDefaultInstance(void* default_instance) { + return reinterpret_cast( + reinterpret_cast(default_instance) - OffsetToDefault()); + } + static constexpr const ClassData* GetClassData(const void* globals) { return static_cast(globals)->class_data.base(); } @@ -678,6 +684,11 @@ struct MessageGlobalsBase { return globals->class_data.tc_table; } + void SetTcParseTableForDynamicMessage( + const internal::TcParseTableBase* tc_table) { + class_data.mutable_base()->tc_table = tc_table; + } + // It also aliases to ClassDataLite. ClassDataFull class_data; };