@@ -33,169 +33,43 @@ void arena_destruct_object(void* object) {
33
33
reinterpret_cast <T*>(object)->~T ();
34
34
}
35
35
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
46
37
// destroyed, and the function to destroy it (`destructor`)
47
38
// elem must be aligned at minimum on a 4 byte boundary.
48
- struct DynamicNode {
49
- uintptr_t elem;
39
+ struct CleanupNode {
40
+ void * elem;
50
41
void (*destructor)(void *);
51
42
};
52
43
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);
65
46
}
66
47
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,
70
50
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};
92
52
memcpy (pos, &n, sizeof (n));
93
53
}
94
54
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) {
109
57
}
110
58
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 );
142
63
}
143
64
144
65
// 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 );
194
68
}
195
69
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 );
199
73
}
200
74
201
75
} // namespace cleanup
0 commit comments