Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d121d71

Browse files
authoredNov 22, 2024··
[libc][NFC] Remove template arguments from Block (#117386)
1 parent b4e000e commit d121d71

File tree

12 files changed

+293
-372
lines changed

12 files changed

+293
-372
lines changed
 

‎libc/src/__support/block.h

Lines changed: 59 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,11 @@ using cpp::optional;
6868
/// The blocks store their offsets to the previous and next blocks. The latter
6969
/// is also the block's size.
7070
///
71-
/// The `ALIGNMENT` constant provided by the derived block is typically the
72-
/// minimum value of `alignof(OffsetType)`. Blocks will always be aligned to a
73-
/// `ALIGNMENT` boundary. Block sizes will always be rounded up to a multiple of
74-
/// `ALIGNMENT`.
71+
/// Blocks will always be aligned to a `ALIGNMENT` boundary. Block sizes will
72+
/// always be rounded up to a multiple of `ALIGNMENT`.
7573
///
76-
/// As an example, the diagram below represents two contiguous
77-
/// `Block<uint32_t, 8>`s. The indices indicate byte offsets:
74+
/// As an example, the diagram below represents two contiguous `Block`s. The
75+
/// indices indicate byte offsets:
7876
///
7977
/// @code{.unparsed}
8078
/// Block 1:
@@ -117,30 +115,15 @@ using cpp::optional;
117115
///
118116
/// The next offset of a block matches the previous offset of its next block.
119117
/// The first block in a list is denoted by having a previous offset of `0`.
120-
///
121-
/// @tparam OffsetType Unsigned integral type used to encode offsets. Larger
122-
/// types can address more memory, but consume greater
123-
/// overhead.
124-
/// @tparam kAlign Sets the overall alignment for blocks. Minimum is
125-
/// `alignof(OffsetType)`, but the default is max_align_t,
126-
/// since the usable space will then already be
127-
/// aligned to max_align_t if the size of OffsetType is no
128-
/// less than half of max_align_t. Larger values cause
129-
/// greater overhead.
130-
template <typename OffsetType = uintptr_t, size_t kAlign = alignof(max_align_t)>
131118
class Block {
132119
// Masks for the contents of the next_ field.
133120
static constexpr size_t PREV_FREE_MASK = 1 << 0;
134121
static constexpr size_t LAST_MASK = 1 << 1;
135122
static constexpr size_t SIZE_MASK = ~(PREV_FREE_MASK | LAST_MASK);
136123

137124
public:
138-
using offset_type = OffsetType;
139-
static_assert(cpp::is_unsigned_v<offset_type>,
140-
"offset type must be unsigned");
141-
static constexpr size_t ALIGNMENT =
142-
cpp::max(cpp::max(kAlign, alignof(offset_type)), size_t{4});
143-
static constexpr size_t BLOCK_OVERHEAD = align_up(sizeof(Block), ALIGNMENT);
125+
static constexpr size_t ALIGNMENT = cpp::max(alignof(max_align_t), size_t{4});
126+
static const size_t BLOCK_OVERHEAD;
144127

145128
// No copy or move.
146129
Block(const Block &other) = delete;
@@ -157,61 +140,61 @@ class Block {
157140
///
158141
/// @warning This method does not do any checking; passing a random
159142
/// pointer will return a non-null pointer.
160-
static Block *from_usable_space(void *usable_space) {
143+
LIBC_INLINE static Block *from_usable_space(void *usable_space) {
161144
auto *bytes = reinterpret_cast<cpp::byte *>(usable_space);
162145
return reinterpret_cast<Block *>(bytes - BLOCK_OVERHEAD);
163146
}
164-
static const Block *from_usable_space(const void *usable_space) {
147+
LIBC_INLINE static const Block *from_usable_space(const void *usable_space) {
165148
const auto *bytes = reinterpret_cast<const cpp::byte *>(usable_space);
166149
return reinterpret_cast<const Block *>(bytes - BLOCK_OVERHEAD);
167150
}
168151

169152
/// @returns The total size of the block in bytes, including the header.
170-
size_t outer_size() const { return next_ & SIZE_MASK; }
153+
LIBC_INLINE size_t outer_size() const { return next_ & SIZE_MASK; }
171154

172-
static size_t outer_size(size_t inner_size) {
155+
LIBC_INLINE static size_t outer_size(size_t inner_size) {
173156
// The usable region includes the prev_ field of the next block.
174157
return inner_size - sizeof(prev_) + BLOCK_OVERHEAD;
175158
}
176159

177160
/// @returns The number of usable bytes inside the block were it to be
178161
/// allocated.
179-
size_t inner_size() const {
162+
LIBC_INLINE size_t inner_size() const {
180163
if (!next())
181164
return 0;
182165
return inner_size(outer_size());
183166
}
184167

185168
/// @returns The number of usable bytes inside a block with the given outer
186169
/// size were it to be allocated.
187-
static size_t inner_size(size_t outer_size) {
170+
LIBC_INLINE static size_t inner_size(size_t outer_size) {
188171
// The usable region includes the prev_ field of the next block.
189172
return inner_size_free(outer_size) + sizeof(prev_);
190173
}
191174

192175
/// @returns The number of usable bytes inside the block if it remains free.
193-
size_t inner_size_free() const {
176+
LIBC_INLINE size_t inner_size_free() const {
194177
if (!next())
195178
return 0;
196179
return inner_size_free(outer_size());
197180
}
198181

199182
/// @returns The number of usable bytes inside a block with the given outer
200183
/// size if it remains free.
201-
static size_t inner_size_free(size_t outer_size) {
184+
LIBC_INLINE static size_t inner_size_free(size_t outer_size) {
202185
return outer_size - BLOCK_OVERHEAD;
203186
}
204187

205188
/// @returns A pointer to the usable space inside this block.
206-
cpp::byte *usable_space() {
189+
LIBC_INLINE cpp::byte *usable_space() {
207190
return reinterpret_cast<cpp::byte *>(this) + BLOCK_OVERHEAD;
208191
}
209-
const cpp::byte *usable_space() const {
192+
LIBC_INLINE const cpp::byte *usable_space() const {
210193
return reinterpret_cast<const cpp::byte *>(this) + BLOCK_OVERHEAD;
211194
}
212195

213196
// @returns The region of memory the block manages, including the header.
214-
ByteSpan region() {
197+
LIBC_INLINE ByteSpan region() {
215198
return {reinterpret_cast<cpp::byte *>(this), outer_size()};
216199
}
217200

@@ -229,42 +212,53 @@ class Block {
229212

230213
/// @returns The block immediately after this one, or a null pointer if this
231214
/// is the last block.
232-
Block *next() const;
215+
LIBC_INLINE Block *next() const {
216+
if (next_ & LAST_MASK)
217+
return nullptr;
218+
return reinterpret_cast<Block *>(reinterpret_cast<uintptr_t>(this) +
219+
outer_size());
220+
}
233221

234222
/// @returns The free block immediately before this one, otherwise nullptr.
235-
Block *prev_free() const;
223+
LIBC_INLINE Block *prev_free() const {
224+
if (!(next_ & PREV_FREE_MASK))
225+
return nullptr;
226+
return reinterpret_cast<Block *>(reinterpret_cast<uintptr_t>(this) - prev_);
227+
}
236228

237229
/// @returns Whether the block is unavailable for allocation.
238-
bool used() const { return !next() || !next()->prev_free(); }
230+
LIBC_INLINE bool used() const { return !next() || !next()->prev_free(); }
239231

240232
/// Marks this block as in use.
241-
void mark_used() {
233+
LIBC_INLINE void mark_used() {
242234
LIBC_ASSERT(next() && "last block is always considered used");
243235
next()->next_ &= ~PREV_FREE_MASK;
244236
}
245237

246238
/// Marks this block as free.
247-
void mark_free() {
239+
LIBC_INLINE void mark_free() {
248240
LIBC_ASSERT(next() && "last block is always considered used");
249241
next()->next_ |= PREV_FREE_MASK;
250242
// The next block's prev_ field becomes alive, as it is no longer part of
251243
// this block's used space.
252-
*new (&next()->prev_) offset_type = outer_size();
244+
*new (&next()->prev_) size_t = outer_size();
253245
}
254246

255247
/// Marks this block as the last one in the chain. Makes next() return
256248
/// nullptr.
257-
void mark_last() { next_ |= LAST_MASK; }
249+
LIBC_INLINE void mark_last() { next_ |= LAST_MASK; }
258250

259-
constexpr Block(size_t outer_size);
251+
LIBC_INLINE constexpr Block(size_t outer_size) : next_(outer_size) {
252+
LIBC_ASSERT(outer_size % ALIGNMENT == 0 && "block sizes must be aligned");
253+
}
260254

261-
bool is_usable_space_aligned(size_t alignment) const {
255+
LIBC_INLINE bool is_usable_space_aligned(size_t alignment) const {
262256
return reinterpret_cast<uintptr_t>(usable_space()) % alignment == 0;
263257
}
264258

265259
/// @returns The new inner size of this block that would give the usable
266260
/// space of the next block the given alignment.
267-
size_t padding_for_alignment(size_t alignment) const {
261+
LIBC_INLINE size_t padding_for_alignment(size_t alignment) const {
268262
if (is_usable_space_aligned(alignment))
269263
return 0;
270264

@@ -322,7 +316,9 @@ class Block {
322316
private:
323317
/// Construct a block to represent a span of bytes. Overwrites only enough
324318
/// memory for the block header; the rest of the span is left alone.
325-
static Block *as_block(ByteSpan bytes);
319+
LIBC_INLINE static Block *as_block(ByteSpan bytes) {
320+
return ::new (bytes.data()) Block(bytes.size());
321+
}
326322

327323
/// Like `split`, but assumes the caller has already checked to parameters to
328324
/// ensure the split will succeed.
@@ -332,11 +328,11 @@ class Block {
332328
/// block. This field is only alive when the previous block is free;
333329
/// otherwise, its memory is reused as part of the previous block's usable
334330
/// space.
335-
offset_type prev_ = 0;
331+
size_t prev_ = 0;
336332

337333
/// Offset from this block to the next block. Valid even if this is the last
338334
/// block, since it equals the size of the block.
339-
offset_type next_ = 0;
335+
size_t next_ = 0;
340336

341337
/// Information about the current state of the block is stored in the two low
342338
/// order bits of the next_ value. These are guaranteed free by a minimum
@@ -347,9 +343,10 @@ class Block {
347343
/// previous block is free.
348344
/// * If the `last` flag is set, the block is the sentinel last block. It is
349345
/// summarily considered used and has no next block.
350-
} __attribute__((packed, aligned(cpp::max(kAlign, size_t{4}))));
346+
} __attribute__((packed, aligned(cpp::max(alignof(max_align_t), size_t{4}))));
351347

352-
// Public template method implementations.
348+
inline constexpr size_t Block::BLOCK_OVERHEAD =
349+
align_up(sizeof(Block), ALIGNMENT);
353350

354351
LIBC_INLINE ByteSpan get_aligned_subspan(ByteSpan bytes, size_t alignment) {
355352
if (bytes.data() == nullptr)
@@ -367,9 +364,8 @@ LIBC_INLINE ByteSpan get_aligned_subspan(ByteSpan bytes, size_t alignment) {
367364
aligned_end - aligned_start);
368365
}
369366

370-
template <typename OffsetType, size_t kAlign>
371-
optional<Block<OffsetType, kAlign> *>
372-
Block<OffsetType, kAlign>::init(ByteSpan region) {
367+
LIBC_INLINE
368+
optional<Block *> Block::init(ByteSpan region) {
373369
optional<ByteSpan> result = get_aligned_subspan(region, ALIGNMENT);
374370
if (!result)
375371
return {};
@@ -379,7 +375,7 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
379375
if (region.size() < 2 * BLOCK_OVERHEAD)
380376
return {};
381377

382-
if (cpp::numeric_limits<OffsetType>::max() < region.size())
378+
if (cpp::numeric_limits<size_t>::max() < region.size())
383379
return {};
384380

385381
Block *block = as_block(region.first(region.size() - BLOCK_OVERHEAD));
@@ -389,9 +385,8 @@ Block<OffsetType, kAlign>::init(ByteSpan region) {
389385
return block;
390386
}
391387

392-
template <typename OffsetType, size_t kAlign>
393-
bool Block<OffsetType, kAlign>::can_allocate(size_t alignment,
394-
size_t size) const {
388+
LIBC_INLINE
389+
bool Block::can_allocate(size_t alignment, size_t size) const {
395390
if (inner_size() < size)
396391
return false;
397392
if (is_usable_space_aligned(alignment))
@@ -406,10 +401,8 @@ bool Block<OffsetType, kAlign>::can_allocate(size_t alignment,
406401
return size <= aligned_inner_size;
407402
}
408403

409-
template <typename OffsetType, size_t kAlign>
410-
typename Block<OffsetType, kAlign>::BlockInfo
411-
Block<OffsetType, kAlign>::allocate(Block *block, size_t alignment,
412-
size_t size) {
404+
LIBC_INLINE
405+
Block::BlockInfo Block::allocate(Block *block, size_t alignment, size_t size) {
413406
LIBC_ASSERT(
414407
block->can_allocate(alignment, size) &&
415408
"Calls to this function for a given alignment and size should only be "
@@ -447,9 +440,8 @@ Block<OffsetType, kAlign>::allocate(Block *block, size_t alignment,
447440
return info;
448441
}
449442

450-
template <typename OffsetType, size_t kAlign>
451-
optional<Block<OffsetType, kAlign> *>
452-
Block<OffsetType, kAlign>::split(size_t new_inner_size) {
443+
LIBC_INLINE
444+
optional<Block *> Block::split(size_t new_inner_size) {
453445
if (used())
454446
return {};
455447
// The prev_ field of the next block is always available, so there is a
@@ -469,9 +461,8 @@ Block<OffsetType, kAlign>::split(size_t new_inner_size) {
469461
return split_impl(new_inner_size);
470462
}
471463

472-
template <typename OffsetType, size_t kAlign>
473-
Block<OffsetType, kAlign> *
474-
Block<OffsetType, kAlign>::split_impl(size_t new_inner_size) {
464+
LIBC_INLINE
465+
Block *Block::split_impl(size_t new_inner_size) {
475466
size_t outer_size1 = outer_size(new_inner_size);
476467
LIBC_ASSERT(outer_size1 % ALIGNMENT == 0 && "new size must be aligned");
477468
ByteSpan new_region = region().subspan(outer_size1);
@@ -484,8 +475,8 @@ Block<OffsetType, kAlign>::split_impl(size_t new_inner_size) {
484475
return new_block;
485476
}
486477

487-
template <typename OffsetType, size_t kAlign>
488-
bool Block<OffsetType, kAlign>::merge_next() {
478+
LIBC_INLINE
479+
bool Block::merge_next() {
489480
if (used() || next()->used())
490481
return false;
491482
size_t new_size = outer_size() + next()->outer_size();
@@ -495,34 +486,6 @@ bool Block<OffsetType, kAlign>::merge_next() {
495486
return true;
496487
}
497488

498-
template <typename OffsetType, size_t kAlign>
499-
Block<OffsetType, kAlign> *Block<OffsetType, kAlign>::next() const {
500-
if (next_ & LAST_MASK)
501-
return nullptr;
502-
return reinterpret_cast<Block *>(reinterpret_cast<uintptr_t>(this) +
503-
outer_size());
504-
}
505-
506-
template <typename OffsetType, size_t kAlign>
507-
Block<OffsetType, kAlign> *Block<OffsetType, kAlign>::prev_free() const {
508-
if (!(next_ & PREV_FREE_MASK))
509-
return nullptr;
510-
return reinterpret_cast<Block *>(reinterpret_cast<uintptr_t>(this) - prev_);
511-
}
512-
513-
// Private template method implementations.
514-
515-
template <typename OffsetType, size_t kAlign>
516-
constexpr Block<OffsetType, kAlign>::Block(size_t outer_size)
517-
: next_(outer_size) {
518-
LIBC_ASSERT(outer_size % ALIGNMENT == 0 && "block sizes must be aligned");
519-
}
520-
521-
template <typename OffsetType, size_t kAlign>
522-
Block<OffsetType, kAlign> *Block<OffsetType, kAlign>::as_block(ByteSpan bytes) {
523-
return ::new (bytes.data()) Block(bytes.size());
524-
}
525-
526489
} // namespace LIBC_NAMESPACE_DECL
527490

528491
#endif // LLVM_LIBC_SRC___SUPPORT_BLOCK_H

‎libc/src/__support/freelist.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace LIBC_NAMESPACE_DECL {
1212

1313
void FreeList::push(Node *node) {
1414
if (begin_) {
15-
LIBC_ASSERT(Block<>::from_usable_space(node)->outer_size() ==
15+
LIBC_ASSERT(Block::from_usable_space(node)->outer_size() ==
1616
begin_->block()->outer_size() &&
1717
"freelist entries must have the same size");
1818
// Since the list is circular, insert the node immediately before begin_.

‎libc/src/__support/freelist.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ class FreeList {
2626
class Node {
2727
public:
2828
/// @returns The block containing this node.
29-
LIBC_INLINE const Block<> *block() const {
30-
return Block<>::from_usable_space(this);
29+
LIBC_INLINE const Block *block() const {
30+
return Block::from_usable_space(this);
3131
}
3232

3333
/// @returns The block containing this node.
34-
LIBC_INLINE Block<> *block() { return Block<>::from_usable_space(this); }
34+
LIBC_INLINE Block *block() { return Block::from_usable_space(this); }
3535

3636
/// @returns The inner size of blocks in the list containing this node.
3737
LIBC_INLINE size_t size() const { return block()->inner_size(); }
@@ -58,11 +58,11 @@ class FreeList {
5858
LIBC_INLINE Node *begin() { return begin_; }
5959

6060
/// @returns The first block in the list.
61-
LIBC_INLINE Block<> *front() { return begin_->block(); }
61+
LIBC_INLINE Block *front() { return begin_->block(); }
6262

6363
/// Push a block to the back of the list.
6464
/// The block must be large enough to contain a node.
65-
LIBC_INLINE void push(Block<> *block) {
65+
LIBC_INLINE void push(Block *block) {
6666
LIBC_ASSERT(!block->used() &&
6767
"only free blocks can be placed on free lists");
6868
LIBC_ASSERT(block->inner_size_free() >= sizeof(FreeList) &&

0 commit comments

Comments
 (0)
Please sign in to comment.