Skip to content

Commit

Permalink
Move fixed_address_empty_string to rodata section when possible.
Browse files Browse the repository at this point in the history
In C++20 take advantage of constexpr support to do so.

PiperOrigin-RevId: 685820979
  • Loading branch information
protobuf-github-bot authored and copybara-github committed Oct 14, 2024
1 parent f3451d2 commit bd03560
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 35 deletions.
3 changes: 2 additions & 1 deletion src/google/protobuf/arenastring.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

Expand Down
10 changes: 3 additions & 7 deletions src/google/protobuf/arenastring.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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) {}

Expand Down
13 changes: 4 additions & 9 deletions src/google/protobuf/arenastring_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 0 additions & 5 deletions src/google/protobuf/explicitly_constructed.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 3 additions & 6 deletions src/google/protobuf/generated_message_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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_;

Expand Down Expand Up @@ -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();


Expand Down
8 changes: 1 addition & 7 deletions src/google/protobuf/message_lite.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
9 changes: 9 additions & 0 deletions src/google/protobuf/port.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 31 additions & 0 deletions src/google/protobuf/port.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bd03560

Please sign in to comment.