• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #ifndef GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
9 #define GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
10 
11 #include <cstddef>
12 #include <cstring>
13 #include <vector>
14 
15 #include "absl/base/attributes.h"
16 #include "absl/base/prefetch.h"
17 
18 // Must be included last.
19 #include "google/protobuf/port_def.inc"
20 
21 namespace google {
22 namespace protobuf {
23 namespace internal {
24 
25 class SerialArena;
26 
27 namespace cleanup {
28 
29 // Helper function invoking the destructor of `object`
30 template <typename T>
arena_destruct_object(void * object)31 void arena_destruct_object(void* object) {
32   reinterpret_cast<T*>(object)->~T();
33 }
34 
35 // CleanupNode contains the object (`elem`) that needs to be
36 // destroyed, and the function to destroy it (`destructor`)
37 // elem must be aligned at minimum on a 4 byte boundary.
38 struct CleanupNode {
39   // Optimization: performs a prefetch on the elem for the cleanup node. We
40   // explicitly use NTA prefetch here to avoid polluting remote caches: we are
41   // destroying these instances, there is no purpose for these cache lines to
42   // linger around in remote caches.
PrefetchCleanupNode43   ABSL_ATTRIBUTE_ALWAYS_INLINE void Prefetch() {
44     // TODO: we should also prefetch the destructor code once
45     // processors support code prefetching.
46     absl::PrefetchToLocalCacheNta(elem);
47   }
48 
49   // Destroys the object referenced by the cleanup node.
DestroyCleanupNode50   ABSL_ATTRIBUTE_ALWAYS_INLINE void Destroy() { destructor(elem); }
51 
52   void* elem;
53   void (*destructor)(void*);
54 };
55 
56 // Manages the list of cleanup nodes in a chunked linked list. Chunks grow by
57 // factors of two up to a limit. Trivially destructible, but Cleanup() must be
58 // called before destruction.
59 class ChunkList {
60  public:
Add(void * elem,void (* destructor)(void *),SerialArena & arena)61   PROTOBUF_ALWAYS_INLINE void Add(void* elem, void (*destructor)(void*),
62                                   SerialArena& arena) {
63     if (PROTOBUF_PREDICT_TRUE(next_ < limit_)) {
64       AddFromExisting(elem, destructor);
65       return;
66     }
67     AddFallback(elem, destructor, arena);
68   }
69 
70   // Runs all inserted cleanups and frees allocated chunks. Must be called
71   // before destruction.
72   void Cleanup(const SerialArena& arena);
73 
74  private:
75   struct Chunk;
76   friend class internal::SerialArena;
77 
78   void AddFallback(void* elem, void (*destructor)(void*), SerialArena& arena);
AddFromExisting(void * elem,void (* destructor)(void *))79   ABSL_ATTRIBUTE_ALWAYS_INLINE void AddFromExisting(void* elem,
80                                                     void (*destructor)(void*)) {
81     *next_++ = CleanupNode{elem, destructor};
82   }
83 
84   // Returns the pointers to the to-be-cleaned objects.
85   std::vector<void*> PeekForTesting();
86 
87   Chunk* head_ = nullptr;
88   CleanupNode* next_ = nullptr;
89   CleanupNode* limit_ = nullptr;
90   // Current prefetch position. Data from `next_` up to but not including
91   // `prefetch_ptr_` is software prefetched. Used in SerialArena prefetching.
92   const char* prefetch_ptr_ = nullptr;
93 };
94 
95 }  // namespace cleanup
96 }  // namespace internal
97 }  // namespace protobuf
98 }  // namespace google
99 
100 #include "google/protobuf/port_undef.inc"
101 
102 #endif  // GOOGLE_PROTOBUF_ARENA_CLEANUP_H__
103