==> src/builder.c <==1/* Byte encoders and the module assembler. */
2#include "wasm/builder.h"
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7
8static void *grow(void *p, size_t n, size_t size) {
9 void *q = realloc(p, (n ? n : 1) * size);
10 if (!q) {
11 fputs("wasm-builder: out of memory\n", stderr);
12 abort();
13 }
14 return q;
15}
16
17void wasm_buf_free(wasm_buf *b) {
18 free(b->data);
19 memset(b, 0, sizeof *b);
20}
21
22void wb_bytes(wasm_buf *b, const void *p, size_t n) {
23 if (b->len + n > b->cap) {
24 b->cap = b->cap ? b->cap * 2 : 64;
25 while (b->cap < b->len + n) b->cap *= 2;
26 b->data = grow(b->data, b->cap, 1);
27 }
28 if (n) memcpy(b->data + b->len, p, n);
29 b->len += n;
30}
31
32void wb_byte(wasm_buf *b, uint8_t v) { wb_bytes(b, &v, 1); }
33
34void wb_u64(wasm_buf *b, uint64_t v) {
35 do {
36 uint8_t x = v & 0x7f;
37 v >>= 7;
38 wb_byte(b, (uint8_t)(x | (v ? 0x80 : 0)));
39 } while (v);
40}
41
42void wb_u32(wasm_buf *b, uint32_t v) { wb_u64(b, v); }
43
44void wb_s64(wasm_buf *b, int64_t v) {
45 for (;;) {
46 uint8_t x = (uint8_t)(v & 0x7f);
47 /* An arithmetic shift, written out so it doesn't depend on the implementation. */
48 v = v < 0 ? ~(~v >> 7) : v >> 7;
49 if ((v == 0 && !(x & 0x40)) || (v == -1 && (x & 0x40))) {
50 wb_byte(b, x);
51 return;
52 }
53 wb_byte(b, (uint8_t)(x | 0x80));
54 }
55}
56
57void wb_s32(wasm_buf *b, int32_t v) { wb_s64(b, v); }
58
59void wb_f32(wasm_buf *b, float v) {
60 uint32_t u;
61 memcpy(&u, &v, 4);
62 uint8_t le[4] = {(uint8_t)u, (uint8_t)(u >> 8), (uint8_t)(u >> 16), (uint8_t)(u >> 24)};
63 wb_bytes(b, le, 4);
64}
65
66void wb_f64(wasm_buf *b, double v) {
67 uint64_t u;
68 memcpy(&u, &v, 8);
69 for (int i = 0; i < 8; i++) wb_byte(b, (uint8_t)(u >> (8 * i)));
70}
71
72void wb_name(wasm_buf *b, const char *s) {
73 size_t n = strlen(s);
74 wb_u32(b, (uint32_t)n);
75 wb_bytes(b, s, n);
76}
77
78void wb_section(wasm_buf *b, uint8_t id, const wasm_buf *payload) {
79 wb_byte(b, id);
80 wb_u32(b, (uint32_t)payload->len);
81 wb_bytes(b, payload->data, payload->len);
82}
83
84void wb_i32_const(wasm_buf *b, int32_t v) {
85 wb_byte(b, 0x41);
86 wb_s32(b, v);
87}
88
89void wb_i64_const(wasm_buf *b, int64_t v) {
90 wb_byte(b, 0x42);
91 wb_s64(b, v);
92}
93
94void wb_op(wasm_buf *b, uint8_t op) { wb_byte(b, op); }
95
96void wb_op_u32(wasm_buf *b, uint8_t op, uint32_t a) {
97 wb_byte(b, op);
98 wb_u32(b, a);
99}
100
101void wb_fc(wasm_buf *b, uint32_t sub) {
102 wb_byte(b, 0xfc);
103 wb_u32(b, sub);
104}
105
106void wb_memarg(wasm_buf *b, uint8_t op, uint32_t align, uint32_t offset) {
107 wb_byte(b, op);
108 wb_u32(b, align);
109 wb_u32(b, offset);
110}
111
112static wasm_valtype letter(char c) {
113 switch (c) {
114 case 'i': return WASM_I32;
115 case 'l': return WASM_I64;
116 case 'f': return WASM_F32;
117 case 'd': return WASM_F64;
118 case 'F': return WASM_FUNCREF;
119 case 'E': return WASM_EXTERNREF;
120 case 'V': return WASM_V128;
121 default: return 0;
122 }
123}
124
125void wasm_builder_free(wasm_builder *w) {
126 wasm_buf_free(&w->types);
127 for (uint32_t i = 0; i < w->nimports; i++) {
128 free(w->imports[i].module);
129 free(w->imports[i].name);
130 }
131 free(w->imports);
132 for (uint32_t i = 0; i < w->nfuncs; i++) {
133 free(w->funcs[i].locals);
134 wasm_buf_free(&w->funcs[i].body);
135 }
136 free(w->funcs);
137 for (uint32_t i = 0; i < w->nglobals; i++) wasm_buf_free(&w->globals[i].init);
138 free(w->globals);
139 for (uint32_t i = 0; i < w->nexports; i++) free(w->exports[i].name);
140 free(w->exports);
141 for (uint32_t i = 0; i < w->nelems; i++) free(w->elems[i].funcs);
142 free(w->elems);
143 for (uint32_t i = 0; i < w->ndatas; i++) wasm_buf_free(&w->datas[i].bytes);
144 free(w->datas);
145 memset(w, 0, sizeof *w);
146}
147
148static char *dup(const char *s) {
149 char *d = grow(NULL, strlen(s) + 1, 1);
150 memcpy(d, s, strlen(s) + 1);
151 return d;
152}
153
154uint32_t wasm_builder_type(wasm_builder *w, const char *sig) {
155 const char *gt = strchr(sig, '>');
156 size_t np = gt ? (size_t)(gt - sig) : strlen(sig);
157 wb_byte(&w->types, WASM_FUNC_FORM);
158 wb_u32(&w->types, (uint32_t)np);
159 for (size_t i = 0; i < np; i++) wb_byte(&w->types, letter(sig[i]));
160 const char *res = gt ? gt + 1 : "";
161 wb_u32(&w->types, (uint32_t)strlen(res));
162 for (const char *c = res; *c; c++) wb_byte(&w->types, letter(*c));
163 return w->ntypes++;
164}
165
166static wasm_builder_import *import(wasm_builder *w, const char *module, const char *name, uint8_t kind) {
167 w->imports = grow(w->imports, w->nimports + 1, sizeof *w->imports);
168 wasm_builder_import *im = &w->imports[w->nimports++];
169 memset(im, 0, sizeof *im);
170 im->module = dup(module);
171 im->name = dup(name);
172 im->kind = kind;
173 return im;
174}
175
176uint32_t wasm_builder_import_func(wasm_builder *w, const char *module, const char *name, uint32_t type) {
177 import(w, module, name, WASM_EXTERN_FUNC)->type = type;
178 return w->nfunc_imports++;
179}
180
181void wasm_builder_import_memory(wasm_builder *w, const char *module, const char *name, uint32_t min) {
182 import(w, module, name, WASM_EXTERN_MEMORY)->min = min;
183}
184
185wasm_buf *wasm_builder_func_add(wasm_builder *w, uint32_t type, const char *locals, uint32_t *index) {
186 w->funcs = grow(w->funcs, w->nfuncs + 1, sizeof *w->funcs);
187 wasm_builder_func *f = &w->funcs[w->nfuncs];
188 memset(f, 0, sizeof *f);
189 f->type = type;
190 f->nlocals = (uint32_t)strlen(locals);
191 f->locals = grow(NULL, f->nlocals, 1);
192 for (uint32_t i = 0; i < f->nlocals; i++) f->locals[i] = letter(locals[i]);
193 if (index) *index = w->nfunc_imports + w->nfuncs;
194 w->nfuncs++;
195 return &f->body;
196}
197
198void wasm_builder_memory(wasm_builder *w, uint32_t min, uint32_t max, bool has_max) {
199 w->has_memory = true;
200 w->mem_min = min;
201 w->mem_max = max;
202 w->mem_has_max = has_max;
203}
204
205void wasm_builder_table(wasm_builder *w, uint32_t min, uint32_t max, bool has_max) {
206 w->has_table = true;
207 w->table_min = min;
208 w->table_max = max;
209 w->table_has_max = has_max;
210}
211
212wasm_buf *wasm_builder_add_global(wasm_builder *w, wasm_valtype type, bool mut) {
213 w->globals = grow(w->globals, w->nglobals + 1, sizeof *w->globals);
214 wasm_builder_global *g = &w->globals[w->nglobals++];
215 memset(g, 0, sizeof *g);
216 g->type = type;
217 g->mut = mut;
218 return &g->init;
219}
220
221void wasm_builder_add_export(wasm_builder *w, const char *name, uint8_t kind, uint32_t index) {
222 w->exports = grow(w->exports, w->nexports + 1, sizeof *w->exports);
223 w->exports[w->nexports++] = (wasm_builder_export){dup(name), kind, index};
224}
225
226void wasm_builder_data(wasm_builder *w, uint32_t offset, const void *bytes, size_t n) {
227 w->datas = grow(w->datas, w->ndatas + 1, sizeof *w->datas);
228 wasm_builder_segment *d = &w->datas[w->ndatas++];
229 memset(d, 0, sizeof *d);
230 d->offset = offset;
231 wb_bytes(&d->bytes, bytes, n);
232}
233
234void wasm_builder_data_passive(wasm_builder *w, const void *bytes, size_t n) {
235 wasm_builder_data(w, 0, bytes, n);
236 w->datas[w->ndatas - 1].passive = true;
237 w->datacount = true;
238}
239
240void wasm_builder_elem(wasm_builder *w, uint32_t offset, const uint32_t *funcs, uint32_t n) {
241 w->elems = grow(w->elems, w->nelems + 1, sizeof *w->elems);
242 wasm_builder_segment *e = &w->elems[w->nelems++];
243 memset(e, 0, sizeof *e);
244 e->offset = offset;
245 e->funcs = grow(NULL, n, sizeof *funcs);
246 if (n) memcpy(e->funcs, funcs, n * sizeof *funcs);
247 e->nfuncs = n;
248}
249
250static void limits(wasm_buf *b, uint32_t min, uint32_t max, bool has_max) {
251 wb_byte(b, has_max ? 1 : 0);
252 wb_u32(b, min);
253 if (has_max) wb_u32(b, max);
254}
255
256void wasm_builder_finish(const wasm_builder *w, wasm_buf *out) {
257 memset(out, 0, sizeof *out);
258 wb_bytes(out, "\0asm\x01\0\0\0", 8);
259 wasm_buf s = {0};
260 if (w->ntypes) {
261 wb_u32(&s, w->ntypes);
262 wb_bytes(&s, w->types.data, w->types.len);
263 wb_section(out, WASM_SEC_TYPE, &s);
264 }
265 if (w->nimports) {
266 s.len = 0;
267 wb_u32(&s, w->nimports);
268 for (uint32_t i = 0; i < w->nimports; i++) {
269 const wasm_builder_import *im = &w->imports[i];
270 wb_name(&s, im->module);
271 wb_name(&s, im->name);
272 wb_byte(&s, im->kind);
273 if (im->kind == WASM_EXTERN_FUNC) wb_u32(&s, im->type);
274 else if (im->kind == WASM_EXTERN_MEMORY) limits(&s, im->min, im->max, im->has_max);
275 }
276 wb_section(out, WASM_SEC_IMPORT, &s);
277 }
278 if (w->nfuncs) {
279 s.len = 0;
280 wb_u32(&s, w->nfuncs);
281 for (uint32_t i = 0; i < w->nfuncs; i++) wb_u32(&s, w->funcs[i].type);
282 wb_section(out, WASM_SEC_FUNCTION, &s);
283 }
284 if (w->has_table) {
285 s.len = 0;
286 wb_u32(&s, 1);
287 wb_byte(&s, WASM_FUNCREF);
288 limits(&s, w->table_min, w->table_max, w->table_has_max);
289 wb_section(out, WASM_SEC_TABLE, &s);
290 }
291 if (w->has_memory) {
292 s.len = 0;
293 wb_u32(&s, 1);
294 limits(&s, w->mem_min, w->mem_max, w->mem_has_max);
295 wb_section(out, WASM_SEC_MEMORY, &s);
296 }
297 if (w->nglobals) {
298 s.len = 0;
299 wb_u32(&s, w->nglobals);
300 for (uint32_t i = 0; i < w->nglobals; i++) {
301 wb_byte(&s, w->globals[i].type);
302 wb_byte(&s, w->globals[i].mut);
303 wb_bytes(&s, w->globals[i].init.data, w->globals[i].init.len);
304 wb_byte(&s, 0x0b);
305 }
306 wb_section(out, WASM_SEC_GLOBAL, &s);
307 }
308 if (w->nexports) {
309 s.len = 0;
310 wb_u32(&s, w->nexports);
311 for (uint32_t i = 0; i < w->nexports; i++) {
312 wb_name(&s, w->exports[i].name);
313 wb_byte(&s, w->exports[i].kind);
314 wb_u32(&s, w->exports[i].index);
315 }
316 wb_section(out, WASM_SEC_EXPORT, &s);
317 }
318 if (w->has_start) {
319 s.len = 0;
320 wb_u32(&s, w->start);
321 wb_section(out, WASM_SEC_START, &s);
322 }
323 if (w->nelems) {
324 s.len = 0;
325 wb_u32(&s, w->nelems);
326 for (uint32_t i = 0; i < w->nelems; i++) {
327 wb_u32(&s, 0);
328 wb_i32_const(&s, (int32_t)w->elems[i].offset);
329 wb_byte(&s, 0x0b);
330 wb_u32(&s, w->elems[i].nfuncs);
331 for (uint32_t k = 0; k < w->elems[i].nfuncs; k++) wb_u32(&s, w->elems[i].funcs[k]);
332 }
333 wb_section(out, WASM_SEC_ELEMENT, &s);
334 }
335 if (w->datacount) {
336 s.len = 0;
337 wb_u32(&s, w->ndatas);
338 wb_section(out, WASM_SEC_DATACOUNT, &s);
339 }
340 if (w->nfuncs) {
341 s.len = 0;
342 wb_u32(&s, w->nfuncs);
343 for (uint32_t i = 0; i < w->nfuncs; i++) {
344 const wasm_builder_func *f = &w->funcs[i];
345 wasm_buf e = {0};
346 /* Locals, run-length encoded. */
347 uint32_t groups = 0;
348 for (uint32_t k = 0; k < f->nlocals; k++)
349 if (k == 0 || f->locals[k] != f->locals[k - 1]) groups++;
350 wb_u32(&e, groups);
351 for (uint32_t k = 0; k < f->nlocals;) {
352 uint32_t n = 1;
353 while (k + n < f->nlocals && f->locals[k + n] == f->locals[k]) n++;
354 wb_u32(&e, n);
355 wb_byte(&e, f->locals[k]);
356 k += n;
357 }
358 wb_bytes(&e, f->body.data, f->body.len);
359 wb_byte(&e, 0x0b);
360 wb_u32(&s, (uint32_t)e.len);
361 wb_bytes(&s, e.data, e.len);
362 wasm_buf_free(&e);
363 }
364 wb_section(out, WASM_SEC_CODE, &s);
365 }
366 if (w->ndatas) {
367 s.len = 0;
368 wb_u32(&s, w->ndatas);
369 for (uint32_t i = 0; i < w->ndatas; i++) {
370 const wasm_builder_segment *d = &w->datas[i];
371 if (d->passive) {
372 wb_u32(&s, 1);
373 } else {
374 wb_u32(&s, 0);
375 wb_i32_const(&s, (int32_t)d->offset);
376 wb_byte(&s, 0x0b);
377 }
378 wb_u32(&s, (uint32_t)d->bytes.len);
379 wb_bytes(&s, d->bytes.data, d->bytes.len);
380 }
381 wb_section(out, WASM_SEC_DATA, &s);
382 }
383 wasm_buf_free(&s);
384}