Short-circuit destruction of an empty field using SSO.

```
name                                   old cpu/op   new cpu/op   delta
BM_RepeatedPtrField_Ctor                133ns ± 2%     78ns ± 1%  -41.64%   (p=0.000 n=80+87)

```

PiperOrigin-RevId: 582667999
pull/14753/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent 531596c5f9
commit 70876bd87e
  1. 6
      src/google/protobuf/implicit_weak_message.h
  2. 15
      src/google/protobuf/repeated_ptr_field.cc
  3. 16
      src/google/protobuf/repeated_ptr_field.h

@ -167,7 +167,11 @@ struct WeakRepeatedPtrField {
// TODO: make this constructor private
explicit WeakRepeatedPtrField(Arena* arena) : weak(arena) {}
~WeakRepeatedPtrField() { weak.template Destroy<TypeHandler>(); }
~WeakRepeatedPtrField() {
if (weak.NeedsDestroy()) {
weak.DestroyProtos();
}
}
typedef internal::RepeatedPtrIterator<MessageLite> iterator;
typedef internal::RepeatedPtrIterator<const MessageLite> const_iterator;

@ -88,20 +88,7 @@ void RepeatedPtrFieldBase::Reserve(int capacity) {
}
void RepeatedPtrFieldBase::DestroyProtos() {
ABSL_DCHECK(tagged_rep_or_elem_);
ABSL_DCHECK(arena_ == nullptr);
if (using_sso()) {
delete static_cast<MessageLite*>(tagged_rep_or_elem_);
} else {
Rep* r = rep();
int n = r->allocated_size;
void* const* elements = r->elements;
for (int i = 0; i < n; i++) {
delete static_cast<MessageLite*>(elements[i]);
}
const size_t size = Capacity() * sizeof(elements[0]) + kRepHeaderSize;
internal::SizedDelete(r, size);
}
Destroy<GenericTypeHandler<MessageLite>>();
// TODO: Eliminate this store when invoked from the destructor,
// since it is dead.

@ -251,10 +251,12 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
// Must be called from destructor.
//
// Pre-condition: NeedsDestroy() returns true.
template <typename TypeHandler>
void Destroy() {
ABSL_DCHECK(NeedsDestroy());
using H = CommonHandler<TypeHandler>;
if (arena_ != nullptr) return;
int n = allocated_size();
void** elems = elements();
for (int i = 0; i < n; i++) {
@ -267,7 +269,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
bool NeedsDestroy() const {
return tagged_rep_or_elem_ != nullptr && arena_ == nullptr;
// TODO: arena check is redundant once all `RepeatedPtrField`s
// with non-null arena are owned by the arena.
return tagged_rep_or_elem_ != nullptr &&
PROTOBUF_PREDICT_FALSE(arena_ == nullptr);
}
void DestroyProtos(); // implemented in the cc file
@ -630,7 +635,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
this->CopyFrom<TypeHandler>(*other);
other->InternalSwap(&temp);
temp.Destroy<TypeHandler>(); // Frees rep_ if `other` had no arena.
if (temp.NeedsDestroy()) {
temp.Destroy<TypeHandler>();
}
}
// Gets the Arena on which this RepeatedPtrField stores its elements.
@ -1374,12 +1381,13 @@ inline RepeatedPtrField<Element>::RepeatedPtrField(Iter begin, Iter end) {
template <typename Element>
RepeatedPtrField<Element>::~RepeatedPtrField() {
StaticValidityCheck();
if (!NeedsDestroy()) return;
#ifdef __cpp_if_constexpr
if constexpr (std::is_base_of<MessageLite, Element>::value) {
#else
if (std::is_base_of<MessageLite, Element>::value) {
#endif
if (NeedsDestroy()) DestroyProtos();
DestroyProtos();
} else {
Destroy<TypeHandler>();
}

Loading…
Cancel
Save