diff options
Diffstat (limited to 'src/google/protobuf/dynamic_message.cc')
-rw-r--r-- | src/google/protobuf/dynamic_message.cc | 313 |
1 files changed, 164 insertions, 149 deletions
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 8d689ac8..ceedf500 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -65,12 +65,8 @@ #include <algorithm> #include <google/protobuf/stubs/hash.h> #include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/scoped_ptr.h> #include <google/protobuf/dynamic_message.h> #include <google/protobuf/descriptor.h> @@ -78,22 +74,23 @@ #include <google/protobuf/generated_message_util.h> #include <google/protobuf/generated_message_reflection.h> #include <google/protobuf/arenastring.h> +#include <google/protobuf/extension_set.h> +#include <google/protobuf/map_field.h> #include <google/protobuf/map_field_inl.h> +#include <google/protobuf/map_type_handler.h> #include <google/protobuf/reflection_ops.h> #include <google/protobuf/repeated_field.h> -#include <google/protobuf/map_type_handler.h> -#include <google/protobuf/extension_set.h> #include <google/protobuf/wire_format.h> -#include <google/protobuf/map_field.h> + namespace google { namespace protobuf { -using internal::WireFormat; +using internal::DynamicMapField; using internal::ExtensionSet; using internal::GeneratedMessageReflection; +using internal::InternalMetadataWithArena; using internal::MapField; -using internal::DynamicMapField; using internal::ArenaStringPtr; @@ -222,9 +219,8 @@ class DynamicMessage : public Message { int size; int has_bits_offset; int oneof_case_offset; - int unknown_fields_offset; + int internal_metadata_offset; int extensions_offset; - int is_default_instance_offset; // Not owned by the TypeInfo. DynamicMessageFactory* factory; // The factory that created this object. @@ -233,24 +229,28 @@ class DynamicMessage : public Message { // Warning: The order in which the following pointers are defined is // important (the prototype must be deleted *before* the offsets). - google::protobuf::scoped_array<int> offsets; - google::protobuf::scoped_ptr<const GeneratedMessageReflection> reflection; - // Don't use a scoped_ptr to hold the prototype: the destructor for + std::unique_ptr<uint32[]> offsets; + std::unique_ptr<uint32[]> has_bits_indices; + std::unique_ptr<const GeneratedMessageReflection> reflection; + // Don't use a unique_ptr to hold the prototype: the destructor for // DynamicMessage needs to know whether it is the prototype, and does so by // looking back at this field. This would assume details about the - // implementation of scoped_ptr. + // implementation of unique_ptr. const DynamicMessage* prototype; - void* default_oneof_instance; + int weak_field_map_offset; // The offset for the weak_field_map; - TypeInfo() : prototype(NULL), default_oneof_instance(NULL) {} + TypeInfo() : prototype(NULL) {} ~TypeInfo() { delete prototype; - operator delete(default_oneof_instance); } }; DynamicMessage(const TypeInfo* type_info); + + // This should only be used by GetPrototypeNoLock() to avoid dead lock. + DynamicMessage(const TypeInfo* type_info, bool lock_factory); + ~DynamicMessage(); // Called on the prototype after construction to initialize message fields. @@ -260,18 +260,28 @@ class DynamicMessage : public Message { Message* New() const; Message* New(::google::protobuf::Arena* arena) const; - ::google::protobuf::Arena* GetArena() const { return NULL; }; + ::google::protobuf::Arena* GetArena() const { return arena_; } int GetCachedSize() const; void SetCachedSize(int size) const; Metadata GetMetadata() const; + // We actually allocate more memory than sizeof(*this) when this + // class's memory is allocated via the global operator new. Thus, we need to + // manually call the global operator delete. Calling the destructor is taken + // care of for us. This makes DynamicMessage compatible with -fsized-delete. + // It doesn't work for MSVC though. +#ifndef _MSC_VER + static void operator delete(void* ptr) { + ::operator delete(ptr); + } +#endif // !_MSC_VER private: - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena); - void SharedCtor(); + + void SharedCtor(bool lock_factory); inline bool is_prototype() const { return type_info_->prototype == this || @@ -288,24 +298,29 @@ class DynamicMessage : public Message { } const TypeInfo* type_info_; + Arena* const arena_; // TODO(kenton): Make this an atomic<int> when C++ supports it. mutable int cached_byte_size_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); }; DynamicMessage::DynamicMessage(const TypeInfo* type_info) - : type_info_(type_info), - cached_byte_size_(0) { - SharedCtor(); + : type_info_(type_info), arena_(NULL), cached_byte_size_(0) { + SharedCtor(true); } DynamicMessage::DynamicMessage(const TypeInfo* type_info, ::google::protobuf::Arena* arena) - : type_info_(type_info), - cached_byte_size_(0) { - SharedCtor(); + : type_info_(type_info), arena_(arena), cached_byte_size_(0) { + SharedCtor(true); +} + +DynamicMessage::DynamicMessage(const TypeInfo* type_info, bool lock_factory) + : type_info_(type_info), arena_(NULL), cached_byte_size_(0) { + SharedCtor(lock_factory); } -void DynamicMessage::SharedCtor() { +void DynamicMessage::SharedCtor(bool lock_factory) { // We need to call constructors for various fields manually and set // default values where appropriate. We use placement new to call // constructors. If you haven't heard of placement new, I suggest Googling @@ -316,24 +331,18 @@ void DynamicMessage::SharedCtor() { // constructor.) const Descriptor* descriptor = type_info_->type; - // Initialize oneof cases. for (int i = 0 ; i < descriptor->oneof_decl_count(); ++i) { - new(OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32) * i)) + new (OffsetToPointer(type_info_->oneof_case_offset + sizeof(uint32) * i)) uint32(0); } - if (type_info_->is_default_instance_offset != -1) { - *reinterpret_cast<bool*>( - OffsetToPointer(type_info_->is_default_instance_offset)) = false; - } - - new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet; + new (OffsetToPointer(type_info_->internal_metadata_offset)) + InternalMetadataWithArena(arena_); if (type_info_->extensions_offset != -1) { - new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet; + new (OffsetToPointer(type_info_->extensions_offset)) ExtensionSet(arena_); } - for (int i = 0; i < descriptor->field_count(); i++) { const FieldDescriptor* field = descriptor->field(i); void* field_ptr = OffsetToPointer(type_info_->offsets[i]); @@ -341,14 +350,14 @@ void DynamicMessage::SharedCtor() { continue; } switch (field->cpp_type()) { -#define HANDLE_TYPE(CPPTYPE, TYPE) \ - case FieldDescriptor::CPPTYPE_##CPPTYPE: \ - if (!field->is_repeated()) { \ - new(field_ptr) TYPE(field->default_value_##TYPE()); \ - } else { \ - new(field_ptr) RepeatedField<TYPE>(); \ - } \ - break; +#define HANDLE_TYPE(CPPTYPE, TYPE) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: \ + if (!field->is_repeated()) { \ + new (field_ptr) TYPE(field->default_value_##TYPE()); \ + } else { \ + new (field_ptr) RepeatedField<TYPE>(arena_); \ + } \ + break; HANDLE_TYPE(INT32 , int32 ); HANDLE_TYPE(INT64 , int64 ); @@ -363,7 +372,7 @@ void DynamicMessage::SharedCtor() { if (!field->is_repeated()) { new(field_ptr) int(field->default_value_enum()->number()); } else { - new(field_ptr) RepeatedField<int>(); + new (field_ptr) RepeatedField<int>(arena_); } break; @@ -376,15 +385,15 @@ void DynamicMessage::SharedCtor() { if (is_prototype()) { default_value = &field->default_value_string(); } else { - default_value = - &(reinterpret_cast<const ArenaStringPtr*>( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i]))->Get(NULL)); + default_value = &(reinterpret_cast<const ArenaStringPtr*>( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i])) + ->Get()); } ArenaStringPtr* asp = new(field_ptr) ArenaStringPtr(); asp->UnsafeSetDefault(default_value); } else { - new(field_ptr) RepeatedPtrField<string>(); + new (field_ptr) RepeatedPtrField<string>(arena_); } break; } @@ -395,10 +404,32 @@ void DynamicMessage::SharedCtor() { new(field_ptr) Message*(NULL); } else { if (IsMapFieldInApi(field)) { - new (field_ptr) DynamicMapField( - type_info_->factory->GetPrototypeNoLock(field->message_type())); + // We need to lock in most cases to avoid data racing. Only not lock + // when the constructor is called inside GetPrototype(), in which + // case we have already locked the factory. + if (lock_factory) { + if (arena_ != NULL) { + new (field_ptr) DynamicMapField( + type_info_->factory->GetPrototype(field->message_type()), + arena_); + } else { + new (field_ptr) DynamicMapField( + type_info_->factory->GetPrototype(field->message_type())); + } + } else { + if (arena_ != NULL) { + new (field_ptr) + DynamicMapField(type_info_->factory->GetPrototypeNoLock( + field->message_type()), + arena_); + } else { + new (field_ptr) + DynamicMapField(type_info_->factory->GetPrototypeNoLock( + field->message_type())); + } + } } else { - new (field_ptr) RepeatedPtrField<Message>(); + new (field_ptr) RepeatedPtrField<Message>(arena_); } } break; @@ -410,8 +441,9 @@ void DynamicMessage::SharedCtor() { DynamicMessage::~DynamicMessage() { const Descriptor* descriptor = type_info_->type; - reinterpret_cast<UnknownFieldSet*>( - OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet(); + reinterpret_cast<InternalMetadataWithArena*>( + OffsetToPointer(type_info_->internal_metadata_offset)) + ->~InternalMetadataWithArena(); if (type_info_->extensions_offset != -1) { reinterpret_cast<ExtensionSet*>( @@ -442,8 +474,10 @@ DynamicMessage::~DynamicMessage() { case FieldOptions::STRING: { const ::std::string* default_value = &(reinterpret_cast<const ArenaStringPtr*>( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i]))->Get(NULL)); + reinterpret_cast<const uint8*>( + type_info_->prototype) + + type_info_->offsets[i]) + ->Get()); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy( default_value, NULL); break; @@ -501,8 +535,9 @@ DynamicMessage::~DynamicMessage() { case FieldOptions::STRING: { const ::std::string* default_value = &(reinterpret_cast<const ArenaStringPtr*>( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i]))->Get(NULL)); + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i])) + ->Get()); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy( default_value, NULL); break; @@ -530,11 +565,6 @@ void DynamicMessage::CrossLinkPrototypes() { for (int i = 0; i < descriptor->field_count(); i++) { const FieldDescriptor* field = descriptor->field(i); void* field_ptr = OffsetToPointer(type_info_->offsets[i]); - if (field->containing_oneof()) { - field_ptr = reinterpret_cast<uint8*>( - type_info_->default_oneof_instance) + type_info_->offsets[i]; - } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && !field->is_repeated()) { // For fields with message types, we need to cross-link with the @@ -545,29 +575,19 @@ void DynamicMessage::CrossLinkPrototypes() { factory->GetPrototypeNoLock(field->message_type()); } } - - // Set as the default instance -- this affects field-presence semantics for - // proto3. - if (type_info_->is_default_instance_offset != -1) { - void* is_default_instance_ptr = - OffsetToPointer(type_info_->is_default_instance_offset); - *reinterpret_cast<bool*>(is_default_instance_ptr) = true; - } } -Message* DynamicMessage::New() const { - void* new_base = operator new(type_info_->size); - memset(new_base, 0, type_info_->size); - return new(new_base) DynamicMessage(type_info_); -} +Message* DynamicMessage::New() const { return New(NULL); } Message* DynamicMessage::New(::google::protobuf::Arena* arena) const { if (arena != NULL) { - Message* message = New(); - arena->Own(message); - return message; + void* new_base = Arena::CreateArray<char>(arena, type_info_->size); + memset(new_base, 0, type_info_->size); + return new (new_base) DynamicMessage(type_info_, arena); } else { - return New(); + void* new_base = operator new(type_info_->size); + memset(new_base, 0, type_info_->size); + return new (new_base) DynamicMessage(type_info_); } } @@ -613,7 +633,7 @@ DynamicMessageFactory::~DynamicMessageFactory() { iter != prototypes_->map_.end(); ++iter) { DeleteDefaultOneofInstance(iter->second->type, iter->second->offsets.get(), - iter->second->default_oneof_instance); + iter->second->prototype); delete iter->second; } } @@ -652,7 +672,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( // or not that field is set. // Compute size and offsets. - int* offsets = new int[type->field_count() + type->oneof_decl_count()]; + uint32* offsets = + new uint32[type->field_count() + type->oneof_decl_count()]; type_info->offsets.reset(offsets); // Decide all field offsets by packing in order. @@ -670,15 +691,12 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( DivideRoundingUp(type->field_count(), bitsizeof(uint32)); size += has_bits_array_size * sizeof(uint32); size = AlignOffset(size); - } - // The is_default_instance member, if any. - if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { - type_info->is_default_instance_offset = size; - size += sizeof(bool); - size = AlignOffset(size); - } else { - type_info->is_default_instance_offset = -1; + uint32* has_bits_indices = new uint32[type->field_count()]; + for (int i = 0; i < type->field_count(); i++) { + has_bits_indices[i] = i; + } + type_info->has_bits_indices.reset(has_bits_indices); } // The oneof_case, if any. It is an array of uint32s. @@ -699,12 +717,15 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( } // All the fields. + // + // TODO(b/31226269): Optimize the order of fields to minimize padding. + int num_weak_fields = 0; for (int i = 0; i < type->field_count(); i++) { // Make sure field is aligned to avoid bus errors. // Oneof fields do not use any space. if (!type->field(i)->containing_oneof()) { int field_size = FieldSpaceUsed(type->field(i)); - size = AlignTo(size, min(kSafeAlignment, field_size)); + size = AlignTo(size, std::min(kSafeAlignment, field_size)); offsets[i] = size; size += field_size; } @@ -717,77 +738,71 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( size += kMaxOneofUnionSize; } - // Add the UnknownFieldSet to the end. + // Add the InternalMetadataWithArena to the end. size = AlignOffset(size); - type_info->unknown_fields_offset = size; - size += sizeof(UnknownFieldSet); + type_info->internal_metadata_offset = size; + size += sizeof(InternalMetadataWithArena); + + type_info->weak_field_map_offset = -1; // Align the final size to make sure no clever allocators think that // alignment is not necessary. - size = AlignOffset(size); type_info->size = size; - // Allocate the prototype. - void* base = operator new(size); - memset(base, 0, size); - // The prototype in type_info has to be set before creating the prototype - // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When - // creating prototype for Foo, prototype of the map entry will also be - // created, which needs the address of the prototype of Foo (the value in - // map). To break the cyclic dependency, we have to assgin the address of - // prototype into type_info first. - type_info->prototype = static_cast<DynamicMessage*>(base); - DynamicMessage* prototype = new(base) DynamicMessage(type_info); // Construct the reflection object. + if (type->oneof_decl_count() > 0) { // Compute the size of default oneof instance and offsets of default // oneof fields. - int oneof_size = 0; for (int i = 0; i < type->oneof_decl_count(); i++) { for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = type->oneof_decl(i)->field(j); int field_size = OneofFieldSpaceUsed(field); - oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size)); - offsets[field->index()] = oneof_size; - oneof_size += field_size; + size = AlignTo(size, std::min(kSafeAlignment, field_size)); + offsets[field->index()] = size; + size += field_size; } } + } + size = AlignOffset(size); + // Allocate the prototype + oneof fields. + void* base = operator new(size); + memset(base, 0, size); + + // The prototype in type_info has to be set before creating the prototype + // instance on memory. e.g., message Foo { map<int32, Foo> a = 1; }. When + // creating prototype for Foo, prototype of the map entry will also be + // created, which needs the address of the prototype of Foo (the value in + // map). To break the cyclic dependency, we have to assgin the address of + // prototype into type_info first. + type_info->prototype = static_cast<DynamicMessage*>(base); + + // We have already locked the factory so we should not lock in the constructor + // of dynamic message to avoid dead lock. + DynamicMessage* prototype = new (base) DynamicMessage(type_info, false); + + if (type->oneof_decl_count() > 0 || num_weak_fields > 0) { // Construct default oneof instance. - type_info->default_oneof_instance = ::operator new(oneof_size); ConstructDefaultOneofInstance(type_info->type, type_info->offsets.get(), - type_info->default_oneof_instance); - type_info->reflection.reset( - new GeneratedMessageReflection( - type_info->type, - type_info->prototype, - type_info->offsets.get(), - type_info->has_bits_offset, - type_info->unknown_fields_offset, - type_info->extensions_offset, - type_info->default_oneof_instance, - type_info->oneof_case_offset, - type_info->pool, - this, - type_info->size, - -1 /* arena_offset */, - type_info->is_default_instance_offset)); - } else { - type_info->reflection.reset( - new GeneratedMessageReflection( - type_info->type, - type_info->prototype, - type_info->offsets.get(), - type_info->has_bits_offset, - type_info->unknown_fields_offset, - type_info->extensions_offset, - type_info->pool, - this, - type_info->size, - -1 /* arena_offset */, - type_info->is_default_instance_offset)); + prototype); } + + internal::ReflectionSchema schema = { + type_info->prototype, + type_info->offsets.get(), + type_info->has_bits_indices.get(), + type_info->has_bits_offset, + type_info->internal_metadata_offset, + type_info->extensions_offset, + type_info->oneof_case_offset, + type_info->size, + type_info->weak_field_map_offset}; + + type_info->reflection.reset(new GeneratedMessageReflection( + type_info->type, schema, type_info->pool, this)); + // Cross link prototypes. prototype->CrossLinkPrototypes(); @@ -796,13 +811,13 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( void DynamicMessageFactory::ConstructDefaultOneofInstance( const Descriptor* type, - const int offsets[], - void* default_oneof_instance) { + const uint32 offsets[], + void* default_oneof_or_weak_instance) { for (int i = 0; i < type->oneof_decl_count(); i++) { for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = type->oneof_decl(i)->field(j); void* field_ptr = reinterpret_cast<uint8*>( - default_oneof_instance) + offsets[field->index()]; + default_oneof_or_weak_instance) + offsets[field->index()]; switch (field->cpp_type()) { #define HANDLE_TYPE(CPPTYPE, TYPE) \ case FieldDescriptor::CPPTYPE_##CPPTYPE: \ @@ -842,8 +857,8 @@ void DynamicMessageFactory::ConstructDefaultOneofInstance( void DynamicMessageFactory::DeleteDefaultOneofInstance( const Descriptor* type, - const int offsets[], - void* default_oneof_instance) { + const uint32 offsets[], + const void* default_oneof_instance) { for (int i = 0; i < type->oneof_decl_count(); i++) { for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = type->oneof_decl(i)->field(j); |