diff options
Diffstat (limited to 'third_party/protobuf/3.6.0/src/google/protobuf/arena.cc')
-rw-r--r-- | third_party/protobuf/3.6.0/src/google/protobuf/arena.cc | 415 |
1 files changed, 0 insertions, 415 deletions
diff --git a/third_party/protobuf/3.6.0/src/google/protobuf/arena.cc b/third_party/protobuf/3.6.0/src/google/protobuf/arena.cc deleted file mode 100644 index c117c9e528..0000000000 --- a/third_party/protobuf/3.6.0/src/google/protobuf/arena.cc +++ /dev/null @@ -1,415 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <google/protobuf/arena.h> - -#include <algorithm> -#include <limits> - - -#ifdef ADDRESS_SANITIZER -#include <sanitizer/asan_interface.h> -#endif // ADDRESS_SANITIZER - -#include <google/protobuf/stubs/port.h> - -namespace google { -static const size_t kMinCleanupListElements = 8; -static const size_t kMaxCleanupListElements = 64; // 1kB on 64-bit. - -namespace protobuf { -namespace internal { - - -std::atomic<int64> ArenaImpl::lifecycle_id_generator_; -#if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) -ArenaImpl::ThreadCache& ArenaImpl::thread_cache() { - static internal::ThreadLocalStorage<ThreadCache>* thread_cache_ = - new internal::ThreadLocalStorage<ThreadCache>(); - return *thread_cache_->Get(); -} -#elif defined(PROTOBUF_USE_DLLS) -ArenaImpl::ThreadCache& ArenaImpl::thread_cache() { - static GOOGLE_THREAD_LOCAL ThreadCache thread_cache_ = { -1, NULL }; - return thread_cache_; -} -#else -GOOGLE_THREAD_LOCAL ArenaImpl::ThreadCache ArenaImpl::thread_cache_ = {-1, NULL}; -#endif - -void ArenaImpl::Init() { - lifecycle_id_ = - lifecycle_id_generator_.fetch_add(1, std::memory_order_relaxed); - hint_.store(nullptr, std::memory_order_relaxed); - threads_.store(nullptr, std::memory_order_relaxed); - - if (initial_block_) { - // Thread which calls Init() owns the first block. This allows the - // single-threaded case to allocate on the first block without having to - // perform atomic operations. - new (initial_block_) Block(options_.initial_block_size, NULL); - SerialArena* serial = - SerialArena::New(initial_block_, &thread_cache(), this); - serial->set_next(NULL); - threads_.store(serial, std::memory_order_relaxed); - space_allocated_.store(options_.initial_block_size, - std::memory_order_relaxed); - CacheSerialArena(serial); - } else { - space_allocated_.store(0, std::memory_order_relaxed); - } -} - -ArenaImpl::~ArenaImpl() { - // Have to do this in a first pass, because some of the destructors might - // refer to memory in other blocks. - CleanupList(); - FreeBlocks(); -} - -uint64 ArenaImpl::Reset() { - // Have to do this in a first pass, because some of the destructors might - // refer to memory in other blocks. - CleanupList(); - uint64 space_allocated = FreeBlocks(); - Init(); - - return space_allocated; -} - -ArenaImpl::Block* ArenaImpl::NewBlock(Block* last_block, size_t min_bytes) { - size_t size; - if (last_block) { - // Double the current block size, up to a limit. - size = std::min(2 * last_block->size(), options_.max_block_size); - } else { - size = options_.start_block_size; - } - // Verify that min_bytes + kBlockHeaderSize won't overflow. - GOOGLE_CHECK_LE(min_bytes, std::numeric_limits<size_t>::max() - kBlockHeaderSize); - size = std::max(size, kBlockHeaderSize + min_bytes); - - void* mem = options_.block_alloc(size); - Block* b = new (mem) Block(size, last_block); - space_allocated_.fetch_add(size, std::memory_order_relaxed); - return b; -} - -ArenaImpl::Block::Block(size_t size, Block* next) - : next_(next), pos_(kBlockHeaderSize), size_(size) {} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -void ArenaImpl::SerialArena::AddCleanupFallback(void* elem, - void (*cleanup)(void*)) { - size_t size = cleanup_ ? cleanup_->size * 2 : kMinCleanupListElements; - size = std::min(size, kMaxCleanupListElements); - size_t bytes = internal::AlignUpTo8(CleanupChunk::SizeOf(size)); - CleanupChunk* list = reinterpret_cast<CleanupChunk*>(AllocateAligned(bytes)); - list->next = cleanup_; - list->size = size; - - cleanup_ = list; - cleanup_ptr_ = &list->nodes[0]; - cleanup_limit_ = &list->nodes[size]; - - AddCleanup(elem, cleanup); -} - -GOOGLE_PROTOBUF_ATTRIBUTE_FUNC_ALIGN(32) -void* ArenaImpl::AllocateAligned(size_t n) { - SerialArena* arena; - if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) { - return arena->AllocateAligned(n); - } else { - return AllocateAlignedFallback(n); - } -} - -void* ArenaImpl::AllocateAlignedAndAddCleanup(size_t n, - void (*cleanup)(void*)) { - SerialArena* arena; - if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) { - return arena->AllocateAlignedAndAddCleanup(n, cleanup); - } else { - return AllocateAlignedAndAddCleanupFallback(n, cleanup); - } -} - -void ArenaImpl::AddCleanup(void* elem, void (*cleanup)(void*)) { - SerialArena* arena; - if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) { - arena->AddCleanup(elem, cleanup); - } else { - return AddCleanupFallback(elem, cleanup); - } -} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -void* ArenaImpl::AllocateAlignedFallback(size_t n) { - return GetSerialArena()->AllocateAligned(n); -} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -void* ArenaImpl::AllocateAlignedAndAddCleanupFallback(size_t n, - void (*cleanup)(void*)) { - return GetSerialArena()->AllocateAlignedAndAddCleanup(n, cleanup); -} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -void ArenaImpl::AddCleanupFallback(void* elem, void (*cleanup)(void*)) { - GetSerialArena()->AddCleanup(elem, cleanup); -} - -inline GOOGLE_PROTOBUF_ATTRIBUTE_ALWAYS_INLINE -bool ArenaImpl::GetSerialArenaFast(ArenaImpl::SerialArena** arena) { - // If this thread already owns a block in this arena then try to use that. - // This fast path optimizes the case where multiple threads allocate from the - // same arena. - ThreadCache* tc = &thread_cache(); - if (GOOGLE_PREDICT_TRUE(tc->last_lifecycle_id_seen == lifecycle_id_)) { - *arena = tc->last_serial_arena; - return true; - } - - // Check whether we own the last accessed SerialArena on this arena. This - // fast path optimizes the case where a single thread uses multiple arenas. - SerialArena* serial = hint_.load(std::memory_order_acquire); - if (GOOGLE_PREDICT_TRUE(serial != NULL && serial->owner() == tc)) { - *arena = serial; - return true; - } - - return false; -} - -ArenaImpl::SerialArena* ArenaImpl::GetSerialArena() { - SerialArena* arena; - if (GOOGLE_PREDICT_TRUE(GetSerialArenaFast(&arena))) { - return arena; - } else { - return GetSerialArenaFallback(&thread_cache()); - } -} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -void* ArenaImpl::SerialArena::AllocateAlignedFallback(size_t n) { - // Sync back to current's pos. - head_->set_pos(head_->size() - (limit_ - ptr_)); - - head_ = arena_->NewBlock(head_, n); - ptr_ = head_->Pointer(head_->pos()); - limit_ = head_->Pointer(head_->size()); - -#ifdef ADDRESS_SANITIZER - ASAN_POISON_MEMORY_REGION(ptr_, limit_ - ptr_); -#endif // ADDRESS_SANITIZER - - return AllocateAligned(n); -} - -uint64 ArenaImpl::SpaceAllocated() const { - return space_allocated_.load(std::memory_order_relaxed); -} - -uint64 ArenaImpl::SpaceUsed() const { - SerialArena* serial = threads_.load(std::memory_order_acquire); - uint64 space_used = 0; - for ( ; serial; serial = serial->next()) { - space_used += serial->SpaceUsed(); - } - return space_used; -} - -uint64 ArenaImpl::SerialArena::SpaceUsed() const { - // Get current block's size from ptr_ (since we can't trust head_->pos(). - uint64 space_used = ptr_ - head_->Pointer(kBlockHeaderSize); - // Get subsequent block size from b->pos(). - for (Block* b = head_->next(); b; b = b->next()) { - space_used += (b->pos() - kBlockHeaderSize); - } - // Remove the overhead of the SerialArena itself. - space_used -= kSerialArenaSize; - return space_used; -} - -uint64 ArenaImpl::FreeBlocks() { - uint64 space_allocated = 0; - // By omitting an Acquire barrier we ensure that any user code that doesn't - // properly synchronize Reset() or the destructor will throw a TSAN warning. - SerialArena* serial = threads_.load(std::memory_order_relaxed); - - while (serial) { - // This is inside a block we are freeing, so we need to read it now. - SerialArena* next = serial->next(); - space_allocated += ArenaImpl::SerialArena::Free(serial, initial_block_, - options_.block_dealloc); - // serial is dead now. - serial = next; - } - - return space_allocated; -} - -uint64 ArenaImpl::SerialArena::Free(ArenaImpl::SerialArena* serial, - Block* initial_block, - void (*block_dealloc)(void*, size_t)) { - uint64 space_allocated = 0; - - // We have to be careful in this function, since we will be freeing the Block - // that contains this SerialArena. Be careful about accessing |serial|. - - for (Block* b = serial->head_; b; ) { - // This is inside the block we are freeing, so we need to read it now. - Block* next_block = b->next(); - space_allocated += (b->size()); - -#ifdef ADDRESS_SANITIZER - // This memory was provided by the underlying allocator as unpoisoned, so - // return it in an unpoisoned state. - ASAN_UNPOISON_MEMORY_REGION(b->Pointer(0), b->size()); -#endif // ADDRESS_SANITIZER - - if (b != initial_block) { - block_dealloc(b, b->size()); - } - - b = next_block; - } - - return space_allocated; -} - -void ArenaImpl::CleanupList() { - // By omitting an Acquire barrier we ensure that any user code that doesn't - // properly synchronize Reset() or the destructor will throw a TSAN warning. - SerialArena* serial = threads_.load(std::memory_order_relaxed); - - for ( ; serial; serial = serial->next()) { - serial->CleanupList(); - } -} - -void ArenaImpl::SerialArena::CleanupList() { - if (cleanup_ != NULL) { - CleanupListFallback(); - } -} - -void ArenaImpl::SerialArena::CleanupListFallback() { - // Cleanup newest chunk: ptrs give us length. - size_t n = cleanup_ptr_ - &cleanup_->nodes[0]; - CleanupNode* node = cleanup_ptr_; - for (size_t i = 0; i < n; i++) { - --node; - node->cleanup(node->elem); - } - - // Cleanup older chunks, which are known to be full. - CleanupChunk* list = cleanup_->next; - while (list) { - size_t n = list->size; - CleanupNode* node = &list->nodes[list->size]; - for (size_t i = 0; i < n; i++) { - --node; - node->cleanup(node->elem); - } - list = list->next; - } -} - -ArenaImpl::SerialArena* ArenaImpl::SerialArena::New(Block* b, void* owner, - ArenaImpl* arena) { - GOOGLE_DCHECK_EQ(b->pos(), kBlockHeaderSize); // Should be a fresh block - GOOGLE_DCHECK_LE(kBlockHeaderSize + kSerialArenaSize, b->size()); - SerialArena* serial = - reinterpret_cast<SerialArena*>(b->Pointer(kBlockHeaderSize)); - b->set_pos(kBlockHeaderSize + kSerialArenaSize); - serial->arena_ = arena; - serial->owner_ = owner; - serial->head_ = b; - serial->ptr_ = b->Pointer(b->pos()); - serial->limit_ = b->Pointer(b->size()); - serial->cleanup_ = NULL; - serial->cleanup_ptr_ = NULL; - serial->cleanup_limit_ = NULL; - return serial; -} - -GOOGLE_PROTOBUF_ATTRIBUTE_NOINLINE -ArenaImpl::SerialArena* ArenaImpl::GetSerialArenaFallback(void* me) { - // Look for this SerialArena in our linked list. - SerialArena* serial = threads_.load(std::memory_order_acquire); - for ( ; serial; serial = serial->next()) { - if (serial->owner() == me) { - break; - } - } - - if (!serial) { - // This thread doesn't have any SerialArena, which also means it doesn't - // have any blocks yet. So we'll allocate its first block now. - Block* b = NewBlock(NULL, kSerialArenaSize); - serial = SerialArena::New(b, me, this); - - SerialArena* head = threads_.load(std::memory_order_relaxed); - do { - serial->set_next(head); - } while (!threads_.compare_exchange_weak( - head, serial, std::memory_order_release, std::memory_order_relaxed)); - } - - CacheSerialArena(serial); - return serial; -} - -} // namespace internal - -void Arena::CallDestructorHooks() { - uint64 space_allocated = impl_.SpaceAllocated(); - // Call the reset hook - if (on_arena_reset_ != NULL) { - on_arena_reset_(this, hooks_cookie_, space_allocated); - } - - // Call the destruction hook - if (on_arena_destruction_ != NULL) { - on_arena_destruction_(this, hooks_cookie_, space_allocated); - } -} - -void Arena::OnArenaAllocation(const std::type_info* allocated_type, - size_t n) const { - if (on_arena_allocation_ != NULL) { - on_arena_allocation_(allocated_type, n, hooks_cookie_); - } -} - -} // namespace protobuf -} // namespace google |