From 3ae5a079fca3451c1f6456d79b42ede63cf6e498 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 12 Sep 2023 10:46:11 -0700 Subject: [PATCH] Reduce code bloat for messages - use virtual methods for Merge/Clear/Delete. PiperOrigin-RevId: 564768912 --- src/google/protobuf/repeated_ptr_field.h | 77 ++++++++++++++---------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index 5aff8124be..f0e20ad27f 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -149,6 +149,13 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { template using Value = typename Handler::Type; + // We use the same Handler for all Message types to deduplicate generated + // code. + template + using CommonHandler = typename std::conditional< + std::is_base_of>::value, + internal::GenericTypeHandler, Handler>::type; + static constexpr int kSSOCapacity = 1; protected: @@ -230,27 +237,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { void Delete(int index) { ABSL_DCHECK_GE(index, 0); ABSL_DCHECK_LT(index, current_size_); - Delete(element_at(index), arena_); + using H = CommonHandler; + Delete(element_at(index), arena_); } // Must be called from destructor. template void Destroy() { + using H = CommonHandler; if (arena_ != nullptr) return; - - if (using_sso()) { - if (tagged_rep_or_elem_ == nullptr) return; - Delete(tagged_rep_or_elem_, nullptr); - return; - } - - Rep* r = rep(); - int n = r->allocated_size; - void* const* elems = r->elements; + int n = allocated_size(); + void** elems = elements(); for (int i = 0; i < n; i++) { - Delete(elems[i], nullptr); + Delete(elems[i], nullptr); + } + if (!using_sso()) { + internal::SizedDelete(rep(), + total_size_ * sizeof(elems[0]) + kRepHeaderSize); } - internal::SizedDelete(r, total_size_ * sizeof(elems[0]) + kRepHeaderSize); } bool NeedsDestroy() const { @@ -281,7 +285,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { const int n = current_size_; ABSL_DCHECK_GE(n, 0); if (n > 0) { - ClearNonEmpty(); + using H = CommonHandler; + ClearNonEmpty(); } } @@ -295,8 +300,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { // calls the object-allocate and merge handlers. ABSL_DCHECK_NE(&other, this); if (other.current_size_ == 0) return; - MergeFromInternal(other, - &RepeatedPtrFieldBase::MergeFromInnerLoop); + using H = CommonHandler; + MergeFromInternal(other, &RepeatedPtrFieldBase::MergeFromInnerLoop); } inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) { @@ -332,7 +337,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { void RemoveLast() { ABSL_DCHECK_GT(current_size_, 0); ExchangeCurrentSize(current_size_ - 1); - TypeHandler::Clear(cast(element_at(current_size_))); + using H = CommonHandler; + H::Clear(cast(element_at(current_size_))); } template @@ -348,9 +354,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { template static inline Value* copy(Value* value) { - auto* new_value = TypeHandler::NewFromPrototype(value, nullptr); - TypeHandler::Merge(*value, new_value); - return new_value; + using H = CommonHandler; + auto* new_value = H::NewFromPrototype(value, nullptr); + H::Merge(*value, new_value); + return cast(new_value); } // Used for constructing iterators. @@ -392,7 +399,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { } template - size_t SpaceUsedExcludingSelfLong() const { + PROTOBUF_NOINLINE size_t SpaceUsedExcludingSelfLong() const { size_t allocated_bytes = using_sso() ? 0 @@ -437,7 +444,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { // cleared objects awaiting reuse. We don't want to grow the array in // this case because otherwise a loop calling AddAllocated() followed by // Clear() would leak memory. - Delete(element_at(current_size_), arena_); + using H = CommonHandler; + Delete(element_at(current_size_), arena_); } else if (current_size_ < allocated_size()) { // We have some cleared objects. We don't care about their order, so we // can just move the first one to the end to make space. @@ -568,8 +576,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { my_arena->Own(value); } else if (my_arena != value_arena) { auto* new_value = TypeHandler::NewFromPrototype(value, my_arena); - TypeHandler::Merge(*value, new_value); - TypeHandler::Delete(value, value_arena); + using H = CommonHandler; + H::Merge(*value, new_value); + H::Delete(value, value_arena); value = new_value; } @@ -741,9 +750,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { const int n = current_size_; void* const* elems = elements(); int i = 0; - ABSL_DCHECK_GT( - n, - 0); // do/while loop to avoid initial test because we know n > 0 + ABSL_DCHECK_GT(n, 0); + // do/while loop to avoid initial test because we know n > 0 do { TypeHandler::Clear(cast(elems[i++])); } while (i < n); @@ -866,7 +874,8 @@ class GenericTypeHandler { // NewFromPrototypeHelper() is not defined inline here, as we will need to do a // virtual function dispatch anyways to go from Message* to call New/Merge. (The // additional helper is needed as a workaround for MSVC.) -MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena); +PROTOBUF_EXPORT MessageLite* NewFromPrototypeHelper( + const MessageLite* prototype, Arena* arena); template <> inline MessageLite* GenericTypeHandler::NewFromPrototype( @@ -885,8 +894,8 @@ PROTOBUF_NOINLINE inline void GenericTypeHandler::Merge( to->MergeFrom(from); } template <> -void GenericTypeHandler::Merge(const MessageLite& from, - MessageLite* to); +PROTOBUF_EXPORT void GenericTypeHandler::Merge( + const MessageLite& from, MessageLite* to); template <> inline void GenericTypeHandler::Clear(std::string* value) { @@ -1642,7 +1651,13 @@ inline Arena* RepeatedPtrField::GetOwningArena() const { template inline size_t RepeatedPtrField::SpaceUsedExcludingSelfLong() const { - return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong(); + // `google::protobuf::Message` has a virtual method `SpaceUsedLong`, hence we can + // instantiate just one function for all protobuf messages. + // Note: std::is_base_of requires that `Element` is a concrete class. + using H = typename std::conditional::value, + internal::GenericTypeHandler, + TypeHandler>::type; + return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong(); } template