Mirai's Miscellaneous Misadventures

M26 / engines / wasm.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
3
4#include <mimimi/allocators.h>
5#include <mimimi/coroutine-providers.h>
6
7struct mimimi_image;
8
9void mimimi_wasm_javascript_stamp(void *data, int x, int y, struct mimimi_image *image);
10void mimimi_wasm_stamp(void *data, int x, int y, struct mimimi_image *image)
11{
12	mimimi_wasm_javascript_stamp(data, x, y, image);
13}
14
15void mimimi_wasm_javascript_invalidate(void *data, struct mimimi_image *image);
16void mimimi_wasm_invalidate(void *data, struct mimimi_image *image)
17{
18	mimimi_wasm_javascript_invalidate(data, image);
19}
20
21static unsigned char *mimimi_wasm_null = 0;
22
23extern unsigned char __heap_base;
24static unsigned char *mimimi_wasm_heap = &__heap_base;
25static unsigned long int mimimi_wasm_start = (unsigned long int)&__heap_base;
26
27static unsigned char mimimi_wasm_blocks[0x10000] = {0};
28
29static void mimimi_wasm_grow(int n)
30{
31	unsigned long int size = __builtin_wasm_memory_size(0) * 0x10000 - mimimi_wasm_start;
32	if (size < n)
33		if (__builtin_wasm_memory_grow(0, (n - size - 1) / 0x10000 + 1) < 0)
34			__builtin_trap();
35}
36
37void *mimimi_wasm_allocate(unsigned int size)
38{
39	int blocks = (size - 1) / 8192 + 1;
40	
41	for (int i = 0 ; i < 0x10000 ; i++)
42	{
43		for (int j = 0 ; j < blocks ; j++)
44		{
45			if (mimimi_wasm_blocks[i + j] != 0)
46				goto next;
47		}
48		
49		mimimi_wasm_blocks[i] = 1;
50		for (int j = 1 ; j < blocks ; j++)
51			mimimi_wasm_blocks[i + j] = 2;
52		
53		unsigned char *data = mimimi_wasm_heap + i * 8192;
54		mimimi_wasm_grow(data - mimimi_wasm_null);
55		return data;
56		
57		next:;
58	}
59	
60	__builtin_trap();
61}
62
63void mimimi_wasm_deallocate(void *data0)
64{
65	unsigned char *data = data0;
66	int block = (data - mimimi_wasm_heap) / 8192;
67	
68	mimimi_wasm_blocks[block] = 0;
69	for (int i = 1 ; mimimi_wasm_blocks[block + i] == 2 ; i++)
70		mimimi_wasm_blocks[block + i] = 0;
71}
72
73void *mimimi_wasm_reallocate(void *data0, unsigned int size)
74{
75	if (data0 == 0) return mimimi_wasm_allocate(size);
76	
77	unsigned char *data = data0;
78	int block = (data - mimimi_wasm_heap) / 8192;
79	
80	int current_count = 1;
81	while (mimimi_wasm_blocks[block + current_count] == 2) current_count++;
82	
83	int target_count = (size - 1) / 8192 + 1;
84	
85	if (target_count <= current_count)
86	{
87		for (int i = target_count ; i < current_count ; i++)
88			mimimi_wasm_blocks[block + i] = 0;
89		return data;
90	}
91	
92	for (int i = current_count ; i < target_count ; i++)
93	{
94		if (mimimi_wasm_blocks[block + i] != 0)
95		{
96			unsigned char *new = mimimi_wasm_allocate(size);
97			for (unsigned int i = 0 ; i < current_count * 8192 ; i++)
98				new[i] = data[i];
99			mimimi_wasm_deallocate(data);
100			return new;
101		}
102	}
103	
104	for (int i = current_count ; i < target_count ; i++)
105		mimimi_wasm_blocks[block + i] = 2;
106	
107	return data;
108}
109
110static struct mimimi_allocator mimimi_wasm_allocator_value = {&mimimi_wasm_allocate, &mimimi_wasm_reallocate, &mimimi_wasm_deallocate, 0};
111struct mimimi_allocator *mimimi_wasm_allocator = &mimimi_wasm_allocator_value;
112
113struct mimimi_behavior *mimimi_wasm_javascript_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data);
114void mimimi_wasm_javascript_yield(void *data);
115void mimimi_wasm_javascript_continue(void *data);
116void mimimi_wasm_javascript_finish_coroutine(void *data);
117void mimimi_wasm_javascript_finish_coroutine2(void *data);
118
119static struct mimimi_behavior *mimimi_wasm_create_coroutine(void (*start)(struct mimimi_behavior *behavior, void *data), void (*finish)(void *data), void *data, void *self)
120{
121	return mimimi_wasm_javascript_create_coroutine(start, finish, data);
122}
123
124void mimimi_wasm_yield(void *data)
125{
126	mimimi_wasm_javascript_yield(data);
127}
128
129void mimimi_wasm_continue(void *data)
130{
131	mimimi_wasm_javascript_continue(data);
132}
133
134void mimimi_wasm_finish_coroutine(void *data)
135{
136	mimimi_wasm_javascript_finish_coroutine(data);
137}
138
139void mimimi_wasm_finish_coroutine2(void *data)
140{
141	mimimi_wasm_javascript_finish_coroutine2(data);
142}
143
144static struct mimimi_coroutine_provider mimimi_wasm_coroutines_value = {&mimimi_wasm_create_coroutine};
145struct mimimi_coroutine_provider *mimimi_wasm_coroutines = &mimimi_wasm_coroutines_value;