diff options
Diffstat (limited to 'src/google/protobuf/generated_message_reflection.cc')
-rw-r--r-- | src/google/protobuf/generated_message_reflection.cc | 245 |
1 files changed, 158 insertions, 87 deletions
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 2f8f8256..247f772c 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -42,9 +42,10 @@ #include <google/protobuf/extension_set.h> #include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/generated_message_util.h> +#include <google/protobuf/inlined_string_field.h> #include <google/protobuf/map_field.h> #include <google/protobuf/repeated_field.h> -// #include "google/protobuf/bridge/compatibility_mode_support.h" +#include <google/protobuf/wire_format.h> #define GOOGLE_PROTOBUF_HAS_ONEOF @@ -190,37 +191,21 @@ GeneratedMessageReflection::GeneratedMessageReflection( schema_(schema), descriptor_pool_((pool == NULL) ? DescriptorPool::generated_pool() : pool), - message_factory_(factory) { + message_factory_(factory), + last_non_weak_field_index_(-1) { + last_non_weak_field_index_ = descriptor_->field_count() - 1; } GeneratedMessageReflection::~GeneratedMessageReflection() {} -namespace { -UnknownFieldSet* empty_unknown_field_set_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(empty_unknown_field_set_once_); - -void DeleteEmptyUnknownFieldSet() { - delete empty_unknown_field_set_; - empty_unknown_field_set_ = NULL; -} - -void InitEmptyUnknownFieldSet() { - empty_unknown_field_set_ = new UnknownFieldSet; - internal::OnShutdown(&DeleteEmptyUnknownFieldSet); -} - -const UnknownFieldSet& GetEmptyUnknownFieldSet() { - ::google::protobuf::GoogleOnceInit(&empty_unknown_field_set_once_, &InitEmptyUnknownFieldSet); - return *empty_unknown_field_set_; -} -} // namespace - const UnknownFieldSet& GeneratedMessageReflection::GetUnknownFields( const Message& message) const { - if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 && + !GetProto3PreserveUnknownsDefault()) { // We have to ensure that any mutations made to the return value of - // MutableUnknownFields() are not reflected here. - return GetEmptyUnknownFieldSet(); + // MutableUnknownFields() are not reflected here when Proto3 defaults to + // discard unknowns. + return *UnknownFieldSet::default_instance(); } else { return GetInternalMetadataWithArena(message).unknown_fields(); } @@ -231,28 +216,25 @@ UnknownFieldSet* GeneratedMessageReflection::MutableUnknownFields( return MutableInternalMetadataWithArena(message)->mutable_unknown_fields(); } -int GeneratedMessageReflection::SpaceUsed(const Message& message) const { +size_t GeneratedMessageReflection::SpaceUsedLong(const Message& message) const { // object_size_ already includes the in-memory representation of each field // in the message, so we only need to account for additional memory used by // the fields. - int total_size = schema_.GetObjectSize(); + size_t total_size = schema_.GetObjectSize(); - total_size += GetUnknownFields(message).SpaceUsedExcludingSelf(); + total_size += GetUnknownFields(message).SpaceUsedExcludingSelfLong(); if (schema_.HasExtensionSet()) { - total_size += GetExtensionSet(message).SpaceUsedExcludingSelf(); + total_size += GetExtensionSet(message).SpaceUsedExcludingSelfLong(); } - - const int field_count = descriptor_->field_count(); - for (int i = 0; i < field_count; i++) { + for (int i = 0; i <= last_non_weak_field_index_; i++) { const FieldDescriptor* field = descriptor_->field(i); - if (field->is_repeated()) { switch (field->cpp_type()) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ case FieldDescriptor::CPPTYPE_##UPPERCASE : \ total_size += GetRaw<RepeatedField<LOWERCASE> >(message, field) \ - .SpaceUsedExcludingSelf(); \ + .SpaceUsedExcludingSelfLong(); \ break HANDLE_TYPE( INT32, int32); @@ -270,21 +252,21 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: total_size += GetRaw<RepeatedPtrField<string> >(message, field) - .SpaceUsedExcludingSelf(); + .SpaceUsedExcludingSelfLong(); break; } break; case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - total_size += - GetRaw<MapFieldBase>(message, field).SpaceUsedExcludingSelf(); + total_size += GetRaw<MapFieldBase>(message, field) + .SpaceUsedExcludingSelfLong(); } else { // We don't know which subclass of RepeatedPtrFieldBase the type is, // so we use RepeatedPtrFieldBase directly. total_size += GetRaw<RepeatedPtrFieldBase>(message, field) - .SpaceUsedExcludingSelf<GenericTypeHandler<Message> >(); + .SpaceUsedExcludingSelfLong<GenericTypeHandler<Message> >(); } break; @@ -309,6 +291,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + if (IsInlined(field)) { + const string* ptr = + &GetField<InlinedStringField>(message, field).GetNoArena(); + total_size += StringSpaceUsedExcludingSelfLong(*ptr); + break; + } + // Initially, the string points to the default value stored in // the prototype. Only count the string if it has been changed // from the default value. @@ -320,7 +309,8 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { if (ptr != default_ptr) { // string fields are represented by just a pointer, so also // include sizeof(string) as well. - total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + total_size += + sizeof(*ptr) + StringSpaceUsedExcludingSelfLong(*ptr); } break; } @@ -335,14 +325,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { } else { const Message* sub_message = GetRaw<const Message*>(message, field); if (sub_message != NULL) { - total_size += sub_message->SpaceUsed(); + total_size += sub_message->SpaceUsedLong(); } } break; } } } - return total_size; } @@ -443,15 +432,25 @@ void GeneratedMessageReflection::SwapField( { Arena* arena1 = GetArena(message1); Arena* arena2 = GetArena(message2); + + if (IsInlined(field)) { + InlinedStringField* string1 = + MutableRaw<InlinedStringField>(message1, field); + InlinedStringField* string2 = + MutableRaw<InlinedStringField>(message2, field); + string1->Swap(string2); + break; + } + ArenaStringPtr* string1 = MutableRaw<ArenaStringPtr>(message1, field); ArenaStringPtr* string2 = MutableRaw<ArenaStringPtr>(message2, field); + const string* default_ptr = + &DefaultRaw<ArenaStringPtr>(field).Get(); if (arena1 == arena2) { - string1->Swap(string2); + string1->Swap(string2, default_ptr, arena1); } else { - const string* default_ptr = - &DefaultRaw<ArenaStringPtr>(field).Get(); const string temp = string1->Get(); string1->Set(default_ptr, string2->Get(), arena1); string2->Set(default_ptr, temp, arena2); @@ -643,14 +642,11 @@ void GeneratedMessageReflection::Swap( } } - const int field_count = descriptor_->field_count(); - for (int i = 0; i < field_count; i++) { + for (int i = 0; i <= last_non_weak_field_index_; i++) { const FieldDescriptor* field = descriptor_->field(i); - if (!field->containing_oneof()) { - SwapField(message1, message2, field); - } + if (field->containing_oneof()) continue; + SwapField(message1, message2, field); } - const int oneof_decl_count = descriptor_->oneof_decl_count(); for (int i = 0; i < oneof_decl_count; i++) { SwapOneofField(message1, message2, descriptor_->oneof_decl(i)); @@ -760,7 +756,15 @@ int GeneratedMessageReflection::FieldSize(const Message& message, case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { - return GetRaw<MapFieldBase>(message, field).GetRepeatedField().size(); + const internal::MapFieldBase& map = + GetRaw<MapFieldBase>(message, field); + if (map.IsRepeatedFieldValid()) { + return map.GetRepeatedField().size(); + } else { + // No need to materialize the repeated field if it is out of sync: + // its size will be the same as the map's size. + return map.size(); + } } else { return GetRaw<RepeatedPtrFieldBase>(message, field).size(); } @@ -782,7 +786,6 @@ void GeneratedMessageReflection::ClearField( ClearOneofField(message, field); return; } - if (HasBit(*message, field)) { ClearBit(message, field); @@ -812,6 +815,14 @@ void GeneratedMessageReflection::ClearField( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + if (IsInlined(field)) { + const string* default_ptr = + &DefaultRaw<InlinedStringField>(field).GetNoArena(); + MutableRaw<InlinedStringField>(message, field)->SetNoArena( + default_ptr, *default_ptr); + break; + } + const string* default_ptr = &DefaultRaw<ArenaStringPtr>(field).Get(); MutableRaw<ArenaStringPtr>(message, field)->SetAllocated( @@ -1025,11 +1036,9 @@ void GeneratedMessageReflection::ListFields( schema_.HasHasbits() ? GetHasBits(message) : NULL; const uint32* const has_bits_indices = schema_.has_bit_indices_; const uint32* const oneof_case_array = - &GetConstRefAtOffset<uint32>(message, schema_.oneof_case_offset_); - - const int field_count = descriptor_->field_count(); - output->reserve(field_count); - for (int i = 0; i < field_count; i++) { + GetConstPointerAtOffset<uint32>(&message, schema_.oneof_case_offset_); + output->reserve(descriptor_->field_count()); + for (int i = 0; i <= last_non_weak_field_index_; i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->is_repeated()) { if (FieldSize(message, field) > 0) { @@ -1052,7 +1061,6 @@ void GeneratedMessageReflection::ListFields( } } } - if (schema_.HasExtensionSet()) { GetExtensionSet(message).AppendToList(descriptor_, descriptor_pool_, output); @@ -1147,12 +1155,13 @@ string GeneratedMessageReflection::GetString( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + if (IsInlined(field)) { + return GetField<InlinedStringField>(message, field).GetNoArena(); + } + return GetField<ArenaStringPtr>(message, field).Get(); } } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return GetEmptyString(); // Make compiler happy. } } @@ -1167,12 +1176,13 @@ const string& GeneratedMessageReflection::GetStringReference( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + if (IsInlined(field)) { + return GetField<InlinedStringField>(message, field).GetNoArena(); + } + return GetField<ArenaStringPtr>(message, field).Get(); } } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return GetEmptyString(); // Make compiler happy. } } @@ -1188,6 +1198,12 @@ void GeneratedMessageReflection::SetString( switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: { + if (IsInlined(field)) { + MutableField<InlinedStringField>(message, field)->SetNoArena( + NULL, value); + break; + } + const string* default_ptr = &DefaultRaw<ArenaStringPtr>(field).Get(); if (field->containing_oneof() && !HasOneofField(*message, field)) { ClearOneof(message, field->containing_oneof()); @@ -1214,9 +1230,6 @@ string GeneratedMessageReflection::GetRepeatedString( case FieldOptions::STRING: return GetRepeatedPtrField<string>(message, field, index); } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return GetEmptyString(); // Make compiler happy. } } @@ -1232,9 +1245,6 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference( case FieldOptions::STRING: return GetRepeatedPtrField<string>(message, field, index); } - - GOOGLE_LOG(FATAL) << "Can't get here."; - return GetEmptyString(); // Make compiler happy. } } @@ -1458,8 +1468,7 @@ const Message& GeneratedMessageReflection::GetMessage( GetExtensionSet(message).GetMessage( field->number(), field->message_type(), factory)); } else { - const Message* result; - result = GetRaw<const Message*>(message, field); + const Message* result = GetRaw<const Message*>(message, field); if (result == NULL) { result = DefaultRaw<const Message*>(field); } @@ -1479,6 +1488,7 @@ Message* GeneratedMessageReflection::MutableMessage( MutableExtensionSet(message)->MutableMessage(field, factory)); } else { Message* result; + Message** result_holder = MutableRaw<Message*>(message, field); if (field->containing_oneof()) { @@ -1906,6 +1916,10 @@ const Type& GeneratedMessageReflection::GetRaw( return GetConstRefAtOffset<Type>(message, schema_.GetFieldOffset(field)); } +bool GeneratedMessageReflection::IsInlined(const FieldDescriptor* field) const { + return schema_.IsFieldInlined(field); +} + template <typename Type> Type* GeneratedMessageReflection::MutableRaw(Message* message, const FieldDescriptor* field) const { @@ -1976,6 +1990,7 @@ inline const Type& GeneratedMessageReflection::DefaultRaw( // Simple accessors for manipulating has_bits_. inline bool GeneratedMessageReflection::HasBit( const Message& message, const FieldDescriptor* field) const { + GOOGLE_DCHECK(!field->options().weak()); if (schema_.HasHasbits()) { return IsIndexInHasBitSet(GetHasBits(message), schema_.HasBitIndex(field)); } @@ -2000,6 +2015,10 @@ inline bool GeneratedMessageReflection::HasBit( case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: { + if (IsInlined(field)) { + return !GetField<InlinedStringField>(message, field) + .GetNoArena().empty(); + } return GetField<ArenaStringPtr>(message, field).Get().size() > 0; } } @@ -2031,6 +2050,7 @@ inline bool GeneratedMessageReflection::HasBit( inline void GeneratedMessageReflection::SetBit( Message* message, const FieldDescriptor* field) const { + GOOGLE_DCHECK(!field->options().weak()); if (!schema_.HasHasbits()) { return; } @@ -2041,6 +2061,7 @@ inline void GeneratedMessageReflection::SetBit( inline void GeneratedMessageReflection::ClearBit( Message* message, const FieldDescriptor* field) const { + GOOGLE_DCHECK(!field->options().weak()); if (!schema_.HasHasbits()) { return; } @@ -2051,6 +2072,7 @@ inline void GeneratedMessageReflection::ClearBit( inline void GeneratedMessageReflection::SwapBit( Message* message1, Message* message2, const FieldDescriptor* field) const { + GOOGLE_DCHECK(!field->options().weak()); if (!schema_.HasHasbits()) { return; } @@ -2236,16 +2258,16 @@ ReflectionSchema MigrationToReflectionSchema( MigrationSchema migration_schema) { ReflectionSchema result; result.default_instance_ = *default_instance; - // First 5 offsets are offsets to the special fields. The following offsets + // First 6 offsets are offsets to the special fields. The following offsets // are the proto fields. - result.offsets_ = offsets + migration_schema.offsets_index + 4; + result.offsets_ = offsets + migration_schema.offsets_index + 5; result.has_bit_indices_ = offsets + migration_schema.has_bit_indices_index; result.has_bits_offset_ = offsets[migration_schema.offsets_index + 0]; result.metadata_offset_ = offsets[migration_schema.offsets_index + 1]; result.extensions_offset_ = offsets[migration_schema.offsets_index + 2]; result.oneof_case_offset_ = offsets[migration_schema.offsets_index + 3]; result.object_size_ = migration_schema.object_size; - result.weak_field_map_offset_ = 0; + result.weak_field_map_offset_ = offsets[migration_schema.offsets_index + 4]; return result; } @@ -2272,17 +2294,16 @@ class AssignDescriptorsHelper { file_level_metadata_->descriptor = descriptor; - if (!descriptor->options().map_entry()) { - // Only set reflection for non map types. - file_level_metadata_->reflection = new GeneratedMessageReflection( - descriptor, MigrationToReflectionSchema(default_instance_data_++, - offsets_, *schemas_), - ::google::protobuf::DescriptorPool::generated_pool(), factory_); - for (int i = 0; i < descriptor->enum_type_count(); i++) { - AssignEnumDescriptor(descriptor->enum_type(i)); - } - schemas_++; + file_level_metadata_->reflection = new GeneratedMessageReflection( + descriptor, + MigrationToReflectionSchema(default_instance_data_, offsets_, + *schemas_), + ::google::protobuf::DescriptorPool::generated_pool(), factory_); + for (int i = 0; i < descriptor->enum_type_count(); i++) { + AssignEnumDescriptor(descriptor->enum_type(i)); } + schemas_++; + default_instance_data_++; file_level_metadata_++; } @@ -2291,6 +2312,8 @@ class AssignDescriptorsHelper { file_level_enum_descriptors_++; } + const Metadata* GetCurrentMetadataPtr() const { return file_level_metadata_; } + private: MessageFactory* factory_; Metadata* file_level_metadata_; @@ -2300,12 +2323,46 @@ class AssignDescriptorsHelper { const uint32* offsets_; }; +// We have the routines that assign descriptors and build reflection +// automatically delete the allocated reflection. MetadataOwner owns +// all the allocated reflection instances. +struct MetadataOwner { + void AddArray(const Metadata* begin, const Metadata* end) { + MutexLock lock(&mu_); + metadata_arrays_.push_back(std::make_pair(begin, end)); + } + + static MetadataOwner* Instance() { + static MetadataOwner* res = new MetadataOwner; + return res; + } + + private: + // Use the constructor to register the shutdown code. Because c++ makes sure + // this called only once. + MetadataOwner() { OnShutdown(&DeleteMetadata); } + ~MetadataOwner() { + for (int i = 0; i < metadata_arrays_.size(); i++) { + for (const Metadata* m = metadata_arrays_[i].first; + m < metadata_arrays_[i].second; m++) { + delete m->reflection; + } + } + } + + static void DeleteMetadata() { + delete Instance(); + } + + Mutex mu_; + std::vector<std::pair<const Metadata*, const Metadata*> > metadata_arrays_; +}; + } // namespace void AssignDescriptors( const string& filename, const MigrationSchema* schemas, const Message* const* default_instances_, const uint32* offsets, - MessageFactory* factory, // update the following descriptor arrays. Metadata* file_level_metadata, const EnumDescriptor** file_level_enum_descriptors, @@ -2314,7 +2371,7 @@ void AssignDescriptors( ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(filename); GOOGLE_CHECK(file != NULL); - if (!factory) factory = MessageFactory::generated_factory(); + MessageFactory* factory = MessageFactory::generated_factory(); AssignDescriptorsHelper<MigrationSchema> helper(factory, file_level_metadata, file_level_enum_descriptors, schemas, @@ -2332,6 +2389,8 @@ void AssignDescriptors( file_level_service_descriptors[i] = file->service(i); } } + MetadataOwner::Instance()->AddArray( + file_level_metadata, helper.GetCurrentMetadataPtr()); } void RegisterAllTypesInternal(const Metadata* file_level_metadata, int size) { @@ -2352,6 +2411,18 @@ void RegisterAllTypes(const Metadata* file_level_metadata, int size) { RegisterAllTypesInternal(file_level_metadata, size); } +void UnknownFieldSetSerializer(const uint8* base, uint32 offset, uint32 tag, + uint32 has_offset, + ::google::protobuf::io::CodedOutputStream* output) { + const void* ptr = base + offset; + const InternalMetadataWithArena* metadata = + static_cast<const InternalMetadataWithArena*>(ptr); + if (metadata->have_unknown_fields()) { + ::google::protobuf::internal::WireFormat::SerializeUnknownFields( + metadata->unknown_fields(), output); + } +} + } // namespace internal } // namespace protobuf } // namespace google |