Skip to content

Commit

Permalink
Clean up assorted things
Browse files Browse the repository at this point in the history
  • Loading branch information
andy-byers committed Aug 14, 2024
1 parent 9bba796 commit 6f94738
Show file tree
Hide file tree
Showing 22 changed files with 410 additions and 1,013 deletions.
178 changes: 56 additions & 122 deletions src/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
#include "mem.h"

#define MIN_RUNTIME_SIZE (32 * 1024)
#define MIN_HEAP_SIZE (aligned(sizeof(struct BlockAllocator)) + \
aligned(sizeof(struct FastBins)) + \
#define MIN_HEAP_SIZE (aligned(sizeof(struct Allocator)) + \
MIN_RUNTIME_SIZE)

#define OS_MALLOC(P, size) ((P)->alloc((P)->ud, NULL, 0, size))
Expand All @@ -19,11 +18,6 @@
#define BUMP(p, n) ERASE_TYPE(CAST_UPTR(p) + (n))
#define ERASE_TYPE(p) CAST(p, void *)

static inline paw_Bool is_pow2(size_t v)
{
return v > 0 && !(v & (v >> 1));
}

static inline paw_Bool is_aligned(void *p, size_t align)
{
return !(CAST_UPTR(p) & (align - 1));
Expand Down Expand Up @@ -51,21 +45,11 @@ void __asan_unpoison_memory_region(const volatile void *ptr, size_t size);
# define UNPOISON_MEMORY_REGION(p, z)
#endif

#define BIN_FACTOR 8
#define MIN_BIN_SIZE (sizeof(Value) * 2)
#define MAX_BIN_SIZE (MIN_BIN_SIZE * FAST_BIN_COUNT)
#define FLAGS_PER_BYTE 8

#define BIN_ID(size) CHECK_EXP((size) > 0 && aligned(size), ((size) - 1) / MIN_BIN_SIZE)
#define FLAG_BASE(H, uptr) CHECK_EXP(Z_IN_BOUNDS(H, uptr), ((uptr) - (H)->bounds[0]) / sizeof(void *))
#define FLAG_ID(base) ((base) / FLAGS_PER_BYTE)
#define FLAG_BIT(base) ((base) % FLAGS_PER_BYTE)

struct BinInfo {
struct BinInfo *prev;
char buffer[];
};

struct BlockId {
uint32_t v;
};
Expand All @@ -86,15 +70,16 @@ struct Block {
#define B_HDR(L, i) (&(L)->blocks[(i) - 1].hdr)
#define B_LIST(L, i) (&(L)->blocks[i].list)

#define BLOCK_NLISTS 61
#define MAX_SMALL 10
#define NUM_HASH 61
#define KEY_BLOCK_SHIFT 3
#define BLOCK_SIZE sizeof(struct Block)
#define BAD_BLOCK 0

// Allocator for larger regions of memory
// Based off of mem3.c from SQLite
struct BlockAllocator {
struct BlockId free[BLOCK_NLISTS];
// Allocator based off of mem3.c from SQLite
struct Allocator {
struct BlockId small[MAX_SMALL - 1];
struct BlockId hash[NUM_HASH];
struct Block *blocks;
size_t nblocks;

Expand Down Expand Up @@ -130,13 +115,10 @@ void pawZ_clear_flag(struct Heap *H, uintptr_t uptr)
*pflag = *pflag & ~(1 << FLAG_BIT(id));
}

static void *block_malloc(struct BlockAllocator *, size_t);
static void block_free(struct BlockAllocator *, void *, size_t);

static void init_block_allocator(struct BlockAllocator *a, void *heap, size_t heap_size)
static void init_block_allocator(struct Allocator *a, void *heap, size_t heap_size)
{
paw_assert(is_aligned(heap, PAW_ALIGN));
memset(a->free, 0, sizeof(a->free));
memset(a, 0, sizeof(*a));

assert(BLOCK_SIZE == 8);
a->blocks = heap;
Expand All @@ -151,13 +133,13 @@ static void init_block_allocator(struct BlockAllocator *a, void *heap, size_t he
B_HDR(a, 1 + a->nblocks)->size4x = 1;
}

static struct Block *block_at(struct BlockAllocator *a, struct BlockId id)
static struct Block *block_at(struct Allocator *a, struct BlockId id)
{
paw_assert(id.v < a->nblocks);
return &a->blocks[id.v];
}

static void unlink_from_list(struct BlockAllocator *a, struct BlockId id, struct BlockId *proot)
static void unlink_from_list(struct Allocator *a, struct BlockId id, struct BlockId *proot)
{
struct Block *b = block_at(a, id);
const struct BlockId prev = b->list.prev;
Expand All @@ -176,18 +158,22 @@ static void unlink_from_list(struct BlockAllocator *a, struct BlockId id, struct
b->list.next.v = 0;
}

static void unlink_block(struct BlockAllocator *a, struct BlockId id)
static void unlink_block(struct Allocator *a, struct BlockId id)
{
paw_assert((B_HDR(a, id.v)->size4x & 1) == 0);
paw_assert(id.v >= 1);
const uint32_t size = B_HDR(a, id.v)->size4x / 4;
paw_assert(size == B_HDR(a, id.v + size)->prev_size);
paw_assert(size >= 2);
const uint32_t hash = size % BLOCK_NLISTS;
unlink_from_list(a, id, &a->free[hash]);
if (size <= MAX_SMALL) {
unlink_from_list(a, id, &a->small[size - 2]);
} else {
const uint32_t hash = size % NUM_HASH;
unlink_from_list(a, id, &a->hash[hash]);
}
}

static void link_into_list(struct BlockAllocator *a, struct BlockId id, struct BlockId *proot)
static void link_into_list(struct Allocator *a, struct BlockId id, struct BlockId *proot)
{
B_LIST(a, id.v)->next = *proot;
B_LIST(a, id.v)->prev.v = 0;
Expand All @@ -197,18 +183,22 @@ static void link_into_list(struct BlockAllocator *a, struct BlockId id, struct B
*proot = id;
}

static void link_block(struct BlockAllocator *a, struct BlockId id)
static void link_block(struct Allocator *a, struct BlockId id)
{
paw_assert(id.v >= 1);
paw_assert((B_HDR(a, id.v)->size4x & 1) == 0);
const uint32_t size = B_HDR(a, id.v)->size4x / 4;
paw_assert(size == B_HDR(a, id.v + size)->prev_size);
paw_assert(size >= 2);
const uint32_t hash = size % BLOCK_NLISTS;
link_into_list(a, id, &a->free[hash]);
if (size <= MAX_SMALL) {
link_into_list(a, id, &a->small[size - 2]);
} else {
const uint32_t hash = size % NUM_HASH;
link_into_list(a, id, &a->hash[hash]);
}
}

static void fix_block_list(struct BlockAllocator *a, struct BlockId *proot)
static void fix_block_list(struct Allocator *a, struct BlockId *proot)
{
struct BlockId next;

Expand Down Expand Up @@ -240,7 +230,7 @@ static void fix_block_list(struct BlockAllocator *a, struct BlockId *proot)
}
}

static void *checkout_block(struct BlockAllocator *a, struct BlockId i, uint32_t nblocks)
static void *checkout_block(struct Allocator *a, struct BlockId i, uint32_t nblocks)
{
paw_assert(i.v >= 1);
paw_assert(B_HDR(a, i.v)->size4x / 4 == nblocks);
Expand All @@ -252,7 +242,7 @@ static void *checkout_block(struct BlockAllocator *a, struct BlockId i, uint32_t
return &a->blocks[i.v];
}

static void *key_block_alloc(struct BlockAllocator *a, uint32_t nblocks)
static void *key_block_alloc(struct Allocator *a, uint32_t nblocks)
{
assert(a->key_size >= nblocks);
if (nblocks >= a->key_size - 1) {
Expand All @@ -279,25 +269,33 @@ static void *key_block_alloc(struct BlockAllocator *a, uint32_t nblocks)
}

#define TOO_MANY_BLOCKS(nbytes) ((nbytes + 11) / BLOCK_SIZE > UINT32_MAX)
#define COMPUTE_NUM_BLOCKS(nbytes) CHECK_EXP(BLOCK_SIZE == 8 && (nbytes) > 12, \
((nbytes) + 11) / BLOCK_SIZE)
#define COMPUTE_NUM_BLOCKS(nbytes) CHECK_EXP(BLOCK_SIZE == 8, (nbytes) <= 12 ? 2 :((nbytes) + 11) / 8)

// Modified from SQLite (mem3.c)
static void *block_malloc(struct BlockAllocator *a, size_t nbytes)
static void *z_malloc(struct Heap *H, size_t nbytes)
{
struct Allocator *a = H->a;
if (TOO_MANY_BLOCKS(nbytes)) return NULL;
uint32_t nblocks = COMPUTE_NUM_BLOCKS(nbytes);
paw_assert(nblocks >= 2);

// search for an exact fit
const uint32_t hash = nblocks % BLOCK_NLISTS;
for (struct BlockId id = a->free[hash];
id.v != BAD_BLOCK;
id = B_LIST(a, id.v)->next) {
if (B_HDR(a, id.v)->size4x / 4 == nblocks) {
unlink_from_list(a, id, &a->free[hash]);
if (nblocks <= MAX_SMALL) {
struct BlockId id = a->small[nblocks - 2];
if (id.v != BAD_BLOCK) {
unlink_from_list(a, id, &a->small[nblocks - 2]);
return checkout_block(a, id, nblocks);
}
} else {
const uint32_t hash = nblocks % NUM_HASH;
for (struct BlockId id = a->hash[hash];
id.v != BAD_BLOCK;
id = B_LIST(a, id.v)->next) {
if (B_HDR(a, id.v)->size4x / 4 == nblocks) {
unlink_from_list(a, id, &a->hash[hash]);
return checkout_block(a, id, nblocks);
}
}
}

if (a->key_size >= nblocks) {
Expand All @@ -312,8 +310,11 @@ static void *block_malloc(struct BlockAllocator *a, size_t nbytes)
a->key.v = BAD_BLOCK;
a->key_size = 0;
}
for (uint32_t i = 0; i < BLOCK_NLISTS; ++i) {
fix_block_list(a, &a->free[i]);
for (uint32_t i = 0; i < NUM_HASH; ++i) {
fix_block_list(a, &a->hash[i]);
}
for (uint32_t i = 0; i < MAX_SMALL - 1; ++i) {
fix_block_list(a, &a->small[i]);
}
if (a->key_size != 0) {
unlink_block(a, a->key);
Expand All @@ -327,8 +328,9 @@ static void *block_malloc(struct BlockAllocator *a, size_t nbytes)
}

// Modified from SQLite (mem3.c)
static void block_free(struct BlockAllocator *a, void *ptr, size_t nbytes)
static void z_free(struct Heap *H, void *ptr, size_t nbytes)
{
struct Allocator *a = H->a;
paw_assert(!TOO_MANY_BLOCKS(nbytes));
uint32_t nblocks = COMPUTE_NUM_BLOCKS(nbytes);
paw_assert(nblocks >= 2);
Expand Down Expand Up @@ -371,41 +373,6 @@ static size_t block_size(void *ptr)
return (b[-1].hdr.size4x & ~3) * 2 - 4;
}

static void *alloc_uninit(struct FastBins *a, size_t id)
{
void *ptr = a->uninit;
const size_t want = MIN_BIN_SIZE * (id + 1);
if (want > a->uninit_size) return NULL;
UNPOISON_MEMORY_REGION(a->uninit, want);
a->uninit = BUMP(a->uninit, want);
a->uninit_size -= want;
return ptr;
}

static void *fast_malloc(struct FastBins *a, size_t size)
{
paw_assert(0 < size && size <= MAX_BIN_SIZE);
const int id = BIN_ID(size);
struct BinInfo **pbin = &a->info[id];
if (*pbin != NULL) {
struct BinInfo *bin = *pbin;
*pbin = bin->prev;
return ERASE_TYPE(bin);
}
return alloc_uninit(a, id);
}

static void fast_free(struct FastBins *a, void *ptr, size_t size)
{
if (ptr == NULL) return;
struct BinInfo *bin = CAST(ptr, struct BinInfo *);
const int id = BIN_ID(size);
*bin = (struct BinInfo){
.prev = a->info[id],
};
a->info[id] = bin;
}

// TODO: Put everything in the same allocation
int pawZ_init(paw_Env *P, size_t heap_size)
{
Expand All @@ -430,21 +397,11 @@ int pawZ_init(paw_Env *P, size_t heap_size)

#define SKIP_CHUNK(z) (heap = BUMP(heap, aligned(z)), \
heap_size -= aligned(z))
H->a_block = heap;
SKIP_CHUNK(sizeof(struct BlockAllocator));
init_block_allocator(H->a_block, heap, heap_size);
H->a = heap;
SKIP_CHUNK(sizeof(struct Allocator));
init_block_allocator(H->a, heap, heap_size);
#undef SKIP_CHUNK

const size_t arena_size = heap_size / BIN_FACTOR;
void *arena = block_malloc(H->a_block, arena_size);
if (arena == NULL) goto no_memory;
POISON_MEMORY_REGION(arena, arena_size);
H->bins = (struct FastBins){
.uninit_size = arena_size,
.arena_size = arena_size,
.uninit = arena,
.arena = arena,
};
H->bounds[0] = CAST_UPTR(H->heap);
H->bounds[1] = H->bounds[0] + H->heap_size;
return PAW_OK;
Expand Down Expand Up @@ -479,10 +436,6 @@ void pawZ_uninit(paw_Env *P)
{
struct Heap *H = P->H;
if (H != NULL) {
if (H->bins.arena != NULL) {
UNPOISON_MEMORY_REGION(H->bins.uninit, H->bins.uninit_size);
block_free(P->H->a_block, H->bins.arena, H->bins.arena_size);
}
if (H->heap != NULL) OS_FREE(P, H->heap, H->heap_size);
OS_FREE(P, H, sizeof(*H) + H->nflags / FLAGS_PER_BYTE);
P->H = NULL;
Expand All @@ -491,25 +444,6 @@ void pawZ_uninit(paw_Env *P)

#define CHECK_UNUSED(H, ptr) paw_assert(!pawZ_get_flag(H, CAST_UPTR(ptr)))

static void z_free(struct Heap *H, void *ptr, size_t size)
{
size = aligned(size);
if (size <= MAX_BIN_SIZE) {
fast_free(&H->bins, ptr, size);
} else {
block_free(H->a_block, ptr, size);
}
}

static void *z_malloc(struct Heap *H, size_t size)
{
size = aligned(size);
void *ptr = size <= MAX_BIN_SIZE
? fast_malloc(&H->bins, size)
: block_malloc(H->a_block, size);
return ptr;
}

static void *z_realloc(struct Heap *H, void *old_ptr, size_t old_size, size_t new_size)
{
void *new_ptr = z_malloc(H, new_size);
Expand Down
13 changes: 1 addition & 12 deletions src/alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,9 @@ struct GcFlag {
uint8_t value;
};

#define FAST_BIN_COUNT 64

struct FastBins {
struct BinInfo *info[FAST_BIN_COUNT];
size_t uninit_size;
size_t arena_size;
void *uninit;
void *arena;
};


struct Heap {
struct FastBins bins;
struct BlockAllocator *a_block;
struct Allocator *a;
uintptr_t bounds[2];
size_t heap_size;
void *heap;
Expand Down
2 changes: 1 addition & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void pawAst_free(struct Ast *ast)
struct T *pawAst_new_##name(struct Ast *ast, enum T##Kind kind) \
{ \
struct T *r = pawK_pool_alloc(ENV(ast), &(ast)->pool, sizeof(struct T)); \
r->hdr.line = (ast)->lex->line; \
r->hdr.line = (ast)->lex->last_line; \
r->hdr.kind = kind; \
return r; \
}
Expand Down
2 changes: 1 addition & 1 deletion src/auxlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ void pawL_add_value(paw_Env *P, Buffer *buf, paw_Type type)
// Table and stringify algorithm modified from micropython
static const uint8_t kLogBase2[] = {
0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, //
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
};

size_t pawL_integer_format_size(size_t nbits, int base)
Expand Down
Loading

0 comments on commit 6f94738

Please sign in to comment.