1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 // This file defines an Arena allocator for better allocation performance.
32 
33 #ifndef GOOGLE_PROTOBUF_ARENA_H__
34 #define GOOGLE_PROTOBUF_ARENA_H__
35 
36 
37 #include <limits>
38 #include <type_traits>
39 #include <utility>
40 #ifdef max
41 #undef max  // Visual Studio defines this macro
42 #endif
43 #if defined(_MSC_VER) && !defined(_LIBCPP_STD_VER) && !_HAS_EXCEPTIONS
44 // Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
45 #include <exception>
46 #include <typeinfo>
47 namespace std {
48 using type_info = ::type_info;
49 }
50 #else
51 #include <typeinfo>
52 #endif
53 
54 #include <type_traits>
55 #include <google/protobuf/arena_impl.h>
56 #include <google/protobuf/port.h>
57 
58 #include <google/protobuf/port_def.inc>
59 
60 #ifdef SWIG
61 #error "You cannot SWIG proto headers"
62 #endif
63 
64 namespace google {
65 namespace protobuf {
66 
67 struct ArenaOptions;  // defined below
68 
69 }  // namespace protobuf
70 }  // namespace google
71 
72 namespace google {
73 namespace protobuf {
74 
75 class Arena;    // defined below
76 class Message;  // defined in message.h
77 class MessageLite;
78 template <typename Key, typename T>
79 class Map;
80 
81 namespace arena_metrics {
82 
83 void EnableArenaMetrics(ArenaOptions* options);
84 
85 }  // namespace arena_metrics
86 
87 namespace internal {
88 
89 struct ArenaStringPtr;  // defined in arenastring.h
90 class LazyField;        // defined in lazy_field.h
91 class EpsCopyInputStream;  // defined in parse_context.h
92 
93 template <typename Type>
94 class GenericTypeHandler;  // defined in repeated_field.h
95 
96 // Templated cleanup methods.
97 template <typename T>
arena_destruct_object(void * object)98 void arena_destruct_object(void* object) {
99   reinterpret_cast<T*>(object)->~T();
100 }
101 template <typename T>
arena_delete_object(void * object)102 void arena_delete_object(void* object) {
103   delete reinterpret_cast<T*>(object);
104 }
arena_free(void * object,size_t size)105 inline void arena_free(void* object, size_t size) {
106 #if defined(__GXX_DELETE_WITH_SIZE__) || defined(__cpp_sized_deallocation)
107   ::operator delete(object, size);
108 #else
109   (void)size;
110   ::operator delete(object);
111 #endif
112 }
113 
114 }  // namespace internal
115 
116 // ArenaOptions provides optional additional parameters to arena construction
117 // that control its block-allocation behavior.
118 struct ArenaOptions {
119   // This defines the size of the first block requested from the system malloc.
120   // Subsequent block sizes will increase in a geometric series up to a maximum.
121   size_t start_block_size;
122 
123   // This defines the maximum block size requested from system malloc (unless an
124   // individual arena allocation request occurs with a size larger than this
125   // maximum). Requested block sizes increase up to this value, then remain
126   // here.
127   size_t max_block_size;
128 
129   // An initial block of memory for the arena to use, or NULL for none. If
130   // provided, the block must live at least as long as the arena itself. The
131   // creator of the Arena retains ownership of the block after the Arena is
132   // destroyed.
133   char* initial_block;
134 
135   // The size of the initial block, if provided.
136   size_t initial_block_size;
137 
138   // A function pointer to an alloc method that returns memory blocks of size
139   // requested. By default, it contains a ptr to the malloc function.
140   //
141   // NOTE: block_alloc and dealloc functions are expected to behave like
142   // malloc and free, including Asan poisoning.
143   void* (*block_alloc)(size_t);
144   // A function pointer to a dealloc method that takes ownership of the blocks
145   // from the arena. By default, it contains a ptr to a wrapper function that
146   // calls free.
147   void (*block_dealloc)(void*, size_t);
148 
ArenaOptionsArenaOptions149   ArenaOptions()
150       : start_block_size(kDefaultStartBlockSize),
151         max_block_size(kDefaultMaxBlockSize),
152         initial_block(NULL),
153         initial_block_size(0),
154         block_alloc(&::operator new),
155         block_dealloc(&internal::arena_free),
156         on_arena_init(NULL),
157         on_arena_reset(NULL),
158         on_arena_destruction(NULL),
159         on_arena_allocation(NULL) {}
160 
161  private:
162   // Hooks for adding external functionality such as user-specific metrics
163   // collection, specific debugging abilities, etc.
164   // Init hook (if set) will always be called at Arena init time. Init hook may
165   // return a pointer to a cookie to be stored in the arena. Reset and
166   // destruction hooks will then be called with the same cookie pointer. This
167   // allows us to save an external object per arena instance and use it on the
168   // other hooks (Note: If init hook returns NULL, the other hooks will NOT be
169   // called on this arena instance).
170   // on_arena_reset and on_arena_destruction also receive the space used in the
171   // arena just before the reset.
172   void* (*on_arena_init)(Arena* arena);
173   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
174   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
175 
176   // type_info is promised to be static - its lifetime extends to
177   // match program's lifetime (It is given by typeid operator).
178   // Note: typeid(void) will be passed as allocated_type every time we
179   // intentionally want to avoid monitoring an allocation. (i.e. internal
180   // allocations for managing the arena)
181   void (*on_arena_allocation)(const std::type_info* allocated_type,
182                               uint64 alloc_size, void* cookie);
183 
184   // Constants define default starting block size and max block size for
185   // arena allocator behavior -- see descriptions above.
186   static const size_t kDefaultStartBlockSize = 256;
187   static const size_t kDefaultMaxBlockSize = 8192;
188 
189   friend void arena_metrics::EnableArenaMetrics(ArenaOptions*);
190   friend class Arena;
191   friend class ArenaOptionsTestFriend;
192 };
193 
194 // Support for non-RTTI environments. (The metrics hooks API uses type
195 // information.)
196 #if PROTOBUF_RTTI
197 #define RTTI_TYPE_ID(type) (&typeid(type))
198 #else
199 #define RTTI_TYPE_ID(type) (NULL)
200 #endif
201 
202 // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
203 // with new/delete, and improves performance by aggregating allocations into
204 // larger blocks and freeing allocations all at once. Protocol messages are
205 // allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
206 // are automatically freed when the arena is destroyed.
207 //
208 // This is a thread-safe implementation: multiple threads may allocate from the
209 // arena concurrently. Destruction is not thread-safe and the destructing
210 // thread must synchronize with users of the arena first.
211 //
212 // An arena provides two allocation interfaces: CreateMessage<T>, which works
213 // for arena-enabled proto2 message types as well as other types that satisfy
214 // the appropriate protocol (described below), and Create<T>, which works for
215 // any arbitrary type T. CreateMessage<T> is better when the type T supports it,
216 // because this interface (i) passes the arena pointer to the created object so
217 // that its sub-objects and internal allocations can use the arena too, and (ii)
218 // elides the object's destructor call when possible. Create<T> does not place
219 // any special requirements on the type T, and will invoke the object's
220 // destructor when the arena is destroyed.
221 //
222 // The arena message allocation protocol, required by CreateMessage<T>, is as
223 // follows:
224 //
225 // - The type T must have (at least) two constructors: a constructor with no
226 //   arguments, called when a T is allocated on the heap; and a constructor with
227 //   a Arena* argument, called when a T is allocated on an arena. If the
228 //   second constructor is called with a NULL arena pointer, it must be
229 //   equivalent to invoking the first (no-argument) constructor.
230 //
231 // - The type T must have a particular type trait: a nested type
232 //   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
233 //   such type trait exists, then the instantiation CreateMessage<T> will fail
234 //   to compile.
235 //
236 // - The type T *may* have the type trait |DestructorSkippable_|. If this type
237 //   trait is present in the type, then its destructor will not be called if and
238 //   only if it was passed a non-NULL arena pointer. If this type trait is not
239 //   present on the type, then its destructor is always called when the
240 //   containing arena is destroyed.
241 //
242 // - One- and two-user-argument forms of CreateMessage<T>() also exist that
243 //   forward these constructor arguments to T's constructor: for example,
244 //   CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
245 //   arg1, arg2).
246 //
247 // This protocol is implemented by all arena-enabled proto2 message classes as
248 // well as protobuf container types like RepeatedPtrField and Map. The protocol
249 // is internal to protobuf and is not guaranteed to be stable. Non-proto types
250 // should not rely on this protocol.
251 class PROTOBUF_EXPORT alignas(8) Arena final {
252  public:
253   // Arena constructor taking custom options. See ArenaOptions below for
254   // descriptions of the options available.
Arena(const ArenaOptions & options)255   explicit Arena(const ArenaOptions& options) : impl_(options) {
256     Init(options);
257   }
258 
259   // Block overhead.  Use this as a guide for how much to over-allocate the
260   // initial block if you want an allocation of size N to fit inside it.
261   //
262   // WARNING: if you allocate multiple objects, it is difficult to guarantee
263   // that a series of allocations will fit in the initial block, especially if
264   // Arena changes its alignment guarantees in the future!
265   static const size_t kBlockOverhead = internal::ArenaImpl::kBlockHeaderSize +
266                                        internal::ArenaImpl::kSerialArenaSize;
267 
268   // Default constructor with sensible default options, tuned for average
269   // use-cases.
Arena()270   Arena() : impl_(ArenaOptions()) { Init(ArenaOptions()); }
271 
~Arena()272   ~Arena() {
273     if (hooks_cookie_) {
274       CallDestructorHooks();
275     }
276   }
277 
Init(const ArenaOptions & options)278   void Init(const ArenaOptions& options) {
279     on_arena_allocation_ = options.on_arena_allocation;
280     on_arena_reset_ = options.on_arena_reset;
281     on_arena_destruction_ = options.on_arena_destruction;
282     // Call the initialization hook
283     if (options.on_arena_init != NULL) {
284       hooks_cookie_ = options.on_arena_init(this);
285     } else {
286       hooks_cookie_ = NULL;
287     }
288   }
289 
290   // API to create proto2 message objects on the arena. If the arena passed in
291   // is NULL, then a heap allocated object is returned. Type T must be a message
292   // defined in a .proto file with cc_enable_arenas set to true, otherwise a
293   // compilation error will occur.
294   //
295   // RepeatedField and RepeatedPtrField may also be instantiated directly on an
296   // arena with this method.
297   //
298   // This function also accepts any type T that satisfies the arena message
299   // allocation protocol, documented above.
300   template <typename T, typename... Args>
CreateMessage(Arena * arena,Args &&...args)301   PROTOBUF_ALWAYS_INLINE static T* CreateMessage(Arena* arena, Args&&... args) {
302     static_assert(
303         InternalHelper<T>::is_arena_constructable::value,
304         "CreateMessage can only construct types that are ArenaConstructable");
305     // We must delegate to CreateMaybeMessage() and NOT CreateMessageInternal()
306     // because protobuf generated classes specialize CreateMaybeMessage() and we
307     // need to use that specialization for code size reasons.
308     return Arena::CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
309   }
310 
311   // API to create any objects on the arena. Note that only the object will
312   // be created on the arena; the underlying ptrs (in case of a proto2 message)
313   // will be still heap allocated. Proto messages should usually be allocated
314   // with CreateMessage<T>() instead.
315   //
316   // Note that even if T satisfies the arena message construction protocol
317   // (InternalArenaConstructable_ trait and optional DestructorSkippable_
318   // trait), as described above, this function does not follow the protocol;
319   // instead, it treats T as a black-box type, just as if it did not have these
320   // traits. Specifically, T's constructor arguments will always be only those
321   // passed to Create<T>() -- no additional arena pointer is implicitly added.
322   // Furthermore, the destructor will always be called at arena destruction time
323   // (unless the destructor is trivial). Hence, from T's point of view, it is as
324   // if the object were allocated on the heap (except that the underlying memory
325   // is obtained from the arena).
326   template <typename T, typename... Args>
Create(Arena * arena,Args &&...args)327   PROTOBUF_ALWAYS_INLINE static T* Create(Arena* arena, Args&&... args) {
328     return CreateNoMessage<T>(arena, is_arena_constructable<T>(),
329                               std::forward<Args>(args)...);
330   }
331 
332   // Create an array of object type T on the arena *without* invoking the
333   // constructor of T. If `arena` is null, then the return value should be freed
334   // with `delete[] x;` (or `::operator delete[](x);`).
335   // To ensure safe uses, this function checks at compile time
336   // (when compiled as C++11) that T is trivially default-constructible and
337   // trivially destructible.
338   template <typename T>
CreateArray(Arena * arena,size_t num_elements)339   PROTOBUF_ALWAYS_INLINE static T* CreateArray(Arena* arena,
340                                                size_t num_elements) {
341     static_assert(std::is_pod<T>::value,
342                   "CreateArray requires a trivially constructible type");
343     static_assert(std::is_trivially_destructible<T>::value,
344                   "CreateArray requires a trivially destructible type");
345     GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
346         << "Requested size is too large to fit into size_t.";
347     if (arena == NULL) {
348       return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
349     } else {
350       return arena->CreateInternalRawArray<T>(num_elements);
351     }
352   }
353 
354   // Returns the total space allocated by the arena, which is the sum of the
355   // sizes of the underlying blocks. This method is relatively fast; a counter
356   // is kept as blocks are allocated.
SpaceAllocated()357   uint64 SpaceAllocated() const { return impl_.SpaceAllocated(); }
358   // Returns the total space used by the arena. Similar to SpaceAllocated but
359   // does not include free space and block overhead. The total space returned
360   // may not include space used by other threads executing concurrently with
361   // the call to this method.
SpaceUsed()362   uint64 SpaceUsed() const { return impl_.SpaceUsed(); }
363 
364   // Frees all storage allocated by this arena after calling destructors
365   // registered with OwnDestructor() and freeing objects registered with Own().
366   // Any objects allocated on this arena are unusable after this call. It also
367   // returns the total space used by the arena which is the sums of the sizes
368   // of the allocated blocks. This method is not thread-safe.
Reset()369   PROTOBUF_NOINLINE uint64 Reset() {
370     // Call the reset hook
371     if (on_arena_reset_ != NULL) {
372       on_arena_reset_(this, hooks_cookie_, impl_.SpaceAllocated());
373     }
374     return impl_.Reset();
375   }
376 
377   // Adds |object| to a list of heap-allocated objects to be freed with |delete|
378   // when the arena is destroyed or reset.
379   template <typename T>
Own(T * object)380   PROTOBUF_NOINLINE void Own(T* object) {
381     OwnInternal(object, std::is_convertible<T*, Message*>());
382   }
383 
384   // Adds |object| to a list of objects whose destructors will be manually
385   // called when the arena is destroyed or reset. This differs from Own() in
386   // that it does not free the underlying memory with |delete|; hence, it is
387   // normally only used for objects that are placement-newed into
388   // arena-allocated memory.
389   template <typename T>
OwnDestructor(T * object)390   PROTOBUF_NOINLINE void OwnDestructor(T* object) {
391     if (object != NULL) {
392       impl_.AddCleanup(object, &internal::arena_destruct_object<T>);
393     }
394   }
395 
396   // Adds a custom member function on an object to the list of destructors that
397   // will be manually called when the arena is destroyed or reset. This differs
398   // from OwnDestructor() in that any member function may be specified, not only
399   // the class destructor.
OwnCustomDestructor(void * object,void (* destruct)(void *))400   PROTOBUF_NOINLINE void OwnCustomDestructor(void* object,
401                                              void (*destruct)(void*)) {
402     impl_.AddCleanup(object, destruct);
403   }
404 
405   // Retrieves the arena associated with |value| if |value| is an arena-capable
406   // message, or NULL otherwise. If possible, the call resolves at compile time.
407   // Note that we can often devirtualize calls to `value->GetArena()` so usually
408   // calling this method is unnecessary.
409   template <typename T>
GetArena(const T * value)410   PROTOBUF_ALWAYS_INLINE static Arena* GetArena(const T* value) {
411     return GetArenaInternal(value);
412   }
413 
414   template <typename T>
415   class InternalHelper {
416     template <typename U>
417     static char DestructorSkippable(const typename U::DestructorSkippable_*);
418     template <typename U>
419     static double DestructorSkippable(...);
420 
421     typedef std::integral_constant<
422         bool, sizeof(DestructorSkippable<T>(static_cast<const T*>(0))) ==
423                       sizeof(char) ||
424                   std::is_trivially_destructible<T>::value>
425         is_destructor_skippable;
426 
427     template <typename U>
428     static char ArenaConstructable(
429         const typename U::InternalArenaConstructable_*);
430     template <typename U>
431     static double ArenaConstructable(...);
432 
433     typedef std::integral_constant<bool, sizeof(ArenaConstructable<T>(
434                                              static_cast<const T*>(0))) ==
435                                              sizeof(char)>
436         is_arena_constructable;
437 
438     template <typename U,
439               typename std::enable_if<
440                   std::is_same<Arena*, decltype(std::declval<const U>()
441                                                     .GetArena())>::value,
442                   int>::type = 0>
443     static char HasGetArena(decltype(&U::GetArena));
444     template <typename U>
445     static double HasGetArena(...);
446 
447     typedef std::integral_constant<bool, sizeof(HasGetArena<T>(nullptr)) ==
448                                              sizeof(char)>
449         has_get_arena;
450 
451     template <typename... Args>
Construct(void * ptr,Args &&...args)452     static T* Construct(void* ptr, Args&&... args) {
453       return new (ptr) T(std::forward<Args>(args)...);
454     }
455 
GetArena(const T * p)456     static Arena* GetArena(const T* p) { return p->GetArenaNoVirtual(); }
457 
458     friend class Arena;
459   };
460 
461   // Helper typetraits that indicates support for arenas in a type T at compile
462   // time. This is public only to allow construction of higher-level templated
463   // utilities.
464   //
465   // is_arena_constructable<T>::value is true if the message type T has arena
466   // support enabled, and false otherwise.
467   //
468   // is_destructor_skippable<T>::value is true if the message type T has told
469   // the arena that it is safe to skip the destructor, and false otherwise.
470   //
471   // This is inside Arena because only Arena has the friend relationships
472   // necessary to see the underlying generated code traits.
473   template <typename T>
474   struct is_arena_constructable : InternalHelper<T>::is_arena_constructable {};
475   template <typename T>
476   struct is_destructor_skippable : InternalHelper<T>::is_destructor_skippable {
477   };
478 
479  private:
480   template <typename T>
481   struct has_get_arena : InternalHelper<T>::has_get_arena {};
482 
483   template <typename T, typename... Args>
CreateMessageInternal(Arena * arena,Args &&...args)484   PROTOBUF_ALWAYS_INLINE static T* CreateMessageInternal(Arena* arena,
485                                                          Args&&... args) {
486     static_assert(
487         InternalHelper<T>::is_arena_constructable::value,
488         "CreateMessage can only construct types that are ArenaConstructable");
489     if (arena == NULL) {
490       return new T(nullptr, std::forward<Args>(args)...);
491     } else {
492       return arena->DoCreateMessage<T>(std::forward<Args>(args)...);
493     }
494   }
495 
496   // This specialization for no arguments is necessary, because its behavior is
497   // slightly different.  When the arena pointer is nullptr, it calls T()
498   // instead of T(nullptr).
499   template <typename T>
CreateMessageInternal(Arena * arena)500   PROTOBUF_ALWAYS_INLINE static T* CreateMessageInternal(Arena* arena) {
501     static_assert(
502         InternalHelper<T>::is_arena_constructable::value,
503         "CreateMessage can only construct types that are ArenaConstructable");
504     if (arena == NULL) {
505       return new T();
506     } else {
507       return arena->DoCreateMessage<T>();
508     }
509   }
510 
511   template <typename T, typename... Args>
CreateInternal(Arena * arena,Args &&...args)512   PROTOBUF_ALWAYS_INLINE static T* CreateInternal(Arena* arena,
513                                                   Args&&... args) {
514     if (arena == NULL) {
515       return new T(std::forward<Args>(args)...);
516     } else {
517       return arena->DoCreate<T>(std::is_trivially_destructible<T>::value,
518                                 std::forward<Args>(args)...);
519     }
520   }
521 
522   void CallDestructorHooks();
523   void OnArenaAllocation(const std::type_info* allocated_type, size_t n) const;
AllocHook(const std::type_info * allocated_type,size_t n)524   inline void AllocHook(const std::type_info* allocated_type, size_t n) const {
525     if (PROTOBUF_PREDICT_FALSE(hooks_cookie_ != NULL)) {
526       OnArenaAllocation(allocated_type, n);
527     }
528   }
529 
530   // Allocate and also optionally call on_arena_allocation callback with the
531   // allocated type info when the hooks are in place in ArenaOptions and
532   // the cookie is not null.
533   template <typename T>
AllocateInternal(bool skip_explicit_ownership)534   PROTOBUF_ALWAYS_INLINE void* AllocateInternal(bool skip_explicit_ownership) {
535     const size_t n = internal::AlignUpTo8(sizeof(T));
536     AllocHook(RTTI_TYPE_ID(T), n);
537     // Monitor allocation if needed.
538     if (skip_explicit_ownership) {
539       return AllocateAlignedNoHook(n);
540     } else {
541       return impl_.AllocateAlignedAndAddCleanup(
542           n, &internal::arena_destruct_object<T>);
543     }
544   }
545 
546   // CreateMessage<T> requires that T supports arenas, but this private method
547   // works whether or not T supports arenas. These are not exposed to user code
548   // as it can cause confusing API usages, and end up having double free in
549   // user code. These are used only internally from LazyField and Repeated
550   // fields, since they are designed to work in all mode combinations.
551   template <typename Msg, typename... Args>
DoCreateMaybeMessage(Arena * arena,std::true_type,Args &&...args)552   PROTOBUF_ALWAYS_INLINE static Msg* DoCreateMaybeMessage(Arena* arena,
553                                                           std::true_type,
554                                                           Args&&... args) {
555     return CreateMessageInternal<Msg>(arena, std::forward<Args>(args)...);
556   }
557 
558   template <typename T, typename... Args>
DoCreateMaybeMessage(Arena * arena,std::false_type,Args &&...args)559   PROTOBUF_ALWAYS_INLINE static T* DoCreateMaybeMessage(Arena* arena,
560                                                         std::false_type,
561                                                         Args&&... args) {
562     return CreateInternal<T>(arena, std::forward<Args>(args)...);
563   }
564 
565   template <typename T, typename... Args>
CreateMaybeMessage(Arena * arena,Args &&...args)566   PROTOBUF_ALWAYS_INLINE static T* CreateMaybeMessage(Arena* arena,
567                                                       Args&&... args) {
568     return DoCreateMaybeMessage<T>(arena, is_arena_constructable<T>(),
569                                    std::forward<Args>(args)...);
570   }
571 
572   template <typename T, typename... Args>
CreateNoMessage(Arena * arena,std::true_type,Args &&...args)573   PROTOBUF_ALWAYS_INLINE static T* CreateNoMessage(Arena* arena, std::true_type,
574                                                    Args&&... args) {
575     // User is constructing with Create() despite the fact that T supports arena
576     // construction.  In this case we have to delegate to CreateInternal(), and
577     // we can't use any CreateMaybeMessage() specialization that may be defined.
578     return CreateInternal<T>(arena, std::forward<Args>(args)...);
579   }
580 
581   template <typename T, typename... Args>
CreateNoMessage(Arena * arena,std::false_type,Args &&...args)582   PROTOBUF_ALWAYS_INLINE static T* CreateNoMessage(Arena* arena,
583                                                    std::false_type,
584                                                    Args&&... args) {
585     // User is constructing with Create() and the type does not support arena
586     // construction.  In this case we can delegate to CreateMaybeMessage() and
587     // use any specialization that may be available for that.
588     return CreateMaybeMessage<T>(arena, std::forward<Args>(args)...);
589   }
590 
591   // Just allocate the required size for the given type assuming the
592   // type has a trivial constructor.
593   template <typename T>
CreateInternalRawArray(size_t num_elements)594   PROTOBUF_ALWAYS_INLINE T* CreateInternalRawArray(size_t num_elements) {
595     GOOGLE_CHECK_LE(num_elements, std::numeric_limits<size_t>::max() / sizeof(T))
596         << "Requested size is too large to fit into size_t.";
597     const size_t n = internal::AlignUpTo8(sizeof(T) * num_elements);
598     // Monitor allocation if needed.
599     AllocHook(RTTI_TYPE_ID(T), n);
600     return static_cast<T*>(AllocateAlignedNoHook(n));
601   }
602 
603   template <typename T, typename... Args>
DoCreate(bool skip_explicit_ownership,Args &&...args)604   PROTOBUF_ALWAYS_INLINE T* DoCreate(bool skip_explicit_ownership,
605                                      Args&&... args) {
606     return new (AllocateInternal<T>(skip_explicit_ownership))
607         T(std::forward<Args>(args)...);
608   }
609   template <typename T, typename... Args>
DoCreateMessage(Args &&...args)610   PROTOBUF_ALWAYS_INLINE T* DoCreateMessage(Args&&... args) {
611     return InternalHelper<T>::Construct(
612         AllocateInternal<T>(InternalHelper<T>::is_destructor_skippable::value),
613         this, std::forward<Args>(args)...);
614   }
615 
616   // CreateInArenaStorage is used to implement map field. Without it,
617   // Map need to call generated message's protected arena constructor,
618   // which needs to declare Map as friend of generated message.
619   template <typename T>
CreateInArenaStorage(T * ptr,Arena * arena)620   static void CreateInArenaStorage(T* ptr, Arena* arena) {
621     CreateInArenaStorageInternal(ptr, arena,
622                                  typename is_arena_constructable<T>::type());
623     RegisterDestructorInternal(
624         ptr, arena,
625         typename InternalHelper<T>::is_destructor_skippable::type());
626   }
627 
628   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena * arena,std::true_type)629   static void CreateInArenaStorageInternal(T* ptr, Arena* arena,
630                                            std::true_type) {
631     InternalHelper<T>::Construct(ptr, arena);
632   }
633   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena *,std::false_type)634   static void CreateInArenaStorageInternal(T* ptr, Arena* /* arena */,
635                                            std::false_type) {
636     new (ptr) T();
637   }
638 
639   template <typename T>
RegisterDestructorInternal(T *,Arena *,std::true_type)640   static void RegisterDestructorInternal(T* /* ptr */, Arena* /* arena */,
641                                          std::true_type) {}
642   template <typename T>
RegisterDestructorInternal(T * ptr,Arena * arena,std::false_type)643   static void RegisterDestructorInternal(T* ptr, Arena* arena,
644                                          std::false_type) {
645     arena->OwnDestructor(ptr);
646   }
647 
648   // These implement Own(), which registers an object for deletion (destructor
649   // call and operator delete()). The second parameter has type 'true_type' if T
650   // is a subtype of Message and 'false_type' otherwise. Collapsing
651   // all template instantiations to one for generic Message reduces code size,
652   // using the virtual destructor instead.
653   template <typename T>
OwnInternal(T * object,std::true_type)654   PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::true_type) {
655     if (object != NULL) {
656       impl_.AddCleanup(object, &internal::arena_delete_object<Message>);
657     }
658   }
659   template <typename T>
OwnInternal(T * object,std::false_type)660   PROTOBUF_ALWAYS_INLINE void OwnInternal(T* object, std::false_type) {
661     if (object != NULL) {
662       impl_.AddCleanup(object, &internal::arena_delete_object<T>);
663     }
664   }
665 
666   // Implementation for GetArena(). Only message objects with
667   // InternalArenaConstructable_ tags can be associated with an arena, and such
668   // objects must implement a GetArenaNoVirtual() method.
669   template <typename T, typename std::enable_if<
670                             is_arena_constructable<T>::value, int>::type = 0>
GetArenaInternal(const T * value)671   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
672     return InternalHelper<T>::GetArena(value);
673   }
674   template <typename T,
675             typename std::enable_if<!is_arena_constructable<T>::value &&
676                                         has_get_arena<T>::value,
677                                     int>::type = 0>
GetArenaInternal(const T * value)678   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
679     return value->GetArena();
680   }
681   template <typename T,
682             typename std::enable_if<!is_arena_constructable<T>::value &&
683                                         !has_get_arena<T>::value,
684                                     int>::type = 0>
GetArenaInternal(const T * value)685   PROTOBUF_ALWAYS_INLINE static Arena* GetArenaInternal(const T* value) {
686     (void)value;
687     return nullptr;
688   }
689 
690   // For friends of arena.
AllocateAligned(size_t n)691   void* AllocateAligned(size_t n) {
692     AllocHook(NULL, n);
693     return AllocateAlignedNoHook(internal::AlignUpTo8(n));
694   }
695 
696   void* AllocateAlignedNoHook(size_t n);
697 
698   internal::ArenaImpl impl_;
699 
700   void (*on_arena_allocation_)(const std::type_info* allocated_type,
701                                uint64 alloc_size, void* cookie);
702   void (*on_arena_reset_)(Arena* arena, void* cookie, uint64 space_used);
703   void (*on_arena_destruction_)(Arena* arena, void* cookie, uint64 space_used);
704 
705   // The arena may save a cookie it receives from the external on_init hook
706   // and then use it when calling the on_reset and on_destruction hooks.
707   void* hooks_cookie_;
708 
709   template <typename Type>
710   friend class internal::GenericTypeHandler;
711   friend struct internal::ArenaStringPtr;  // For AllocateAligned.
712   friend class internal::LazyField;        // For CreateMaybeMessage.
713   friend class internal::EpsCopyInputStream;  // For parser performance
714   friend class MessageLite;
715   template <typename Key, typename T>
716   friend class Map;
717 };
718 
719 // Defined above for supporting environments without RTTI.
720 #undef RTTI_TYPE_ID
721 
722 }  // namespace protobuf
723 }  // namespace google
724 
725 #include <google/protobuf/port_undef.inc>
726 
727 #endif  // GOOGLE_PROTOBUF_ARENA_H__
728