Mirai's Miscellaneous Misadventures

M39 / engines / wasm-llvm.c

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

#include <mimimi/allocators.h>
#include <mimimi/coroutine-providers.h>
#include <mimimi/assets.h>

void *mimimi_wasm_llvm_javascript_texture(void *data, struct mimimi_image *image);
void *mimimi_wasm_llvm_texture(void *data, struct mimimi_image *image)
{
	return mimimi_wasm_llvm_javascript_texture(data, image);
}

void mimimi_wasm_llvm_javascript_invalidate(void *data, void *texture);
void mimimi_wasm_llvm_invalidate(void *data, void *texture)
{
	mimimi_wasm_llvm_javascript_invalidate(data, texture);
}

void mimimi_wasm_llvm_javascript_stamp(void *data, int x, int y, void *texture);
void mimimi_wasm_llvm_stamp(void *data, int x, int y, void *texture)
{
	mimimi_wasm_llvm_javascript_stamp(data, x, y, texture);
}

extern unsigned char __heap_base;
static unsigned char *mimimi_wasm_llvm_heap = &__heap_base;
static unsigned long int mimimi_wasm_llvm_start = (unsigned long int) &__heap_base;

static unsigned char mimimi_wasm_llvm_blocks[0x10000] = {0};

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

void *mimimi_wasm_llvm_allocate(void *ignored, unsigned int size)
{
	(void) ignored;
	
	int blocks = (size - 1) / 8192 + 1;
	
	for (int i = 0 ; i < 0x10000 ; i++)
	{
		for (int j = 0 ; j < blocks ; j++)
		{
			if (mimimi_wasm_llvm_blocks[i + j] != 0)
				goto next;
		}
		
		mimimi_wasm_llvm_blocks[i] = 1;
		for (int j = 1 ; j < blocks ; j++)
			mimimi_wasm_llvm_blocks[i + j] = 2;
		
		unsigned char *null = 0;
		unsigned char *data = mimimi_wasm_llvm_heap + i * 8192;
		mimimi_wasm_llvm_grow(data - null + size);
		return data;
		
		next:;
	}
	
	__builtin_trap();
}

void mimimi_wasm_llvm_deallocate(void *ignored, void *data0)
{
	(void) ignored;
	
	unsigned char *data = data0;
	int block = (data - mimimi_wasm_llvm_heap) / 8192;
	
	mimimi_wasm_llvm_blocks[block] = 0;
	for (int i = 1 ; mimimi_wasm_llvm_blocks[block + i] == 2 ; i++)
		mimimi_wasm_llvm_blocks[block + i] = 0;
}

void *mimimi_wasm_llvm_reallocate(void *ignored, void *data0, unsigned int size)
{
	(void) ignored;
	
	if (data0 == 0) return mimimi_wasm_llvm_allocate(0, size);
	
	unsigned char *data = data0;
	int block = (data - mimimi_wasm_llvm_heap) / 8192;
	
	unsigned int current_count = 1;
	while (mimimi_wasm_llvm_blocks[block + current_count] == 2) current_count++;
	
	unsigned int target_count = (size - 1) / 8192 + 1;
	
	if (target_count <= current_count)
	{
		for (unsigned int i = target_count ; i < current_count ; i++)
			mimimi_wasm_llvm_blocks[block + i] = 0;
		return data;
	}
	
	for (unsigned int i = current_count ; i < target_count ; i++)
	{
		if (mimimi_wasm_llvm_blocks[block + i] != 0)
		{
			unsigned char *new = mimimi_wasm_llvm_allocate(0, size);
			for (unsigned int i = 0 ; i < current_count * 8192 ; i++)
				new[i] = data[i];
			mimimi_wasm_llvm_deallocate(0, data);
			return new;
		}
	}
	
	for (unsigned int i = current_count ; i < target_count ; i++)
		mimimi_wasm_llvm_blocks[block + i] = 2;
	
	return data;
}

static struct mimimi_allocator mimimi_wasm_llvm_allocator_value = {&mimimi_wasm_llvm_allocate, &mimimi_wasm_llvm_reallocate, &mimimi_wasm_llvm_deallocate, 0, 0};
struct mimimi_allocator *mimimi_wasm_llvm_allocator = &mimimi_wasm_llvm_allocator_value;

struct mimimi_behavior *mimimi_wasm_llvm_javascript_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data);
void mimimi_wasm_llvm_javascript_yield(void *data);
void mimimi_wasm_llvm_javascript_continue(void *data);
void mimimi_wasm_llvm_javascript_finish_coroutine(void *data);
void mimimi_wasm_llvm_javascript_finish_coroutine2(void *data);

static struct mimimi_behavior *mimimi_wasm_llvm_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data, void *self)
{
	(void) self;
	return mimimi_wasm_llvm_javascript_create_coroutine(start, finish, data);
}

void mimimi_wasm_llvm_yield(void *data)
{
	mimimi_wasm_llvm_javascript_yield(data);
}

void mimimi_wasm_llvm_continue(void *data)
{
	mimimi_wasm_llvm_javascript_continue(data);
}

void mimimi_wasm_llvm_finish_coroutine(void *data)
{
	mimimi_wasm_llvm_javascript_finish_coroutine(data);
}

void mimimi_wasm_llvm_finish_coroutine2(void *data)
{
	mimimi_wasm_llvm_javascript_finish_coroutine2(data);
}

static struct mimimi_coroutine_provider mimimi_wasm_llvm_coroutines_value = {&mimimi_wasm_llvm_create_coroutine, 0};
struct mimimi_coroutine_provider *mimimi_wasm_llvm_coroutines = &mimimi_wasm_llvm_coroutines_value;