#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "stdlib.h"
#ifndef __wasm__
#include "solana_sdk.h"
#endif
struct chunk
{
struct chunk *next, *prev;
uint32_t length;
uint32_t allocated;
};
#ifdef __wasm__
#define HEAP_START ((struct chunk *)0x10000)
void __init_heap()
{
struct chunk *first = HEAP_START;
first->next = first->prev = NULL;
first->allocated = false;
first->length = (uint32_t)(__builtin_wasm_memory_size(0) * 0x10000 - (size_t)first - sizeof(struct chunk));
}
#else
#define HEAP_START ((struct chunk *)0x300000000)
void __init_heap()
{
struct chunk *first = HEAP_START;
first->next = first->prev = NULL;
first->allocated = false;
first->length = (32 * 1024) - sizeof(struct chunk);
}
#endif
void __attribute__((noinline)) __free(void *m)
{
struct chunk *cur = m;
cur--;
if (m)
{
cur->allocated = false;
struct chunk *next = cur->next;
if (next && !next->allocated)
{
if ((cur->next = next->next) != NULL)
cur->next->prev = cur;
cur->length += next->length + sizeof(struct chunk);
next = cur->next;
}
struct chunk *prev = cur->prev;
if (prev && !prev->allocated)
{
prev->next = next;
next->prev = prev;
prev->length += cur->length + sizeof(struct chunk);
}
}
}
static void shrink_chunk(struct chunk *cur, uint32_t size)
{
size = (size + 7) & ~7;
if (cur->length - size >= (8 + sizeof(struct chunk)))
{
void *data = (cur + 1);
struct chunk *new = data + size;
if ((new->next = cur->next) != NULL)
new->next->prev = new;
cur->next = new;
new->prev = cur;
new->allocated = false;
new->length = cur->length - size - sizeof(struct chunk);
cur->length = size;
}
}
void *__attribute__((noinline)) __malloc(uint32_t size)
{
struct chunk *cur = HEAP_START;
while (cur && (cur->allocated || size > cur->length))
cur = cur->next;
if (cur)
{
shrink_chunk(cur, size);
cur->allocated = true;
return ++cur;
}
else
{
#ifdef __wasm__
__builtin_unreachable();
#else
sol_log("out of heap memory");
sol_panic();
#endif
return NULL;
}
}
void *__realloc(void *m, uint32_t size)
{
struct chunk *cur = m;
cur--;
struct chunk *next = cur->next;
if (next && !next->allocated && size <= (cur->length + next->length + sizeof(struct chunk)))
{
cur->next = next->next;
if (cur->next)
cur->next->prev = cur;
cur->length += next->length + sizeof(struct chunk);
shrink_chunk(cur, size);
return m;
}
else
{
uint32_t len = cur->length;
if (size < len)
len = size;
void *n = __malloc(size);
__memcpy8(n, m, (len + 7) / 8);
__free(m);
return n;
}
}