From bd03560d9f17487737efc71dd03f21141a942f29 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 14 Oct 2024 13:42:45 -0700 Subject: [PATCH] Move fixed_address_empty_string to rodata section when possible. In C++20 take advantage of constexpr support to do so. PiperOrigin-RevId: 685820979 --- src/google/protobuf/arenastring.cc | 3 +- src/google/protobuf/arenastring.h | 10 ++---- src/google/protobuf/arenastring_unittest.cc | 13 +++----- src/google/protobuf/explicitly_constructed.h | 5 --- src/google/protobuf/generated_message_util.cc | 9 ++---- src/google/protobuf/message_lite.h | 8 +---- src/google/protobuf/port.cc | 9 ++++++ src/google/protobuf/port.h | 31 +++++++++++++++++++ 8 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/google/protobuf/arenastring.cc b/src/google/protobuf/arenastring.cc index 0ccacfbc8d..ae1929d0b8 100644 --- a/src/google/protobuf/arenastring.cc +++ b/src/google/protobuf/arenastring.cc @@ -15,6 +15,7 @@ #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/message_lite.h" #include "google/protobuf/parse_context.h" +#include "google/protobuf/port.h" // clang-format off #include "google/protobuf/port_def.inc" @@ -42,7 +43,7 @@ constexpr size_t kNewAlign = alignof(std::max_align_t); constexpr size_t kStringAlign = alignof(std::string); static_assert((kStringAlign > kNewAlign ? kStringAlign : kNewAlign) >= 4, ""); -static_assert(alignof(ExplicitlyConstructedArenaString) >= 4, ""); +static_assert(alignof(GlobalEmptyString) >= 4, ""); } // namespace diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h index e8b417f06e..d45f45af8c 100644 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -35,10 +35,6 @@ class EpsCopyInputStream; class SwapFieldHelper; -// Declared in message_lite.h -PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString - fixed_address_empty_string; - // Lazy string instance to support string fields with non-empty default. // These are initialized on the first call to .get(). class PROTOBUF_EXPORT LazyString { @@ -107,8 +103,8 @@ class PROTOBUF_EXPORT TaggedStringPtr { }; TaggedStringPtr() = default; - explicit constexpr TaggedStringPtr(ExplicitlyConstructedArenaString* ptr) - : ptr_(ptr) {} + explicit constexpr TaggedStringPtr(const GlobalEmptyString* ptr) + : ptr_(const_cast(static_cast(ptr))) {} // Sets the value to `p`, tagging the value as being a 'default' value. // See documentation for kDefault for more info. @@ -231,7 +227,7 @@ struct PROTOBUF_EXPORT ArenaStringPtr { ArenaStringPtr() = default; // Constexpr constructor, initializes to a constexpr, empty string value. - constexpr ArenaStringPtr(ExplicitlyConstructedArenaString* default_value, + constexpr ArenaStringPtr(const GlobalEmptyString* default_value, ConstantInitialized) : tagged_ptr_(default_value) {} diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc index 01def5611a..f2a5947b59 100644 --- a/src/google/protobuf/arenastring_unittest.cc +++ b/src/google/protobuf/arenastring_unittest.cc @@ -90,16 +90,11 @@ TEST_P(SingleArena, NullDefault) { } TEST(ArenaStringPtrTest, ConstInit) { - // Verify that we can constinit construct an ArenaStringPtr from an arbitrary - // ExplicitlyConstructed*. - static internal::ExplicitlyConstructedArenaString str; - PROTOBUF_CONSTINIT static ArenaStringPtr ptr(&str, - internal::ConstantInitialized{}); - EXPECT_EQ(&ptr.Get(), str.get_mutable()); - - PROTOBUF_CONSTINIT static const ArenaStringPtr ptr2( + // Verify that we can constinit construct an ArenaStringPtr from the global + // string. + PROTOBUF_CONSTINIT static const ArenaStringPtr ptr( &internal::fixed_address_empty_string, internal::ConstantInitialized{}); - EXPECT_EQ(&ptr2.Get(), &internal::GetEmptyStringAlreadyInited()); + EXPECT_EQ(&ptr.Get(), &internal::GetEmptyStringAlreadyInited()); } TEST_P(SingleArena, ConstructEmpty) { diff --git a/src/google/protobuf/explicitly_constructed.h b/src/google/protobuf/explicitly_constructed.h index e9e27c6aec..3527c4e42e 100644 --- a/src/google/protobuf/explicitly_constructed.h +++ b/src/google/protobuf/explicitly_constructed.h @@ -58,11 +58,6 @@ class ExplicitlyConstructed { } union_; }; -// ArenaStringPtr compatible explicitly constructed string type. -// This empty string type is aligned with a minimum alignment of 8 bytes -// which is the minimum requirement of ArenaStringPtr -using ExplicitlyConstructedArenaString = ExplicitlyConstructed; - } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index 09b7db5d66..354861adb3 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -42,10 +42,6 @@ void DestroyString(const void* s) { static_cast(s)->~basic_string(); } -PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT - PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 ExplicitlyConstructedArenaString - fixed_address_empty_string{}; // NOLINT - PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT const EmptyCord empty_cord_; @@ -89,8 +85,9 @@ void InitWeakDefaults() {} PROTOBUF_CONSTINIT std::atomic init_protobuf_defaults_state{false}; static bool InitProtobufDefaultsImpl() { - fixed_address_empty_string.DefaultConstruct(); - OnShutdownDestroyString(fixed_address_empty_string.get_mutable()); + if (auto* to_destroy = fixed_address_empty_string.Init()) { + OnShutdownDestroyString(to_destroy); + } InitWeakDefaults(); diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index bbd9dc9b38..4ddb1a3699 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -312,14 +312,8 @@ using GetTypeNameReturnType = absl::string_view; using GetTypeNameReturnType = std::string; #endif -// Default empty string object. Don't use this directly. Instead, call -// GetEmptyString() to get the reference. This empty string is aligned with a -// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr. -PROTOBUF_EXPORT extern ExplicitlyConstructedArenaString - fixed_address_empty_string; - -PROTOBUF_EXPORT constexpr const std::string& GetEmptyStringAlreadyInited() { +PROTOBUF_EXPORT inline const std::string& GetEmptyStringAlreadyInited() { return fixed_address_empty_string.get(); } diff --git a/src/google/protobuf/port.cc b/src/google/protobuf/port.cc index 196f43228e..0261a94e17 100644 --- a/src/google/protobuf/port.cc +++ b/src/google/protobuf/port.cc @@ -97,6 +97,15 @@ void RealDebugCounter::Register(absl::string_view name) { } } +#if defined(__cpp_lib_constexpr_string) +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT const GlobalEmptyString + fixed_address_empty_string{}; +#else +PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT + PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 GlobalEmptyString + fixed_address_empty_string{}; +#endif + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/port.h b/src/google/protobuf/port.h index 6e3ebb955d..8f6e05d044 100644 --- a/src/google/protobuf/port.h +++ b/src/google/protobuf/port.h @@ -452,6 +452,37 @@ class NoopDebugCounter { constexpr void Inc() {} }; +// Default empty string object. Don't use this directly. Instead, call +// GetEmptyString() to get the reference. This empty string is aligned with a +// minimum alignment of 8 bytes to match the requirement of ArenaStringPtr. +#if defined(__cpp_lib_constexpr_string) +// Take advantage of C++20 constexpr support in std::string. +class alignas(8) GlobalEmptyString { + public: + const std::string& get() const { return value_; } + // Nothing to init, or destroy. + std::string* Init() const { return nullptr; } + + private: + std::string value_; +}; +PROTOBUF_EXPORT extern const GlobalEmptyString fixed_address_empty_string; +#else +class alignas(8) GlobalEmptyString { + public: + const std::string& get() const { + return *reinterpret_cast(internal::Launder(buffer_)); + } + std::string* Init() { + return ::new (static_cast(buffer_)) std::string(); + } + + private: + alignas(std::string) char buffer_[sizeof(std::string)]; +}; +PROTOBUF_EXPORT extern GlobalEmptyString fixed_address_empty_string; +#endif + } // namespace internal } // namespace protobuf } // namespace google