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