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