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 #ifndef GOOGLE_PROTOBUF_ARENA_H__
32 #define GOOGLE_PROTOBUF_ARENA_H__
33 
34 #include <limits>
35 #ifdef max
36 #undef max  // Visual Studio defines this macro
37 #endif
38 #if __cplusplus >= 201103L
39 #include <google/protobuf/stubs/type_traits.h>
40 #endif
41 #if defined(_MSC_VER) && !_HAS_EXCEPTIONS
42 // Work around bugs in MSVC <typeinfo> header when _HAS_EXCEPTIONS=0.
43 #include <exception>
44 #include <typeinfo>
45 namespace std {
46 using type_info = ::type_info;
47 }
48 #else
49 #include <typeinfo>
50 #endif
51 
52 #include <google/protobuf/stubs/atomic_sequence_num.h>
53 #include <google/protobuf/stubs/atomicops.h>
54 #include <google/protobuf/stubs/common.h>
55 #include <google/protobuf/stubs/logging.h>
56 #include <google/protobuf/stubs/mutex.h>
57 #include <google/protobuf/stubs/type_traits.h>
58 
59 
60 namespace google {
61 namespace protobuf {
62 
63 class Arena;       // defined below
64 class Message;     // message.h
65 
66 namespace internal {
67 class ArenaString; // arenastring.h
68 class LazyField;   // lazy_field.h
69 
70 template<typename Type>
71 class GenericTypeHandler; // repeated_field.h
72 
73 // Templated cleanup methods.
arena_destruct_object(void * object)74 template<typename T> void arena_destruct_object(void* object) {
75   reinterpret_cast<T*>(object)->~T();
76 }
arena_delete_object(void * object)77 template<typename T> void arena_delete_object(void* object) {
78   delete reinterpret_cast<T*>(object);
79 }
arena_free(void * object,size_t)80 inline void arena_free(void* object, size_t /* size */) {
81   free(object);
82 }
83 
84 }  // namespace internal
85 
86 // ArenaOptions provides optional additional parameters to arena construction
87 // that control its block-allocation behavior.
88 struct ArenaOptions {
89   // This defines the size of the first block requested from the system malloc.
90   // Subsequent block sizes will increase in a geometric series up to a maximum.
91   size_t start_block_size;
92 
93   // This defines the maximum block size requested from system malloc (unless an
94   // individual arena allocation request occurs with a size larger than this
95   // maximum). Requested block sizes increase up to this value, then remain
96   // here.
97   size_t max_block_size;
98 
99   // An initial block of memory for the arena to use, or NULL for none. If
100   // provided, the block must live at least as long as the arena itself. The
101   // creator of the Arena retains ownership of the block after the Arena is
102   // destroyed.
103   char* initial_block;
104 
105   // The size of the initial block, if provided.
106   size_t initial_block_size;
107 
108   // A function pointer to an alloc method that returns memory blocks of size
109   // requested. By default, it contains a ptr to the malloc function.
110   //
111   // NOTE: block_alloc and dealloc functions are expected to behave like
112   // malloc and free, including Asan poisoning.
113   void* (*block_alloc)(size_t);
114   // A function pointer to a dealloc method that takes ownership of the blocks
115   // from the arena. By default, it contains a ptr to a wrapper function that
116   // calls free.
117   void (*block_dealloc)(void*, size_t);
118 
119   // Hooks for adding external functionality such as user-specific metrics
120   // collection, specific debugging abilities, etc.
121   // Init hook may return a pointer to a cookie to be stored in the arena.
122   // reset and destruction hooks will then be called with the same cookie
123   // pointer. This allows us to save an external object per arena instance and
124   // use it on the other hooks (Note: It is just as legal for init to return
125   // NULL and not use the cookie feature).
126   // on_arena_reset and on_arena_destruction also receive the space used in
127   // the arena just before the reset.
128   void* (*on_arena_init)(Arena* arena);
129   void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
130   void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
131 
132   // type_info is promised to be static - its lifetime extends to
133   // match program's lifetime (It is given by typeid operator).
134   // Note: typeid(void) will be passed as allocated_type every time we
135   // intentionally want to avoid monitoring an allocation. (i.e. internal
136   // allocations for managing the arena)
137   void (*on_arena_allocation)(const std::type_info* allocated_type,
138       uint64 alloc_size, void* cookie);
139 
ArenaOptionsArenaOptions140   ArenaOptions()
141       : start_block_size(kDefaultStartBlockSize),
142         max_block_size(kDefaultMaxBlockSize),
143         initial_block(NULL),
144         initial_block_size(0),
145         block_alloc(&malloc),
146         block_dealloc(&internal::arena_free),
147         on_arena_init(NULL),
148         on_arena_reset(NULL),
149         on_arena_destruction(NULL),
150         on_arena_allocation(NULL) {}
151 
152  private:
153   // Constants define default starting block size and max block size for
154   // arena allocator behavior -- see descriptions above.
155   static const size_t kDefaultStartBlockSize = 256;
156   static const size_t kDefaultMaxBlockSize   = 8192;
157 };
158 
159 // Support for non-RTTI environments. (The metrics hooks API uses type
160 // information.)
161 #if !defined(GOOGLE_PROTOBUF_NO_RTTI) && defined(__GXX_RTTI)
162 #define RTTI_TYPE_ID(type) (&typeid(type))
163 #else
164 #define RTTI_TYPE_ID(type) (NULL)
165 #endif
166 
167 // Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
168 // with new/delete, and improves performance by aggregating allocations into
169 // larger blocks and freeing allocations all at once. Protocol messages are
170 // allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
171 // are automatically freed when the arena is destroyed.
172 //
173 // This is a thread-safe implementation: multiple threads may allocate from the
174 // arena concurrently. Destruction is not thread-safe and the destructing
175 // thread must synchronize with users of the arena first.
176 //
177 // An arena provides two allocation interfaces: CreateMessage<T>, which works
178 // for arena-enabled proto2 message types as well as other types that satisfy
179 // the appropriate protocol (described below), and Create<T>, which works for
180 // any arbitrary type T. CreateMessage<T> is better when the type T supports it,
181 // because this interface (i) passes the arena pointer to the created object so
182 // that its sub-objects and internal allocations can use the arena too, and (ii)
183 // elides the object's destructor call when possible. Create<T> does not place
184 // any special requirements on the type T, and will invoke the object's
185 // destructor when the arena is destroyed.
186 //
187 // The arena message allocation protocol, required by CreateMessage<T>, is as
188 // follows:
189 //
190 // - The type T must have (at least) two constructors: a constructor with no
191 //   arguments, called when a T is allocated on the heap; and a constructor with
192 //   a google::protobuf::Arena* argument, called when a T is allocated on an arena. If the
193 //   second constructor is called with a NULL arena pointer, it must be
194 //   equivalent to invoking the first (no-argument) constructor.
195 //
196 // - The type T must have a particular type trait: a nested type
197 //   |InternalArenaConstructable_|. This is usually a typedef to |void|. If no
198 //   such type trait exists, then the instantiation CreateMessage<T> will fail
199 //   to compile.
200 //
201 // - The type T *may* have the type trait |DestructorSkippable_|. If this type
202 //   trait is present in the type, then its destructor will not be called if and
203 //   only if it was passed a non-NULL arena pointer. If this type trait is not
204 //   present on the type, then its destructor is always called when the
205 //   containing arena is destroyed.
206 //
207 // - One- and two-user-argument forms of CreateMessage<T>() also exist that
208 //   forward these constructor arguments to T's constructor: for example,
209 //   CreateMessage<T>(Arena*, arg1, arg2) forwards to a constructor T(Arena*,
210 //   arg1, arg2).
211 //
212 // This protocol is implemented by all arena-enabled proto2 message classes as
213 // well as RepeatedPtrField.
214 
215 #if __cplusplus >= 201103L
216 class Arena final {
217 #else
218 class LIBPROTOBUF_EXPORT Arena {
219 #endif
220  public:
221   // Arena constructor taking custom options. See ArenaOptions below for
222   // descriptions of the options available.
Arena(const ArenaOptions & options)223   explicit Arena(const ArenaOptions& options) : options_(options) {
224     Init();
225   }
226 
227   // Default constructor with sensible default options, tuned for average
228   // use-cases.
Arena()229   Arena() {
230     Init();
231   }
232 
233   // Destructor deletes all owned heap allocated objects, and destructs objects
234   // that have non-trivial destructors, except for proto2 message objects whose
235   // destructors can be skipped. Also, frees all blocks except the initial block
236   // if it was passed in.
237   ~Arena();
238 
239   // API to create proto2 message objects on the arena. If the arena passed in
240   // is NULL, then a heap allocated object is returned. Type T must be a message
241   // defined in a .proto file with cc_enable_arenas set to true, otherwise a
242   // compilation error will occur.
243   //
244   // RepeatedField and RepeatedPtrField may also be instantiated directly on an
245   // arena with this method.
246   //
247   // This function also accepts any type T that satisfies the arena message
248   // allocation protocol, documented above.
249   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessage(::google::protobuf::Arena * arena)250   static T* CreateMessage(::google::protobuf::Arena* arena) {
251     if (arena == NULL) {
252       return new T;
253     } else {
254       return arena->CreateMessageInternal<T>(static_cast<T*>(0));
255     }
256   }
257 
258   // One-argument form of CreateMessage. This is useful for constructing objects
259   // that implement the arena message construction protocol described above but
260   // take additional constructor arguments.
261   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessage(::google::protobuf::Arena * arena,const Arg & arg)262   static T* CreateMessage(::google::protobuf::Arena* arena, const Arg& arg) {
263     if (arena == NULL) {
264       return new T(NULL, arg);
265     } else {
266       return arena->CreateMessageInternal<T>(static_cast<T*>(0),
267                                              arg);
268     }
269   }
270 
271   // Two-argument form of CreateMessage. This is useful for constructing objects
272   // that implement the arena message construction protocol described above but
273   // take additional constructor arguments.
274   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessage(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2)275   static T* CreateMessage(::google::protobuf::Arena* arena,
276                           const Arg1& arg1,
277                           const Arg2& arg2) {
278     if (arena == NULL) {
279       return new T(NULL, arg1, arg2);
280     } else {
281       return arena->CreateMessageInternal<T>(static_cast<T*>(0),
282                                              arg1, arg2);
283     }
284   }
285 
286   // API to create any objects on the arena. Note that only the object will
287   // be created on the arena; the underlying ptrs (in case of a proto2 message)
288   // will be still heap allocated. Proto messages should usually be allocated
289   // with CreateMessage<T>() instead.
290   //
291   // Note that even if T satisfies the arena message construction protocol
292   // (InternalArenaConstructable_ trait and optional DestructorSkippable_
293   // trait), as described above, this function does not follow the protocol;
294   // instead, it treats T as a black-box type, just as if it did not have these
295   // traits. Specifically, T's constructor arguments will always be only those
296   // passed to Create<T>() -- no additional arena pointer is implicitly added.
297   // Furthermore, the destructor will always be called at arena destruction time
298   // (unless the destructor is trivial). Hence, from T's point of view, it is as
299   // if the object were allocated on the heap (except that the underlying memory
300   // is obtained from the arena).
301   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Create(::google::protobuf::Arena * arena)302   static T* Create(::google::protobuf::Arena* arena) {
303     if (arena == NULL) {
304       return new T();
305     } else {
306       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value);
307     }
308   }
309 
310   // Version of the above with one constructor argument for the created object.
311   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Create(::google::protobuf::Arena * arena,const Arg & arg)312   static T* Create(::google::protobuf::Arena* arena, const Arg& arg) {
313     if (arena == NULL) {
314       return new T(arg);
315     } else {
316       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
317                                       arg);
318     }
319   }
320 
321   // Version of the above with two constructor arguments for the created object.
322   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2)323   static T* Create(::google::protobuf::Arena* arena, const Arg1& arg1, const Arg2& arg2) {
324     if (arena == NULL) {
325       return new T(arg1, arg2);
326     } else {
327       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
328                                       arg1, arg2);
329     }
330   }
331 
332   // Version of the above with three constructor arguments for the created
333   // object.
334   template <typename T, typename Arg1, typename Arg2, typename Arg3>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3)335   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
336                                            const Arg1& arg1, const Arg2& arg2,
337                                            const Arg3& arg3) {
338     if (arena == NULL) {
339       return new T(arg1, arg2, arg3);
340     } else {
341       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
342                                       arg1, arg2, arg3);
343     }
344   }
345 
346   // Version of the above with four constructor arguments for the created
347   // object.
348   template <typename T, typename Arg1, typename Arg2, typename Arg3,
349             typename Arg4>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4)350   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
351                                            const Arg1& arg1, const Arg2& arg2,
352                                            const Arg3& arg3, const Arg4& arg4) {
353     if (arena == NULL) {
354       return new T(arg1, arg2, arg3, arg4);
355     } else {
356       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
357                                       arg1, arg2, arg3, arg4);
358     }
359   }
360 
361   // Version of the above with five constructor arguments for the created
362   // object.
363   template <typename T, typename Arg1, typename Arg2, typename Arg3,
364             typename Arg4, typename Arg5>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5)365   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
366                                            const Arg1& arg1, const Arg2& arg2,
367                                            const Arg3& arg3, const Arg4& arg4,
368                                            const Arg5& arg5) {
369     if (arena == NULL) {
370       return new T(arg1, arg2, arg3, arg4, arg5);
371     } else {
372       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
373                                       arg1, arg2, arg3, arg4, arg5);
374     }
375   }
376 
377   // Version of the above with six constructor arguments for the created
378   // object.
379   template <typename T, typename Arg1, typename Arg2, typename Arg3,
380             typename Arg4, typename Arg5, typename Arg6>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6)381   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
382                                            const Arg1& arg1, const Arg2& arg2,
383                                            const Arg3& arg3, const Arg4& arg4,
384                                            const Arg5& arg5, const Arg6& arg6) {
385     if (arena == NULL) {
386       return new T(arg1, arg2, arg3, arg4, arg5, arg6);
387     } else {
388       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
389                                       arg1, arg2, arg3, arg4, arg5, arg6);
390     }
391   }
392 
393   // Version of the above with seven constructor arguments for the created
394   // object.
395   template <typename T, typename Arg1, typename Arg2, typename Arg3,
396             typename Arg4, typename Arg5, typename Arg6, typename Arg7>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6,const Arg7 & arg7)397   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
398                                            const Arg1& arg1, const Arg2& arg2,
399                                            const Arg3& arg3, const Arg4& arg4,
400                                            const Arg5& arg5, const Arg6& arg6,
401                                            const Arg7& arg7) {
402     if (arena == NULL) {
403       return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
404     } else {
405       return arena->CreateInternal<T>(google::protobuf::internal::has_trivial_destructor<T>::value,
406                                       arg1, arg2, arg3, arg4, arg5, arg6, arg7);
407     }
408   }
409 
410   // Version of the above with eight constructor arguments for the created
411   // object.
412   template <typename T, typename Arg1, typename Arg2, typename Arg3,
413             typename Arg4, typename Arg5, typename Arg6, typename Arg7,
414             typename Arg8>
Create(::google::protobuf::Arena * arena,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6,const Arg7 & arg7,const Arg8 & arg8)415   GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
416                                            const Arg1& arg1, const Arg2& arg2,
417                                            const Arg3& arg3, const Arg4& arg4,
418                                            const Arg5& arg5, const Arg6& arg6,
419                                            const Arg7& arg7, const Arg8& arg8) {
420     if (arena == NULL) {
421       return new T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
422     } else {
423       return arena->CreateInternal<T>(
424           google::protobuf::internal::has_trivial_destructor<T>::value,
425           arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
426     }
427   }
428 
429   // Create an array of object type T on the arena *without* invoking the
430   // constructor of T. If `arena` is null, then the return value should be freed
431   // with `delete[] x;` (or `::operator delete[](x);`).
432   // To ensure safe uses, this function checks at compile time
433   // (when compiled as C++11) that T is trivially default-constructible and
434   // trivially destructible.
435   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateArray(::google::protobuf::Arena * arena,size_t num_elements)436   static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
437     GOOGLE_CHECK_LE(num_elements,
438              std::numeric_limits<size_t>::max() / sizeof(T))
439         << "Requested size is too large to fit into size_t.";
440     if (arena == NULL) {
441       return static_cast<T*>(::operator new[](num_elements * sizeof(T)));
442     } else {
443       return arena->CreateInternalRawArray<T>(num_elements);
444     }
445   }
446 
447   // Returns the total space used by the arena, which is the sums of the sizes
448   // of the underlying blocks. The total space used may not include the new
449   // blocks that are allocated by this arena from other threads concurrently
450   // with the call to this method.
451   GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceAllocated() const;
452   // As above, but does not include any free space in underlying blocks.
453   GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() const;
454 
455   // Combines SpaceAllocated and SpaceUsed. Returns a pair of
456   // <space_allocated, space_used>.
457   GOOGLE_ATTRIBUTE_NOINLINE pair<uint64, uint64> SpaceAllocatedAndUsed() const;
458 
459   // Frees all storage allocated by this arena after calling destructors
460   // registered with OwnDestructor() and freeing objects registered with Own().
461   // Any objects allocated on this arena are unusable after this call. It also
462   // returns the total space used by the arena which is the sums of the sizes
463   // of the allocated blocks. This method is not thread-safe.
464   GOOGLE_ATTRIBUTE_NOINLINE uint64 Reset();
465 
466   // Adds |object| to a list of heap-allocated objects to be freed with |delete|
467   // when the arena is destroyed or reset.
468   template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
Own(T * object)469   void Own(T* object) {
470     OwnInternal(object, google::protobuf::internal::is_convertible<T*, ::google::protobuf::Message*>());
471   }
472 
473   // Adds |object| to a list of objects whose destructors will be manually
474   // called when the arena is destroyed or reset. This differs from Own() in
475   // that it does not free the underlying memory with |delete|; hence, it is
476   // normally only used for objects that are placement-newed into
477   // arena-allocated memory.
478   template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
OwnDestructor(T * object)479   void OwnDestructor(T* object) {
480     if (object != NULL) {
481       AddListNode(object, &internal::arena_destruct_object<T>);
482     }
483   }
484 
485   // Adds a custom member function on an object to the list of destructors that
486   // will be manually called when the arena is destroyed or reset. This differs
487   // from OwnDestructor() in that any member function may be specified, not only
488   // the class destructor.
OwnCustomDestructor(void * object,void (* destruct)(void *))489   GOOGLE_ATTRIBUTE_NOINLINE void OwnCustomDestructor(void* object,
490                                               void (*destruct)(void*)) {
491     AddListNode(object, destruct);
492   }
493 
494   // Retrieves the arena associated with |value| if |value| is an arena-capable
495   // message, or NULL otherwise. This differs from value->GetArena() in that the
496   // latter is a virtual call, while this method is a templated call that
497   // resolves at compile-time.
498   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
GetArena(const T * value)499   static ::google::protobuf::Arena* GetArena(const T* value) {
500     return GetArenaInternal(value, static_cast<T*>(0));
501   }
502 
503  private:
504   struct InternalIsArenaConstructableHelper {
505     template<typename U>
506     static char ArenaConstructable(
507         const typename U::InternalArenaConstructable_*);
508     template<typename U>
509     static double ArenaConstructable(...);
510   };
511 
512  public:
513   // Helper typetrait that indicates support for arenas in a type T at compile
514   // time. This is public only to allow construction of higher-level templated
515   // utilities. is_arena_constructable<T>::value is true if the message type T
516   // has arena support enabled, and false otherwise.
517   //
518   // This is inside Arena because only Arena has the friend relationships
519   // necessary to see the underlying generated code traits.
520   template <typename T>
521   struct is_arena_constructable
522       : public google::protobuf::internal::integral_constant<
523             bool, sizeof(InternalIsArenaConstructableHelper::ArenaConstructable<
524                          const T>(static_cast<const T*>(0))) == sizeof(char)> {
525   };
526 
527  private:
528   // Blocks are variable length malloc-ed objects.  The following structure
529   // describes the common header for all blocks.
530   struct Block {
531     void* owner;   // &ThreadCache of thread that owns this block, or
532                    // &this->owner if not yet owned by a thread.
533     Block* next;   // Next block in arena (may have different owner)
534     // ((char*) &block) + pos is next available byte. It is always
535     // aligned at a multiple of 8 bytes.
536     size_t pos;
537     size_t size;  // total size of the block.
availBlock538     GOOGLE_ATTRIBUTE_ALWAYS_INLINE size_t avail() const { return size - pos; }
539     // data follows
540   };
541 
542   template<typename Type> friend class ::google::protobuf::internal::GenericTypeHandler;
543   friend class MockArena;              // For unit-testing.
544   friend class internal::ArenaString;  // For AllocateAligned.
545   friend class internal::LazyField;    // For CreateMaybeMessage.
546 
547   struct ThreadCache {
548     // The ThreadCache is considered valid as long as this matches the
549     // lifecycle_id of the arena being used.
550     int64 last_lifecycle_id_seen;
551     Block* last_block_used_;
552   };
553 
554   static const size_t kHeaderSize = sizeof(Block);
555   static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
556 #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL)
557   // Android ndk does not support GOOGLE_THREAD_LOCAL keyword so we use a custom thread
558   // local storage class we implemented.
559   // iOS also does not support the GOOGLE_THREAD_LOCAL keyword.
560   static ThreadCache& thread_cache();
561 #elif defined(PROTOBUF_USE_DLLS)
562   // Thread local variables cannot be exposed through DLL interface but we can
563   // wrap them in static functions.
564   static ThreadCache& thread_cache();
565 #else
566   static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_;
thread_cache()567   static ThreadCache& thread_cache() { return thread_cache_; }
568 #endif
569 
570   // SFINAE for skipping addition to delete list for a message type when created
571   // with CreateMessage. This is mainly to skip proto2/proto1 message objects
572   // with cc_enable_arenas=true from being part of the delete list. Also, note,
573   // compiler will optimize out the branch in CreateInternal<T>.
574   template<typename T>
SkipDeleteList(typename T::DestructorSkippable_ *)575   static inline bool SkipDeleteList(typename T::DestructorSkippable_*) {
576     return true;
577   }
578 
579   // For message objects that don't have the DestructorSkippable_ trait, we
580   // always add to the delete list.
581   template<typename T>
SkipDeleteList(...)582   static inline bool SkipDeleteList(...) {
583     return google::protobuf::internal::has_trivial_destructor<T>::value;
584   }
585 
586  private:
587   struct InternalIsDestructorSkippableHelper {
588     template<typename U>
589     static char DestructorSkippable(
590         const typename U::DestructorSkippable_*);
591     template<typename U>
592     static double DestructorSkippable(...);
593   };
594 
595  public:
596   // Helper typetrait that indicates whether the desctructor of type T should be
597   // called when arena is destroyed at compile time. This is only to allow
598   // construction of higher-level templated utilities.
599   // is_destructor_skippable<T>::value is true if the destructor of the message
600   // type T should not be called when arena is destroyed or false otherwise.
601   // This is inside Arena because only Arena has the friend relationships
602   // necessary to see the underlying generated code traits.
603   template<typename T>
604   struct is_destructor_skippable
605       : public google::protobuf::internal::integral_constant<
606             bool,
607             sizeof(InternalIsDestructorSkippableHelper::DestructorSkippable<
608                    const T>(static_cast<const T*>(0))) == sizeof(char) ||
609                 google::protobuf::internal::has_trivial_destructor<T>::value> {};
610 
611   // CreateMessage<T> requires that T supports arenas, but this private method
612   // works whether or not T supports arenas. These are not exposed to user code
613   // as it can cause confusing API usages, and end up having double free in
614   // user code. These are used only internally from LazyField and Repeated
615   // fields, since they are designed to work in all mode combinations.
616   template<typename Msg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMaybeMessage(Arena * arena,typename Msg::InternalArenaConstructable_ *)617   static Msg* CreateMaybeMessage(
618       Arena* arena, typename Msg::InternalArenaConstructable_*) {
619     return CreateMessage<Msg>(arena);
620   }
621 
622   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMaybeMessage(Arena * arena,...)623   static T* CreateMaybeMessage(Arena* arena, ...) {
624     return Create<T>(arena);
625   }
626 
627   // Just allocate the required size for the given type assuming the
628   // type has a trivial constructor.
629   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateInternalRawArray(size_t num_elements)630   T* CreateInternalRawArray(size_t num_elements) {
631     GOOGLE_CHECK_LE(num_elements,
632              std::numeric_limits<size_t>::max() / sizeof(T))
633         << "Requested size is too large to fit into size_t.";
634     return static_cast<T*>(
635         AllocateAligned(RTTI_TYPE_ID(T), sizeof(T) * num_elements));
636   }
637 
638   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateInternal(bool skip_explicit_ownership)639   T* CreateInternal(bool skip_explicit_ownership) {
640     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T();
641     if (!skip_explicit_ownership) {
642       AddListNode(t, &internal::arena_destruct_object<T>);
643     }
644     return t;
645   }
646 
647   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateInternal(bool skip_explicit_ownership,const Arg & arg)648   T* CreateInternal(bool skip_explicit_ownership, const Arg& arg) {
649     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg);
650     if (!skip_explicit_ownership) {
651       AddListNode(t, &internal::arena_destruct_object<T>);
652     }
653     return t;
654   }
655 
656   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2)657   T* CreateInternal(
658       bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
659     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T))) T(arg1, arg2);
660     if (!skip_explicit_ownership) {
661       AddListNode(t, &internal::arena_destruct_object<T>);
662     }
663     return t;
664   }
665 
666   template <typename T, typename Arg1, typename Arg2, typename Arg3>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3)667   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
668                                             const Arg1& arg1,
669                                             const Arg2& arg2,
670                                             const Arg3& arg3) {
671     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
672         T(arg1, arg2, arg3);
673     if (!skip_explicit_ownership) {
674       AddListNode(t, &internal::arena_destruct_object<T>);
675     }
676     return t;
677   }
678 
679   template <typename T, typename Arg1, typename Arg2, typename Arg3,
680             typename Arg4>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4)681   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
682                                             const Arg1& arg1,
683                                             const Arg2& arg2,
684                                             const Arg3& arg3,
685                                             const Arg4& arg4) {
686     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
687         T(arg1, arg2, arg3, arg4);
688     if (!skip_explicit_ownership) {
689       AddListNode(t, &internal::arena_destruct_object<T>);
690     }
691     return t;
692   }
693 
694   template <typename T, typename Arg1, typename Arg2, typename Arg3,
695             typename Arg4, typename Arg5>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5)696   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
697                                             const Arg1& arg1,
698                                             const Arg2& arg2,
699                                             const Arg3& arg3,
700                                             const Arg4& arg4,
701                                             const Arg5& arg5) {
702     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
703         T(arg1, arg2, arg3, arg4, arg5);
704     if (!skip_explicit_ownership) {
705       AddListNode(t, &internal::arena_destruct_object<T>);
706     }
707     return t;
708   }
709 
710   template <typename T, typename Arg1, typename Arg2, typename Arg3,
711             typename Arg4, typename Arg5, typename Arg6>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6)712   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
713                                             const Arg1& arg1,
714                                             const Arg2& arg2,
715                                             const Arg3& arg3,
716                                             const Arg4& arg4,
717                                             const Arg5& arg5,
718                                             const Arg6& arg6) {
719     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
720         T(arg1, arg2, arg3, arg4, arg5, arg6);
721     if (!skip_explicit_ownership) {
722       AddListNode(t, &internal::arena_destruct_object<T>);
723     }
724     return t;
725   }
726 
727   template <typename T, typename Arg1, typename Arg2, typename Arg3,
728             typename Arg4, typename Arg5, typename Arg6, typename Arg7>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6,const Arg7 & arg7)729   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
730                                             const Arg1& arg1,
731                                             const Arg2& arg2,
732                                             const Arg3& arg3,
733                                             const Arg4& arg4,
734                                             const Arg5& arg5,
735                                             const Arg6& arg6,
736                                             const Arg7& arg7) {
737     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
738         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
739     if (!skip_explicit_ownership) {
740       AddListNode(t, &internal::arena_destruct_object<T>);
741     }
742     return t;
743   }
744 
745   template <typename T, typename Arg1, typename Arg2, typename Arg3,
746             typename Arg4, typename Arg5, typename Arg6, typename Arg7,
747             typename Arg8>
CreateInternal(bool skip_explicit_ownership,const Arg1 & arg1,const Arg2 & arg2,const Arg3 & arg3,const Arg4 & arg4,const Arg5 & arg5,const Arg6 & arg6,const Arg7 & arg7,const Arg8 & arg8)748   GOOGLE_ATTRIBUTE_ALWAYS_INLINE T* CreateInternal(bool skip_explicit_ownership,
749                                             const Arg1& arg1,
750                                             const Arg2& arg2,
751                                             const Arg3& arg3,
752                                             const Arg4& arg4,
753                                             const Arg5& arg5,
754                                             const Arg6& arg6,
755                                             const Arg7& arg7,
756                                             const Arg8& arg8) {
757     T* t = new (AllocateAligned(RTTI_TYPE_ID(T), sizeof(T)))
758         T(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
759     if (!skip_explicit_ownership) {
760       AddListNode(t, &internal::arena_destruct_object<T>);
761     }
762     return t;
763   }
764 
765   template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessageInternal(typename T::InternalArenaConstructable_ *)766   T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
767     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
768                                      this);
769   }
770 
771   template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessageInternal(typename T::InternalArenaConstructable_ *,const Arg & arg)772   T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
773                            const Arg& arg) {
774     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
775                                      this, arg);
776   }
777 
778   template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
CreateMessageInternal(typename T::InternalArenaConstructable_ *,const Arg1 & arg1,const Arg2 & arg2)779   T* CreateMessageInternal(typename T::InternalArenaConstructable_*,
780                            const Arg1& arg1, const Arg2& arg2) {
781     return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
782                                      this, arg1, arg2);
783   }
784 
785   // CreateInArenaStorage is used to implement map field. Without it,
786   // google::protobuf::Map need to call generated message's protected arena constructor,
787   // which needs to declare google::protobuf::Map as friend of generated message.
788   template <typename T>
CreateInArenaStorage(T * ptr,Arena * arena)789   static void CreateInArenaStorage(T* ptr, Arena* arena) {
790     CreateInArenaStorageInternal(ptr, arena,
791                                  typename is_arena_constructable<T>::type());
792     RegisterDestructorInternal(ptr, arena,
793                                typename is_destructor_skippable<T>::type());
794   }
795 
796   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena * arena,google::protobuf::internal::true_type)797   static void CreateInArenaStorageInternal(
798       T* ptr, Arena* arena, google::protobuf::internal::true_type) {
799     new (ptr) T(arena);
800   }
801   template <typename T>
CreateInArenaStorageInternal(T * ptr,Arena *,google::protobuf::internal::false_type)802   static void CreateInArenaStorageInternal(
803       T* ptr, Arena*, google::protobuf::internal::false_type) {
804     new (ptr) T;
805   }
806 
807   template <typename T>
RegisterDestructorInternal(T *,Arena *,google::protobuf::internal::true_type)808   static void RegisterDestructorInternal(
809       T*, Arena*, google::protobuf::internal::true_type) {}
810   template <typename T>
RegisterDestructorInternal(T * ptr,Arena * arena,google::protobuf::internal::false_type)811   static void RegisterDestructorInternal(
812       T* ptr, Arena* arena, google::protobuf::internal::false_type) {
813     arena->OwnDestructor(ptr);
814   }
815 
816   // These implement Own(), which registers an object for deletion (destructor
817   // call and operator delete()). The second parameter has type 'true_type' if T
818   // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
819   // all template instantiations to one for generic Message reduces code size,
820   // using the virtual destructor instead.
821   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
OwnInternal(T * object,google::protobuf::internal::true_type)822   void OwnInternal(T* object, google::protobuf::internal::true_type) {
823     if (object != NULL) {
824       AddListNode(object, &internal::arena_delete_object< ::google::protobuf::Message >);
825     }
826   }
827   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
OwnInternal(T * object,google::protobuf::internal::false_type)828   void OwnInternal(T* object, google::protobuf::internal::false_type) {
829     if (object != NULL) {
830       AddListNode(object, &internal::arena_delete_object<T>);
831     }
832   }
833 
834   // Implementation for GetArena(). Only message objects with
835   // InternalArenaConstructable_ tags can be associated with an arena, and such
836   // objects must implement a GetArenaNoVirtual() method.
837   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
GetArenaInternal(const T * value,typename T::InternalArenaConstructable_ *)838   static ::google::protobuf::Arena* GetArenaInternal(
839       const T* value, typename T::InternalArenaConstructable_*) {
840     return value->GetArenaNoVirtual();
841   }
842 
843   template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
GetArenaInternal(const T *,...)844   static ::google::protobuf::Arena* GetArenaInternal(const T*, ...) {
845     return NULL;
846   }
847 
848   // Allocate and also optionally call on_arena_allocation callback with the
849   // allocated type info when the hooks are in place in ArenaOptions and
850   // the cookie is not null.
851   void* AllocateAligned(const std::type_info* allocated, size_t n);
852 
853   // Allocate an internal allocation, avoiding optional typed monitoring.
AllocateAligned(size_t n)854   GOOGLE_ATTRIBUTE_ALWAYS_INLINE void* AllocateAligned(size_t n) {
855     return AllocateAligned(NULL, n);
856   }
857 
858   void Init();
859 
860   // Free all blocks and return the total space used which is the sums of sizes
861   // of the all the allocated blocks.
862   uint64 FreeBlocks();
863 
864   // Add object pointer and cleanup function pointer to the list.
865   // TODO(rohananil, cfallin): We could pass in a sub-arena into this method
866   // to avoid polluting blocks of this arena with list nodes. This would help in
867   // mixed mode (where many protobufs have cc_enable_arenas=false), and is an
868   // alternative to a chunked linked-list, but with extra overhead of *next.
869   void AddListNode(void* elem, void (*cleanup)(void*));
870   // Delete or Destruct all objects owned by the arena.
871   void CleanupList();
872   uint64 ResetInternal();
873 
SetThreadCacheBlock(Block * block)874   inline void SetThreadCacheBlock(Block* block) {
875     thread_cache().last_block_used_ = block;
876     thread_cache().last_lifecycle_id_seen = lifecycle_id_;
877   }
878 
879   int64 lifecycle_id_;  // Unique for each arena. Changes on Reset().
880 
881   google::protobuf::internal::AtomicWord blocks_;  // Head of linked list of all allocated blocks
882   google::protobuf::internal::AtomicWord hint_;    // Fast thread-local block access
883 
884   // Node contains the ptr of the object to be cleaned up and the associated
885   // cleanup function ptr.
886   struct Node {
887     void* elem;              // Pointer to the object to be cleaned up.
888     void (*cleanup)(void*);  // Function pointer to the destructor or deleter.
889     Node* next;              // Next node in the list.
890   };
891 
892   google::protobuf::internal::AtomicWord cleanup_list_;  // Head of a linked list of nodes containing object
893                              // ptrs and cleanup methods.
894 
895   bool owns_first_block_;    // Indicates that arena owns the first block
896   Mutex blocks_lock_;
897 
898   void AddBlock(Block* b);
899   // Access must be synchronized, either by blocks_lock_ or by being called from
900   // Init()/Reset().
901   void AddBlockInternal(Block* b);
902   void* SlowAlloc(size_t n);
903   Block* FindBlock(void* me);
904   Block* NewBlock(void* me, Block* my_last_block, size_t n,
905                   size_t start_block_size, size_t max_block_size);
906   static void* AllocFromBlock(Block* b, size_t n);
907   template <typename Key, typename T>
908   friend class Map;
909 
910   // The arena may save a cookie it receives from the external on_init hook
911   // and then use it when calling the on_reset and on_destruction hooks.
912   void* hooks_cookie_;
913 
914   ArenaOptions options_;
915 
916   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
917 };
918 
919 // Defined above for supporting environments without RTTI.
920 #undef RTTI_TYPE_ID
921 
922 }  // namespace protobuf
923 
924 }  // namespace google
925 #endif  // GOOGLE_PROTOBUF_ARENA_H__
926