Mirai's Miscellaneous Misadventures

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