@@ -33,169 +33,43 @@ void arena_destruct_object(void* object) {
3333 reinterpret_cast <T*>(object)->~T ();
3434}
3535
36- // Tag defines the type of cleanup / cleanup object. This tag is stored in the
37- // lowest 2 bits of the `elem` value identifying the type of node. All node
38- // types must start with a `uintptr_t` that stores `Tag` in its low two bits.
39- enum class Tag : uintptr_t {
40- kDynamic = 0 , // DynamicNode
41- kString = 1 , // TaggedNode (std::string)
42- kCord = 2 , // TaggedNode (absl::Cord)
43- };
44-
45- // DynamicNode contains the object (`elem`) that needs to be
36+ // CleanupNode contains the object (`elem`) that needs to be
4637// destroyed, and the function to destroy it (`destructor`)
4738// elem must be aligned at minimum on a 4 byte boundary.
48- struct DynamicNode {
49- uintptr_t elem;
39+ struct CleanupNode {
40+ void * elem;
5041 void (*destructor)(void *);
5142};
5243
53- // TaggedNode contains a `std::string` or `absl::Cord` object (`elem`) that
54- // needs to be destroyed. The lowest 2 bits of `elem` contain the non-zero
55- // `kString` or `kCord` tag.
56- struct TaggedNode {
57- uintptr_t elem;
58- };
59-
60- // EnableSpecializedTags() return true if the alignment of tagged objects
61- // such as std::string allow us to poke tags in the 2 LSB bits.
62- inline constexpr bool EnableSpecializedTags () {
63- // For now we require 2 bits
64- return alignof (std::string) >= 8 && alignof (absl::Cord) >= 8 ;
44+ inline ABSL_ATTRIBUTE_ALWAYS_INLINE CleanupNode* ToCleanup (void * pos) {
45+ return reinterpret_cast <CleanupNode*>(pos);
6546}
6647
67- // Adds a cleanup entry identified by `tag` at memory location `pos`.
68- inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode (Tag tag, void * pos,
69- const void * elem_raw,
48+ // Adds a cleanup entry at memory location `pos`.
49+ inline ABSL_ATTRIBUTE_ALWAYS_INLINE void CreateNode (void * pos, void * elem,
7050 void (*destructor)(void *)) {
71- auto elem = reinterpret_cast <uintptr_t >(elem_raw);
72- if (EnableSpecializedTags ()) {
73- ABSL_DCHECK_EQ (elem & 3 , 0ULL ); // Must be aligned
74- switch (tag) {
75- case Tag::kString : {
76- TaggedNode n = {elem | static_cast <uintptr_t >(Tag::kString )};
77- memcpy (pos, &n, sizeof (n));
78- return ;
79- }
80- case Tag::kCord : {
81- TaggedNode n = {elem | static_cast <uintptr_t >(Tag::kCord )};
82- memcpy (pos, &n, sizeof (n));
83- return ;
84- }
85-
86- case Tag::kDynamic :
87- default :
88- break ;
89- }
90- }
91- DynamicNode n = {elem, destructor};
51+ CleanupNode n = {elem, destructor};
9252 memcpy (pos, &n, sizeof (n));
9353}
9454
95- // Optimization: performs a prefetch on `elem_address`.
96- // Returns the size of the cleanup (meta) data at this address, allowing the
97- // caller to advance cleanup iterators without needing to examine or know
98- // anything about the underlying cleanup node or cleanup meta data / tags.
99- inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t
100- PrefetchNode (const void * elem_address) {
101- if (EnableSpecializedTags ()) {
102- uintptr_t elem;
103- memcpy (&elem, elem_address, sizeof (elem));
104- if (static_cast <Tag>(elem & 3 ) != Tag::kDynamic ) {
105- return sizeof (TaggedNode);
106- }
107- }
108- return sizeof (DynamicNode);
55+ // Optimization: performs a prefetch on the elem for the cleanup node at `pos`.
56+ inline ABSL_ATTRIBUTE_ALWAYS_INLINE void PrefetchNode (void * pos) {
10957}
11058
111- // Destroys the object referenced by the cleanup node at memory location `pos`.
112- // Returns the size of the cleanup (meta) data at this address, allowing the
113- // caller to advance cleanup iterators without needing to examine or know
114- // anything about the underlying cleanup node or cleanup meta data / tags.
115- inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t DestroyNode (const void * pos) {
116- uintptr_t elem;
117- memcpy (&elem, pos, sizeof (elem));
118- if (EnableSpecializedTags ()) {
119- switch (static_cast <Tag>(elem & 3 )) {
120- case Tag::kString : {
121- // Some compilers don't like fully qualified explicit dtor calls,
122- // so use an alias to avoid having to type `::`.
123- using T = std::string;
124- reinterpret_cast <T*>(elem - static_cast <uintptr_t >(Tag::kString ))->~T ();
125- return sizeof (TaggedNode);
126- }
127- case Tag::kCord : {
128- using T = absl::Cord;
129- reinterpret_cast <T*>(elem - static_cast <uintptr_t >(Tag::kCord ))->~T ();
130- return sizeof (TaggedNode);
131- }
132-
133- case Tag::kDynamic :
134-
135- default :
136- break ;
137- }
138- }
139- static_cast <const DynamicNode*>(pos)->destructor (
140- reinterpret_cast <void *>(elem - static_cast <uintptr_t >(Tag::kDynamic )));
141- return sizeof (DynamicNode);
59+ // Destroys the object referenced by the cleanup node.
60+ inline ABSL_ATTRIBUTE_ALWAYS_INLINE void DestroyNode (void * pos) {
61+ CleanupNode* cleanup = ToCleanup (pos);
62+ cleanup->destructor (cleanup->elem );
14263}
14364
14465// Append in `out` the pointer to the to-be-cleaned object in `pos`.
145- // Return the length of the cleanup node to allow the caller to advance the
146- // position, like `DestroyNode` does.
147- inline size_t PeekNode (const void * pos, std::vector<void *>& out) {
148- uintptr_t elem;
149- memcpy (&elem, pos, sizeof (elem));
150- out.push_back (reinterpret_cast <void *>(elem & ~3 ));
151- if (EnableSpecializedTags ()) {
152- switch (static_cast <Tag>(elem & 3 )) {
153- case Tag::kString :
154- case Tag::kCord :
155- return sizeof (TaggedNode);
156-
157- case Tag::kDynamic :
158- default :
159- break ;
160- }
161- }
162- return sizeof (DynamicNode);
163- }
164-
165- // Returns the `tag` identifying the type of object for `destructor` or
166- // kDynamic if `destructor` does not identify a well know object type.
167- inline ABSL_ATTRIBUTE_ALWAYS_INLINE Tag Type (void (*destructor)(void *)) {
168- if (EnableSpecializedTags ()) {
169- if (destructor == &arena_destruct_object<std::string>) {
170- return Tag::kString ;
171- }
172- if (destructor == &arena_destruct_object<absl::Cord>) {
173- return Tag::kCord ;
174- }
175- }
176- return Tag::kDynamic ;
177- }
178-
179- // Returns the required size in bytes off the node type identified by `tag`.
180- inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size (Tag tag) {
181- if (!EnableSpecializedTags ()) return sizeof (DynamicNode);
182-
183- switch (tag) {
184- case Tag::kDynamic :
185- return sizeof (DynamicNode);
186- case Tag::kString :
187- return sizeof (TaggedNode);
188- case Tag::kCord :
189- return sizeof (TaggedNode);
190- default :
191- ABSL_DCHECK (false ) << " Corrupted cleanup tag: " << static_cast <int >(tag);
192- return sizeof (DynamicNode);
193- }
66+ inline void PeekNode (void * pos, std::vector<void *>& out) {
67+ out.push_back (ToCleanup (pos)->elem );
19468}
19569
196- // Returns the required size in bytes off the node type for `destructor` .
197- inline ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size (void (*destructor)( void *) ) {
198- return destructor == nullptr ? 0 : Size ( Type (destructor) );
70+ // Returns the required size for a cleanup node.
71+ constexpr ABSL_ATTRIBUTE_ALWAYS_INLINE size_t Size () {
72+ return sizeof (CleanupNode );
19973}
20074
20175} // namespace cleanup
0 commit comments