Rework allocation and oversizing of ByteBufs Always round up capacity to next multiple of eight.
Don't call Memory_oversize, but oversize by custom amount of 25%. Check for integer overflow. This should only matter on exotic platforms, but it doesn't cost much. Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/7165ca56 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/7165ca56 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/7165ca56 Branch: refs/heads/master Commit: 7165ca565d24596191eb8c417d3af1523dcf1a1d Parents: 8c4b290 Author: Nick Wellnhofer <wellnho...@aevum.de> Authored: Wed Dec 9 14:55:53 2015 +0100 Committer: Nick Wellnhofer <wellnho...@aevum.de> Committed: Wed Dec 9 15:04:01 2015 +0100 ---------------------------------------------------------------------- runtime/core/Clownfish/ByteBuf.c | 107 ++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/7165ca56/runtime/core/Clownfish/ByteBuf.c ---------------------------------------------------------------------- diff --git a/runtime/core/Clownfish/ByteBuf.c b/runtime/core/Clownfish/ByteBuf.c index 3ab5ddd..14ede6f 100644 --- a/runtime/core/Clownfish/ByteBuf.c +++ b/runtime/core/Clownfish/ByteBuf.c @@ -29,8 +29,21 @@ #include "Clownfish/String.h" #include "Clownfish/Util/Memory.h" +// Ensure that the ByteBuf's capacity is at least (size + extra). +// If the buffer must be grown, oversize the allocation. +static CFISH_INLINE void +SI_add_grow_and_oversize(ByteBuf *self, size_t size, size_t extra); + +// Compilers tend to inline this function although this is the unlikely +// slow path. If we ever add cross-platform support for the noinline +// attribute, it should be marked as such to reduce code size. +static void +S_grow_and_oversize(ByteBuf *self, size_t min_size); + +// Not inlining the THROW macro reduces code size and complexity of +// SI_add_grow_and_oversize. static void -S_grow(ByteBuf *self, size_t size); +S_overflow_error(); ByteBuf* BB_new(size_t capacity) { @@ -39,12 +52,15 @@ BB_new(size_t capacity) { } ByteBuf* -BB_init(ByteBuf *self, size_t capacity) { - size_t amount = capacity ? capacity : sizeof(int64_t); - self->buf = NULL; - self->size = 0; - self->cap = 0; - S_grow(self, amount); +BB_init(ByteBuf *self, size_t min_cap) { + // Round up to next multiple of eight. + size_t capacity = (min_cap + 7) & ~7; + // Check for overflow. + if (capacity < min_cap) { capacity = SIZE_MAX; } + + self->buf = (char*)MALLOCATE(capacity); + self->size = 0; + self->cap = capacity; return self; } @@ -56,9 +72,15 @@ BB_new_bytes(const void *bytes, size_t size) { ByteBuf* BB_init_bytes(ByteBuf *self, const void *bytes, size_t size) { - BB_init(self, size); - memcpy(self->buf, bytes, size); + // Round up to next multiple of eight. + size_t capacity = (size + 7) & ~7; + // Check for overflow. + if (capacity < size) { capacity = SIZE_MAX; } + + self->buf = (char*)MALLOCATE(capacity); self->size = size; + self->cap = capacity; + memcpy(self->buf, bytes, size); return self; } @@ -133,12 +155,9 @@ BB_Equals_Bytes_IMP(ByteBuf *self, const void *bytes, size_t size) { static CFISH_INLINE void SI_cat_bytes(ByteBuf *self, const void *bytes, size_t size) { - const size_t new_size = self->size + size; - if (new_size > self->cap) { - S_grow(self, Memory_oversize(new_size, sizeof(char))); - } - memcpy((self->buf + self->size), bytes, size); - self->size = new_size; + SI_add_grow_and_oversize(self, self->size, size); + memcpy(self->buf + self->size, bytes, size); + self->size += size; } void @@ -151,23 +170,18 @@ BB_Cat_IMP(ByteBuf *self, Blob *blob) { SI_cat_bytes(self, Blob_Get_Buf(blob), Blob_Get_Size(blob)); } -static void -S_grow(ByteBuf *self, size_t size) { - if (size > self->cap) { - size_t amount = size; - size_t remainder = amount % sizeof(int64_t); - if (remainder) { - amount += sizeof(int64_t); - amount -= remainder; - } - self->buf = (char*)REALLOCATE(self->buf, amount); - self->cap = amount; +char* +BB_Grow_IMP(ByteBuf *self, size_t min_cap) { + if (min_cap > self->cap) { + // Round up to next multiple of eight. + size_t capacity = (min_cap + 7) & ~7; + // Check for overflow. + if (capacity < min_cap) { capacity = SIZE_MAX; } + + self->buf = (char*)REALLOCATE(self->buf, capacity); + self->cap = capacity; } -} -char* -BB_Grow_IMP(ByteBuf *self, size_t size) { - if (size > self->cap) { S_grow(self, size); } return self->buf; } @@ -204,4 +218,37 @@ BB_Compare_To_IMP(ByteBuf *self, Obj *other) { return comparison; } +static CFISH_INLINE void +SI_add_grow_and_oversize(ByteBuf *self, size_t size, size_t extra) { + size_t min_size = size + extra; + if (min_size < size) { + S_overflow_error(); + return; + } + + if (min_size > self->cap) { + S_grow_and_oversize(self, min_size); + } +} + +static void +S_grow_and_oversize(ByteBuf *self, size_t min_size) { + // Oversize by 25%, but at least eight bytes. + size_t extra = min_size / 4; + // Round up to next multiple of eight. + extra = (extra + 7) & ~7; + + size_t capacity = min_size + extra; + // Check for overflow. + if (capacity < min_size) { capacity = SIZE_MAX; } + + self->buf = (char*)REALLOCATE(self->buf, capacity); + self->cap = capacity; +} + +static void +S_overflow_error() { + THROW(ERR, "ByteBuf buffer overflow"); +} +