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 #ifndef GOOGLE_PROTOBUF_NO_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 LIBPROTOBUF_EXPORT 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 * arena,google::protobuf::internal::false_type)802 static void CreateInArenaStorageInternal(
803 T* ptr, Arena* arena, google::protobuf::internal::false_type) {
804 new (ptr) T();
805 }
806
807 template <typename T>
RegisterDestructorInternal(T * ptr,Arena * arena,google::protobuf::internal::true_type)808 static void RegisterDestructorInternal(
809 T* ptr, Arena* 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 * value,...)844 static ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
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