/src/LPM/external.protobuf/include/google/protobuf/arena.h
Line | Count | Source (jump to first uncovered line) |
1 | | // Protocol Buffers - Google's data interchange format |
2 | | // Copyright 2008 Google Inc. All rights reserved. |
3 | | // |
4 | | // Use of this source code is governed by a BSD-style |
5 | | // license that can be found in the LICENSE file or at |
6 | | // https://developers.google.com/open-source/licenses/bsd |
7 | | |
8 | | // This file defines an Arena allocator for better allocation performance. |
9 | | |
10 | | #ifndef GOOGLE_PROTOBUF_ARENA_H__ |
11 | | #define GOOGLE_PROTOBUF_ARENA_H__ |
12 | | |
13 | | #include <cstddef> |
14 | | #include <cstdint> |
15 | | #include <limits> |
16 | | #include <new> // IWYU pragma: keep for operator new(). |
17 | | #include <string> |
18 | | #include <type_traits> |
19 | | #include <utility> |
20 | | #include <vector> |
21 | | #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS |
22 | | // Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0. |
23 | | #include <exception> |
24 | | #include <typeinfo> |
25 | | namespace std { |
26 | | using type_info = ::type_info; |
27 | | } |
28 | | #endif |
29 | | |
30 | | #include "absl/base/attributes.h" |
31 | | #include "absl/base/macros.h" |
32 | | #include "absl/base/optimization.h" |
33 | | #include "absl/base/prefetch.h" |
34 | | #include "absl/log/absl_check.h" |
35 | | #include "absl/utility/internal/if_constexpr.h" |
36 | | #include "google/protobuf/arena_align.h" |
37 | | #include "google/protobuf/arena_allocation_policy.h" |
38 | | #include "google/protobuf/port.h" |
39 | | #include "google/protobuf/serial_arena.h" |
40 | | #include "google/protobuf/thread_safe_arena.h" |
41 | | |
42 | | // Must be included last. |
43 | | #include "google/protobuf/port_def.inc" |
44 | | |
45 | | #ifdef SWIG |
46 | | #error "You cannot SWIG proto headers" |
47 | | #endif |
48 | | |
49 | | namespace google { |
50 | | namespace protobuf { |
51 | | |
52 | | struct ArenaOptions; // defined below |
53 | | class Arena; // defined below |
54 | | class Message; // defined in message.h |
55 | | class MessageLite; |
56 | | template <typename Key, typename T> |
57 | | class Map; |
58 | | namespace internal { |
59 | | struct RepeatedFieldBase; |
60 | | class ExtensionSet; |
61 | | } // namespace internal |
62 | | |
63 | | namespace arena_metrics { |
64 | | |
65 | | void EnableArenaMetrics(ArenaOptions* options); |
66 | | |
67 | | } // namespace arena_metrics |
68 | | |
69 | | namespace TestUtil { |
70 | | class ReflectionTester; // defined in test_util.h |
71 | | } // namespace TestUtil |
72 | | |
73 | | namespace internal { |
74 | | |
75 | | struct ArenaTestPeer; // defined in arena_test_util.h |
76 | | class InternalMetadata; // defined in metadata_lite.h |
77 | | class LazyField; // defined in lazy_field.h |
78 | | class EpsCopyInputStream; // defined in parse_context.h |
79 | | class UntypedMapBase; // defined in map.h |
80 | | class RepeatedPtrFieldBase; // defined in repeated_ptr_field.h |
81 | | class TcParser; // defined in generated_message_tctable_impl.h |
82 | | |
83 | | template <typename Type> |
84 | | class GenericTypeHandler; // defined in repeated_field.h |
85 | | |
86 | | template <typename T> |
87 | 0 | void arena_delete_object(void* object) { |
88 | 0 | delete reinterpret_cast<T*>(object); |
89 | 0 | } |
90 | | |
91 | 0 | inline bool CanUseInternalSwap(Arena* lhs, Arena* rhs) { |
92 | 0 | if (DebugHardenForceCopyInSwap()) { |
93 | 0 | // We force copy in swap when we are not using an arena. |
94 | 0 | // If we did with an arena we would grow arena usage too much. |
95 | 0 | return lhs != nullptr && lhs == rhs; |
96 | 0 | } else { |
97 | 0 | return lhs == rhs; |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 0 | inline bool CanMoveWithInternalSwap(Arena* lhs, Arena* rhs) { |
102 | 0 | if (DebugHardenForceCopyInMove()) { |
103 | 0 | // We force copy in move when we are not using an arena. |
104 | 0 | // If we did with an arena we would grow arena usage too much. |
105 | 0 | return lhs != nullptr && lhs == rhs; |
106 | 0 | } else { |
107 | 0 | return lhs == rhs; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | | } // namespace internal |
112 | | |
113 | | // ArenaOptions provides optional additional parameters to arena construction |
114 | | // that control its block-allocation behavior. |
115 | | struct ArenaOptions { |
116 | | // This defines the size of the first block requested from the system malloc. |
117 | | // Subsequent block sizes will increase in a geometric series up to a maximum. |
118 | | size_t start_block_size = internal::AllocationPolicy::kDefaultStartBlockSize; |
119 | | |
120 | | // This defines the maximum block size requested from system malloc (unless an |
121 | | // individual arena allocation request occurs with a size larger than this |
122 | | // maximum). Requested block sizes increase up to this value, then remain |
123 | | // here. |
124 | | size_t max_block_size = internal::AllocationPolicy::kDefaultMaxBlockSize; |
125 | | |
126 | | // An initial block of memory for the arena to use, or nullptr for none. If |
127 | | // provided, the block must live at least as long as the arena itself. The |
128 | | // creator of the Arena retains ownership of the block after the Arena is |
129 | | // destroyed. |
130 | | char* initial_block = nullptr; |
131 | | |
132 | | // The size of the initial block, if provided. |
133 | | size_t initial_block_size = 0; |
134 | | |
135 | | // A function pointer to an alloc method that returns memory blocks of size |
136 | | // requested. By default, it contains a ptr to the malloc function. |
137 | | // |
138 | | // NOTE: block_alloc and dealloc functions are expected to behave like |
139 | | // malloc and free, including Asan poisoning. |
140 | | void* (*block_alloc)(size_t) = nullptr; |
141 | | // A function pointer to a dealloc method that takes ownership of the blocks |
142 | | // from the arena. By default, it contains a ptr to a wrapper function that |
143 | | // calls free. |
144 | | void (*block_dealloc)(void*, size_t) = nullptr; |
145 | | |
146 | | private: |
147 | 0 | internal::AllocationPolicy AllocationPolicy() const { |
148 | 0 | internal::AllocationPolicy res; |
149 | 0 | res.start_block_size = start_block_size; |
150 | 0 | res.max_block_size = max_block_size; |
151 | 0 | res.block_alloc = block_alloc; |
152 | 0 | res.block_dealloc = block_dealloc; |
153 | 0 | return res; |
154 | 0 | } |
155 | | |
156 | | friend class Arena; |
157 | | friend class ArenaOptionsTestFriend; |
158 | | }; |
159 | | |
160 | | // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation |
161 | | // with new/delete, and improves performance by aggregating allocations into |
162 | | // larger blocks and freeing allocations all at once. Protocol messages are |
163 | | // allocated on an arena by using Arena::Create<T>(Arena*), below, and are |
164 | | // automatically freed when the arena is destroyed. |
165 | | // |
166 | | // This is a thread-safe implementation: multiple threads may allocate from the |
167 | | // arena concurrently. Destruction is not thread-safe and the destructing |
168 | | // thread must synchronize with users of the arena first. |
169 | | class PROTOBUF_EXPORT PROTOBUF_ALIGNAS(8) Arena final { |
170 | | public: |
171 | | // Default constructor with sensible default options, tuned for average |
172 | | // use-cases. |
173 | 0 | inline Arena() : impl_() {} |
174 | | |
175 | | // Construct an arena with default options, except for the supplied |
176 | | // initial block. It is more efficient to use this constructor |
177 | | // instead of passing ArenaOptions if the only configuration needed |
178 | | // by the caller is supplying an initial block. |
179 | | inline Arena(char* initial_block, size_t initial_block_size) |
180 | 0 | : impl_(initial_block, initial_block_size) {} |
181 | | |
182 | | // Arena constructor taking custom options. See ArenaOptions above for |
183 | | // descriptions of the options available. |
184 | | explicit Arena(const ArenaOptions& options) |
185 | | : impl_(options.initial_block, options.initial_block_size, |
186 | 0 | options.AllocationPolicy()) {} |
187 | | |
188 | | // Block overhead. Use this as a guide for how much to over-allocate the |
189 | | // initial block if you want an allocation of size N to fit inside it. |
190 | | // |
191 | | // WARNING: if you allocate multiple objects, it is difficult to guarantee |
192 | | // that a series of allocations will fit in the initial block, especially if |
193 | | // Arena changes its alignment guarantees in the future! |
194 | | static const size_t kBlockOverhead = |
195 | | internal::ThreadSafeArena::kBlockHeaderSize + |
196 | | internal::ThreadSafeArena::kSerialArenaSize; |
197 | | |
198 | | inline ~Arena() = default; |
199 | | |
200 | | #ifndef PROTOBUF_FUTURE_REMOVE_CREATEMESSAGE |
201 | | // Deprecated. Use Create<T> instead. |
202 | | template <typename T, typename... Args> |
203 | | ABSL_DEPRECATED("Use Create") |
204 | | static T* CreateMessage(Arena* arena, Args&&... args) { |
205 | | using Type = std::remove_const_t<T>; |
206 | | static_assert( |
207 | | is_arena_constructable<Type>::value, |
208 | | "CreateMessage can only construct types that are ArenaConstructable"); |
209 | | return Create<Type>(arena, std::forward<Args>(args)...); |
210 | | } |
211 | | #endif // !PROTOBUF_FUTURE_REMOVE_CREATEMESSAGE |
212 | | |
213 | | // Allocates an object type T if the arena passed in is not nullptr; |
214 | | // otherwise, returns a heap-allocated object. |
215 | | template <typename T, typename... Args> |
216 | 0 | PROTOBUF_NDEBUG_INLINE static T* Create(Arena* arena, Args&&... args) { |
217 | 0 | return absl::utility_internal::IfConstexprElse< |
218 | 0 | is_arena_constructable<T>::value>( |
219 | 0 | // Arena-constructable |
220 | 0 | [arena](auto&&... args) { |
221 | 0 | using Type = std::remove_const_t<T>; |
222 | 0 | #ifdef __cpp_if_constexpr |
223 | 0 | // DefaultConstruct/CopyConstruct are optimized for messages, which |
224 | 0 | // are both arena constructible and destructor skippable and they |
225 | 0 | // assume much. Don't use these functions unless the invariants |
226 | 0 | // hold. |
227 | 0 | if constexpr (is_destructor_skippable<T>::value) { |
228 | 0 | constexpr auto construct_type = GetConstructType<T, Args&&...>(); |
229 | 0 | // We delegate to DefaultConstruct/CopyConstruct where appropriate |
230 | 0 | // because protobuf generated classes have external templates for |
231 | 0 | // these functions for code size reasons. When `if constexpr` is not |
232 | 0 | // available always use the fallback. |
233 | 0 | if constexpr (construct_type == ConstructType::kDefault) { |
234 | 0 | return static_cast<Type*>(DefaultConstruct<Type>(arena)); |
235 | 0 | } else if constexpr (construct_type == ConstructType::kCopy) { |
236 | 0 | return static_cast<Type*>(CopyConstruct<Type>(arena, &args...)); |
237 | 0 | } |
238 | 0 | } |
239 | 0 | #endif |
240 | 0 | return CreateArenaCompatible<Type>(arena, |
241 | 0 | std::forward<Args>(args)...); |
242 | 0 | }, |
243 | 0 | // Non arena-constructable |
244 | 0 | [arena](auto&&... args) { |
245 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
246 | 0 | return new T(std::forward<Args>(args)...); |
247 | 0 | } |
248 | 0 | return new (arena->AllocateInternal<T>()) |
249 | 0 | T(std::forward<Args>(args)...); |
250 | 0 | }, Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJRS9_EEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJSA_EEEDaSJ_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJS9_EEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJS9_EEEDaSI_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINS0_8internal16InternalMetadata9ContainerINSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEEEEJEEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJEEEDaSM_ Unexecuted instantiation: _ZZN6google8protobuf5Arena6CreateINSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEJEEEPT_PS1_DpOT0_ENKUlDpOT_E0_clIJEEEDaSI_ |
251 | 0 | std::forward<Args>(args)...); |
252 | 0 | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* google::protobuf::Arena::Create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(google::protobuf::Arena*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* google::protobuf::Arena::Create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(google::protobuf::Arena*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&&) Unexecuted instantiation: google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >* google::protobuf::Arena::Create<google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >>(google::protobuf::Arena*) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >* google::protobuf::Arena::Create<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >>(google::protobuf::Arena*) Unexecuted instantiation: google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>* google::protobuf::Arena::Create<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>>(google::protobuf::Arena*) |
253 | | |
254 | | // API to delete any objects not on an arena. This can be used to safely |
255 | | // clean up messages or repeated fields without knowing whether or not they're |
256 | | // owned by an arena. The pointer passed to this function should not be used |
257 | | // again. |
258 | | template <typename T> |
259 | | PROTOBUF_ALWAYS_INLINE static void Destroy(T* obj) { |
260 | | if (InternalGetArena(obj) == nullptr) delete obj; |
261 | | } |
262 | | |
263 | | // Allocates memory with the specific size and alignment. |
264 | 0 | void* AllocateAligned(size_t size, size_t align = 8) { |
265 | 0 | if (align <= internal::ArenaAlignDefault::align) { |
266 | 0 | return Allocate(internal::ArenaAlignDefault::Ceil(size)); |
267 | 0 | } else { |
268 | 0 | // We are wasting space by over allocating align - 8 bytes. Compared |
269 | 0 | // to a dedicated function that takes current alignment in consideration. |
270 | 0 | // Such a scheme would only waste (align - 8)/2 bytes on average, but |
271 | 0 | // requires a dedicated function in the outline arena allocation |
272 | 0 | // functions. Possibly re-evaluate tradeoffs later. |
273 | 0 | auto align_as = internal::ArenaAlignAs(align); |
274 | 0 | return align_as.Ceil(Allocate(align_as.Padded(size))); |
275 | 0 | } |
276 | 0 | } |
277 | | |
278 | | // Create an array of object type T on the arena *without* invoking the |
279 | | // constructor of T. If `arena` is null, then the return value should be freed |
280 | | // with `delete[] x;` (or `::operator delete[](x);`). |
281 | | // To ensure safe uses, this function checks at compile time |
282 | | // (when compiled as C++11) that T is trivially default-constructible and |
283 | | // trivially destructible. |
284 | | template <typename T> |
285 | | PROTOBUF_NDEBUG_INLINE static T* CreateArray(Arena* arena, |
286 | 0 | size_t num_elements) { |
287 | 0 | static_assert(std::is_trivial<T>::value, |
288 | 0 | "CreateArray requires a trivially constructible type"); |
289 | 0 | static_assert(std::is_trivially_destructible<T>::value, |
290 | 0 | "CreateArray requires a trivially destructible type"); |
291 | 0 | ABSL_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T)) |
292 | 0 | << "Requested size is too large to fit into size_t."; |
293 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
294 | 0 | return new T[num_elements]; |
295 | 0 | } else { |
296 | 0 | // We count on compiler to realize that if sizeof(T) is a multiple of |
297 | 0 | // 8 AlignUpTo can be elided. |
298 | 0 | return static_cast<T*>( |
299 | 0 | arena->AllocateAlignedForArray(sizeof(T) * num_elements, alignof(T))); |
300 | 0 | } |
301 | 0 | } Unexecuted instantiation: char* google::protobuf::Arena::CreateArray<char>(google::protobuf::Arena*, unsigned long) Unexecuted instantiation: unsigned char* google::protobuf::Arena::CreateArray<unsigned char>(google::protobuf::Arena*, unsigned long) |
302 | | |
303 | | // The following routines are for monitoring. They will approximate the total |
304 | | // sum allocated and used memory, but the exact value is an implementation |
305 | | // deal. For instance allocated space depends on growth policies. Do not use |
306 | | // these in unit tests. Returns the total space allocated by the arena, which |
307 | | // is the sum of the sizes of the underlying blocks. |
308 | 0 | uint64_t SpaceAllocated() const { return impl_.SpaceAllocated(); } |
309 | | // Returns the total space used by the arena. Similar to SpaceAllocated but |
310 | | // does not include free space and block overhead. This is a best-effort |
311 | | // estimate and may inaccurately calculate space used by other threads |
312 | | // executing concurrently with the call to this method. These inaccuracies |
313 | | // are due to race conditions, and are bounded but unpredictable. Stale data |
314 | | // can lead to underestimates of the space used, and race conditions can lead |
315 | | // to overestimates (up to the current block size). |
316 | 0 | uint64_t SpaceUsed() const { return impl_.SpaceUsed(); } |
317 | | |
318 | | // Frees all storage allocated by this arena after calling destructors |
319 | | // registered with OwnDestructor() and freeing objects registered with Own(). |
320 | | // Any objects allocated on this arena are unusable after this call. It also |
321 | | // returns the total space used by the arena which is the sums of the sizes |
322 | | // of the allocated blocks. This method is not thread-safe. |
323 | 0 | uint64_t Reset() { return impl_.Reset(); } |
324 | | |
325 | | // Adds |object| to a list of heap-allocated objects to be freed with |delete| |
326 | | // when the arena is destroyed or reset. |
327 | | template <typename T> |
328 | 0 | PROTOBUF_ALWAYS_INLINE void Own(T* object) { |
329 | 0 | // Collapsing all template instantiations to one for generic Message reduces |
330 | 0 | // code size, using the virtual destructor instead. |
331 | 0 | using TypeToUse = |
332 | 0 | std::conditional_t<std::is_convertible<T*, MessageLite*>::value, |
333 | 0 | MessageLite, T>; |
334 | 0 | if (object != nullptr) { |
335 | 0 | impl_.AddCleanup(static_cast<TypeToUse*>(object), |
336 | 0 | &internal::arena_delete_object<TypeToUse>); |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | | // Adds |object| to a list of objects whose destructors will be manually |
341 | | // called when the arena is destroyed or reset. This differs from Own() in |
342 | | // that it does not free the underlying memory with |delete|; hence, it is |
343 | | // normally only used for objects that are placement-newed into |
344 | | // arena-allocated memory. |
345 | | template <typename T> |
346 | | PROTOBUF_ALWAYS_INLINE void OwnDestructor(T* object) { |
347 | | if (object != nullptr) { |
348 | | impl_.AddCleanup(object, &internal::cleanup::arena_destruct_object<T>); |
349 | | } |
350 | | } |
351 | | |
352 | | // Adds a custom member function on an object to the list of destructors that |
353 | | // will be manually called when the arena is destroyed or reset. This differs |
354 | | // from OwnDestructor() in that any member function may be specified, not only |
355 | | // the class destructor. |
356 | | PROTOBUF_ALWAYS_INLINE void OwnCustomDestructor(void* object, |
357 | 0 | void (*destruct)(void*)) { |
358 | 0 | impl_.AddCleanup(object, destruct); |
359 | 0 | } |
360 | | |
361 | | // Retrieves the arena associated with |value| if |value| is an arena-capable |
362 | | // message, or nullptr otherwise. If possible, the call resolves at compile |
363 | | // time. Note that we can often devirtualize calls to `value->GetArena()` so |
364 | | // usually calling this method is unnecessary. |
365 | | // TODO: remove this function. |
366 | | template <typename T> |
367 | | ABSL_DEPRECATED( |
368 | | "This will be removed in a future release. Call value->GetArena() " |
369 | | "instead.") |
370 | | PROTOBUF_ALWAYS_INLINE static Arena* GetArena(T* value) { |
371 | | return GetArenaInternal(value); |
372 | | } |
373 | | |
374 | | template <typename T> |
375 | | class InternalHelper { |
376 | | private: |
377 | | // A SFINAE friendly trait that probes for `U` but always evalues to |
378 | | // `Arena*`. |
379 | | template <typename U> |
380 | | using EnableIfArena = |
381 | | typename std::enable_if<std::is_same<Arena*, U>::value, Arena*>::type; |
382 | | |
383 | | // Use go/ranked-overloads for dispatching. |
384 | | struct Rank0 {}; |
385 | | struct Rank1 : Rank0 {}; |
386 | | |
387 | | static void InternalSwap(T* a, T* b) { a->InternalSwap(b); } |
388 | | |
389 | | static Arena* GetArena(T* p) { return GetArena(Rank1{}, p); } |
390 | | |
391 | | template <typename U> |
392 | | static auto GetArena(Rank1, |
393 | | U* p) -> EnableIfArena<decltype(p->GetArena())> { |
394 | | return p->GetArena(); |
395 | | } |
396 | | |
397 | | template <typename U> |
398 | | static Arena* GetArena(Rank0, U*) { |
399 | | return nullptr; |
400 | | } |
401 | | |
402 | | // If an object type T satisfies the appropriate protocol, it is deemed |
403 | | // "arena compatible" and handled more efficiently because this interface |
404 | | // (i) passes the arena pointer to the created object so that its |
405 | | // sub-objects and internal allocations can use the arena too, and (ii) |
406 | | // elides the object's destructor call when possible; e.g. protobuf |
407 | | // messages, RepeatedField, etc. Otherwise, the arena will invoke the |
408 | | // object's destructor when the arena is destroyed. |
409 | | // |
410 | | // To be "arena-compatible", a type T must satisfy the following: |
411 | | // |
412 | | // - The type T must have (at least) two constructors: a constructor |
413 | | // callable with `args` (without `arena`), called when a T is allocated on |
414 | | // the heap; and a constructor callable with `Arena* arena, Args&&... |
415 | | // args`, called when a T is allocated on an arena. If the second |
416 | | // constructor is called with a null arena pointer, it must be equivalent |
417 | | // to invoking the first |
418 | | // (`args`-only) constructor. |
419 | | // |
420 | | // - The type T must have a particular type trait: a nested type |
421 | | // |InternalArenaConstructable_|. This is usually a typedef to |void|. |
422 | | // |
423 | | // - The type T *may* have the type trait |DestructorSkippable_|. If this |
424 | | // type trait is present in the type, then its destructor will not be |
425 | | // called if and only if it was passed a non-null arena pointer. If this |
426 | | // type trait is not present on the type, then its destructor is always |
427 | | // called when the containing arena is destroyed. |
428 | | // |
429 | | // The protocol is implemented by all protobuf message classes as well as |
430 | | // protobuf container types like RepeatedPtrField and Map. It is internal to |
431 | | // protobuf and is not guaranteed to be stable. Non-proto types should not |
432 | | // rely on this protocol. |
433 | | template <typename U> |
434 | | static char DestructorSkippable(const typename U::DestructorSkippable_*); |
435 | | template <typename U> |
436 | | static double DestructorSkippable(...); |
437 | | |
438 | | typedef std::integral_constant< |
439 | | bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) == |
440 | | sizeof(char) || |
441 | | std::is_trivially_destructible<T>::value> |
442 | | is_destructor_skippable; |
443 | | |
444 | | template <typename U> |
445 | | static char ArenaConstructable( |
446 | | const typename U::InternalArenaConstructable_*); |
447 | | template <typename U> |
448 | | static double ArenaConstructable(...); |
449 | | |
450 | | typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>( |
451 | | static_cast<const T*>(0))) == |
452 | | sizeof(char)> |
453 | | is_arena_constructable; |
454 | | |
455 | | |
456 | | template <typename... Args> |
457 | 0 | static T* Construct(void* ptr, Args&&... args) { |
458 | 0 | return new (ptr) T(static_cast<Args&&>(args)...); |
459 | 0 | } |
460 | | |
461 | 0 | static inline PROTOBUF_ALWAYS_INLINE T* New() { |
462 | 0 | return new T(nullptr); |
463 | 0 | } |
464 | | |
465 | | friend class Arena; |
466 | | friend class TestUtil::ReflectionTester; |
467 | | }; |
468 | | |
469 | | // Provides access to protected GetArena to generated messages. |
470 | | // For internal use only. |
471 | | template <typename T> |
472 | | static Arena* InternalGetArena(T* p) { |
473 | | return InternalHelper<T>::GetArena(p); |
474 | | } |
475 | | |
476 | | // Helper typetraits that indicates support for arenas in a type T at compile |
477 | | // time. This is public only to allow construction of higher-level templated |
478 | | // utilities. |
479 | | // |
480 | | // is_arena_constructable<T>::value is true if the message type T has arena |
481 | | // support enabled, and false otherwise. |
482 | | // |
483 | | // is_destructor_skippable<T>::value is true if the message type T has told |
484 | | // the arena that it is safe to skip the destructor, and false otherwise. |
485 | | // |
486 | | // This is inside Arena because only Arena has the friend relationships |
487 | | // necessary to see the underlying generated code traits. |
488 | | template <typename T> |
489 | | struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {}; |
490 | | template <typename T> |
491 | | struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable { |
492 | | }; |
493 | | |
494 | | private: |
495 | | internal::ThreadSafeArena impl_; |
496 | | |
497 | | enum class ConstructType { kUnknown, kDefault, kCopy, kMove }; |
498 | | // Overload set to detect which kind of construction is going to happen for a |
499 | | // specific set of input arguments. This is used to dispatch to different |
500 | | // helper functions. |
501 | | template <typename T> |
502 | | static auto ProbeConstructType() |
503 | | -> std::integral_constant<ConstructType, ConstructType::kDefault>; |
504 | | template <typename T> |
505 | | static auto ProbeConstructType(const T&) |
506 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
507 | | template <typename T> |
508 | | static auto ProbeConstructType(T&) |
509 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
510 | | template <typename T> |
511 | | static auto ProbeConstructType(const T&&) |
512 | | -> std::integral_constant<ConstructType, ConstructType::kCopy>; |
513 | | template <typename T> |
514 | | static auto ProbeConstructType(T&&) |
515 | | -> std::integral_constant<ConstructType, ConstructType::kMove>; |
516 | | template <typename T, typename... U> |
517 | | static auto ProbeConstructType(U&&...) |
518 | | -> std::integral_constant<ConstructType, ConstructType::kUnknown>; |
519 | | |
520 | | template <typename T, typename... Args> |
521 | 0 | static constexpr auto GetConstructType() { |
522 | 0 | return std::is_base_of<MessageLite, T>::value |
523 | 0 | ? decltype(ProbeConstructType<T>(std::declval<Args>()...))::value |
524 | 0 | : ConstructType::kUnknown; |
525 | 0 | } |
526 | | |
527 | 0 | void ReturnArrayMemory(void* p, size_t size) { |
528 | 0 | impl_.ReturnArrayMemory(p, size); |
529 | 0 | } |
530 | | |
531 | | template <typename T, typename... Args> |
532 | | PROTOBUF_NDEBUG_INLINE static T* CreateArenaCompatible(Arena* arena, |
533 | | Args&&... args) { |
534 | | static_assert(is_arena_constructable<T>::value, |
535 | | "Can only construct types that are ArenaConstructable"); |
536 | | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
537 | | return new T(nullptr, static_cast<Args&&>(args)...); |
538 | | } else { |
539 | | return arena->DoCreateMessage<T>(static_cast<Args&&>(args)...); |
540 | | } |
541 | | } |
542 | | |
543 | | // This specialization for no arguments is necessary, because its behavior is |
544 | | // slightly different. When the arena pointer is nullptr, it calls T() |
545 | | // instead of T(nullptr). |
546 | | template <typename T> |
547 | 0 | PROTOBUF_NDEBUG_INLINE static T* CreateArenaCompatible(Arena* arena) { |
548 | 0 | static_assert(is_arena_constructable<T>::value, |
549 | 0 | "Can only construct types that are ArenaConstructable"); |
550 | 0 | if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) { |
551 | 0 | // Generated arena constructor T(Arena*) is protected. Call via |
552 | 0 | // InternalHelper. |
553 | 0 | return InternalHelper<T>::New(); |
554 | 0 | } else { |
555 | 0 | return arena->DoCreateMessage<T>(); |
556 | 0 | } |
557 | 0 | } |
558 | | |
559 | | template <typename T, bool trivial = std::is_trivially_destructible<T>::value> |
560 | 0 | PROTOBUF_NDEBUG_INLINE void* AllocateInternal() { |
561 | 0 | if (trivial) { |
562 | 0 | return AllocateAligned(sizeof(T), alignof(T)); |
563 | 0 | } else { |
564 | 0 | // We avoid instantiating arena_destruct_object<T> in the trivial case. |
565 | 0 | constexpr auto dtor = &internal::cleanup::arena_destruct_object< |
566 | 0 | std::conditional_t<trivial, std::string, T>>; |
567 | 0 | return AllocateAlignedWithCleanup(sizeof(T), alignof(T), dtor); |
568 | 0 | } |
569 | 0 | } Unexecuted instantiation: void* google::protobuf::Arena::AllocateInternal<google::protobuf::internal::InternalMetadata::Container<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, false>() Unexecuted instantiation: void* google::protobuf::Arena::AllocateInternal<google::protobuf::internal::InternalMetadata::Container<google::protobuf::UnknownFieldSet>, true>() |
570 | | |
571 | | // DefaultConstruct/CopyConstruct: |
572 | | // |
573 | | // Functions with a generic signature to support taking the address in generic |
574 | | // contexts, like RepeatedPtrField, etc. |
575 | | // These are also used as a hook for `extern template` instantiations where |
576 | | // codegen can offload the instantiations to the respective .pb.cc files. This |
577 | | // has two benefits: |
578 | | // - It reduces the library bloat as callers don't have to instantiate the |
579 | | // function. |
580 | | // - It allows the optimizer to see the constructors called to |
581 | | // further optimize the instantiation. |
582 | | template <typename T> |
583 | | static void* DefaultConstruct(Arena* arena); |
584 | | template <typename T> |
585 | | static void* CopyConstruct(Arena* arena, const void* from); |
586 | | |
587 | | template <typename T, typename... Args> |
588 | 0 | PROTOBUF_NDEBUG_INLINE T* DoCreateMessage(Args&&... args) { |
589 | 0 | return InternalHelper<T>::Construct( |
590 | 0 | AllocateInternal<T, is_destructor_skippable<T>::value>(), this, |
591 | 0 | std::forward<Args>(args)...); |
592 | 0 | } |
593 | | |
594 | | // CreateInArenaStorage is used to implement map field. Without it, |
595 | | // Map need to call generated message's protected arena constructor, |
596 | | // which needs to declare Map as friend of generated message. |
597 | | template <typename T, typename... Args> |
598 | | static void CreateInArenaStorage(T* ptr, Arena* arena, Args&&... args) { |
599 | | CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>(), |
600 | | std::forward<Args>(args)...); |
601 | | if (PROTOBUF_PREDICT_TRUE(arena != nullptr)) { |
602 | | RegisterDestructorInternal(ptr, arena, is_destructor_skippable<T>()); |
603 | | } |
604 | | } |
605 | | |
606 | | template <typename T, typename... Args> |
607 | | static void CreateInArenaStorageInternal(T* ptr, Arena* arena, |
608 | | std::true_type, Args&&... args) { |
609 | | InternalHelper<T>::Construct(ptr, arena, std::forward<Args>(args)...); |
610 | | } |
611 | | template <typename T, typename... Args> |
612 | | static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */, |
613 | | std::false_type, Args&&... args) { |
614 | | new (ptr) T(std::forward<Args>(args)...); |
615 | | } |
616 | | |
617 | | template <typename T> |
618 | | static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */, |
619 | | std::true_type) {} |
620 | | template <typename T> |
621 | | static void RegisterDestructorInternal(T* ptr, Arena* arena, |
622 | | std::false_type) { |
623 | | arena->OwnDestructor(ptr); |
624 | | } |
625 | | |
626 | | // Implementation for GetArena(). Only message objects with |
627 | | // InternalArenaConstructable_ tags can be associated with an arena, and such |
628 | | // objects must implement a GetArena() method. |
629 | | template <typename T> |
630 | | PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(T* value) { |
631 | | return InternalHelper<T>::GetArena(value); |
632 | | } |
633 | | |
634 | 0 | void* AllocateAlignedForArray(size_t n, size_t align) { |
635 | 0 | if (align <= internal::ArenaAlignDefault::align) { |
636 | 0 | return AllocateForArray(internal::ArenaAlignDefault::Ceil(n)); |
637 | 0 | } else { |
638 | 0 | // We are wasting space by over allocating align - 8 bytes. Compared |
639 | 0 | // to a dedicated function that takes current alignment in consideration. |
640 | 0 | // Such a scheme would only waste (align - 8)/2 bytes on average, but |
641 | 0 | // requires a dedicated function in the outline arena allocation |
642 | 0 | // functions. Possibly re-evaluate tradeoffs later. |
643 | 0 | auto align_as = internal::ArenaAlignAs(align); |
644 | 0 | return align_as.Ceil(AllocateForArray(align_as.Padded(n))); |
645 | 0 | } |
646 | 0 | } |
647 | | |
648 | | void* Allocate(size_t n); |
649 | | void* AllocateForArray(size_t n); |
650 | | void* AllocateAlignedWithCleanup(size_t n, size_t align, |
651 | | void (*destructor)(void*)); |
652 | | |
653 | | // Test only API. |
654 | | // It returns the objects that are in the cleanup list for the current |
655 | | // SerialArena. This API is meant for tests that want to see if something was |
656 | | // added or not to the cleanup list. Sometimes adding something to the cleanup |
657 | | // list has no visible side effect so peeking into the list is the only way to |
658 | | // test. |
659 | | std::vector<void*> PeekCleanupListForTesting(); |
660 | | |
661 | | template <typename Type> |
662 | | friend class internal::GenericTypeHandler; |
663 | | friend class internal::InternalMetadata; // For user_arena(). |
664 | | friend class internal::LazyField; // For DefaultConstruct. |
665 | | friend class internal::EpsCopyInputStream; // For parser performance |
666 | | friend class internal::TcParser; // For parser performance |
667 | | friend class MessageLite; |
668 | | template <typename Key, typename T> |
669 | | friend class Map; |
670 | | template <typename> |
671 | | friend class RepeatedField; // For ReturnArrayMemory |
672 | | friend class internal::RepeatedPtrFieldBase; // For ReturnArrayMemory |
673 | | friend class internal::UntypedMapBase; // For ReturnArrayMemory |
674 | | friend class internal::ExtensionSet; // For ReturnArrayMemory |
675 | | |
676 | | friend struct internal::ArenaTestPeer; |
677 | | }; |
678 | | |
679 | | // DefaultConstruct/CopyConstruct |
680 | | // |
681 | | // IMPORTANT: These have to be defined out of line and without an `inline` |
682 | | // keyword to make sure the `extern template` suppresses instantiations. |
683 | | template <typename T> |
684 | 0 | PROTOBUF_NOINLINE void* Arena::DefaultConstruct(Arena* arena) { |
685 | 0 | static_assert(is_destructor_skippable<T>::value, ""); |
686 | 0 | void* mem = arena != nullptr ? arena->AllocateAligned(sizeof(T)) |
687 | 0 | : ::operator new(sizeof(T)); |
688 | 0 | return new (mem) T(arena); |
689 | 0 | } Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<HttpProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::Any>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::UninterpretedOption_NamePart>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::SourceCodeInfo_Location>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::GeneratedCodeInfo_Annotation>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions_FeatureSupport>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions_EditionDefault>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSet>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ExtensionRangeOptions_Declaration>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumDescriptorProto_EnumReservedRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto_ReservedRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::UninterpretedOption>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::SourceCodeInfo>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::GeneratedCodeInfo>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSetDefaults_FeatureSetEditionDefault>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ServiceOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::OneofOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MethodOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MessageOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FeatureSetDefaults>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ExtensionRangeOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumValueOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumOptions>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::OneofDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::MethodDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FieldDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumValueDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto_ExtensionRange>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::ServiceDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::EnumDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::DescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileDescriptorProto>(google::protobuf::Arena*) Unexecuted instantiation: void* google::protobuf::Arena::DefaultConstruct<google::protobuf::FileDescriptorSet>(google::protobuf::Arena*) |
690 | | |
691 | | template <typename T> |
692 | | PROTOBUF_NOINLINE void* Arena::CopyConstruct(Arena* arena, const void* from) { |
693 | | // If the object is larger than half a cache line, prefetch it. |
694 | | // This way of prefetching is a little more aggressive than if we |
695 | | // condition off a whole cache line, but benchmarks show better results. |
696 | | if (sizeof(T) > ABSL_CACHELINE_SIZE / 2) { |
697 | | PROTOBUF_PREFETCH_WITH_OFFSET(from, 64); |
698 | | } |
699 | | static_assert(is_destructor_skippable<T>::value, ""); |
700 | | void* mem = arena != nullptr ? arena->AllocateAligned(sizeof(T)) |
701 | | : ::operator new(sizeof(T)); |
702 | | return new (mem) T(arena, *static_cast<const T*>(from)); |
703 | | } |
704 | | |
705 | | template <> |
706 | 0 | inline void* Arena::AllocateInternal<std::string, false>() { |
707 | 0 | return impl_.AllocateFromStringBlock(); |
708 | 0 | } |
709 | | |
710 | | } // namespace protobuf |
711 | | } // namespace google |
712 | | |
713 | | #include "google/protobuf/port_undef.inc" |
714 | | |
715 | | #endif // GOOGLE_PROTOBUF_ARENA_H__ |