Home | History | Annotate | Download | only in protobuf
      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.
     74 template<typename T> void arena_destruct_object(void* object) {
     75   reinterpret_cast<T*>(object)->~T();
     76 }
     77 template<typename T> void arena_delete_object(void* object) {
     78   delete reinterpret_cast<T*>(object);
     79 }
     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 
    140   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.
    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.
    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
    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
    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
    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
    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
    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
    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>
    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>
    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>
    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>
    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>
    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>
    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
    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
    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
    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.
    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
    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.
    538     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_;
    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>
    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>
    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
    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
    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
    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
    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
    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
    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>
    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>
    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>
    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>
    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>
    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>
    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
    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
    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
    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>
    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>
    797   static void CreateInArenaStorageInternal(
    798       T* ptr, Arena* arena, google::protobuf::internal::true_type) {
    799     new (ptr) T(arena);
    800   }
    801   template <typename T>
    802   static void CreateInArenaStorageInternal(
    803       T* ptr, Arena*, google::protobuf::internal::false_type) {
    804     new (ptr) T;
    805   }
    806 
    807   template <typename T>
    808   static void RegisterDestructorInternal(
    809       T*, Arena*, google::protobuf::internal::true_type) {}
    810   template <typename T>
    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
    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
    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
    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
    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.
    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 
    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