blob: a83a4fbf722bed0ba1c59c797ad0c14e640c564a [file] [log] [blame]
Feng Xiao6ef984a2014-11-10 17:34:54 -08001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31// This header is logically internal, but is made public because it is used
32// from protocol-compiler-generated code, which may reside in other components.
33
34#ifndef GOOGLE_PROTOBUF_ARENA_H__
35#define GOOGLE_PROTOBUF_ARENA_H__
36
Jisi Liu885b6122015-02-28 14:51:22 -080037#include <typeinfo>
38
Feng Xiao6ef984a2014-11-10 17:34:54 -080039#include <google/protobuf/stubs/atomic_sequence_num.h>
40#include <google/protobuf/stubs/atomicops.h>
Jisi Liu885b6122015-02-28 14:51:22 -080041#include <google/protobuf/stubs/common.h>
Feng Xiao6ef984a2014-11-10 17:34:54 -080042#include <google/protobuf/stubs/type_traits.h>
43
44namespace google {
45namespace protobuf {
46
47class Arena; // defined below
48class Message; // message.h
49
50namespace internal {
51class ArenaString; // arenastring.h
52class LazyField; // lazy_field.h
53
54template<typename Type>
55class GenericTypeHandler; // repeated_field.h
56
57// Templated cleanup methods.
58template<typename T> void arena_destruct_object(void* object) {
59 reinterpret_cast<T*>(object)->~T();
60}
61template<typename T> void arena_delete_object(void* object) {
62 delete reinterpret_cast<T*>(object);
63}
64inline void arena_free(void* object, size_t size) {
65 free(object);
66}
67
68} // namespace internal
69
70// ArenaOptions provides optional additional parameters to arena construction
71// that control its block-allocation behavior.
72struct ArenaOptions {
73 // This defines the size of the first block requested from the system malloc.
74 // Subsequent block sizes will increase in a geometric series up to a maximum.
75 size_t start_block_size;
76
77 // This defines the maximum block size requested from system malloc (unless an
78 // individual arena allocation request occurs with a size larger than this
79 // maximum). Requested block sizes increase up to this value, then remain
80 // here.
81 size_t max_block_size;
82
83 // An initial block of memory for the arena to use, or NULL for none. If
84 // provided, the block must live at least as long as the arena itself. The
85 // creator of the Arena retains ownership of the block after the Arena is
86 // destroyed.
87 char* initial_block;
88
89 // The size of the initial block, if provided.
90 size_t initial_block_size;
91
92 // A function pointer to an alloc method that returns memory blocks of size
93 // requested. By default, it contains a ptr to the malloc function.
Jisi Liu885b6122015-02-28 14:51:22 -080094 //
95 // NOTE: block_alloc and dealloc functions are expected to behave like
96 // malloc and free, including Asan poisoning.
Feng Xiao6ef984a2014-11-10 17:34:54 -080097 void* (*block_alloc)(size_t);
98 // A function pointer to a dealloc method that takes ownership of the blocks
99 // from the arena. By default, it contains a ptr to a wrapper function that
100 // calls free.
101 void (*block_dealloc)(void*, size_t);
102
Jisi Liu885b6122015-02-28 14:51:22 -0800103 // Hooks for adding external functionality such as user-specific metrics
104 // collection, specific debugging abilities, etc.
105 // Init hook may return a pointer to a cookie to be stored in the arena.
106 // reset and destruction hooks will then be called with the same cookie
107 // pointer. This allows us to save an external object per arena instance and
108 // use it on the other hooks (Note: It is just as legal for init to return
109 // NULL and not use the cookie feature).
110 // on_arena_reset and on_arena_destruction also receive the space used in
111 // the arena just before the reset.
112 void* (*on_arena_init)(Arena* arena);
113 void (*on_arena_reset)(Arena* arena, void* cookie, uint64 space_used);
114 void (*on_arena_destruction)(Arena* arena, void* cookie, uint64 space_used);
115
116 // type_name is promised to be a static string - its lifetime extends to
117 // match program's lifetime.
118 void (*on_arena_allocation)(const char* type_name, uint64 alloc_size,
119 Arena* arena, void* cookie);
120
Feng Xiao6ef984a2014-11-10 17:34:54 -0800121 ArenaOptions()
122 : start_block_size(kDefaultStartBlockSize),
123 max_block_size(kDefaultMaxBlockSize),
124 initial_block(NULL),
125 initial_block_size(0),
126 block_alloc(&malloc),
Jisi Liu885b6122015-02-28 14:51:22 -0800127 block_dealloc(&internal::arena_free),
128 on_arena_init(NULL),
129 on_arena_reset(NULL),
130 on_arena_destruction(NULL),
131 on_arena_allocation(NULL) {}
Feng Xiao6ef984a2014-11-10 17:34:54 -0800132
133 private:
134 // Constants define default starting block size and max block size for
135 // arena allocator behavior -- see descriptions above.
136 static const size_t kDefaultStartBlockSize = 256;
137 static const size_t kDefaultMaxBlockSize = 8192;
138};
139
140// Arena allocator. Arena allocation replaces ordinary (heap-based) allocation
141// with new/delete, and improves performance by aggregating allocations into
142// larger blocks and freeing allocations all at once. Protocol messages are
143// allocated on an arena by using Arena::CreateMessage<T>(Arena*), below, and
144// are automatically freed when the arena is destroyed.
145//
146// This is a thread-safe implementation: multiple threads may allocate from the
147// arena concurrently. Destruction is not thread-safe and the destructing
148// thread must synchronize with users of the arena first.
149class LIBPROTOBUF_EXPORT Arena {
150 public:
151 // Arena constructor taking custom options. See ArenaOptions below for
152 // descriptions of the options available.
Jisi Liu885b6122015-02-28 14:51:22 -0800153 explicit Arena(const ArenaOptions& options) : options_(options) {
154 Init();
Feng Xiao6ef984a2014-11-10 17:34:54 -0800155 }
156
157 // Default constructor with sensible default options, tuned for average
158 // use-cases.
159 Arena() {
Jisi Liu885b6122015-02-28 14:51:22 -0800160 Init();
Feng Xiao6ef984a2014-11-10 17:34:54 -0800161 }
162
163 // Destructor deletes all owned heap allocated objects, and destructs objects
164 // that have non-trivial destructors, except for proto2 message objects whose
165 // destructors can be skipped. Also, frees all blocks except the initial block
166 // if it was passed in.
Jisi Liu885b6122015-02-28 14:51:22 -0800167 ~Arena();
Feng Xiao6ef984a2014-11-10 17:34:54 -0800168
169 // API to create proto2 message objects on the arena. If the arena passed in
170 // is NULL, then a heap allocated object is returned. Type T must be a message
171 // defined in a .proto file with cc_enable_arenas set to true, otherwise a
172 // compilation error will occur.
173 //
174 // RepeatedField and RepeatedPtrField may also be instantiated directly on an
175 // arena with this method: they act as "arena-capable message types" for the
176 // purposes of the Arena API.
177 template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
178 static T* CreateMessage(::google::protobuf::Arena* arena) {
179 if (arena == NULL) {
180 return new T;
181 } else {
182 return arena->CreateMessageInternal<T>(static_cast<T*>(0));
183 }
184 }
185
186 // API to create any objects on the arena. Note that only the object will
187 // be created on the arena; the underlying ptrs (in case of a proto2 message)
188 // will be still heap allocated. Proto messages should usually be allocated
189 // with CreateMessage<T>() instead.
190 template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
191 static T* Create(::google::protobuf::Arena* arena) {
192 if (arena == NULL) {
193 return new T();
194 } else {
195 return arena->CreateInternal<T>(
196 SkipDeleteList<T>(static_cast<T*>(0)));
197 }
198 }
199
200 // Version of the above with one constructor argument for the created object.
201 template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
202 static T* Create(::google::protobuf::Arena* arena, const Arg& arg) {
203 if (arena == NULL) {
204 return new T(arg);
205 } else {
206 return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
207 arg);
208 }
209 }
210
211 // Version of the above with two constructor arguments for the created object.
212 template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
213 static T* Create(::google::protobuf::Arena* arena, const Arg1& arg1, const Arg2& arg2) {
214 if (arena == NULL) {
215 return new T(arg1, arg2);
216 } else {
217 return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
218 arg1,
219 arg2);
220 }
221 }
222
Jisi Liu885b6122015-02-28 14:51:22 -0800223 // Version of the above with three constructor arguments for the created
224 // object.
225 template <typename T, typename Arg1, typename Arg2, typename Arg3>
226 GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
227 const Arg1& arg1, const Arg2& arg2,
228 const Arg3& arg3) {
229 if (arena == NULL) {
230 return new T(arg1, arg2, arg3);
231 } else {
232 return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
233 arg1,
234 arg2,
235 arg3);
236 }
237 }
238
239 // Version of the above with four constructor arguments for the created
240 // object.
241 template <typename T, typename Arg1, typename Arg2, typename Arg3,
242 typename Arg4>
243 GOOGLE_ATTRIBUTE_ALWAYS_INLINE static T* Create(::google::protobuf::Arena* arena,
244 const Arg1& arg1, const Arg2& arg2,
245 const Arg3& arg3, const Arg4& arg4) {
246 if (arena == NULL) {
247 return new T(arg1, arg2, arg3, arg4);
248 } else {
249 return arena->CreateInternal<T>(SkipDeleteList<T>(static_cast<T*>(0)),
250 arg1,
251 arg2,
252 arg3,
253 arg4);
254 }
255 }
256
Feng Xiao6ef984a2014-11-10 17:34:54 -0800257 // Create an array of object type T on the arena. Type T must have a trivial
258 // constructor, as it will not be invoked when created on the arena.
259 template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
260 static T* CreateArray(::google::protobuf::Arena* arena, size_t num_elements) {
261 if (arena == NULL) {
262 return new T[num_elements];
263 } else {
Jisi Liu885b6122015-02-28 14:51:22 -0800264 return arena->CreateInternalRawArray<T>(num_elements);
Feng Xiao6ef984a2014-11-10 17:34:54 -0800265 }
266 }
267
268 // Returns the total space used by the arena, which is the sums of the sizes
269 // of the underlying blocks. The total space used may not include the new
270 // blocks that are allocated by this arena from other threads concurrently
271 // with the call to this method.
Jisi Liu885b6122015-02-28 14:51:22 -0800272 uint64 SpaceAllocated() const GOOGLE_ATTRIBUTE_NOINLINE;
273 // As above, but does not include any free space in underlying blocks.
Feng Xiao6ef984a2014-11-10 17:34:54 -0800274 uint64 SpaceUsed() const GOOGLE_ATTRIBUTE_NOINLINE;
275
276 // Frees all storage allocated by this arena after calling destructors
277 // registered with OwnDestructor() and freeing objects registered with Own().
278 // Any objects allocated on this arena are unusable after this call. It also
279 // returns the total space used by the arena which is the sums of the sizes
280 // of the allocated blocks. This method is not thread-safe.
281 uint64 Reset() GOOGLE_ATTRIBUTE_NOINLINE;
282
283 // Adds |object| to a list of heap-allocated objects to be freed with |delete|
284 // when the arena is destroyed or reset.
285 template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
286 void Own(T* object) {
287 OwnInternal(object, google::protobuf::internal::is_convertible<T*, ::google::protobuf::Message*>());
288 }
289
290 // Adds |object| to a list of objects whose destructors will be manually
291 // called when the arena is destroyed or reset. This differs from Own() in
292 // that it does not free the underlying memory with |delete|; hence, it is
293 // normally only used for objects that are placement-newed into
294 // arena-allocated memory.
295 template <typename T> GOOGLE_ATTRIBUTE_NOINLINE
296 void OwnDestructor(T* object) {
297 if (object != NULL) {
298 AddListNode(object, &internal::arena_destruct_object<T>);
299 }
300 }
301
302 // Adds a custom member function on an object to the list of destructors that
303 // will be manually called when the arena is destroyed or reset. This differs
304 // from OwnDestructor() in that any member function may be specified, not only
305 // the class destructor.
306 void OwnCustomDestructor(void* object, void (*destruct)(void*))
307 GOOGLE_ATTRIBUTE_NOINLINE {
308 AddListNode(object, destruct);
309 }
310
311 // Retrieves the arena associated with |value| if |value| is an arena-capable
312 // message, or NULL otherwise. This differs from value->GetArena() in that the
313 // latter is a virtual call, while this method is a templated call that
314 // resolves at compile-time.
315 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Jisi Liu885b6122015-02-28 14:51:22 -0800316 static inline ::google::protobuf::Arena* GetArena(const T* value) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800317 return GetArenaInternal(value, static_cast<T*>(0));
318 }
319
320 // Helper typetrait that indicates support for arenas in a type T at compile
321 // time. This is public only to allow construction of higher-level templated
322 // utilities. is_arena_constructable<T>::value is an instance of
323 // google::protobuf::internal::true_type if the message type T has arena support enabled, and
324 // google::protobuf::internal::false_type otherwise.
325 //
326 // This is inside Arena because only Arena has the friend relationships
327 // necessary to see the underlying generated code traits.
328 template<typename T>
329 struct is_arena_constructable {
330 template<typename U>
331 static char ArenaConstructable(
332 const typename U::InternalArenaConstructable_*);
333 template<typename U>
334 static double ArenaConstructable(...);
335
336 // This will resolve to either google::protobuf::internal::true_type or google::protobuf::internal::false_type.
337 typedef google::protobuf::internal::integral_constant<bool,
338 sizeof(ArenaConstructable<const T>(static_cast<const T*>(0))) ==
339 sizeof(char)> type;
340 static const type value;
341 };
342
343 private:
344 // Blocks are variable length malloc-ed objects. The following structure
345 // describes the common header for all blocks.
346 struct Block {
347 void* owner; // &ThreadCache of thread that owns this block, or
348 // &this->owner if not yet owned by a thread.
349 Block* next; // Next block in arena (may have different owner)
350 // ((char*) &block) + pos is next available byte. It is always
351 // aligned at a multiple of 8 bytes.
352 size_t pos;
353 size_t size; // total size of the block.
354 size_t avail() const GOOGLE_ATTRIBUTE_ALWAYS_INLINE { return size - pos; }
355 // data follows
356 };
357
Feng Xiao6ef984a2014-11-10 17:34:54 -0800358 template<typename Type> friend class ::google::protobuf::internal::GenericTypeHandler;
359 friend class MockArena; // For unit-testing.
360 friend class internal::ArenaString; // For AllocateAligned.
361 friend class internal::LazyField; // For CreateMaybeMessage.
362
363 struct ThreadCache {
364 // The ThreadCache is considered valid as long as this matches the
365 // lifecycle_id of the arena being used.
366 int64 last_lifecycle_id_seen;
367 Block* last_block_used_;
368 };
369
370 static const size_t kHeaderSize = sizeof(Block);
371 static google::protobuf::internal::SequenceNumber lifecycle_id_generator_;
Feng Xiao8d5d7cc2014-12-09 17:05:10 -0800372#ifdef PROTOBUF_USE_DLLS
Josh Habermancb3caf12015-02-17 18:23:41 -0800373 // Thread local variables cannot be exposed through DLL interface but we can
374 // wrap them in static functions.
Feng Xiao8d5d7cc2014-12-09 17:05:10 -0800375 static ThreadCache& thread_cache();
376#else
Jisi Liu885b6122015-02-28 14:51:22 -0800377 static __thread ThreadCache thread_cache_;
Feng Xiao8d5d7cc2014-12-09 17:05:10 -0800378 static ThreadCache& thread_cache() { return thread_cache_; }
379#endif
Feng Xiao6ef984a2014-11-10 17:34:54 -0800380
381 // SFINAE for skipping addition to delete list for a Type. This is mainly to
382 // skip proto2/proto1 message objects with cc_enable_arenas=true from being
383 // part of the delete list. Also, note, compiler will optimize out the branch
384 // in CreateInternal<T>.
385 //
386 template<typename T>
387 static inline bool SkipDeleteList(typename T::DestructorSkippable_*) {
388 return true;
389 }
390
391 // For non message objects, we skip addition to delete list if the object has
392 // a trivial destructor.
393 template<typename T>
394 static inline bool SkipDeleteList(...) {
395 return google::protobuf::internal::has_trivial_destructor<T>::value;
396 }
397
398 // CreateMessage<T> requires that T supports arenas, but this private method
399 // works whether or not T supports arenas. These are not exposed to user code
400 // as it can cause confusing API usages, and end up having double free in
401 // user code. These are used only internally from LazyField and Repeated
402 // fields, since they are designed to work in all mode combinations.
403 template<typename Msg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
404 static Msg* CreateMaybeMessage(
405 Arena* arena, typename Msg::InternalArenaConstructable_*) {
406 return CreateMessage<Msg>(arena);
407 }
408
409 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
410 static T* CreateMaybeMessage(Arena* arena, ...) {
411 return Create<T>(arena);
412 }
413
Jisi Liu885b6122015-02-28 14:51:22 -0800414 // Just allocate the required size for the given type assuming the
415 // type has a trivial constructor.
416 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
417 inline T* CreateInternalRawArray(uint32 num_elements) {
418 return static_cast<T*>(AllocateAligned(sizeof(T) * num_elements));
419 }
420
Feng Xiao6ef984a2014-11-10 17:34:54 -0800421 template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
422 inline T* CreateInternal(
423 bool skip_explicit_ownership) {
424 T* t = new (AllocateAligned(sizeof(T))) T();
425 if (!skip_explicit_ownership) {
426 AddListNode(t, &internal::arena_destruct_object<T>);
427 }
428 return t;
429 }
430
431 template <typename T, typename Arg> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
432 inline T* CreateInternal(
433 bool skip_explicit_ownership, const Arg& arg) {
434 T* t = new (AllocateAligned(sizeof(T))) T(arg);
435 if (!skip_explicit_ownership) {
436 AddListNode(t, &internal::arena_destruct_object<T>);
437 }
438 return t;
439 }
440
441 template <typename T, typename Arg1, typename Arg2> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
442 inline T* CreateInternal(
443 bool skip_explicit_ownership, const Arg1& arg1, const Arg2& arg2) {
444 T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2);
445 if (!skip_explicit_ownership) {
446 AddListNode(t, &internal::arena_destruct_object<T>);
447 }
448 return t;
449 }
450
Jisi Liu885b6122015-02-28 14:51:22 -0800451 template <typename T, typename Arg1, typename Arg2, typename Arg3>
452 GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
453 const Arg1& arg1,
454 const Arg2& arg2,
455 const Arg3& arg3) {
456 T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3);
457 if (!skip_explicit_ownership) {
458 AddListNode(t, &internal::arena_destruct_object<T>);
459 }
460 return t;
461 }
462
463 template <typename T, typename Arg1, typename Arg2, typename Arg3,
464 typename Arg4>
465 GOOGLE_ATTRIBUTE_ALWAYS_INLINE inline T* CreateInternal(bool skip_explicit_ownership,
466 const Arg1& arg1,
467 const Arg2& arg2,
468 const Arg3& arg3,
469 const Arg4& arg4) {
470 T* t = new (AllocateAligned(sizeof(T))) T(arg1, arg2, arg3, arg4);
471 if (!skip_explicit_ownership) {
472 AddListNode(t, &internal::arena_destruct_object<T>);
473 }
474 return t;
475 }
476
Feng Xiao6ef984a2014-11-10 17:34:54 -0800477 template <typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
478 inline T* CreateMessageInternal(typename T::InternalArenaConstructable_*) {
479 return CreateInternal<T, Arena*>(SkipDeleteList<T>(static_cast<T*>(0)),
480 this);
481 }
482
Jisi Liu885b6122015-02-28 14:51:22 -0800483 // CreateInArenaStorage is used to implement map field. Without it,
484 // google::protobuf::Map need to call generated message's protected arena constructor,
485 // which needs to declare google::protobuf::Map as friend of generated message.
486 template <typename T>
487 static void CreateInArenaStorage(T* ptr, Arena* arena) {
488 CreateInArenaStorageInternal(ptr, arena, is_arena_constructable<T>::value);
489 }
490 template <typename T>
491 static void CreateInArenaStorageInternal(
492 T* ptr, Arena* arena, google::protobuf::internal::true_type) {
493 new (ptr) T(arena);
494 }
495
496 template <typename T>
497 static void CreateInArenaStorageInternal(
498 T* ptr, Arena* arena, google::protobuf::internal::false_type) {
499 new (ptr) T;
500 }
501
Feng Xiao6ef984a2014-11-10 17:34:54 -0800502 // These implement Own(), which registers an object for deletion (destructor
503 // call and operator delete()). The second parameter has type 'true_type' if T
504 // is a subtype of ::google::protobuf::Message and 'false_type' otherwise. Collapsing
505 // all template instantiations to one for generic Message reduces code size,
506 // using the virtual destructor instead.
507 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
508 void OwnInternal(T* object, google::protobuf::internal::true_type) {
509 if (object != NULL) {
510 AddListNode(object, &internal::arena_delete_object< ::google::protobuf::Message >);
511 }
512 }
513 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
514 void OwnInternal(T* object, google::protobuf::internal::false_type) {
515 if (object != NULL) {
516 AddListNode(object, &internal::arena_delete_object<T>);
517 }
518 }
519
520 // Implementation for GetArena(). Only message objects with
521 // InternalArenaConstructable_ tags can be associated with an arena, and such
522 // objects must implement a GetArenaNoVirtual() method.
523 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Jisi Liu885b6122015-02-28 14:51:22 -0800524 static inline ::google::protobuf::Arena* GetArenaInternal(const T* value,
Feng Xiao6ef984a2014-11-10 17:34:54 -0800525 typename T::InternalArenaConstructable_*) {
526 return value->GetArenaNoVirtual();
527 }
528
529 template<typename T> GOOGLE_ATTRIBUTE_ALWAYS_INLINE
Jisi Liu885b6122015-02-28 14:51:22 -0800530 static inline ::google::protobuf::Arena* GetArenaInternal(const T* value, ...) {
Feng Xiao6ef984a2014-11-10 17:34:54 -0800531 return NULL;
532 }
533
534
535 void* AllocateAligned(size_t size);
536
Jisi Liu885b6122015-02-28 14:51:22 -0800537 void Init();
Feng Xiao6ef984a2014-11-10 17:34:54 -0800538
539 // Free all blocks and return the total space used which is the sums of sizes
540 // of the all the allocated blocks.
541 uint64 FreeBlocks();
542
543 // Add object pointer and cleanup function pointer to the list.
544 // TODO(rohananil, cfallin): We could pass in a sub-arena into this method
545 // to avoid polluting blocks of this arena with list nodes. This would help in
546 // mixed mode (where many protobufs have cc_enable_arenas=false), and is an
547 // alternative to a chunked linked-list, but with extra overhead of *next.
548 void AddListNode(void* elem, void (*cleanup)(void*));
549 // Delete or Destruct all objects owned by the arena.
550 void CleanupList();
551
552 inline void SetThreadCacheBlock(Block* block) {
Feng Xiao8d5d7cc2014-12-09 17:05:10 -0800553 thread_cache().last_block_used_ = block;
554 thread_cache().last_lifecycle_id_seen = lifecycle_id_;
Feng Xiao6ef984a2014-11-10 17:34:54 -0800555 }
556
557 int64 lifecycle_id_; // Unique for each arena. Changes on Reset().
Feng Xiao6ef984a2014-11-10 17:34:54 -0800558
559 google::protobuf::internal::AtomicWord blocks_; // Head of linked list of all allocated blocks
560 google::protobuf::internal::AtomicWord hint_; // Fast thread-local block access
561
562 // Node contains the ptr of the object to be cleaned up and the associated
563 // cleanup function ptr.
564 struct Node {
565 void* elem; // Pointer to the object to be cleaned up.
566 void (*cleanup)(void*); // Function pointer to the destructor or deleter.
567 Node* next; // Next node in the list.
568 };
569
570 google::protobuf::internal::AtomicWord cleanup_list_; // Head of a linked list of nodes containing object
571 // ptrs and cleanup methods.
572
573 bool owns_first_block_; // Indicates that arena owns the first block
574 Mutex blocks_lock_;
575
576 void AddBlock(Block* b);
577 void* SlowAlloc(size_t n);
578 Block* FindBlock(void* me);
579 Block* NewBlock(void* me, Block* my_last_block, size_t n,
580 size_t start_block_size, size_t max_block_size);
581 static void* AllocFromBlock(Block* b, size_t n);
Jisi Liu885b6122015-02-28 14:51:22 -0800582 template <typename Key, typename T>
583 friend class Map;
584
585 // The arena may save a cookie it receives from the external on_init hook
586 // and then use it when calling the on_reset and on_destruction hooks.
587 void* hooks_cookie_;
588
589 ArenaOptions options_;
590
Feng Xiao6ef984a2014-11-10 17:34:54 -0800591 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Arena);
592};
593
594template<typename T>
595const typename Arena::is_arena_constructable<T>::type
596 Arena::is_arena_constructable<T>::value =
597 typename Arena::is_arena_constructable<T>::type();
598
599} // namespace protobuf
600
601} // namespace google
602#endif // GOOGLE_PROTOBUF_ARENA_H__