Mirai's Miscellaneous Misadventures

M19 / engines / wasm.c

// copyright 2022 zamfofex
// license: AGPLv3 or later

#include <mimimi/allocators.h>

struct mimimi_image;

void mimimi_wasm_javascript_stamp(void *data, int x, int y, struct mimimi_image *image);
void mimimi_wasm_stamp(void *data, int x, int y, struct mimimi_image *image)
{
	mimimi_wasm_javascript_stamp(data, x, y, image);
}

static unsigned char *mimimi_wasm_null = 0;

extern unsigned char __heap_base;
static unsigned char *mimimi_wasm_heap = &__heap_base;
static unsigned long int mimimi_wasm_start = (unsigned long int)&__heap_base;

static unsigned char mimimi_wasm_blocks[8192] = {};

static void mimimi_wasm_grow(int n)
{
	unsigned long int size = __builtin_wasm_memory_size(0) * 0x10000 - mimimi_wasm_start;
	if (size < n)
		if (__builtin_wasm_memory_grow(0, (n - size - 1) / 0x10000 + 1) < 0)
			__builtin_trap();
}

void *mimimi_wasm_allocate(unsigned int size)
{
	int blocks = (size - 1) / 8192 + 1;
	
	for (int i = 0 ; i < 8192 ; i++)
	{
		for (int j = 0 ; j < blocks ; j++)
		{
			if (mimimi_wasm_blocks[i + j] != 0)
				goto next;
		}
		
		mimimi_wasm_blocks[i] = 1;
		for (int j = 1 ; j < blocks ; j++)
			mimimi_wasm_blocks[i + j] = 2;
		
		unsigned char *data = mimimi_wasm_heap + i * 8192;
		mimimi_wasm_grow(data - mimimi_wasm_null);
		return data;
		
		next:;
	}
	
	__builtin_trap();
}

static void mimimi_wasm_deallocate(void *data0)
{
	unsigned char *data = data0;
	int block = (data - mimimi_wasm_heap) / 8192;
	
	mimimi_wasm_blocks[block] = 0;
	for (int i = 1 ; mimimi_wasm_blocks[block + i] == 2 ; i++)
		mimimi_wasm_blocks[block + i] = 0;
}

static void *mimimi_wasm_reallocate(void *data0, unsigned int size)
{
	if (data0 == 0) return mimimi_wasm_allocate(size);
	
	unsigned char *data = data0;
	int block = (data - mimimi_wasm_heap) / 8192;
	
	int current_count = 1;
	while (mimimi_wasm_blocks[block + current_count] == 2) current_count++;
	
	int target_count = (size - 1) / 8192 + 1;
	
	if (target_count <= current_count)
	{
		for (int i = target_count ; i < current_count ; i++)
			mimimi_wasm_blocks[block + i] = 0;
		return data;
	}
	
	for (int i = current_count ; i < target_count ; i++)
	{
		if (mimimi_wasm_blocks[block + i] != 0)
		{
			unsigned char *new = mimimi_wasm_allocate(size);
			for (unsigned int i = 0 ; i < current_count * 8192 ; i++)
				new[i] = data[i];
			mimimi_wasm_deallocate(data);
			return new;
		}
	}
	
	for (int i = current_count ; i < target_count ; i++)
		mimimi_wasm_blocks[block + i] = 2;
	return data;
}

static struct mimimi_allocator mimimi_wasm_allocator_value = {&mimimi_wasm_allocate, &mimimi_wasm_reallocate, &mimimi_wasm_deallocate, 0};
struct mimimi_allocator *mimimi_wasm_allocator = &mimimi_wasm_allocator_value;