diff options
Diffstat (limited to 'src/allocator.h')
-rw-r--r-- | src/allocator.h | 65 |
1 files changed, 37 insertions, 28 deletions
diff --git a/src/allocator.h b/src/allocator.h index 363ee91..b4dee5a 100644 --- a/src/allocator.h +++ b/src/allocator.h @@ -33,6 +33,7 @@ #include <cassert> #include <utility> +#include <span> #include "template.h" @@ -48,6 +49,18 @@ struct MemBlock { uint8_t *begin, *last, *end; }; +static_assert((sizeof(MemBlock) & 0xf) == 0); + +struct ChunkHead { + union { + size_t size; + uint64_t pad1; + }; + uint64_t pad2; +}; + +static_assert(sizeof(ChunkHead) == 16); + // BlockAllocator allocates memory block with given size at once, and // cuts the region from it when allocation is requested. If the // requested size is larger than given threshold (plus small internal @@ -88,7 +101,7 @@ struct BlockAllocator { void reset() { for (auto mb = retain; mb;) { auto next = mb->next; - delete[] reinterpret_cast<uint8_t *>(mb); + operator delete[](reinterpret_cast<uint8_t *>(mb), std::align_val_t(16)); mb = next; } @@ -97,36 +110,40 @@ struct BlockAllocator { } MemBlock *alloc_mem_block(size_t size) { - auto block = new uint8_t[sizeof(MemBlock) + size]; + auto block = new (std::align_val_t(16)) uint8_t[sizeof(MemBlock) + size]; auto mb = reinterpret_cast<MemBlock *>(block); mb->next = retain; - mb->begin = mb->last = block + sizeof(MemBlock); + mb->begin = mb->last = reinterpret_cast<uint8_t *>( + (reinterpret_cast<intptr_t>(block + sizeof(MemBlock)) + 0xf) & ~0xf); mb->end = mb->begin + size; retain = mb; return mb; } + constexpr size_t alloc_unit(size_t size) { return sizeof(ChunkHead) + size; } + void *alloc(size_t size) { - if (size + sizeof(size_t) >= isolation_threshold) { - auto len = std::max(static_cast<size_t>(16), size); + auto au = alloc_unit(size); + + if (au >= isolation_threshold) { + size = std::max(static_cast<size_t>(16), size); // We will store the allocated size in size_t field. - auto mb = alloc_mem_block(len + sizeof(size_t)); - auto sp = reinterpret_cast<size_t *>(mb->begin); - *sp = len; + auto mb = alloc_mem_block(alloc_unit(size)); + auto ch = reinterpret_cast<ChunkHead *>(mb->begin); + ch->size = size; mb->last = mb->end; - return mb->begin + sizeof(size_t); + return mb->begin + sizeof(ChunkHead); } - if (!head || - static_cast<size_t>(head->end - head->last) < size + sizeof(size_t)) { + if (!head || static_cast<size_t>(head->end - head->last) < au) { head = alloc_mem_block(block_size); } // We will store the allocated size in size_t field. - auto res = head->last + sizeof(size_t); - auto sp = reinterpret_cast<size_t *>(head->last); - *sp = size; + auto res = head->last + sizeof(ChunkHead); + auto ch = reinterpret_cast<ChunkHead *>(head->last); + ch->size = size; head->last = reinterpret_cast<uint8_t *>( (reinterpret_cast<intptr_t>(res + size) + 0xf) & ~0xf); @@ -137,8 +154,9 @@ struct BlockAllocator { // Returns allocated size for memory pointed by |ptr|. We assume // that |ptr| was returned from alloc() or realloc(). size_t get_alloc_length(void *ptr) { - return *reinterpret_cast<size_t *>(static_cast<uint8_t *>(ptr) - - sizeof(size_t)); + return reinterpret_cast<ChunkHead *>(static_cast<uint8_t *>(ptr) - + sizeof(ChunkHead)) + ->size; } // Allocates memory of at least |size| bytes. If |ptr| is nullptr, @@ -253,19 +271,10 @@ StringRef realloc_concat_string_ref(BlockAllocator &alloc, return StringRef{dst, len}; } -struct ByteRef { - // The pointer to the beginning of the buffer. - uint8_t *base; - // The length of the buffer. - size_t len; -}; - -// Makes a buffer with given size. The resulting byte string might -// not be NULL-terminated. +// Makes an uninitialized buffer with given size. template <typename BlockAllocator> -ByteRef make_byte_ref(BlockAllocator &alloc, size_t size) { - auto dst = static_cast<uint8_t *>(alloc.alloc(size)); - return {dst, size}; +std::span<uint8_t> make_byte_ref(BlockAllocator &alloc, size_t size) { + return {static_cast<uint8_t *>(alloc.alloc(size)), size}; } } // namespace nghttp2 |