Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Side by Side Diff: third_party/protobuf/src/google/protobuf/arena.h

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

Powered by Google App Engine
This is Rietveld 408576698