Move fixed_address_empty_string to rodata section when possible.

In C++20 take advantage of constexpr support to do so.

PiperOrigin-RevId: 685820979
pull/18713/head
Protobuf Team Bot 1 month ago committed by Copybara-Service
parent f3451d2679
commit bd03560d9f
  1. 3
      src/google/protobuf/arenastring.cc
  2. 10
      src/google/protobuf/arenastring.h
  3. 13
      src/google/protobuf/arenastring_unittest.cc
  4. 5
      src/google/protobuf/explicitly_constructed.h
  5. 9
      src/google/protobuf/generated_message_util.cc
  6. 8
      src/google/protobuf/message_lite.h
  7. 9
      src/google/protobuf/port.cc
  8. 31
      src/google/protobuf/port.h

@ -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

@ -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<void*>(static_cast<const void*>(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) {}

@ -90,16 +90,11 @@ TEST_P(SingleArena, NullDefault) {
}
TEST(ArenaStringPtrTest, ConstInit) {
// Verify that we can constinit construct an ArenaStringPtr from an arbitrary
// ExplicitlyConstructed<std::string>*.
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) {

@ -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<std::string, 8>;
} // namespace internal
} // namespace protobuf
} // namespace google

@ -42,10 +42,6 @@ void DestroyString(const void* s) {
static_cast<const std::string*>(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<bool> 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();

@ -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();
}

@ -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

@ -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<const std::string*>(internal::Launder(buffer_));
}
std::string* Init() {
return ::new (static_cast<void*>(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

Loading…
Cancel
Save