Skip to content

Commit 71ceb75

Browse files
committed
[WIP][libc] Add freelist malloc
1 parent d6bbe2e commit 71ceb75

File tree

13 files changed

+620
-43
lines changed

13 files changed

+620
-43
lines changed

libc/config/baremetal/riscv/entrypoints.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ set(TARGET_LIBC_ENTRYPOINTS
170170
libc.src.stdlib.ldiv
171171
libc.src.stdlib.llabs
172172
libc.src.stdlib.lldiv
173+
libc.src.stdlib.malloc
173174
libc.src.stdlib.qsort
174175
libc.src.stdlib.rand
175176
libc.src.stdlib.srand

libc/src/__support/fixedvector.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ template <typename T, size_t CAPACITY> class FixedVector {
2525
constexpr FixedVector() = default;
2626

2727
using iterator = typename cpp::array<T, CAPACITY>::iterator;
28-
constexpr FixedVector(iterator begin, iterator end) {
28+
constexpr FixedVector(iterator begin, iterator end) : store{} {
2929
for (; begin != end; ++begin)
3030
push_back(*begin);
3131
}
3232

33-
constexpr FixedVector(size_t count, const T &value) {
33+
constexpr FixedVector(size_t count, const T &value) : store{} {
3434
for (size_t i = 0; i < count; ++i)
3535
push_back(value);
3636
}
3737

38-
bool push_back(const T &obj) {
38+
constexpr bool push_back(const T &obj) {
3939
if (item_count == CAPACITY)
4040
return false;
4141
store[item_count] = obj;
@@ -54,13 +54,13 @@ template <typename T, size_t CAPACITY> class FixedVector {
5454
return true;
5555
}
5656

57-
T &operator[](size_t idx) { return store[idx]; }
57+
constexpr T &operator[](size_t idx) { return store[idx]; }
5858

59-
const T &operator[](size_t idx) const { return store[idx]; }
59+
constexpr const T &operator[](size_t idx) const { return store[idx]; }
6060

6161
bool empty() const { return item_count == 0; }
6262

63-
size_t size() const { return item_count; }
63+
constexpr size_t size() const { return item_count; }
6464

6565
// Empties the store for all practical purposes.
6666
void reset() { item_count = 0; }

libc/src/__support/macros/attributes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,10 @@
3030
#define LIBC_THREAD_LOCAL thread_local
3131
#endif
3232

33+
#if __cplusplus >= 202002L
34+
#define LIBC_CONSTINIT constinit
35+
#else
36+
#define LIBC_CONSTINIT __attribute__((__require_constant_initialization__))
37+
#endif
38+
3339
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H

libc/src/__support/threads/thread.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ class ThreadAtExitCallbackMgr {
115115
public:
116116
constexpr ThreadAtExitCallbackMgr()
117117
: mtx(/*timed=*/false, /*recursive=*/false, /*robust=*/false,
118-
/*pshared=*/false) {}
118+
/*pshared=*/false),
119+
callback_list() {}
119120

120121
int add_callback(AtExitCallback *callback, void *obj) {
121122
cpp::lock_guard lock(mtx);

libc/src/stdlib/CMakeLists.txt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,24 @@ else()
401401
libc.src.__support.CPP.cstddef
402402
libc.src.__support.CPP.array
403403
libc.src.__support.CPP.span
404+
libc.src.stdio.printf
404405
)
405-
add_entrypoint_external(
406+
add_entrypoint_object(
406407
malloc
408+
SRCS
409+
freelist_malloc.cpp
410+
HDRS
411+
malloc.h
412+
DEPENDS
413+
.block
414+
.freelist
415+
libc.src.__support.CPP.new
416+
libc.src.__support.CPP.optional
417+
libc.src.__support.CPP.span
418+
libc.src.__support.CPP.type_traits
419+
libc.src.__support.fixedvector
420+
libc.src.string.memcpy
421+
libc.src.string.memset
407422
)
408423
add_entrypoint_external(
409424
free

libc/src/stdlib/block.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class Block {
245245
void mark_free() { info_.used = 0; }
246246

247247
/// Marks this block as the last one in the chain.
248-
void mark_last() { info_.last = 1; }
248+
constexpr void mark_last() { info_.last = 1; }
249249

250250
/// Clears the last bit from this block.
251251
void clear_last() { info_.last = 1; }
@@ -259,15 +259,15 @@ class Block {
259259
return check_status() == internal::BlockStatus::VALID;
260260
}
261261

262+
constexpr Block(size_t prev_outer_size, size_t outer_size);
263+
262264
private:
263265
/// Consumes the block and returns as a span of bytes.
264266
static ByteSpan as_bytes(Block *&&block);
265267

266268
/// Consumes the span of bytes and uses it to construct and return a block.
267269
static Block *as_block(size_t prev_outer_size, ByteSpan bytes);
268270

269-
Block(size_t prev_outer_size, size_t outer_size);
270-
271271
/// Returns a `BlockStatus` that is either VALID or indicates the reason why
272272
/// the block is invalid.
273273
///
@@ -442,7 +442,9 @@ Block<OffsetType, kAlign> *Block<OffsetType, kAlign>::prev() const {
442442
// Private template method implementations.
443443

444444
template <typename OffsetType, size_t kAlign>
445-
Block<OffsetType, kAlign>::Block(size_t prev_outer_size, size_t outer_size) {
445+
constexpr Block<OffsetType, kAlign>::Block(size_t prev_outer_size,
446+
size_t outer_size)
447+
: info_{} {
446448
prev_ = prev_outer_size / ALIGNMENT;
447449
next_ = outer_size / ALIGNMENT;
448450
info_.used = 0;

libc/src/stdlib/freelist.h

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,43 +68,53 @@ template <size_t NUM_BUCKETS = 6> class FreeList {
6868
/// Removes a chunk from this freelist.
6969
bool remove_chunk(cpp::span<cpp::byte> chunk);
7070

71-
private:
72-
// For a given size, find which index into chunks_ the node should be written
73-
// to.
74-
size_t find_chunk_ptr_for_size(size_t size, bool non_null) const;
71+
/// For a given size, find which index into chunks_ the node should be written
72+
/// to.
73+
constexpr size_t find_chunk_ptr_for_size(size_t size, bool non_null) const;
7574

7675
struct FreeListNode {
7776
FreeListNode *next;
7877
size_t size;
7978
};
8079

81-
public:
82-
explicit FreeList(cpp::array<size_t, NUM_BUCKETS> sizes)
80+
constexpr void set_freelist_node(FreeListNode *node,
81+
cpp::span<cpp::byte> chunk);
82+
83+
constexpr explicit FreeList(cpp::array<size_t, NUM_BUCKETS> sizes)
8384
: chunks_(NUM_BUCKETS + 1, 0), sizes_(sizes.begin(), sizes.end()) {}
8485

86+
private:
8587
FixedVector<FreeList::FreeListNode *, NUM_BUCKETS + 1> chunks_;
8688
FixedVector<size_t, NUM_BUCKETS> sizes_;
8789
};
8890

91+
template <size_t NUM_BUCKETS>
92+
constexpr void FreeList<NUM_BUCKETS>::set_freelist_node(FreeListNode *node,
93+
span<cpp::byte> chunk) {
94+
// Add it to the correct list.
95+
size_t chunk_ptr = find_chunk_ptr_for_size(chunk.size(), false);
96+
node->size = chunk.size();
97+
node->next = chunks_[chunk_ptr];
98+
chunks_[chunk_ptr] = node;
99+
}
100+
89101
template <size_t NUM_BUCKETS>
90102
bool FreeList<NUM_BUCKETS>::add_chunk(span<cpp::byte> chunk) {
91103
// Check that the size is enough to actually store what we need
92104
if (chunk.size() < sizeof(FreeListNode))
93105
return false;
94106

107+
// FIXME: This is UB since type punning is not allowed in C++. THe idea here
108+
// is that we write the FreeListNode `size` and `next` onto the start of the
109+
// buffer. Unless the original underlying bytes were a `FreeListNode`, the
110+
// only safe way to do this is with `memcpy`.
95111
union {
96112
FreeListNode *node;
97113
cpp::byte *bytes;
98114
} aliased;
99115

100116
aliased.bytes = chunk.data();
101-
102-
size_t chunk_ptr = find_chunk_ptr_for_size(chunk.size(), false);
103-
104-
// Add it to the correct list.
105-
aliased.node->size = chunk.size();
106-
aliased.node->next = chunks_[chunk_ptr];
107-
chunks_[chunk_ptr] = aliased.node;
117+
set_freelist_node(aliased.node, chunk);
108118

109119
return true;
110120
}
@@ -180,8 +190,9 @@ bool FreeList<NUM_BUCKETS>::remove_chunk(span<cpp::byte> chunk) {
180190
}
181191

182192
template <size_t NUM_BUCKETS>
183-
size_t FreeList<NUM_BUCKETS>::find_chunk_ptr_for_size(size_t size,
184-
bool non_null) const {
193+
constexpr size_t
194+
FreeList<NUM_BUCKETS>::find_chunk_ptr_for_size(size_t size,
195+
bool non_null) const {
185196
size_t chunk_ptr = 0;
186197
for (chunk_ptr = 0u; chunk_ptr < sizes_.size(); chunk_ptr++) {
187198
if (sizes_[chunk_ptr] >= size &&

0 commit comments

Comments
 (0)