// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ #define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__ #include #include #include #include "absl/base/attributes.h" #include "absl/base/prefetch.h" // Must be included last. #include "google/protobuf/port_def.inc" namespace google { namespace protobuf { namespace internal { class SerialArena; namespace cleanup { // Helper function invoking the destructor of `object` template void arena_destruct_object(void* object) { reinterpret_cast(object)->~T(); } // CleanupNode contains the object (`elem`) that needs to be // destroyed, and the function to destroy it (`destructor`) // elem must be aligned at minimum on a 4 byte boundary. struct CleanupNode { // Optimization: performs a prefetch on the elem for the cleanup node. We // explicitly use NTA prefetch here to avoid polluting remote caches: we are // destroying these instances, there is no purpose for these cache lines to // linger around in remote caches. ABSL_ATTRIBUTE_ALWAYS_INLINE void Prefetch() { // TODO: we should also prefetch the destructor code once // processors support code prefetching. absl::PrefetchToLocalCacheNta(elem); } // Destroys the object referenced by the cleanup node. ABSL_ATTRIBUTE_ALWAYS_INLINE void Destroy() { destructor(elem); } void* elem; void (*destructor)(void*); }; // Manages the list of cleanup nodes in a chunked linked list. Chunks grow by // factors of two up to a limit. Trivially destructible, but Cleanup() must be // called before destruction. class ChunkList { public: PROTOBUF_ALWAYS_INLINE void Add(void* elem, void (*destructor)(void*), SerialArena& arena) { if (PROTOBUF_PREDICT_TRUE(next_ < limit_)) { AddFromExisting(elem, destructor); return; } AddFallback(elem, destructor, arena); } // Runs all inserted cleanups and frees allocated chunks. Must be called // before destruction. void Cleanup(const SerialArena& arena); private: struct Chunk; friend class internal::SerialArena; void AddFallback(void* elem, void (*destructor)(void*), SerialArena& arena); ABSL_ATTRIBUTE_ALWAYS_INLINE void AddFromExisting(void* elem, void (*destructor)(void*)) { *next_++ = CleanupNode{elem, destructor}; } // Returns the pointers to the to-be-cleaned objects. std::vector PeekForTesting(); Chunk* head_ = nullptr; CleanupNode* next_ = nullptr; CleanupNode* limit_ = nullptr; // Current prefetch position. Data from `next_` up to but not including // `prefetch_ptr_` is software prefetched. Used in SerialArena prefetching. const char* prefetch_ptr_ = nullptr; }; } // namespace cleanup } // namespace internal } // namespace protobuf } // namespace google #include "google/protobuf/port_undef.inc" #endif // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__