Skip to content

Commit ff7ac00

Browse files
ClaytonKnittelcopybara-github
authored andcommitted
Allocate FieldArenaRep type in Arena::DefaultConstruct when using arenas.
This change is prerequisite to supporting split fields with removed arena pointers. Split field types which have removed arena pointers have a larger representation on the arena which holds a copy of `InternalMetadata` from the parent message, since they need to be able to find a nearby `InternalMetadata` within a 32-bit offset. This is exactly how directly arena-allocated field types with arena offsets will work, but this logic is currently only implemented in `DoCreateMessage`. We will do the same trick here to construct this larger type when allocating in `Arena::DefaultConstruct`, which is the API split fields use. PiperOrigin-RevId: 814896561
1 parent 5ef4ee1 commit ff7ac00

File tree

1 file changed

+19
-6
lines changed

1 file changed

+19
-6
lines changed

src/google/protobuf/arena.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -741,18 +741,31 @@ class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8)
741741
template <typename T>
742742
PROTOBUF_NOINLINE void* PROTOBUF_NONNULL
743743
Arena::DefaultConstruct(Arena* PROTOBUF_NULLABLE arena) {
744-
static_assert(is_destructor_skippable<T>::value, "");
745-
void* mem;
746744
if (arena != nullptr) {
747-
mem = arena->AllocateAligned(sizeof(T));
745+
using ArenaRepT = typename internal::FieldArenaRep<T>::Type;
746+
static_assert(is_destructor_skippable<ArenaRepT>::value, "");
747+
748+
void* mem = arena->AllocateAligned(sizeof(ArenaRepT));
749+
ArenaRepT* arena_rep = new (mem) ArenaRepT(arena);
750+
return internal::FieldArenaRep<T>::Get(arena_rep);
748751
} else {
752+
static_assert(is_destructor_skippable<T>::value, "");
753+
749754
#if ABSL_HAVE_BUILTIN(__builtin_operator_new)
750-
mem = __builtin_operator_new(sizeof(T));
755+
void* mem = __builtin_operator_new(sizeof(T));
751756
#else
752-
mem = ::operator new(sizeof(T));
757+
void* mem = ::operator new(sizeof(T));
753758
#endif
759+
760+
// Fields which use arena offsets don't have constructors that take an arena
761+
// pointer. Since the arena is nullptr, it is safe to default construct the
762+
// object.
763+
if constexpr (internal::FieldHasArenaOffset<T>()) {
764+
return new (mem) T();
765+
} else {
766+
return new (mem) T(nullptr);
767+
}
754768
}
755-
return new (mem) T(arena);
756769
}
757770

758771
template <typename T>

0 commit comments

Comments
 (0)