diff --git a/src/google/protobuf/compiler/cpp/field.cc b/src/google/protobuf/compiler/cpp/field.cc index 4402e76f2f3ed..5819d3f23c6eb 100644 --- a/src/google/protobuf/compiler/cpp/field.cc +++ b/src/google/protobuf/compiler/cpp/field.cc @@ -186,7 +186,7 @@ void FieldGeneratorBase::GenerateMemberCopyConstructor(io::Printer* p) const { p->Emit({InternalMetadataOffsetSub(p)}, R"cc( $name$_ { - visibility, $internal_metadata_offset$, from.$name$_ + visibility, $internal_metadata_offset$, arena, from.$name$_ } )cc"); } else { diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc index beb0d1c628640..87edeedfdd687 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc @@ -324,7 +324,7 @@ class RepeatedEnum : public FieldGeneratorBase { p->Emit({InternalMetadataOffsetSub(p)}, R"cc( $name$_ { - visibility, $internal_metadata_offset$, from.$name$_ + visibility, $internal_metadata_offset$, arena, from.$name$_ } )cc"); } diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc index b16c9a8e22527..e4a1d7f1ecd39 100644 --- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc @@ -381,7 +381,7 @@ class RepeatedPrimitive final : public FieldGeneratorBase { p->Emit({InternalMetadataOffsetSub(p)}, R"cc( $name$_ { - visibility, $internal_metadata_offset$, from.$name$_ + visibility, $internal_metadata_offset$, arena, from.$name$_ } )cc"); } diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index d38e339283e9d..e7e3abef97a30 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -1196,14 +1196,14 @@ PROTOBUF_NDEBUG_INLINE CodeGeneratorRequest::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::compiler::CodeGeneratorRequest, PROTOBUF_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, _impl_.file_to_generate_)>() - , from.file_to_generate_ + , arena, from.file_to_generate_ } , proto_file_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::compiler::CodeGeneratorRequest, PROTOBUF_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, _impl_.proto_file_)>() - , from.proto_file_ + , arena, from.proto_file_ } , parameter_(arena, from.parameter_), @@ -1211,7 +1211,7 @@ PROTOBUF_NDEBUG_INLINE CodeGeneratorRequest::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::compiler::CodeGeneratorRequest, PROTOBUF_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorRequest, _impl_.source_file_descriptors_)>() - , from.source_file_descriptors_ + , arena, from.source_file_descriptors_ } {} @@ -1844,7 +1844,7 @@ PROTOBUF_NDEBUG_INLINE CodeGeneratorResponse::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::compiler::CodeGeneratorResponse, PROTOBUF_FIELD_OFFSET(::google::protobuf::compiler::CodeGeneratorResponse, _impl_.file_)>() - , from.file_ + , arena, from.file_ } , error_(arena, from.error_) {} diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index b6303bff53b27..7c44baa1a199a 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -7896,7 +7896,7 @@ PROTOBUF_NDEBUG_INLINE FileDescriptorSet::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorSet, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorSet, _impl_.file_)>() - , from.file_ + , arena, from.file_ } {} @@ -8138,56 +8138,56 @@ PROTOBUF_NDEBUG_INLINE FileDescriptorProto::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.dependency_)>() - , from.dependency_ + , arena, from.dependency_ } , message_type_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.message_type_)>() - , from.message_type_ + , arena, from.message_type_ } , enum_type_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.enum_type_)>() - , from.enum_type_ + , arena, from.enum_type_ } , service_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.service_)>() - , from.service_ + , arena, from.service_ } , extension_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.extension_)>() - , from.extension_ + , arena, from.extension_ } , public_dependency_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.public_dependency_)>() - , from.public_dependency_ + , arena, from.public_dependency_ } , weak_dependency_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.weak_dependency_)>() - , from.weak_dependency_ + , arena, from.weak_dependency_ } , option_dependency_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileDescriptorProto, _impl_.option_dependency_)>() - , from.option_dependency_ + , arena, from.option_dependency_ } , name_(arena, from.name_), @@ -9298,56 +9298,56 @@ PROTOBUF_NDEBUG_INLINE DescriptorProto::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.field_)>() - , from.field_ + , arena, from.field_ } , nested_type_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.nested_type_)>() - , from.nested_type_ + , arena, from.nested_type_ } , enum_type_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.enum_type_)>() - , from.enum_type_ + , arena, from.enum_type_ } , extension_range_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.extension_range_)>() - , from.extension_range_ + , arena, from.extension_range_ } , extension_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.extension_)>() - , from.extension_ + , arena, from.extension_ } , oneof_decl_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.oneof_decl_)>() - , from.oneof_decl_ + , arena, from.oneof_decl_ } , reserved_range_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.reserved_range_)>() - , from.reserved_range_ + , arena, from.reserved_range_ } , reserved_name_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::DescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::DescriptorProto, _impl_.reserved_name_)>() - , from.reserved_name_ + , arena, from.reserved_name_ } , name_(arena, from.name_) {} @@ -10196,14 +10196,14 @@ PROTOBUF_NDEBUG_INLINE ExtensionRangeOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::ExtensionRangeOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::ExtensionRangeOptions, _impl_.declaration_)>() - , from.declaration_ + , arena, from.declaration_ } , uninterpreted_option_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::ExtensionRangeOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::ExtensionRangeOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -11440,21 +11440,21 @@ PROTOBUF_NDEBUG_INLINE EnumDescriptorProto::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::EnumDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::EnumDescriptorProto, _impl_.value_)>() - , from.value_ + , arena, from.value_ } , reserved_range_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::EnumDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::EnumDescriptorProto, _impl_.reserved_range_)>() - , from.reserved_range_ + , arena, from.reserved_range_ } , reserved_name_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::EnumDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::EnumDescriptorProto, _impl_.reserved_name_)>() - , from.reserved_name_ + , arena, from.reserved_name_ } , name_(arena, from.name_) {} @@ -12104,7 +12104,7 @@ PROTOBUF_NDEBUG_INLINE ServiceDescriptorProto::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::ServiceDescriptorProto, PROTOBUF_FIELD_OFFSET(::google::protobuf::ServiceDescriptorProto, _impl_.method_)>() - , from.method_ + , arena, from.method_ } , name_(arena, from.name_) {} @@ -12733,7 +12733,7 @@ PROTOBUF_NDEBUG_INLINE FileOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FileOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::FileOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -13362,7 +13362,7 @@ PROTOBUF_NDEBUG_INLINE MessageOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::MessageOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::MessageOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -14239,21 +14239,21 @@ PROTOBUF_NDEBUG_INLINE FieldOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FieldOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::FieldOptions, _impl_.edition_defaults_)>() - , from.edition_defaults_ + , arena, from.edition_defaults_ } , uninterpreted_option_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FieldOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::FieldOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } , targets_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FieldOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::FieldOptions, _impl_.targets_)>() - , from.targets_ + , arena, from.targets_ } {} @@ -14771,7 +14771,7 @@ PROTOBUF_NDEBUG_INLINE OneofOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::OneofOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::OneofOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -15056,7 +15056,7 @@ PROTOBUF_NDEBUG_INLINE EnumOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::EnumOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::EnumOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -15392,7 +15392,7 @@ PROTOBUF_NDEBUG_INLINE EnumValueOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::EnumValueOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::EnumValueOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -15748,7 +15748,7 @@ PROTOBUF_NDEBUG_INLINE ServiceOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::ServiceOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::ServiceOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -16056,7 +16056,7 @@ PROTOBUF_NDEBUG_INLINE MethodOptions::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::MethodOptions, PROTOBUF_FIELD_OFFSET(::google::protobuf::MethodOptions, _impl_.uninterpreted_option_)>() - , from.uninterpreted_option_ + , arena, from.uninterpreted_option_ } {} @@ -16615,7 +16615,7 @@ PROTOBUF_NDEBUG_INLINE UninterpretedOption::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::UninterpretedOption, PROTOBUF_FIELD_OFFSET(::google::protobuf::UninterpretedOption, _impl_.name_)>() - , from.name_ + , arena, from.name_ } , identifier_value_(arena, from.identifier_value_), @@ -17752,7 +17752,7 @@ PROTOBUF_NDEBUG_INLINE FeatureSetDefaults::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::FeatureSetDefaults, PROTOBUF_FIELD_OFFSET(::google::protobuf::FeatureSetDefaults, _impl_.defaults_)>() - , from.defaults_ + , arena, from.defaults_ } {} @@ -18036,21 +18036,21 @@ PROTOBUF_NDEBUG_INLINE SourceCodeInfo_Location::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::SourceCodeInfo_Location, PROTOBUF_FIELD_OFFSET(::google::protobuf::SourceCodeInfo_Location, _impl_.path_)>() - , from.path_ + , arena, from.path_ } , span_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::SourceCodeInfo_Location, PROTOBUF_FIELD_OFFSET(::google::protobuf::SourceCodeInfo_Location, _impl_.span_)>() - , from.span_ + , arena, from.span_ } , leading_detached_comments_ { visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::SourceCodeInfo_Location, PROTOBUF_FIELD_OFFSET(::google::protobuf::SourceCodeInfo_Location, _impl_.leading_detached_comments_)>() - , from.leading_detached_comments_ + , arena, from.leading_detached_comments_ } , leading_comments_(arena, from.leading_comments_), @@ -18377,7 +18377,7 @@ PROTOBUF_NDEBUG_INLINE SourceCodeInfo::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::SourceCodeInfo, PROTOBUF_FIELD_OFFSET(::google::protobuf::SourceCodeInfo, _impl_.location_)>() - , from.location_ + , arena, from.location_ } {} @@ -18617,7 +18617,7 @@ PROTOBUF_NDEBUG_INLINE GeneratedCodeInfo_Annotation::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::GeneratedCodeInfo_Annotation, PROTOBUF_FIELD_OFFSET(::google::protobuf::GeneratedCodeInfo_Annotation, _impl_.path_)>() - , from.path_ + , arena, from.path_ } , source_file_(arena, from.source_file_) {} @@ -18930,7 +18930,7 @@ PROTOBUF_NDEBUG_INLINE GeneratedCodeInfo::Impl_::Impl_( visibility, ::_pbi::InternalMetadataOffset::Build< ::google::protobuf::GeneratedCodeInfo, PROTOBUF_FIELD_OFFSET(::google::protobuf::GeneratedCodeInfo, _impl_.annotation_)>() - , from.annotation_ + , arena, from.annotation_ } {} diff --git a/src/google/protobuf/field_with_arena.h b/src/google/protobuf/field_with_arena.h index 3fd37da934986..e3b18ad8734b8 100644 --- a/src/google/protobuf/field_with_arena.h +++ b/src/google/protobuf/field_with_arena.h @@ -2,6 +2,7 @@ #define GOOGLE_PROTOBUF_FIELD_WITH_ARENA_H__ #include +#include #include "absl/log/absl_check.h" #include "google/protobuf/arena.h" @@ -16,6 +17,18 @@ namespace google { namespace protobuf { namespace internal { +// Checks whether `T` has a constructor that takes an internal metadata offset +// and an arena pointer. Some constructors won't take the arena pointer if they +// don't need it. +// +// We check for both `InternalVisibility` constructors and normal constructors, +// as `std::is_constructible` can only see public constructors. +template +inline constexpr bool kOffsetConstructorTakesArenaPointer = + std::is_constructible_v || + std::is_constructible_v; + // A container that holds a `T` and an arena pointer, where `T` has an // `InternalMetadataResolver` member. This is used for both directly // arena-allocated `T`'s and split `T`'s. Both cases need to return the correct @@ -41,7 +54,11 @@ class FieldWithArena : public ContainerDestructorSkippableBase { StaticallyVerifyLayout(); // Construct `T` after setting `_internal_metadata_` so that `T` can safely // call ResolveArena(). - new (&field_) T(BuildOffset(), std::forward(args)...); + if constexpr (kOffsetConstructorTakesArenaPointer) { + new (&field_) T(BuildOffset(), arena, std::forward(args)...); + } else { + new (&field_) T(BuildOffset(), std::forward(args)...); + } } ~FieldWithArena() { diff --git a/src/google/protobuf/field_with_arena_test.cc b/src/google/protobuf/field_with_arena_test.cc index be0bb1ef536d4..a9fd7fb3e96ae 100644 --- a/src/google/protobuf/field_with_arena_test.cc +++ b/src/google/protobuf/field_with_arena_test.cc @@ -19,7 +19,7 @@ struct TestType { InternalMetadataResolver resolver; explicit TestType(int value) : value(value) {} - TestType(InternalMetadataOffset offset, int value) + TestType(InternalMetadataOffset offset, Arena* arena, int value) : value(value), resolver(offset) {} Arena* GetArena() const { return ResolveArena<&TestType::resolver>(this); } @@ -43,7 +43,7 @@ struct TestTypeNotDestructorSkippable { explicit TestTypeNotDestructorSkippable(std::string value) : value(std::move(value)) {} - TestTypeNotDestructorSkippable(InternalMetadataOffset offset, + TestTypeNotDestructorSkippable(InternalMetadataOffset offset, Arena* arena, std::string value) : value(std::move(value)), resolver(offset) {} diff --git a/src/google/protobuf/internal_metadata_locator_test.cc b/src/google/protobuf/internal_metadata_locator_test.cc index c025637080ffd..462f317cbf33e 100644 --- a/src/google/protobuf/internal_metadata_locator_test.cc +++ b/src/google/protobuf/internal_metadata_locator_test.cc @@ -32,7 +32,8 @@ static constexpr size_t kTestOneRepeatedFieldInternalMetadataOffset = #endif struct FieldWithInternalMetadataOffset { - explicit FieldWithInternalMetadataOffset(InternalMetadataOffset offset) + explicit FieldWithInternalMetadataOffset(InternalMetadataOffset offset, + Arena* arena) : resolver(offset) {} int field = 0; @@ -43,8 +44,9 @@ struct StructWithInternalMetadata { explicit StructWithInternalMetadata(Arena* arena) : _internal_metadata_(arena), field(InternalMetadataOffset::Build< - StructWithInternalMetadata, - PROTOBUF_FIELD_OFFSET(StructWithInternalMetadata, field)>()) {} + StructWithInternalMetadata, + PROTOBUF_FIELD_OFFSET(StructWithInternalMetadata, field)>(), + arena) {} Arena* GetArena() const { return ResolveArena<&FieldWithInternalMetadataOffset::resolver>(&field); diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 53ca91d4489f5..e08d297f91d53 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -1156,13 +1156,14 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED Map using hasher = absl::Hash; constexpr Map() : Map(internal::InternalMetadataOffset()) {} - Map(const Map& other) : Map(internal::InternalMetadataOffset(), other) {} + Map(const Map& other) + : Map(internal::InternalMetadataOffset(), /*arena=*/nullptr, other) {} Map(internal::InternalVisibility, internal::InternalMetadataOffset offset) : Map(offset) {} Map(internal::InternalVisibility, internal::InternalMetadataOffset offset, - const Map& other) - : Map(offset, other) {} + Arena* arena, const Map& other) + : Map(offset, arena, other) {} Map(Map&& other) noexcept : Map(internal::InternalMetadataOffset()) { if (other.arena() != nullptr) { @@ -1203,9 +1204,10 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED Map StaticValidityCheck(); } - Map(internal::InternalMetadataOffset offset, const Map& other) : Map(offset) { + Map(internal::InternalMetadataOffset offset, Arena* arena, const Map& other) + : Map(offset) { StaticValidityCheck(); - CopyFromImpl(arena(), other); + CopyFromImpl(arena, other); } static_assert(!std::is_const::value && diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index a5d1d1daf2547..e715f495bcdfc 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -563,12 +563,12 @@ class TypeDefinedMapFieldBase : public MapFieldBase { map_)>()) {} TypeDefinedMapFieldBase(const Message* prototype, - InternalMetadataOffset offset, + InternalMetadataOffset offset, Arena* arena, const TypeDefinedMapFieldBase& from) : MapFieldBase(prototype), map_(offset .TranslateForMember(), - from.GetMap()) {} + arena, from.GetMap()) {} protected: ~TypeDefinedMapFieldBase() { map_.~Map(); } @@ -622,12 +622,12 @@ class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED MapField final : MapField(offset) {} constexpr MapField(InternalVisibility, InternalMetadataOffset offset) : MapField(offset) {} - MapField(InternalVisibility, InternalMetadataOffset offset, + MapField(InternalVisibility, InternalMetadataOffset offset, Arena* arena, const MapField& from) : TypeDefinedMapFieldBase( MessageGlobalsBase::ToDefaultInstance( Derived::internal_message_globals()), - offset, from) {} + offset, arena, from) {} private: explicit constexpr MapField(InternalMetadataOffset offset) diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h index 583044d20a9b4..4dba6010eefd4 100644 --- a/src/google/protobuf/map_field_lite.h +++ b/src/google/protobuf/map_field_lite.h @@ -46,7 +46,7 @@ class MapFieldLite { constexpr MapFieldLite(InternalVisibility, InternalMetadataOffset offset) : map_(offset) {} - MapFieldLite(InternalVisibility, InternalMetadataOffset offset, + MapFieldLite(InternalVisibility, InternalMetadataOffset offset, Arena* arena, const MapFieldLite& from) : map_(offset) { MergeFrom(from); diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 15ba8470e1bfa..378e84997d7f4 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -56,7 +56,7 @@ MessageLite* MessageLite::CopyConstruct(Arena* arena, const MessageLite& from) { void MessageLite::DestroyInstance() { #if defined(PROTOBUF_CUSTOM_VTABLE) - _class_data_->destroy_message(*this); + class_data()->destroy_message(*this); #else // PROTOBUF_CUSTOM_VTABLE this->~MessageLite(); #endif // PROTOBUF_CUSTOM_VTABLE diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index 83cb4b3eb1b72..9aa4f308485a3 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -797,7 +797,7 @@ class PROTOBUF_EXPORT MessageLite { // will likely be needed again, so the memory used may not be freed. // To ensure that all memory used by a Message is freed, you must delete it. #if defined(PROTOBUF_CUSTOM_VTABLE) - void Clear() { (this->*_class_data_->clear)(); } + void Clear() { (this->*class_data()->clear)(); } #else virtual void Clear() = 0; #endif // PROTOBUF_CUSTOM_VTABLE @@ -1096,7 +1096,7 @@ class PROTOBUF_EXPORT MessageLite { // proto. #if defined(PROTOBUF_CUSTOM_VTABLE) PROTOBUF_FUTURE_ADD_EARLY_NODISCARD size_t ByteSizeLong() const { - return _class_data_->byte_size_long(*this); + return class_data()->byte_size_long(*this); } #else PROTOBUF_FUTURE_ADD_EARLY_NODISCARD virtual size_t ByteSizeLong() const = 0; @@ -1231,9 +1231,10 @@ class PROTOBUF_EXPORT MessageLite { // This is a work in progress. There are still some types (eg MapEntry) that // return a default table instead of a unique one. #if defined(PROTOBUF_CUSTOM_VTABLE) + const internal::ClassData* class_data() const { return _class_data_; } const internal::ClassData* GetClassData() const { ::absl::PrefetchToLocalCache(_class_data_); - return _class_data_; + return class_data(); } #else // PROTOBUF_CUSTOM_VTABLE virtual const internal::ClassData* GetClassData() const = 0; @@ -1311,7 +1312,7 @@ class PROTOBUF_EXPORT MessageLite { #if defined(PROTOBUF_CUSTOM_VTABLE) PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint8_t* _InternalSerialize( uint8_t* ptr, io::EpsCopyOutputStream* stream) const { - return _class_data_->serialize(*this, ptr, stream); + return class_data()->serialize(*this, ptr, stream); } #else // PROTOBUF_CUSTOM_VTABLE PROTOBUF_FUTURE_ADD_EARLY_NODISCARD virtual uint8_t* _InternalSerialize( diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 45fbbd848d504..943268f615cc6 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -334,7 +334,8 @@ class ABSL_ATTRIBUTE_WARN_UNUSED PROTOBUF_DECLSPEC_EMPTY_BASES constexpr RepeatedField(); RepeatedField(const RepeatedField& rhs) - : RepeatedField(internal::InternalMetadataOffset(), rhs) {} + : RepeatedField(internal::InternalMetadataOffset(), /*arena=*/nullptr, + rhs) {} template (); explicit constexpr RepeatedField(internal::InternalMetadataOffset offset); - RepeatedField(internal::InternalMetadataOffset offset, + RepeatedField(internal::InternalMetadataOffset offset, Arena* arena, const RepeatedField& rhs); - RepeatedField(internal::InternalMetadataOffset offset, RepeatedField&& rhs); + RepeatedField(internal::InternalMetadataOffset offset, Arena* arena, + RepeatedField&& rhs); template void ResizeImpl(int new_size, Init init); @@ -811,14 +814,16 @@ constexpr RepeatedField::RepeatedField( template inline RepeatedField::RepeatedField( - internal::InternalMetadataOffset offset, const RepeatedField& rhs) + internal::InternalMetadataOffset offset, Arena* arena, + const RepeatedField& rhs) : RepeatedField(offset) { StaticValidityCheck(); + ABSL_DCHECK_EQ(arena, GetArena()); AnnotateSize(kSooCapacityElements, 0); if (auto size = rhs.size()) { bool is_soo = true; if (size > kSooCapacityElements) { - Grow(SelfArena{}, is_soo, 0, size); + Grow(arena, is_soo, 0, size); is_soo = false; } ExchangeCurrentSize(size); @@ -866,9 +871,9 @@ inline RepeatedField& RepeatedField::operator=( template inline RepeatedField::RepeatedField( - internal::InternalMetadataOffset offset, RepeatedField&& rhs) + internal::InternalMetadataOffset offset, Arena* arena, RepeatedField&& rhs) : RepeatedField(offset) { - Arena* arena = GetArena(); + ABSL_DCHECK_EQ(arena, GetArena()); if (internal::CanMoveWithInternalSwap(arena, rhs.GetArena())) { InternalSwap(&rhs); } else { diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc index 903bb1c1a45da..9962ab47ebbc3 100644 --- a/src/google/protobuf/repeated_ptr_field.cc +++ b/src/google/protobuf/repeated_ptr_field.cc @@ -100,6 +100,29 @@ void RepeatedPtrFieldBase::ReserveWithArena(Arena* arena, int capacity) { } } +void RepeatedPtrFieldBase::DestroyMessageLites(const ClassData* class_data) { + ABSL_DCHECK(NeedsDestroy()); + ABSL_DCHECK_EQ(GetArena(), nullptr); + + using H = GenericTypeHandler; + const int n = allocated_size(); + ABSL_DCHECK_LE(n, Capacity()); + void** elems = elements(); + void (*destroy)(MessageLite&) = class_data->destroy_message; + const size_t allocation_size = class_data->allocation_size(); + for (int i = 0; i < n; i++) { + if (i + 5 < n) { + absl::PrefetchToLocalCacheNta(elems[i + 5]); + } + auto* ptr = cast(elems[i]); + destroy(*ptr); + internal::SizedDelete(ptr, allocation_size); + } + if (!using_sso()) { + internal::SizedDelete(rep(), Capacity() * sizeof(void*) + kRepHeaderSize); + } +} + void RepeatedPtrFieldBase::DestroyProtos() { PROTOBUF_ALWAYS_INLINE_CALL Destroy>(); diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index 96c6ff0991dc0..325f53d934209 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -331,6 +331,11 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { } } +#if defined(PROTOBUF_CUSTOM_VTABLE) + // Specialized destructor routine for repeated message objects. + void DestroyMessageLites(const ClassData* class_data); +#endif // PROTOBUF_CUSTOM_VTABLE + inline bool NeedsDestroy() const { // Either there is an allocated element in SSO buffer or there is an // allocated Rep. @@ -1231,20 +1236,22 @@ class ABSL_ATTRIBUTE_WARN_UNUSED RepeatedPtrField final : RepeatedPtrField(offset) {} PROTOBUF_ALWAYS_INLINE RepeatedPtrField( internal::InternalVisibility, internal::InternalMetadataOffset offset, - const RepeatedPtrField& rhs) - : RepeatedPtrField(offset, rhs) {} + Arena* arena, const RepeatedPtrField& rhs) + : RepeatedPtrField(offset, arena, rhs) {} template ())>>> RepeatedPtrField(Iter begin, Iter end); PROTOBUF_ALWAYS_INLINE RepeatedPtrField(const RepeatedPtrField& rhs) - : RepeatedPtrField(internal::InternalMetadataOffset(), rhs) {} + : RepeatedPtrField(internal::InternalMetadataOffset(), /*arena=*/nullptr, + rhs) {} RepeatedPtrField& operator=(const RepeatedPtrField& other) ABSL_ATTRIBUTE_LIFETIME_BOUND; PROTOBUF_ALWAYS_INLINE RepeatedPtrField(RepeatedPtrField&& rhs) noexcept - : RepeatedPtrField(internal::InternalMetadataOffset(), std::move(rhs)) {} + : RepeatedPtrField(internal::InternalMetadataOffset(), /*arena=*/nullptr, + std::move(rhs)) {} RepeatedPtrField& operator=(RepeatedPtrField&& other) noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND; @@ -1569,9 +1576,9 @@ class ABSL_ATTRIBUTE_WARN_UNUSED RepeatedPtrField final using TypeHandler = internal::GenericTypeHandler; constexpr explicit RepeatedPtrField(internal::InternalMetadataOffset offset); - RepeatedPtrField(internal::InternalMetadataOffset offset, + RepeatedPtrField(internal::InternalMetadataOffset offset, Arena* arena, const RepeatedPtrField& rhs); - RepeatedPtrField(internal::InternalMetadataOffset offset, + RepeatedPtrField(internal::InternalMetadataOffset offset, Arena* arena, RepeatedPtrField&& rhs); @@ -1625,10 +1632,13 @@ constexpr PROTOBUF_ALWAYS_INLINE RepeatedPtrField::RepeatedPtrField( template PROTOBUF_ALWAYS_INLINE RepeatedPtrField::RepeatedPtrField( - internal::InternalMetadataOffset offset, const RepeatedPtrField& rhs) + internal::InternalMetadataOffset offset, Arena* arena, + const RepeatedPtrField& rhs) : RepeatedPtrFieldBase(offset) { StaticValidityCheck(); - MergeFrom(rhs); + ABSL_DCHECK_EQ(arena, GetArena()); + if (rhs.empty()) return; + RepeatedPtrFieldBase::MergeFrom(rhs, arena); } template @@ -1643,8 +1653,11 @@ template RepeatedPtrField::~RepeatedPtrField() { StaticValidityCheck(); if (!NeedsDestroy()) return; - if constexpr (std::is_base_of_v) { + if constexpr (std::is_same_v || + std::is_same_v) { DestroyProtos(); + } else if constexpr (std::is_base_of_v) { + DestroyMessageLites(internal::MessageTraits::class_data()); } else { Destroy(); } @@ -1682,11 +1695,12 @@ inline RepeatedPtrField& RepeatedPtrField::operator=( template inline RepeatedPtrField::RepeatedPtrField( - internal::InternalMetadataOffset offset, RepeatedPtrField&& rhs) + internal::InternalMetadataOffset offset, Arena* arena, + RepeatedPtrField&& rhs) : RepeatedPtrFieldBase(offset) { + ABSL_DCHECK_EQ(arena, GetArena()); // We don't just call Swap(&rhs) here because it would perform 3 copies if rhs // is on a different arena. - Arena* arena = GetArena(); if (internal::CanMoveWithInternalSwap(arena, rhs.GetArena())) { InternalSwap(&rhs); } else {