Add prefetching of subsequent extensions in ExtensionSet::ForEach.

PiperOrigin-RevId: 671457336
pull/18137/head
Evan Brown 6 months ago committed by Copybara-Service
parent f72e5ce370
commit 9b019ee271
  1. 63
      src/google/protobuf/extension_set.cc
  2. 96
      src/google/protobuf/extension_set.h
  3. 53
      src/google/protobuf/extension_set_heavy.cc
  4. 163
      src/google/protobuf/reflection_visit_fields.h

@ -186,7 +186,8 @@ void ExtensionSet::RegisterMessageExtension(const MessageLite* extendee,
ExtensionSet::~ExtensionSet() { ExtensionSet::~ExtensionSet() {
// Deletes all allocated extensions. // Deletes all allocated extensions.
if (arena_ == nullptr) { if (arena_ == nullptr) {
ForEach([](int /* number */, Extension& ext) { ext.Free(); }); ForEach([](int /* number */, Extension& ext) { ext.Free(); },
PrefetchNta{});
if (PROTOBUF_PREDICT_FALSE(is_large())) { if (PROTOBUF_PREDICT_FALSE(is_large())) {
delete map_.large; delete map_.large;
} else { } else {
@ -225,7 +226,7 @@ bool ExtensionSet::HasLazy(int number) const {
int ExtensionSet::NumExtensions() const { int ExtensionSet::NumExtensions() const {
int result = 0; int result = 0;
ForEach([&result](int /* number */, const Extension& ext) { ForEachNoPrefetch([&result](int /* number */, const Extension& ext) {
if (!ext.is_cleared) { if (!ext.is_cleared) {
++result; ++result;
} }
@ -308,6 +309,7 @@ enum { REPEATED_FIELD, OPTIONAL_FIELD };
ABSL_DCHECK_EQ(cpp_type(extension->type), \ ABSL_DCHECK_EQ(cpp_type(extension->type), \
WireFormatLite::CPPTYPE_##UPPERCASE); \ WireFormatLite::CPPTYPE_##UPPERCASE); \
extension->is_repeated = false; \ extension->is_repeated = false; \
extension->is_pointer = false; \
} else { \ } else { \
ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE); \ ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, UPPERCASE); \
} \ } \
@ -351,6 +353,7 @@ enum { REPEATED_FIELD, OPTIONAL_FIELD };
ABSL_DCHECK_EQ(cpp_type(extension->type), \ ABSL_DCHECK_EQ(cpp_type(extension->type), \
WireFormatLite::CPPTYPE_##UPPERCASE); \ WireFormatLite::CPPTYPE_##UPPERCASE); \
extension->is_repeated = true; \ extension->is_repeated = true; \
extension->is_pointer = true; \
extension->is_packed = packed; \ extension->is_packed = packed; \
extension->ptr.repeated_##LOWERCASE##_value = \ extension->ptr.repeated_##LOWERCASE##_value = \
Arena::Create<RepeatedField<LOWERCASE>>(arena_); \ Arena::Create<RepeatedField<LOWERCASE>>(arena_); \
@ -391,6 +394,7 @@ void* ExtensionSet::MutableRawRepeatedField(int number, FieldType field_type,
// extension. // extension.
if (MaybeNewExtension(number, desc, &extension)) { if (MaybeNewExtension(number, desc, &extension)) {
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
extension->type = field_type; extension->type = field_type;
extension->is_packed = packed; extension->is_packed = packed;
@ -487,6 +491,7 @@ void ExtensionSet::SetEnum(int number, FieldType type, int value,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = false;
} else { } else {
ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM); ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, ENUM);
} }
@ -522,6 +527,7 @@ void ExtensionSet::AddEnum(int number, FieldType type, bool packed, int value,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM);
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
extension->is_packed = packed; extension->is_packed = packed;
extension->ptr.repeated_enum_value = extension->ptr.repeated_enum_value =
Arena::Create<RepeatedField<int>>(arena_); Arena::Create<RepeatedField<int>>(arena_);
@ -554,6 +560,7 @@ std::string* ExtensionSet::MutableString(int number, FieldType type,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
extension->ptr.string_value = Arena::Create<std::string>(arena_); extension->ptr.string_value = Arena::Create<std::string>(arena_);
} else { } else {
ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING); ABSL_DCHECK_TYPE(*extension, OPTIONAL_FIELD, STRING);
@ -584,6 +591,7 @@ std::string* ExtensionSet::AddString(int number, FieldType type,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING);
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
extension->is_packed = false; extension->is_packed = false;
extension->ptr.repeated_string_value = extension->ptr.repeated_string_value =
Arena::Create<RepeatedPtrField<std::string>>(arena_); Arena::Create<RepeatedPtrField<std::string>>(arena_);
@ -626,6 +634,7 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
extension->is_lazy = false; extension->is_lazy = false;
extension->ptr.message_value = prototype.New(arena_); extension->ptr.message_value = prototype.New(arena_);
extension->is_cleared = false; extension->is_cleared = false;
@ -663,6 +672,7 @@ void ExtensionSet::SetAllocatedMessage(int number, FieldType type,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
extension->is_lazy = false; extension->is_lazy = false;
if (message_arena == arena) { if (message_arena == arena) {
extension->ptr.message_value = message; extension->ptr.message_value = message;
@ -707,6 +717,7 @@ void ExtensionSet::UnsafeArenaSetAllocatedMessage(
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
extension->is_lazy = false; extension->is_lazy = false;
extension->ptr.message_value = message; extension->ptr.message_value = message;
} else { } else {
@ -805,6 +816,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
extension->type = type; extension->type = type;
ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE);
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
extension->ptr.repeated_message_value = extension->ptr.repeated_message_value =
Arena::Create<RepeatedPtrField<MessageLite>>(arena_); Arena::Create<RepeatedPtrField<MessageLite>>(arena_);
} else { } else {
@ -920,7 +932,7 @@ void ExtensionSet::SwapElements(int number, int index1, int index2) {
// =================================================================== // ===================================================================
void ExtensionSet::Clear() { void ExtensionSet::Clear() {
ForEach([](int /* number */, Extension& ext) { ext.Clear(); }); ForEach([](int /* number */, Extension& ext) { ext.Clear(); }, Prefetch{});
} }
namespace { namespace {
@ -969,9 +981,11 @@ void ExtensionSet::MergeFrom(const MessageLite* extendee,
other.map_.large->end())); other.map_.large->end()));
} }
} }
other.ForEach([extendee, this, &other](int number, const Extension& ext) { other.ForEach(
this->InternalExtensionMergeFrom(extendee, number, ext, other.arena_); [extendee, this, &other](int number, const Extension& ext) {
}); this->InternalExtensionMergeFrom(extendee, number, ext, other.arena_);
},
Prefetch{});
} }
void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee, void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee,
@ -987,6 +1001,7 @@ void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee,
extension->type = other_extension.type; extension->type = other_extension.type;
extension->is_packed = other_extension.is_packed; extension->is_packed = other_extension.is_packed;
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
} else { } else {
ABSL_DCHECK_EQ(extension->type, other_extension.type); ABSL_DCHECK_EQ(extension->type, other_extension.type);
ABSL_DCHECK_EQ(extension->is_packed, other_extension.is_packed); ABSL_DCHECK_EQ(extension->is_packed, other_extension.is_packed);
@ -1049,6 +1064,7 @@ void ExtensionSet::InternalExtensionMergeFrom(const MessageLite* extendee,
extension->type = other_extension.type; extension->type = other_extension.type;
extension->is_packed = other_extension.is_packed; extension->is_packed = other_extension.is_packed;
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
if (other_extension.is_lazy) { if (other_extension.is_lazy) {
extension->is_lazy = true; extension->is_lazy = true;
extension->ptr.lazymessage_value = extension->ptr.lazymessage_value =
@ -1226,6 +1242,13 @@ const char* ExtensionSet::ParseMessageSetItem(
metadata, ctx); metadata, ctx);
} }
bool ExtensionSet::FieldTypeIsPointer(FieldType type) {
return type == WireFormatLite::TYPE_STRING ||
type == WireFormatLite::TYPE_BYTES ||
type == WireFormatLite::TYPE_GROUP ||
type == WireFormatLite::TYPE_MESSAGE;
}
uint8_t* ExtensionSet::_InternalSerializeImpl( uint8_t* ExtensionSet::_InternalSerializeImpl(
const MessageLite* extendee, int start_field_number, int end_field_number, const MessageLite* extendee, int start_field_number, int end_field_number,
uint8_t* target, io::EpsCopyOutputStream* stream) const { uint8_t* target, io::EpsCopyOutputStream* stream) const {
@ -1252,19 +1275,23 @@ uint8_t* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
const MessageLite* extendee, uint8_t* target, const MessageLite* extendee, uint8_t* target,
io::EpsCopyOutputStream* stream) const { io::EpsCopyOutputStream* stream) const {
const ExtensionSet* extension_set = this; const ExtensionSet* extension_set = this;
ForEach([&target, extendee, stream, extension_set](int number, ForEach(
const Extension& ext) { [&target, extendee, stream, extension_set](int number,
target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray( const Extension& ext) {
extendee, extension_set, number, target, stream); target = ext.InternalSerializeMessageSetItemWithCachedSizesToArray(
}); extendee, extension_set, number, target, stream);
},
Prefetch{});
return target; return target;
} }
size_t ExtensionSet::ByteSize() const { size_t ExtensionSet::ByteSize() const {
size_t total_size = 0; size_t total_size = 0;
ForEach([&total_size](int number, const Extension& ext) { ForEach(
total_size += ext.ByteSize(number); [&total_size](int number, const Extension& ext) {
}); total_size += ext.ByteSize(number);
},
Prefetch{});
return total_size; return total_size;
} }
@ -1932,9 +1959,11 @@ size_t ExtensionSet::Extension::MessageSetItemByteSize(int number) const {
size_t ExtensionSet::MessageSetByteSize() const { size_t ExtensionSet::MessageSetByteSize() const {
size_t total_size = 0; size_t total_size = 0;
ForEach([&total_size](int number, const Extension& ext) { ForEach(
total_size += ext.MessageSetItemByteSize(number); [&total_size](int number, const Extension& ext) {
}); total_size += ext.MessageSetItemByteSize(number);
},
Prefetch{});
return total_size; return total_size;
} }

@ -28,6 +28,8 @@
#include "google/protobuf/stubs/common.h" #include "google/protobuf/stubs/common.h"
#include "absl/base/call_once.h" #include "absl/base/call_once.h"
#include "absl/base/casts.h"
#include "absl/base/prefetch.h"
#include "absl/container/btree_map.h" #include "absl/container/btree_map.h"
#include "absl/log/absl_check.h" #include "absl/log/absl_check.h"
#include "google/protobuf/internal_visibility.h" #include "google/protobuf/internal_visibility.h"
@ -555,6 +557,8 @@ class PROTOBUF_EXPORT ExtensionSet {
friend void internal::InitializeLazyExtensionSet(); friend void internal::InitializeLazyExtensionSet();
static bool FieldTypeIsPointer(FieldType type);
const int32_t& GetRefInt32(int number, const int32_t& default_value) const; const int32_t& GetRefInt32(int number, const int32_t& default_value) const;
const int64_t& GetRefInt64(int number, const int64_t& default_value) const; const int64_t& GetRefInt64(int number, const int64_t& default_value) const;
const uint32_t& GetRefUInt32(int number, const uint32_t& default_value) const; const uint32_t& GetRefUInt32(int number, const uint32_t& default_value) const;
@ -670,6 +674,12 @@ class PROTOBUF_EXPORT ExtensionSet {
size_t SpaceUsedExcludingSelfLong() const; size_t SpaceUsedExcludingSelfLong() const;
bool IsInitialized(const ExtensionSet* ext_set, const MessageLite* extendee, bool IsInitialized(const ExtensionSet* ext_set, const MessageLite* extendee,
int number, Arena* arena) const; int number, Arena* arena) const;
const void* PrefetchPtr() const {
ABSL_DCHECK_EQ(is_pointer, is_repeated || FieldTypeIsPointer(type));
// We don't want to prefetch invalid/null pointers so if there isn't a
// pointer to prefetch, then return `this`.
return is_pointer ? absl::bit_cast<const void*>(ptr) : this;
}
// The order of these fields packs Extension into 24 bytes when using 8 // The order of these fields packs Extension into 24 bytes when using 8
// byte alignment. Consider this when adding or removing fields here. // byte alignment. Consider this when adding or removing fields here.
@ -708,20 +718,23 @@ class PROTOBUF_EXPORT ExtensionSet {
FieldType type; FieldType type;
bool is_repeated; bool is_repeated;
// Whether the extension is a pointer. This is used for prefetching.
bool is_pointer : 1;
// For singular types, indicates if the extension is "cleared". This // For singular types, indicates if the extension is "cleared". This
// happens when an extension is set and then later cleared by the caller. // happens when an extension is set and then later cleared by the caller.
// We want to keep the Extension object around for reuse, so instead of // We want to keep the Extension object around for reuse, so instead of
// removing it from the map, we just set is_cleared = true. This has no // removing it from the map, we just set is_cleared = true. This has no
// meaning for repeated types; for those, the size of the RepeatedField // meaning for repeated types; for those, the size of the RepeatedField
// simply becomes zero when cleared. // simply becomes zero when cleared.
bool is_cleared : 4; bool is_cleared : 1;
// For singular message types, indicates whether lazy parsing is enabled // For singular message types, indicates whether lazy parsing is enabled
// for this extension. This field is only valid when type == TYPE_MESSAGE // for this extension. This field is only valid when type == TYPE_MESSAGE
// and !is_repeated because we only support lazy parsing for singular // and !is_repeated because we only support lazy parsing for singular
// message types currently. If is_lazy = true, the extension is stored in // message types currently. If is_lazy = true, the extension is stored in
// lazymessage_value. Otherwise, the extension will be message_value. // lazymessage_value. Otherwise, the extension will be message_value.
bool is_lazy : 4; bool is_lazy : 1;
// For repeated types, this indicates if the [packed=true] option is set. // For repeated types, this indicates if the [packed=true] option is set.
bool is_packed; bool is_packed;
@ -779,32 +792,93 @@ class PROTOBUF_EXPORT ExtensionSet {
return PROTOBUF_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_; return PROTOBUF_PREDICT_FALSE(is_large()) ? map_.large->size() : flat_size_;
} }
// For use as `PrefetchFunctor`s in `ForEach`.
struct Prefetch {
void operator()(const void* ptr) const { absl::PrefetchToLocalCache(ptr); }
};
struct PrefetchNta {
void operator()(const void* ptr) const {
absl::PrefetchToLocalCacheNta(ptr);
}
};
template <typename Iterator, typename KeyValueFunctor,
typename PrefetchFunctor>
static KeyValueFunctor ForEachPrefetchImpl(Iterator it, Iterator end,
KeyValueFunctor func,
PrefetchFunctor prefetch_func) {
// Note: based on arena's ChunkList::Cleanup().
// Prefetch distance 16 performs better than 8 in load tests.
constexpr int kPrefetchDistance = 16;
Iterator prefetch = it;
// Prefetch the first kPrefetchDistance extensions.
for (int i = 0; prefetch != end && i < kPrefetchDistance; ++prefetch, ++i) {
prefetch_func(prefetch->second.PrefetchPtr());
}
// For the middle extensions, call func and then prefetch the extension
// kPrefetchDistance after the current one.
for (; prefetch != end; ++it, ++prefetch) {
func(it->first, it->second);
prefetch_func(prefetch->second.PrefetchPtr());
}
// Call func on the rest without prefetching.
for (; it != end; ++it) func(it->first, it->second);
return std::move(func);
}
// Similar to std::for_each. // Similar to std::for_each.
// Each Iterator is decomposed into ->first and ->second fields, so // Each Iterator is decomposed into ->first and ->second fields, so
// that the KeyValueFunctor can be agnostic vis-a-vis KeyValue-vs-std::pair. // that the KeyValueFunctor can be agnostic vis-a-vis KeyValue-vs-std::pair.
// Applies a functor to the <int, Extension&> pairs in sorted order and
// prefetches ahead.
template <typename KeyValueFunctor, typename PrefetchFunctor>
KeyValueFunctor ForEach(KeyValueFunctor func, PrefetchFunctor prefetch_func) {
if (PROTOBUF_PREDICT_FALSE(is_large())) {
return ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
std::move(func), std::move(prefetch_func));
}
return ForEachPrefetchImpl(flat_begin(), flat_end(), std::move(func),
std::move(prefetch_func));
}
// As above, but const.
template <typename KeyValueFunctor, typename PrefetchFunctor>
KeyValueFunctor ForEach(KeyValueFunctor func,
PrefetchFunctor prefetch_func) const {
if (PROTOBUF_PREDICT_FALSE(is_large())) {
return ForEachPrefetchImpl(map_.large->begin(), map_.large->end(),
std::move(func), std::move(prefetch_func));
}
return ForEachPrefetchImpl(flat_begin(), flat_end(), std::move(func),
std::move(prefetch_func));
}
// As above, but without prefetching. This is for use in cases where we never
// use the pointed-to extension values in `func`.
template <typename Iterator, typename KeyValueFunctor> template <typename Iterator, typename KeyValueFunctor>
static KeyValueFunctor ForEach(Iterator begin, Iterator end, static KeyValueFunctor ForEachNoPrefetch(Iterator begin, Iterator end,
KeyValueFunctor func) { KeyValueFunctor func) {
for (Iterator it = begin; it != end; ++it) func(it->first, it->second); for (Iterator it = begin; it != end; ++it) func(it->first, it->second);
return std::move(func); return std::move(func);
} }
// Applies a functor to the <int, Extension&> pairs in sorted order. // Applies a functor to the <int, Extension&> pairs in sorted order.
template <typename KeyValueFunctor> template <typename KeyValueFunctor>
KeyValueFunctor ForEach(KeyValueFunctor func) { KeyValueFunctor ForEachNoPrefetch(KeyValueFunctor func) {
if (PROTOBUF_PREDICT_FALSE(is_large())) { if (PROTOBUF_PREDICT_FALSE(is_large())) {
return ForEach(map_.large->begin(), map_.large->end(), std::move(func)); return ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
std::move(func));
} }
return ForEach(flat_begin(), flat_end(), std::move(func)); return ForEachNoPrefetch(flat_begin(), flat_end(), std::move(func));
} }
// Applies a functor to the <int, const Extension&> pairs in sorted order. // As above, but const.
template <typename KeyValueFunctor> template <typename KeyValueFunctor>
KeyValueFunctor ForEach(KeyValueFunctor func) const { KeyValueFunctor ForEachNoPrefetch(KeyValueFunctor func) const {
if (PROTOBUF_PREDICT_FALSE(is_large())) { if (PROTOBUF_PREDICT_FALSE(is_large())) {
return ForEach(map_.large->begin(), map_.large->end(), std::move(func)); return ForEachNoPrefetch(map_.large->begin(), map_.large->end(),
std::move(func));
} }
return ForEach(flat_begin(), flat_end(), std::move(func)); return ForEachNoPrefetch(flat_begin(), flat_end(), std::move(func));
} }
// Merges existing Extension from other_extension // Merges existing Extension from other_extension

@ -64,27 +64,30 @@ class DescriptorPoolExtensionFinder {
void ExtensionSet::AppendToList( void ExtensionSet::AppendToList(
const Descriptor* extendee, const DescriptorPool* pool, const Descriptor* extendee, const DescriptorPool* pool,
std::vector<const FieldDescriptor*>* output) const { std::vector<const FieldDescriptor*>* output) const {
ForEach([extendee, pool, &output](int number, const Extension& ext) { ForEach(
bool has = false; [extendee, pool, &output](int number, const Extension& ext) {
if (ext.is_repeated) { bool has = false;
has = ext.GetSize() > 0; if (ext.is_repeated) {
} else { has = ext.GetSize() > 0;
has = !ext.is_cleared; } else {
} has = !ext.is_cleared;
}
if (has) {
// TODO: Looking up each field by number is somewhat unfortunate.
// Is there a better way? The problem is that descriptors are lazily-
// initialized, so they might not even be constructed until
// AppendToList() is called.
if (ext.descriptor == nullptr) { if (has) {
output->push_back(pool->FindExtensionByNumber(extendee, number)); // TODO: Looking up each field by number is somewhat
} else { // unfortunate.
output->push_back(ext.descriptor); // Is there a better way? The problem is that descriptors are
} // lazily-initialized, so they might not even be constructed until
} // AppendToList() is called.
});
if (ext.descriptor == nullptr) {
output->push_back(pool->FindExtensionByNumber(extendee, number));
} else {
output->push_back(ext.descriptor);
}
}
},
Prefetch{});
} }
inline FieldDescriptor::Type real_type(FieldType type) { inline FieldDescriptor::Type real_type(FieldType type) {
@ -133,6 +136,7 @@ MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
extension->type = descriptor->type(); extension->type = descriptor->type();
ABSL_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
extension->is_repeated = false; extension->is_repeated = false;
extension->is_pointer = true;
extension->is_packed = false; extension->is_packed = false;
const MessageLite* prototype = const MessageLite* prototype =
factory->GetPrototype(descriptor->message_type()); factory->GetPrototype(descriptor->message_type());
@ -210,6 +214,7 @@ ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(
extension->type = descriptor->type(); extension->type = descriptor->type();
ABSL_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); ABSL_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
extension->is_repeated = true; extension->is_repeated = true;
extension->is_pointer = true;
extension->ptr.repeated_message_value = extension->ptr.repeated_message_value =
Arena::Create<RepeatedPtrField<MessageLite> >(arena_); Arena::Create<RepeatedPtrField<MessageLite> >(arena_);
} else { } else {
@ -353,9 +358,11 @@ int ExtensionSet::SpaceUsedExcludingSelf() const {
size_t ExtensionSet::SpaceUsedExcludingSelfLong() const { size_t ExtensionSet::SpaceUsedExcludingSelfLong() const {
size_t total_size = size_t total_size =
(is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue); (is_large() ? map_.large->size() : flat_capacity_) * sizeof(KeyValue);
ForEach([&total_size](int /* number */, const Extension& ext) { ForEach(
total_size += ext.SpaceUsedExcludingSelfLong(); [&total_size](int /* number */, const Extension& ext) {
}); total_size += ext.SpaceUsedExcludingSelfLong();
},
Prefetch{});
return total_size; return total_size;
} }

@ -303,102 +303,105 @@ void ReflectionVisit::VisitFields(MessageT& message, CallbackFn&& func,
auto* extendee = reflection->descriptor_; auto* extendee = reflection->descriptor_;
auto* pool = reflection->descriptor_pool_; auto* pool = reflection->descriptor_pool_;
set.ForEach([&](int number, auto& ext) { set.ForEach(
ABSL_DCHECK_GT(ext.type, 0); [&](int number, auto& ext) {
ABSL_DCHECK_LE(ext.type, FieldDescriptor::MAX_TYPE); ABSL_DCHECK_GT(ext.type, 0);
ABSL_DCHECK_LE(ext.type, FieldDescriptor::MAX_TYPE);
if (!ShouldVisit(mask, FieldDescriptor::TypeToCppType(
static_cast<FieldDescriptor::Type>(ext.type)))) { if (!ShouldVisit(mask,
return; FieldDescriptor::TypeToCppType(
} static_cast<FieldDescriptor::Type>(ext.type)))) {
return;
}
if (ext.is_repeated) { if (ext.is_repeated) {
if (ext.GetSize() == 0) return; if (ext.GetSize() == 0) return;
switch (ext.type) { switch (ext.type) {
#define PROTOBUF_HANDLE_CASE(TYPE, NAME) \ #define PROTOBUF_HANDLE_CASE(TYPE, NAME) \
case FieldDescriptor::TYPE_##TYPE: \ case FieldDescriptor::TYPE_##TYPE: \
func(internal::Repeated##NAME##DynamicExtensionInfo<decltype(ext)>{ \ func(internal::Repeated##NAME##DynamicExtensionInfo<decltype(ext)>{ \
ext, number}); \ ext, number}); \
break; break;
PROTOBUF_HANDLE_CASE(DOUBLE, Double); PROTOBUF_HANDLE_CASE(DOUBLE, Double);
PROTOBUF_HANDLE_CASE(FLOAT, Float); PROTOBUF_HANDLE_CASE(FLOAT, Float);
PROTOBUF_HANDLE_CASE(INT64, Int64); PROTOBUF_HANDLE_CASE(INT64, Int64);
PROTOBUF_HANDLE_CASE(UINT64, UInt64); PROTOBUF_HANDLE_CASE(UINT64, UInt64);
PROTOBUF_HANDLE_CASE(INT32, Int32); PROTOBUF_HANDLE_CASE(INT32, Int32);
PROTOBUF_HANDLE_CASE(FIXED64, Fixed64); PROTOBUF_HANDLE_CASE(FIXED64, Fixed64);
PROTOBUF_HANDLE_CASE(FIXED32, Fixed32); PROTOBUF_HANDLE_CASE(FIXED32, Fixed32);
PROTOBUF_HANDLE_CASE(BOOL, Bool); PROTOBUF_HANDLE_CASE(BOOL, Bool);
PROTOBUF_HANDLE_CASE(UINT32, UInt32); PROTOBUF_HANDLE_CASE(UINT32, UInt32);
PROTOBUF_HANDLE_CASE(ENUM, Enum); PROTOBUF_HANDLE_CASE(ENUM, Enum);
PROTOBUF_HANDLE_CASE(SFIXED32, SFixed32); PROTOBUF_HANDLE_CASE(SFIXED32, SFixed32);
PROTOBUF_HANDLE_CASE(SFIXED64, SFixed64); PROTOBUF_HANDLE_CASE(SFIXED64, SFixed64);
PROTOBUF_HANDLE_CASE(SINT32, SInt32); PROTOBUF_HANDLE_CASE(SINT32, SInt32);
PROTOBUF_HANDLE_CASE(SINT64, SInt64); PROTOBUF_HANDLE_CASE(SINT64, SInt64);
PROTOBUF_HANDLE_CASE(MESSAGE, Message); PROTOBUF_HANDLE_CASE(MESSAGE, Message);
PROTOBUF_HANDLE_CASE(GROUP, Group); PROTOBUF_HANDLE_CASE(GROUP, Group);
case FieldDescriptor::TYPE_BYTES: case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
func(internal::RepeatedStringDynamicExtensionInfo<decltype(ext)>{ func(internal::RepeatedStringDynamicExtensionInfo<decltype(ext)>{
ext, number}); ext, number});
break; break;
default: default:
internal::Unreachable(); internal::Unreachable();
break; break;
#undef PROTOBUF_HANDLE_CASE #undef PROTOBUF_HANDLE_CASE
} }
} else { } else {
if (ext.is_cleared) return; if (ext.is_cleared) return;
switch (ext.type) { switch (ext.type) {
#define PROTOBUF_HANDLE_CASE(TYPE, NAME) \ #define PROTOBUF_HANDLE_CASE(TYPE, NAME) \
case FieldDescriptor::TYPE_##TYPE: \ case FieldDescriptor::TYPE_##TYPE: \
func(internal::NAME##DynamicExtensionInfo<decltype(ext)>{ext, number}); \ func(internal::NAME##DynamicExtensionInfo<decltype(ext)>{ext, number}); \
break; break;
PROTOBUF_HANDLE_CASE(DOUBLE, Double); PROTOBUF_HANDLE_CASE(DOUBLE, Double);
PROTOBUF_HANDLE_CASE(FLOAT, Float); PROTOBUF_HANDLE_CASE(FLOAT, Float);
PROTOBUF_HANDLE_CASE(INT64, Int64); PROTOBUF_HANDLE_CASE(INT64, Int64);
PROTOBUF_HANDLE_CASE(UINT64, UInt64); PROTOBUF_HANDLE_CASE(UINT64, UInt64);
PROTOBUF_HANDLE_CASE(INT32, Int32); PROTOBUF_HANDLE_CASE(INT32, Int32);
PROTOBUF_HANDLE_CASE(FIXED64, Fixed64); PROTOBUF_HANDLE_CASE(FIXED64, Fixed64);
PROTOBUF_HANDLE_CASE(FIXED32, Fixed32); PROTOBUF_HANDLE_CASE(FIXED32, Fixed32);
PROTOBUF_HANDLE_CASE(BOOL, Bool); PROTOBUF_HANDLE_CASE(BOOL, Bool);
PROTOBUF_HANDLE_CASE(UINT32, UInt32); PROTOBUF_HANDLE_CASE(UINT32, UInt32);
PROTOBUF_HANDLE_CASE(ENUM, Enum); PROTOBUF_HANDLE_CASE(ENUM, Enum);
PROTOBUF_HANDLE_CASE(SFIXED32, SFixed32); PROTOBUF_HANDLE_CASE(SFIXED32, SFixed32);
PROTOBUF_HANDLE_CASE(SFIXED64, SFixed64); PROTOBUF_HANDLE_CASE(SFIXED64, SFixed64);
PROTOBUF_HANDLE_CASE(SINT32, SInt32); PROTOBUF_HANDLE_CASE(SINT32, SInt32);
PROTOBUF_HANDLE_CASE(SINT64, SInt64); PROTOBUF_HANDLE_CASE(SINT64, SInt64);
PROTOBUF_HANDLE_CASE(GROUP, Group); PROTOBUF_HANDLE_CASE(GROUP, Group);
case FieldDescriptor::TYPE_MESSAGE: { case FieldDescriptor::TYPE_MESSAGE: {
const FieldDescriptor* field = const FieldDescriptor* field =
ext.descriptor != nullptr ext.descriptor != nullptr
? ext.descriptor ? ext.descriptor
: pool->FindExtensionByNumber(extendee, number); : pool->FindExtensionByNumber(extendee, number);
ABSL_DCHECK_EQ(field->number(), number); ABSL_DCHECK_EQ(field->number(), number);
bool is_mset = bool is_mset =
field->containing_type()->options().message_set_wire_format(); field->containing_type()->options().message_set_wire_format();
func(internal::MessageDynamicExtensionInfo<decltype(ext)>{ext, number, func(internal::MessageDynamicExtensionInfo<decltype(ext)>{
is_mset}); ext, number, is_mset});
break; break;
} }
case FieldDescriptor::TYPE_BYTES: case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
func( func(internal::StringDynamicExtensionInfo<decltype(ext)>{ext,
internal::StringDynamicExtensionInfo<decltype(ext)>{ext, number}); number});
break; break;
default: default:
internal::Unreachable(); internal::Unreachable();
break; break;
#undef PROTOBUF_HANDLE_CASE #undef PROTOBUF_HANDLE_CASE
} }
} }
}); },
ExtensionSet::Prefetch{});
} }
template <typename CallbackFn> template <typename CallbackFn>

Loading…
Cancel
Save