kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 2e3bc93c4d520c5d535c59d1e6a0a972017921b8
parent de7b25ff43c391fe820d41f84e1b0bca8ba9d360
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 18 May 2026 00:02:24 -0700

Implement Wasm runtime instance slots

Diffstat:
Mdoc/WASM.md | 40++++++++++++++++++++++++++++++----------
Mlang/wasm/runtime_abi.h | 28++++++++++++++++++++++++----
Mlang/wasm/wasm.c | 5136++++++++++++++++++++++++++++++++++++++++---------------------------------------
Atest/wasm/cases/import_slot_unused.expect | 1+
Atest/wasm/cases/import_slot_unused.wat | 4++++
Atest/wasm/cases/table_offset.expect | 1+
Atest/wasm/cases/table_offset.wat | 9+++++++++
7 files changed, 2695 insertions(+), 2524 deletions(-)

diff --git a/doc/WASM.md b/doc/WASM.md @@ -762,7 +762,11 @@ Current checked reader/encoder and validation items describe the re-encode the listed module metadata. Native lowering now covers mutable numeric globals, imported function declarations, active tables/elements for `call_indirect`, start functions, and growable single-memory state for the -accepted frontend subset. +accepted frontend subset. The native runner path now uses an explicit +`CfreeWasmInstance*` ABI: lowered functions, direct calls, `call_indirect` +arms, start dispatch, and `__cfree_wasm_init` all receive the instance; +single-memory metadata and numeric globals live under that instance. Import +slots and runtime table storage remain open work. ### Frontend Source and Driver @@ -843,28 +847,44 @@ accepted frontend subset. and MVP conversions. - [x] Lower f32/f64 arithmetic, comparisons, constants, conversions, and reinterpret ops. +- [ ] Add checked traps for `i32/i64.trunc_f32/f64_{s,u}` NaN/out-of-range + cases; current lowering relies on target float-to-int conversion behavior. - [x] Lower single linear memory load/store operations, `memory.size`, and active data initialization. - [x] Implement checked single-memory loads/stores and growable storage. - [x] Implement numeric globals for native lowering. - [x] Implement imported function declarations for native lowering. - [x] Implement tables, active elements, and `call_indirect`. -- [ ] Move lowered memory/global/import/table state behind the explicit - `CfreeWasmInstance` ABI instead of generated module-local storage/direct - external declarations. +- [x] Pass an explicit `CfreeWasmInstance*` through lowered functions, direct + calls, `call_indirect` arms, start dispatch, and module initialization. +- [x] Move lowered single-memory metadata and numeric global state behind the + explicit `CfreeWasmInstance` ABI instead of generated module-local storage. +- [x] Move imported functions, imported globals, imported memories, and tables + behind instance import/table slots instead of direct external declarations + and compile-time active-element dispatch. - [ ] Define and implement the C-facing exported wrapper ABI that keeps the instance parameter explicit. ### Runtime and Instance Model -- [ ] Add internal `CfreeWasmInstance`, memory, table, global, and import-slot - structs under `lang/wasm` or `rt`. +- [x] Add an internal runtime ABI header under `lang/wasm` with + `CfreeWasmMemory`, opaque `CfreeWasmInstance`, and `CfreeWasmInitFn`. +- [x] Allocate runner-owned instances and linear memories in `cfree run`, + `jit-runner`, and the Wasm executable start harness without process-global + Wasm instance or memory storage. +- [x] Define initialization for single memories, active data, numeric globals, + and start functions in `__cfree_wasm_init(instance)`. +- [x] Add internal `CfreeWasmTable` and import-slot structs under `lang/wasm` + or `rt`, and use them for imported functions/globals/memories and active + element initialization. - [ ] Add trap helpers for unreachable, division traps, invalid conversion, bounds checks, table checks, and indirect-call signature checks. -- [ ] Define ownership and initialization for memories, tables, active data, - elements, mutable globals, and start functions. -- [ ] Add tests that instantiate modules with memory/import/global state - without process-global state. +- [x] Define ownership and initialization for runtime tables, active elements, + and imported state. +- [x] Add frontend runner tests that instantiate memory/global/start modules + without process-global Wasm state. +- [x] Add frontend runner tests for instance-owned import slots and runtime + table state once those slots exist. ### Wasm Target Backend diff --git a/lang/wasm/runtime_abi.h b/lang/wasm/runtime_abi.h @@ -4,16 +4,36 @@ #include <stdint.h> typedef struct CfreeWasmMemory { - uint8_t *data; + uint8_t* data; uint32_t pages; uint32_t max_pages; } CfreeWasmMemory; +typedef struct CfreeWasmFuncImport { + void* fn; +} CfreeWasmFuncImport; + +typedef struct CfreeWasmGlobalImport { + void* addr; +} CfreeWasmGlobalImport; + +typedef struct CfreeWasmTableEntry { + void* fn; + uint32_t typeidx; +} CfreeWasmTableEntry; + +typedef struct CfreeWasmTable { + CfreeWasmTableEntry* entries; + uint32_t len; + uint32_t max; +} CfreeWasmTable; + /* Opaque to C callers for now. The compiler emits a module-specific instance - * layout with CfreeWasmMemory first when the module has linear memory, followed - * by lowered global slots. */ + * layout with CfreeWasmMemory first, followed by import slots, runtime tables, + * and lowered global slots. Table entry storage is instance-owned for + * defined tables; embedders fill import slots before calling the init hook. */ typedef struct CfreeWasmInstance CfreeWasmInstance; -typedef void (*CfreeWasmInitFn)(CfreeWasmInstance *); +typedef void (*CfreeWasmInitFn)(CfreeWasmInstance*); #endif diff --git a/lang/wasm/wasm.c b/lang/wasm/wasm.c @@ -179,27 +179,27 @@ typedef struct WasmInsn { } WasmInsn; typedef struct WasmFunc { - char *name; + char* name; uint32_t typeidx; int has_typeidx; int is_import; - char *import_module; - char *import_name; + char* import_module; + char* import_name; WasmValType params[16]; uint32_t nparams; WasmValType locals[32]; uint32_t nlocals; - char *local_names[48]; + char* local_names[48]; WasmValType results[1]; uint32_t nresults; - char *export_name; - WasmInsn *insns; + char* export_name; + WasmInsn* insns; uint32_t ninsns; uint32_t cap_insns; } WasmFunc; typedef struct WasmFuncType { - char *name; + char* name; WasmValType params[16]; uint32_t nparams; WasmValType results[1]; @@ -207,40 +207,40 @@ typedef struct WasmFuncType { } WasmFuncType; typedef struct WasmMemory { - char *name; + char* name; uint32_t min_pages; uint32_t max_pages; int has_max; int is_import; - char *import_module; - char *import_name; - char *export_name; - uint8_t *data; + char* import_module; + char* import_name; + char* export_name; + uint8_t* data; uint32_t data_len; uint32_t data_init_len; } WasmMemory; typedef struct WasmTable { - char *name; + char* name; WasmValType elem_type; uint32_t min; uint32_t max; int has_max; int is_import; - char *import_module; - char *import_name; - char *export_name; + char* import_module; + char* import_name; + char* export_name; } WasmTable; typedef struct WasmGlobal { - char *name; + char* name; WasmValType type; uint8_t mutable_; WasmInsn init; int is_import; - char *import_module; - char *import_name; - char *export_name; + char* import_module; + char* import_name; + char* export_name; } WasmGlobal; typedef struct WasmElemSegment { @@ -251,40 +251,40 @@ typedef struct WasmElemSegment { } WasmElemSegment; typedef struct WasmExport { - char *name; + char* name; uint8_t kind; uint32_t index; } WasmExport; typedef struct WasmCustom { - char *name; - uint8_t *data; + char* name; + uint8_t* data; uint32_t len; } WasmCustom; typedef struct WasmModule { - CfreeHeap *heap; - WasmFuncType *types; + CfreeHeap* heap; + WasmFuncType* types; uint32_t ntypes; uint32_t cap_types; - WasmFunc *funcs; + WasmFunc* funcs; uint32_t nfuncs; uint32_t cap_funcs; WasmMemory memory; int has_memory; - WasmTable *tables; + WasmTable* tables; uint32_t ntables; uint32_t cap_tables; - WasmGlobal *globals; + WasmGlobal* globals; uint32_t nglobals; uint32_t cap_globals; - WasmElemSegment *elems; + WasmElemSegment* elems; uint32_t nelems; uint32_t cap_elems; - WasmExport *exports; + WasmExport* exports; uint32_t nexports; uint32_t cap_exports; - WasmCustom *customs; + WasmCustom* customs; uint32_t ncustoms; uint32_t cap_customs; uint32_t start_func; @@ -293,7 +293,7 @@ typedef struct WasmModule { } WasmModule; typedef struct WasmTok { - const char *p; + const char* p; size_t len; uint32_t line; uint32_t col; @@ -309,23 +309,23 @@ enum { }; typedef struct WatParser { - CfreeCompiler *c; - const char *name; - const char *src; + CfreeCompiler* c; + const char* name; + const char* src; size_t len; size_t pos; uint32_t line; uint32_t col; WasmTok tok; - WasmModule *module; + WasmModule* module; } WatParser; typedef struct BinReader { - CfreeCompiler *c; - const uint8_t *data; + CfreeCompiler* c; + const uint8_t* data; size_t len; size_t pos; - WasmModule *module; + WasmModule* module; } BinReader; static CfreeSrcLoc wasm_loc(uint32_t line, uint32_t col) { @@ -336,50 +336,46 @@ static CfreeSrcLoc wasm_loc(uint32_t line, uint32_t col) { return loc; } -static void wasm_error(CfreeCompiler *c, CfreeSrcLoc loc, const char *fmt, +static void wasm_error(CfreeCompiler* c, CfreeSrcLoc loc, const char* fmt, ...) { va_list ap; va_start(ap, fmt); cfree_frontend_vfatal(c, loc, fmt, ap); } -static void *wasm_realloc(CfreeHeap *h, void *p, size_t old_n, size_t new_n) { +static void* wasm_realloc(CfreeHeap* h, void* p, size_t old_n, size_t new_n) { return h->realloc(h, p, old_n ? old_n : 1u, new_n ? new_n : 1u, _Alignof(max_align_t)); } -static char *wasm_strdup(CfreeHeap *h, const char *s, size_t len) { - char *out = (char *)h->alloc(h, len + 1u, 1); - if (!out) - return NULL; - if (len) - memcpy(out, s, len); +static char* wasm_strdup(CfreeHeap* h, const char* s, size_t len) { + char* out = (char*)h->alloc(h, len + 1u, 1); + if (!out) return NULL; + if (len) memcpy(out, s, len); out[len] = '\0'; return out; } -static void wasm_free_str(CfreeHeap *h, char **s) { +static void wasm_free_str(CfreeHeap* h, char** s) { if (*s) { h->free(h, *s, strlen(*s) + 1u); *s = NULL; } } -static void wasm_module_init(WasmModule *m, CfreeHeap *heap) { +static void wasm_module_init(WasmModule* m, CfreeHeap* heap) { memset(m, 0, sizeof *m); m->heap = heap; } -static void wasm_module_free(WasmModule *m) { +static void wasm_module_free(WasmModule* m) { uint32_t i; - if (!m || !m->heap) - return; - for (i = 0; i < m->ntypes; ++i) - wasm_free_str(m->heap, &m->types[i].name); + if (!m || !m->heap) return; + for (i = 0; i < m->ntypes; ++i) wasm_free_str(m->heap, &m->types[i].name); if (m->types) m->heap->free(m->heap, m->types, sizeof(*m->types) * m->cap_types); for (i = 0; i < m->nfuncs; ++i) { - WasmFunc *f = &m->funcs[i]; + WasmFunc* f = &m->funcs[i]; wasm_free_str(m->heap, &f->name); wasm_free_str(m->heap, &f->import_module); wasm_free_str(m->heap, &f->import_name); @@ -415,8 +411,7 @@ static void wasm_module_free(WasmModule *m) { m->heap->free(m->heap, m->globals, sizeof(*m->globals) * m->cap_globals); if (m->elems) m->heap->free(m->heap, m->elems, sizeof(*m->elems) * m->cap_elems); - for (i = 0; i < m->nexports; ++i) - wasm_free_str(m->heap, &m->exports[i].name); + for (i = 0; i < m->nexports; ++i) wasm_free_str(m->heap, &m->exports[i].name); if (m->exports) m->heap->free(m->heap, m->exports, sizeof(*m->exports) * m->cap_exports); for (i = 0; i < m->ncustoms; ++i) { @@ -429,37 +424,33 @@ static void wasm_module_free(WasmModule *m) { memset(m, 0, sizeof *m); } -static void wasm_memory_ensure(CfreeCompiler *c, WasmModule *m, +static void wasm_memory_ensure(CfreeCompiler* c, WasmModule* m, uint32_t min_len) { uint32_t old_len, new_len; - void *p; + void* p; if (!m->has_memory) wasm_error(c, wasm_loc(0, 0), "wasm: data segment without memory"); old_len = m->memory.data_len; new_len = old_len; - if (new_len < min_len) - new_len = min_len; + if (new_len < min_len) new_len = min_len; if (m->memory.min_pages && new_len < m->memory.min_pages * 65536u) new_len = m->memory.min_pages * 65536u; - if (new_len == old_len) - return; + if (new_len == old_len) return; p = wasm_realloc(m->heap, m->memory.data, old_len, new_len); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->memory.data = (uint8_t *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->memory.data = (uint8_t*)p; memset(m->memory.data + old_len, 0, new_len - old_len); m->memory.data_len = new_len; } -static WasmFunc *wasm_add_func(CfreeCompiler *c, WasmModule *m) { - WasmFunc *f; +static WasmFunc* wasm_add_func(CfreeCompiler* c, WasmModule* m) { + WasmFunc* f; if (m->nfuncs == m->cap_funcs) { uint32_t new_cap = m->cap_funcs ? m->cap_funcs * 2u : 4u; - void *p = wasm_realloc(m->heap, m->funcs, sizeof(*m->funcs) * m->cap_funcs, + void* p = wasm_realloc(m->heap, m->funcs, sizeof(*m->funcs) * m->cap_funcs, sizeof(*m->funcs) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->funcs = (WasmFunc *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->funcs = (WasmFunc*)p; memset(m->funcs + m->cap_funcs, 0, sizeof(*m->funcs) * (new_cap - m->cap_funcs)); m->cap_funcs = new_cap; @@ -469,15 +460,14 @@ static WasmFunc *wasm_add_func(CfreeCompiler *c, WasmModule *m) { return f; } -static WasmFuncType *wasm_add_type(CfreeCompiler *c, WasmModule *m) { - WasmFuncType *t; +static WasmFuncType* wasm_add_type(CfreeCompiler* c, WasmModule* m) { + WasmFuncType* t; if (m->ntypes == m->cap_types) { uint32_t new_cap = m->cap_types ? m->cap_types * 2u : 8u; - void *p = wasm_realloc(m->heap, m->types, sizeof(*m->types) * m->cap_types, + void* p = wasm_realloc(m->heap, m->types, sizeof(*m->types) * m->cap_types, sizeof(*m->types) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->types = (WasmFuncType *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->types = (WasmFuncType*)p; memset(m->types + m->cap_types, 0, sizeof(*m->types) * (new_cap - m->cap_types)); m->cap_types = new_cap; @@ -487,11 +477,11 @@ static WasmFuncType *wasm_add_type(CfreeCompiler *c, WasmModule *m) { return t; } -static uint32_t wasm_intern_func_type(CfreeCompiler *c, WasmModule *m, - const WasmFunc *f) { +static uint32_t wasm_intern_func_type(CfreeCompiler* c, WasmModule* m, + const WasmFunc* f) { uint32_t i; for (i = 0; i < m->ntypes; ++i) { - WasmFuncType *t = &m->types[i]; + WasmFuncType* t = &m->types[i]; if (t->nparams == f->nparams && t->nresults == f->nresults && memcmp(t->params, f->params, sizeof(t->params[0]) * t->nparams) == 0 && memcmp(t->results, f->results, sizeof(t->results[0]) * t->nresults) == @@ -499,7 +489,7 @@ static uint32_t wasm_intern_func_type(CfreeCompiler *c, WasmModule *m, return i; } { - WasmFuncType *t = wasm_add_type(c, m); + WasmFuncType* t = wasm_add_type(c, m); t->nparams = f->nparams; memcpy(t->params, f->params, sizeof(t->params[0]) * f->nparams); t->nresults = f->nresults; @@ -508,16 +498,15 @@ static uint32_t wasm_intern_func_type(CfreeCompiler *c, WasmModule *m, } } -static WasmTable *wasm_add_table(CfreeCompiler *c, WasmModule *m) { - WasmTable *t; +static WasmTable* wasm_add_table(CfreeCompiler* c, WasmModule* m) { + WasmTable* t; if (m->ntables == m->cap_tables) { uint32_t new_cap = m->cap_tables ? m->cap_tables * 2u : 2u; - void *p = + void* p = wasm_realloc(m->heap, m->tables, sizeof(*m->tables) * m->cap_tables, sizeof(*m->tables) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->tables = (WasmTable *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->tables = (WasmTable*)p; memset(m->tables + m->cap_tables, 0, sizeof(*m->tables) * (new_cap - m->cap_tables)); m->cap_tables = new_cap; @@ -527,16 +516,15 @@ static WasmTable *wasm_add_table(CfreeCompiler *c, WasmModule *m) { return t; } -static WasmGlobal *wasm_add_global(CfreeCompiler *c, WasmModule *m) { - WasmGlobal *g; +static WasmGlobal* wasm_add_global(CfreeCompiler* c, WasmModule* m) { + WasmGlobal* g; if (m->nglobals == m->cap_globals) { uint32_t new_cap = m->cap_globals ? m->cap_globals * 2u : 4u; - void *p = + void* p = wasm_realloc(m->heap, m->globals, sizeof(*m->globals) * m->cap_globals, sizeof(*m->globals) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->globals = (WasmGlobal *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->globals = (WasmGlobal*)p; memset(m->globals + m->cap_globals, 0, sizeof(*m->globals) * (new_cap - m->cap_globals)); m->cap_globals = new_cap; @@ -546,15 +534,14 @@ static WasmGlobal *wasm_add_global(CfreeCompiler *c, WasmModule *m) { return g; } -static WasmElemSegment *wasm_add_elem(CfreeCompiler *c, WasmModule *m) { - WasmElemSegment *e; +static WasmElemSegment* wasm_add_elem(CfreeCompiler* c, WasmModule* m) { + WasmElemSegment* e; if (m->nelems == m->cap_elems) { uint32_t new_cap = m->cap_elems ? m->cap_elems * 2u : 4u; - void *p = wasm_realloc(m->heap, m->elems, sizeof(*m->elems) * m->cap_elems, + void* p = wasm_realloc(m->heap, m->elems, sizeof(*m->elems) * m->cap_elems, sizeof(*m->elems) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->elems = (WasmElemSegment *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->elems = (WasmElemSegment*)p; memset(m->elems + m->cap_elems, 0, sizeof(*m->elems) * (new_cap - m->cap_elems)); m->cap_elems = new_cap; @@ -564,16 +551,15 @@ static WasmElemSegment *wasm_add_elem(CfreeCompiler *c, WasmModule *m) { return e; } -static WasmExport *wasm_add_export(CfreeCompiler *c, WasmModule *m) { - WasmExport *e; +static WasmExport* wasm_add_export(CfreeCompiler* c, WasmModule* m) { + WasmExport* e; if (m->nexports == m->cap_exports) { uint32_t new_cap = m->cap_exports ? m->cap_exports * 2u : 8u; - void *p = + void* p = wasm_realloc(m->heap, m->exports, sizeof(*m->exports) * m->cap_exports, sizeof(*m->exports) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->exports = (WasmExport *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->exports = (WasmExport*)p; memset(m->exports + m->cap_exports, 0, sizeof(*m->exports) * (new_cap - m->cap_exports)); m->cap_exports = new_cap; @@ -583,16 +569,15 @@ static WasmExport *wasm_add_export(CfreeCompiler *c, WasmModule *m) { return e; } -static WasmCustom *wasm_add_custom(CfreeCompiler *c, WasmModule *m) { - WasmCustom *cs; +static WasmCustom* wasm_add_custom(CfreeCompiler* c, WasmModule* m) { + WasmCustom* cs; if (m->ncustoms == m->cap_customs) { uint32_t new_cap = m->cap_customs ? m->cap_customs * 2u : 4u; - void *p = + void* p = wasm_realloc(m->heap, m->customs, sizeof(*m->customs) * m->cap_customs, sizeof(*m->customs) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - m->customs = (WasmCustom *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + m->customs = (WasmCustom*)p; memset(m->customs + m->cap_customs, 0, sizeof(*m->customs) * (new_cap - m->cap_customs)); m->cap_customs = new_cap; @@ -602,15 +587,14 @@ static WasmCustom *wasm_add_custom(CfreeCompiler *c, WasmModule *m) { return cs; } -static void wasm_func_add_insn(CfreeCompiler *c, WasmModule *m, WasmFunc *f, +static void wasm_func_add_insn(CfreeCompiler* c, WasmModule* m, WasmFunc* f, WasmInsnKind kind, int64_t imm) { if (f->ninsns == f->cap_insns) { uint32_t new_cap = f->cap_insns ? f->cap_insns * 2u : 16u; - void *p = wasm_realloc(m->heap, f->insns, sizeof(*f->insns) * f->cap_insns, + void* p = wasm_realloc(m->heap, f->insns, sizeof(*f->insns) * f->cap_insns, sizeof(*f->insns) * new_cap); - if (!p) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); - f->insns = (WasmInsn *)p; + if (!p) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + f->insns = (WasmInsn*)p; f->cap_insns = new_cap; } f->insns[f->ninsns].kind = (uint8_t)kind; @@ -622,50 +606,45 @@ static void wasm_func_add_insn(CfreeCompiler *c, WasmModule *m, WasmFunc *f, f->ninsns++; } -static void wasm_func_add_mem_insn(CfreeCompiler *c, WasmModule *m, WasmFunc *f, +static void wasm_func_add_mem_insn(CfreeCompiler* c, WasmModule* m, WasmFunc* f, WasmInsnKind kind, uint32_t align, uint32_t offset) { wasm_func_add_insn(c, m, f, kind, (int64_t)offset); f->insns[f->ninsns - 1u].align = align; } -static void wasm_func_add_fp_insn(CfreeCompiler *c, WasmModule *m, WasmFunc *f, +static void wasm_func_add_fp_insn(CfreeCompiler* c, WasmModule* m, WasmFunc* f, WasmInsnKind kind, double value) { wasm_func_add_insn(c, m, f, kind, 0); f->insns[f->ninsns - 1u].fp = value; } -static int tok_is(WasmTok t, const char *s) { +static int tok_is(WasmTok t, const char* s) { size_t n = strlen(s); return t.kind == WT_ATOM && t.len == n && memcmp(t.p, s, n) == 0; } -static int wasm_name_eq(const char *name, WasmTok t) { +static int wasm_name_eq(const char* name, WasmTok t) { size_t n; - if (!name || t.kind != WT_ATOM) - return 0; + if (!name || t.kind != WT_ATOM) return 0; n = strlen(name); return t.len == n && memcmp(name, t.p, n) == 0; } static int wat_hex(char ch) { - if (ch >= '0' && ch <= '9') - return ch - '0'; - if (ch >= 'a' && ch <= 'f') - return ch - 'a' + 10; - if (ch >= 'A' && ch <= 'F') - return ch - 'A' + 10; + if (ch >= '0' && ch <= '9') return ch - '0'; + if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; + if (ch >= 'A' && ch <= 'F') return ch - 'A' + 10; return -1; } -static char *wat_dup_string(WatParser *p, WasmTok t, size_t *len_out) { - char *out; +static char* wat_dup_string(WatParser* p, WasmTok t, size_t* len_out) { + char* out; size_t i, n = 0; if (t.kind != WT_STRING) wasm_error(p->c, wasm_loc(t.line, t.col), "wasm wat: expected string"); - out = (char *)p->module->heap->alloc(p->module->heap, t.len + 1u, 1); - if (!out) - wasm_error(p->c, wasm_loc(t.line, t.col), "wasm: out of memory"); + out = (char*)p->module->heap->alloc(p->module->heap, t.len + 1u, 1); + if (!out) wasm_error(p->c, wasm_loc(t.line, t.col), "wasm: out of memory"); for (i = 0; i < t.len; ++i) { char ch = t.p[i]; if (ch != '\\') { @@ -677,40 +656,39 @@ static char *wat_dup_string(WatParser *p, WasmTok t, size_t *len_out) { "wasm wat: unterminated string escape"); ch = t.p[i]; switch (ch) { - case 'n': - out[n++] = '\n'; - break; - case 'r': - out[n++] = '\r'; - break; - case 't': - out[n++] = '\t'; - break; - case '"': - case '\'': - case '\\': - out[n++] = ch; - break; - default: { - int hi = wat_hex(ch); - int lo = (i + 1u < t.len) ? wat_hex(t.p[i + 1u]) : -1; - if (hi < 0 || lo < 0) - wasm_error(p->c, wasm_loc(t.line, t.col), - "wasm wat: unsupported string escape"); - out[n++] = (char)((hi << 4) | lo); - i++; - break; - } + case 'n': + out[n++] = '\n'; + break; + case 'r': + out[n++] = '\r'; + break; + case 't': + out[n++] = '\t'; + break; + case '"': + case '\'': + case '\\': + out[n++] = ch; + break; + default: { + int hi = wat_hex(ch); + int lo = (i + 1u < t.len) ? wat_hex(t.p[i + 1u]) : -1; + if (hi < 0 || lo < 0) + wasm_error(p->c, wasm_loc(t.line, t.col), + "wasm wat: unsupported string escape"); + out[n++] = (char)((hi << 4) | lo); + i++; + break; + } } } out[n] = '\0'; - if (len_out) - *len_out = n; + if (len_out) *len_out = n; return out; } -static void wat_next(WatParser *p) { - const char *s = p->src; +static void wat_next(WatParser* p) { + const char* s = p->src; while (p->pos < p->len) { char ch = s[p->pos]; if (ch == '\n') { @@ -767,8 +745,7 @@ static void wat_next(WatParser *p) { p->tok.line = p->line; p->tok.col = p->col; p->tok.kind = WT_EOF; - if (p->pos >= p->len) - return; + if (p->pos >= p->len) return; if (s[p->pos] == '(') { p->tok.kind = WT_LPAREN; p->tok.len = 1; @@ -792,8 +769,7 @@ static void wat_next(WatParser *p) { if (s[p->pos] == '\\') { p->pos++; p->col++; - if (p->pos >= p->len) - break; + if (p->pos >= p->len) break; } else if ((unsigned char)s[p->pos] < 0x20) { wasm_error(p->c, wasm_loc(p->line, p->col), "wasm wat: unsupported string escape/control character"); @@ -821,21 +797,20 @@ static void wat_next(WatParser *p) { p->tok.len = (size_t)(s + p->pos - p->tok.p); } -static void wat_expect(WatParser *p, uint8_t kind, const char *what) { +static void wat_expect(WatParser* p, uint8_t kind, const char* what) { if (p->tok.kind != kind) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected %s", what); wat_next(p); } -static int wat_parse_i64(WatParser *p, int64_t *out) { - const char *s = p->tok.p; +static int wat_parse_i64(WatParser* p, int64_t* out) { + const char* s = p->tok.p; size_t n = p->tok.len, i = 0; uint64_t v = 0; int neg = 0; unsigned base = 10; - if (p->tok.kind != WT_ATOM || n == 0) - return 0; + if (p->tok.kind != WT_ATOM || n == 0) return 0; if (s[0] == '-' || s[0] == '+') { neg = s[0] == '-'; i = 1; @@ -844,28 +819,24 @@ static int wat_parse_i64(WatParser *p, int64_t *out) { base = 16; i += 2u; } - if (i == n) - return 0; + if (i == n) return 0; for (; i < n; ++i) { int hd; unsigned d; - if (s[i] == '_') - continue; + if (s[i] == '_') continue; hd = wat_hex(s[i]); - if (hd < 0 || (unsigned)hd >= base) - return 0; + if (hd < 0 || (unsigned)hd >= base) return 0; d = (unsigned)hd; - if (v > (UINT64_MAX - d) / base) - return 0; + if (v > (UINT64_MAX - d) / base) return 0; v = v * base + d; } *out = neg ? -(int64_t)v : (int64_t)v; return 1; } -static int wat_parse_f64(WatParser *p, double *out) { +static int wat_parse_f64(WatParser* p, double* out) { char buf[128]; - char *end = NULL; + char* end = NULL; if (p->tok.kind != WT_ATOM || p->tok.len == 0 || p->tok.len >= sizeof buf) return 0; memcpy(buf, p->tok.p, p->tok.len); @@ -874,7 +845,7 @@ static int wat_parse_f64(WatParser *p, double *out) { return end && *end == '\0'; } -static int wat_val_type(WasmTok t, WasmValType *out) { +static int wat_val_type(WasmTok t, WasmValType* out) { if (tok_is(t, "i32")) { *out = WASM_VAL_I32; return 1; @@ -908,18 +879,14 @@ static int wasm_is_num_type(WasmValType vt) { } static uint8_t wasm_export_kind_from_tok(WasmTok t) { - if (tok_is(t, "func")) - return 0; - if (tok_is(t, "table")) - return 1; - if (tok_is(t, "memory")) - return 2; - if (tok_is(t, "global")) - return 3; + if (tok_is(t, "func")) return 0; + if (tok_is(t, "table")) return 1; + if (tok_is(t, "memory")) return 2; + if (tok_is(t, "global")) return 3; return 0xffu; } -static void wat_skip_list(WatParser *p) { +static void wat_skip_list(WatParser* p) { uint32_t depth = 1; while (depth && p->tok.kind != WT_EOF) { if (p->tok.kind == WT_LPAREN) @@ -930,7 +897,7 @@ static void wat_skip_list(WatParser *p) { } } -static int wat_instr_kind(WasmTok t, WasmInsnKind *out, int *has_imm) { +static int wat_instr_kind(WasmTok t, WasmInsnKind* out, int* has_imm) { *has_imm = 0; if (tok_is(t, "unreachable")) { *out = WASM_INSN_UNREACHABLE; @@ -1539,7 +1506,7 @@ static int wat_instr_kind(WasmTok t, WasmInsnKind *out, int *has_imm) { return 0; } -static void wat_parse_func_index(WatParser *p, int64_t *out) { +static void wat_parse_func_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->nfuncs; ++i) { @@ -1556,7 +1523,7 @@ static void wat_parse_func_index(WatParser *p, int64_t *out) { "wasm wat: expected instruction immediate"); } -static void wat_parse_type_index(WatParser *p, int64_t *out) { +static void wat_parse_type_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->ntypes; ++i) { @@ -1573,7 +1540,7 @@ static void wat_parse_type_index(WatParser *p, int64_t *out) { "wasm wat: expected type index"); } -static void wat_parse_local_index(WatParser *p, WasmFunc *f, int64_t *out) { +static void wat_parse_local_index(WatParser* p, WasmFunc* f, int64_t* out) { uint32_t i, nlocals = f->nparams + f->nlocals; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < nlocals; ++i) { @@ -1590,7 +1557,7 @@ static void wat_parse_local_index(WatParser *p, WasmFunc *f, int64_t *out) { "wasm wat: expected instruction immediate"); } -static void wat_parse_global_index(WatParser *p, int64_t *out) { +static void wat_parse_global_index(WatParser* p, int64_t* out) { uint32_t i; if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { for (i = 0; i < p->module->nglobals; ++i) { @@ -1607,26 +1574,26 @@ static void wat_parse_global_index(WatParser *p, int64_t *out) { "wasm wat: expected global index"); } -static void wat_parse_instr_imm(WatParser *p, WasmFunc *f, WasmInsnKind kind, - int64_t *out) { +static void wat_parse_instr_imm(WatParser* p, WasmFunc* f, WasmInsnKind kind, + int64_t* out) { switch (kind) { - case WASM_INSN_CALL: - wat_parse_func_index(p, out); - break; - case WASM_INSN_GLOBAL_GET: - case WASM_INSN_GLOBAL_SET: - wat_parse_global_index(p, out); - break; - case WASM_INSN_LOCAL_GET: - case WASM_INSN_LOCAL_SET: - case WASM_INSN_LOCAL_TEE: - wat_parse_local_index(p, f, out); - break; - default: - if (!wat_parse_i64(p, out)) - wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), - "wasm wat: expected instruction immediate"); - break; + case WASM_INSN_CALL: + wat_parse_func_index(p, out); + break; + case WASM_INSN_GLOBAL_GET: + case WASM_INSN_GLOBAL_SET: + wat_parse_global_index(p, out); + break; + case WASM_INSN_LOCAL_GET: + case WASM_INSN_LOCAL_SET: + case WASM_INSN_LOCAL_TEE: + wat_parse_local_index(p, f, out); + break; + default: + if (!wat_parse_i64(p, out)) + wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), + "wasm wat: expected instruction immediate"); + break; } } @@ -1650,41 +1617,36 @@ static int wasm_insn_is_mem(WasmInsnKind kind) { return wasm_insn_is_load(kind) || wasm_insn_is_store(kind); } -static int wat_atom_prefix(WasmTok t, const char *prefix) { +static int wat_atom_prefix(WasmTok t, const char* prefix) { size_t n = strlen(prefix); return t.kind == WT_ATOM && t.len >= n && memcmp(t.p, prefix, n) == 0; } -static int wat_parse_u32_atom(WasmTok t, uint32_t *out) { +static int wat_parse_u32_atom(WasmTok t, uint32_t* out) { uint64_t v = 0; size_t i = 0; unsigned base = 10; - if (t.kind != WT_ATOM || t.len == 0) - return 0; + if (t.kind != WT_ATOM || t.len == 0) return 0; if (i + 2u <= t.len && t.p[i] == '0' && (t.p[i + 1u] == 'x' || t.p[i + 1u] == 'X')) { base = 16; i += 2u; } - if (i == t.len) - return 0; + if (i == t.len) return 0; for (; i < t.len; ++i) { int hd; - if (t.p[i] == '_') - continue; + if (t.p[i] == '_') continue; hd = wat_hex(t.p[i]); - if (hd < 0 || (unsigned)hd >= base) - return 0; - if (v > (UINT32_MAX - (uint32_t)hd) / base) - return 0; + if (hd < 0 || (unsigned)hd >= base) return 0; + if (v > (UINT32_MAX - (uint32_t)hd) / base) return 0; v = v * base + (uint32_t)hd; } *out = (uint32_t)v; return 1; } -static void wat_parse_mem_attrs(WatParser *p, uint32_t *align, - uint32_t *offset) { +static void wat_parse_mem_attrs(WatParser* p, uint32_t* align, + uint32_t* offset) { while (p->tok.kind == WT_ATOM) { WasmTok val; if (wat_atom_prefix(p->tok, "align=")) { @@ -1709,9 +1671,8 @@ static void wat_parse_mem_attrs(WatParser *p, uint32_t *align, } } -static void wat_reject_inline_result(WatParser *p, const char *what) { - if (p->tok.kind != WT_LPAREN) - return; +static void wat_reject_inline_result(WatParser* p, const char* what) { + if (p->tok.kind != WT_LPAREN) return; wat_next(p); if (!tok_is(p->tok, "result")) { p->pos = (size_t)(p->tok.p - p->src); @@ -1728,9 +1689,9 @@ static void wat_reject_inline_result(WatParser *p, const char *what) { "wasm wat: %s results are unsupported", what); } -static void wat_parse_instr(WatParser *p, WasmFunc *f); +static void wat_parse_instr(WatParser* p, WasmFunc* f); -static uint32_t wat_parse_call_indirect_type(WatParser *p) { +static uint32_t wat_parse_call_indirect_type(WatParser* p) { int64_t typeidx; wat_expect(p, WT_LPAREN, "'('"); if (!tok_is(p->tok, "type")) @@ -1746,7 +1707,7 @@ static uint32_t wat_parse_call_indirect_type(WatParser *p) { return (uint32_t)typeidx; } -static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { +static void wat_parse_instr_list(WatParser* p, WasmFunc* f) { WasmInsnKind kind; int has_imm; int64_t imm = 0; @@ -1798,8 +1759,7 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { p->tok.len = 1; p->tok.line = save_line; p->tok.col = save_col - 1u; - if (tok_is(save_head, "then") || tok_is(save_head, "else")) - break; + if (tok_is(save_head, "then") || tok_is(save_head, "else")) break; if (tok_is(save_head, "result")) wasm_error(p->c, wasm_loc(save_head.line, save_head.col), "wasm wat: if results are unsupported"); @@ -1838,14 +1798,13 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { if (wasm_insn_is_mem(kind)) { uint32_t align = 0, offset = 0; wat_parse_mem_attrs(p, &align, &offset); - while (p->tok.kind == WT_LPAREN) - wat_parse_instr(p, f); + while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f); wasm_func_add_mem_insn(p->c, p->module, f, kind, align, offset); wat_expect(p, WT_RPAREN, "')'"); return; } if (kind == WASM_INSN_BR_TABLE) { - WasmInsn *in; + WasmInsn* in; uint32_t n = 0; while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) { int64_t target; @@ -1868,8 +1827,7 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { } if (kind == WASM_INSN_CALL_INDIRECT) { uint32_t typeidx = wat_parse_call_indirect_type(p); - while (p->tok.kind == WT_LPAREN) - wat_parse_instr(p, f); + while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f); wasm_func_add_insn(p->c, p->module, f, kind, typeidx); wat_expect(p, WT_RPAREN, "')'"); return; @@ -1881,8 +1839,7 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected float immediate"); wat_next(p); - while (p->tok.kind == WT_LPAREN) - wat_parse_instr(p, f); + while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f); wasm_func_add_fp_insn(p->c, p->module, f, kind, fv); wat_expect(p, WT_RPAREN, "')'"); return; @@ -1891,13 +1848,12 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) { wat_next(p); } } - while (p->tok.kind == WT_LPAREN) - wat_parse_instr(p, f); + while (p->tok.kind == WT_LPAREN) wat_parse_instr(p, f); wasm_func_add_insn(p->c, p->module, f, kind, imm); wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_instr(WatParser *p, WasmFunc *f) { +static void wat_parse_instr(WatParser* p, WasmFunc* f) { WasmInsnKind kind; int has_imm; if (p->tok.kind == WT_LPAREN) { @@ -1919,7 +1875,7 @@ static void wat_parse_instr(WatParser *p, WasmFunc *f) { return; } if (kind == WASM_INSN_BR_TABLE) { - WasmInsn *in; + WasmInsn* in; uint32_t n = 0; wasm_func_add_insn(p->c, p->module, f, WASM_INSN_BR_TABLE, 0); in = &f->insns[f->ninsns - 1u]; @@ -1927,8 +1883,7 @@ static void wat_parse_instr(WatParser *p, WasmFunc *f) { WasmInsnKind next_kind; int next_has_imm; int64_t target; - if (wat_instr_kind(p->tok, &next_kind, &next_has_imm)) - break; + if (wat_instr_kind(p->tok, &next_kind, &next_has_imm)) break; if (n >= 16u) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: too many br_table targets"); @@ -1965,8 +1920,8 @@ static void wat_parse_instr(WatParser *p, WasmFunc *f) { } } -static void wat_parse_func(WatParser *p) { - WasmFunc *f = wasm_add_func(p->c, p->module); +static void wat_parse_func(WatParser* p) { + WasmFunc* f = wasm_add_func(p->c, p->module); uint32_t checked_params = 0; uint32_t checked_results = 0; wat_expect(p, WT_LPAREN, "'('"); @@ -1991,7 +1946,7 @@ static void wat_parse_func(WatParser *p) { "wasm wat: expected export string"); f->export_name = wat_dup_string(p, p->tok, NULL); { - WasmExport *ex = wasm_add_export(p->c, p->module); + WasmExport* ex = wasm_add_export(p->c, p->module); ex->name = wasm_strdup(p->module->heap, f->export_name, strlen(f->export_name)); if (!ex->name) @@ -2145,8 +2100,8 @@ static void wat_parse_func(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_type_field(WatParser *p) { - WasmFuncType *t = wasm_add_type(p->c, p->module); +static void wat_parse_type_field(WatParser* p) { + WasmFuncType* t = wasm_add_type(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { t->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); if (!t->name) @@ -2201,8 +2156,8 @@ static void wat_parse_type_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_export_field(WatParser *p) { - char *name; +static void wat_parse_export_field(WatParser* p) { + char* name; int64_t idx = 0; uint8_t kind; if (p->tok.kind != WT_STRING) @@ -2225,7 +2180,7 @@ static void wat_parse_export_field(WatParser *p) { wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: export index out of range"); { - WasmExport *ex = wasm_add_export(p->c, p->module); + WasmExport* ex = wasm_add_export(p->c, p->module); ex->name = name; ex->kind = kind; ex->index = (uint32_t)idx; @@ -2264,13 +2219,12 @@ static void wat_parse_export_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_memory_field(WatParser *p) { +static void wat_parse_memory_field(WatParser* p) { int64_t min_pages, max_pages; if (p->module->has_memory) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: multiple memories are unsupported"); - if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') - wat_next(p); + if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') wat_next(p); if (!wat_parse_i64(p, &min_pages) || min_pages < 0 || min_pages > UINT16_MAX) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected memory minimum"); @@ -2290,8 +2244,8 @@ static void wat_parse_memory_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_limits(WatParser *p, uint32_t *min, uint32_t *max, - int *has_max, const char *what) { +static void wat_parse_limits(WatParser* p, uint32_t* min, uint32_t* max, + int* has_max, const char* what) { int64_t lo, hi; if (!wat_parse_i64(p, &lo) || lo < 0 || lo > UINT32_MAX) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), @@ -2308,7 +2262,7 @@ static void wat_parse_limits(WatParser *p, uint32_t *min, uint32_t *max, } } -static void wat_parse_table_limits_and_type(WatParser *p, WasmTable *t) { +static void wat_parse_table_limits_and_type(WatParser* p, WasmTable* t) { int64_t lo, hi; if (!wat_parse_i64(p, &lo) || lo < 0 || lo > UINT32_MAX) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), @@ -2332,7 +2286,7 @@ static void wat_parse_table_limits_and_type(WatParser *p, WasmTable *t) { wat_next(p); } -static void wat_parse_import_field(WatParser *p) { +static void wat_parse_import_field(WatParser* p) { char *mod, *name; if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), @@ -2346,7 +2300,7 @@ static void wat_parse_import_field(WatParser *p) { wat_next(p); wat_expect(p, WT_LPAREN, "'('"); if (tok_is(p->tok, "func")) { - WasmFunc *f = wasm_add_func(p->c, p->module); + WasmFunc* f = wasm_add_func(p->c, p->module); f->is_import = 1; f->import_module = mod; f->import_name = name; @@ -2412,8 +2366,7 @@ static void wat_parse_import_field(WatParser *p) { } wat_expect(p, WT_RPAREN, "')'"); } - if (!f->has_typeidx) - f->typeidx = wasm_intern_func_type(p->c, p->module, f); + if (!f->has_typeidx) f->typeidx = wasm_intern_func_type(p->c, p->module, f); } else if (tok_is(p->tok, "memory")) { if (p->module->has_memory) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), @@ -2435,7 +2388,7 @@ static void wat_parse_import_field(WatParser *p) { &p->module->memory.max_pages, &p->module->memory.has_max, "memory"); } else if (tok_is(p->tok, "table")) { - WasmTable *t = wasm_add_table(p->c, p->module); + WasmTable* t = wasm_add_table(p->c, p->module); t->is_import = 1; t->import_module = mod; t->import_name = name; @@ -2449,7 +2402,7 @@ static void wat_parse_import_field(WatParser *p) { } wat_parse_table_limits_and_type(p, t); } else if (tok_is(p->tok, "global")) { - WasmGlobal *g = wasm_add_global(p->c, p->module); + WasmGlobal* g = wasm_add_global(p->c, p->module); g->is_import = 1; g->import_module = mod; g->import_name = name; @@ -2487,8 +2440,8 @@ static void wat_parse_import_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_table_field(WatParser *p) { - WasmTable *t = wasm_add_table(p->c, p->module); +static void wat_parse_table_field(WatParser* p) { + WasmTable* t = wasm_add_table(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { t->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); if (!t->name) @@ -2500,7 +2453,7 @@ static void wat_parse_table_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_const_expr(WatParser *p, WasmInsn *out) { +static void wat_parse_const_expr(WatParser* p, WasmInsn* out) { WasmInsnKind kind; int has_imm; memset(out, 0, sizeof *out); @@ -2524,8 +2477,8 @@ static void wat_parse_const_expr(WatParser *p, WasmInsn *out) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_global_field(WatParser *p) { - WasmGlobal *g = wasm_add_global(p->c, p->module); +static void wat_parse_global_field(WatParser* p) { + WasmGlobal* g = wasm_add_global(p->c, p->module); if (p->tok.kind == WT_ATOM && p->tok.len && p->tok.p[0] == '$') { g->name = wasm_strdup(p->module->heap, p->tok.p, p->tok.len); if (!g->name) @@ -2542,7 +2495,7 @@ static void wat_parse_global_field(WatParser *p) { "wasm wat: expected export string"); g->export_name = wat_dup_string(p, p->tok, NULL); { - WasmExport *ex = wasm_add_export(p->c, p->module); + WasmExport* ex = wasm_add_export(p->c, p->module); ex->name = wasm_strdup(p->module->heap, g->export_name, strlen(g->export_name)); if (!ex->name) @@ -2578,8 +2531,8 @@ static void wat_parse_global_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_elem_field(WatParser *p) { - WasmElemSegment *e = wasm_add_elem(p->c, p->module); +static void wat_parse_elem_field(WatParser* p) { + WasmElemSegment* e = wasm_add_elem(p->c, p->module); e->tableidx = 0; if (p->tok.kind == WT_ATOM) { int64_t tableidx; @@ -2599,8 +2552,7 @@ static void wat_parse_elem_field(WatParser *p) { "wasm wat: element offset must be i32.const"); e->offset = off.imm; } - if (tok_is(p->tok, "func")) - wat_next(p); + if (tok_is(p->tok, "func")) wat_next(p); while (p->tok.kind != WT_RPAREN && p->tok.kind != WT_EOF) { int64_t idx; if (e->nfuncs >= 64u) @@ -2616,7 +2568,7 @@ static void wat_parse_elem_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_start_field(WatParser *p) { +static void wat_parse_start_field(WatParser* p) { int64_t idx; wat_parse_func_index(p, &idx); if (idx < 0 || idx > UINT32_MAX) @@ -2628,10 +2580,10 @@ static void wat_parse_start_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_custom_field(WatParser *p) { - WasmCustom *cs; +static void wat_parse_custom_field(WatParser* p) { + WasmCustom* cs; size_t n = 0; - char *bytes; + char* bytes; if (p->tok.kind != WT_STRING) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected custom section name"); @@ -2643,8 +2595,7 @@ static void wat_parse_custom_field(WatParser *p) { wat_next(p); if (p->tok.kind == WT_STRING) { bytes = wat_dup_string(p, p->tok, &n); - cs->data = - (uint8_t *)p->module->heap->alloc(p->module->heap, n ? n : 1u, 1); + cs->data = (uint8_t*)p->module->heap->alloc(p->module->heap, n ? n : 1u, 1); if (!cs->data) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm: out of memory"); @@ -2656,13 +2607,12 @@ static void wat_parse_custom_field(WatParser *p) { wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_data_field(WatParser *p) { +static void wat_parse_data_field(WatParser* p) { int64_t offset = 0; - char *bytes; + char* bytes; size_t nbytes; size_t alloc_len; - if (p->tok.kind == WT_ATOM) - wat_next(p); + if (p->tok.kind == WT_ATOM) wat_next(p); wat_expect(p, WT_LPAREN, "'('"); if (!tok_is(p->tok, "i32.const")) wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), @@ -2684,20 +2634,19 @@ static void wat_parse_data_field(WatParser *p) { wasm_memory_ensure(p->c, p->module, (uint32_t)offset + (uint32_t)nbytes); memcpy(p->module->memory.data + (uint32_t)offset, bytes, nbytes); if ((uint64_t)offset + nbytes > p->module->memory.data_init_len) - p->module->memory.data_init_len = - (uint32_t)((uint64_t)offset + nbytes); + p->module->memory.data_init_len = (uint32_t)((uint64_t)offset + nbytes); p->module->heap->free(p->module->heap, bytes, alloc_len); wat_next(p); wat_expect(p, WT_RPAREN, "')'"); } -static void wat_parse_module(CfreeCompiler *c, const CfreeBytesInput *input, - WasmModule *out) { +static void wat_parse_module(CfreeCompiler* c, const CfreeBytesInput* input, + WasmModule* out) { WatParser p; memset(&p, 0, sizeof p); p.c = c; p.name = input->name; - p.src = (const char *)input->data; + p.src = (const char*)input->data; p.len = input->len; p.line = 1; p.col = 1; @@ -2762,13 +2711,13 @@ static void wat_parse_module(CfreeCompiler *c, const CfreeBytesInput *input, "wasm wat: trailing tokens after module"); } -static uint8_t bin_u8(BinReader *r) { +static uint8_t bin_u8(BinReader* r) { if (r->pos >= r->len) wasm_error(r->c, wasm_loc(0, 0), "wasm: unexpected end of file"); return r->data[r->pos++]; } -static uint32_t bin_uleb(BinReader *r) { +static uint32_t bin_uleb(BinReader* r) { uint32_t result = 0, shift = 0; uint32_t nbytes = 0; for (;;) { @@ -2776,13 +2725,12 @@ static uint32_t bin_uleb(BinReader *r) { if (nbytes++ >= 5u || (shift == 28u && (b & 0xf0u))) wasm_error(r->c, wasm_loc(0, 0), "wasm: invalid uleb128"); result |= (uint32_t)(b & 0x7fu) << shift; - if (!(b & 0x80u)) - return result; + if (!(b & 0x80u)) return result; shift += 7u; } } -static int64_t bin_sleb(BinReader *r, uint32_t bits) { +static int64_t bin_sleb(BinReader* r, uint32_t bits) { int64_t result = 0; uint32_t shift = 0; uint32_t max_bytes = (bits + 6u) / 7u; @@ -2795,69 +2743,63 @@ static int64_t bin_sleb(BinReader *r, uint32_t bits) { result |= (int64_t)(b & 0x7fu) << shift; shift += 7u; } while (b & 0x80u); - if (shift < bits && (b & 0x40u)) - result |= -((int64_t)1 << shift); + if (shift < bits && (b & 0x40u)) result |= -((int64_t)1 << shift); return result; } -static double bin_f32(BinReader *r) { +static double bin_f32(BinReader* r) { uint32_t bits = 0; float f; - for (uint32_t i = 0; i < 4u; ++i) - bits |= (uint32_t)bin_u8(r) << (i * 8u); + for (uint32_t i = 0; i < 4u; ++i) bits |= (uint32_t)bin_u8(r) << (i * 8u); memcpy(&f, &bits, sizeof f); return (double)f; } -static double bin_f64(BinReader *r) { +static double bin_f64(BinReader* r) { uint64_t bits = 0; double d; - for (uint32_t i = 0; i < 8u; ++i) - bits |= (uint64_t)bin_u8(r) << (i * 8u); + for (uint32_t i = 0; i < 8u; ++i) bits |= (uint64_t)bin_u8(r) << (i * 8u); memcpy(&d, &bits, sizeof d); return d; } -static void bin_need(BinReader *r, size_t n) { +static void bin_need(BinReader* r, size_t n) { if (n > r->len || r->pos > r->len - n) wasm_error(r->c, wasm_loc(0, 0), "wasm: section length out of bounds"); } -static char *bin_name(BinReader *r, CfreeHeap *h, uint32_t *len_out) { +static char* bin_name(BinReader* r, CfreeHeap* h, uint32_t* len_out) { uint32_t n = bin_uleb(r); - char *s; + char* s; bin_need(r, n); - s = wasm_strdup(h, (const char *)(r->data + r->pos), n); - if (!s) - wasm_error(r->c, wasm_loc(0, 0), "wasm: out of memory"); + s = wasm_strdup(h, (const char*)(r->data + r->pos), n); + if (!s) wasm_error(r->c, wasm_loc(0, 0), "wasm: out of memory"); r->pos += n; - if (len_out) - *len_out = n; + if (len_out) *len_out = n; return s; } -static WasmValType bin_val_type(BinReader *r, int refs_ok) { +static WasmValType bin_val_type(BinReader* r, int refs_ok) { uint8_t b = bin_u8(r); switch (b) { - case WASM_VAL_I32: - case WASM_VAL_I64: - case WASM_VAL_F32: - case WASM_VAL_F64: - return (WasmValType)b; - case WASM_VAL_FUNCREF: - case WASM_VAL_EXTERNREF: - if (refs_ok) + case WASM_VAL_I32: + case WASM_VAL_I64: + case WASM_VAL_F32: + case WASM_VAL_F64: return (WasmValType)b; - break; - default: - break; + case WASM_VAL_FUNCREF: + case WASM_VAL_EXTERNREF: + if (refs_ok) return (WasmValType)b; + break; + default: + break; } wasm_error(r->c, wasm_loc(0, 0), "wasm: unsupported value type 0x%02x", b); return WASM_VAL_I32; } -static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, - WasmModule *out) { +static void wasm_decode_binary(CfreeCompiler* c, const CfreeBytesInput* input, + WasmModule* out) { BinReader r; uint32_t nfunc_types = 0; uint8_t last_id = 0; @@ -2877,8 +2819,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, end = r.pos + size; if (id != 0 && id <= last_id) wasm_error(c, wasm_loc(0, 0), "wasm: sections out of order"); - if (id != 0) - last_id = id; + if (id != 0) last_id = id; if (id == 0) { uint32_t name_len = bin_uleb(&r); bin_need(&r, name_len); @@ -2886,20 +2827,18 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: relocatable object metadata is not frontend input"); { - WasmCustom *cs = wasm_add_custom(c, out); + WasmCustom* cs = wasm_add_custom(c, out); cs->name = - wasm_strdup(out->heap, (const char *)(r.data + r.pos), name_len); - if (!cs->name) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + wasm_strdup(out->heap, (const char*)(r.data + r.pos), name_len); + if (!cs->name) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); r.pos += name_len; if (strcmp(cs->name, "target_features") == 0 || strcmp(cs->name, "target-feature") == 0) out->has_target_features = 1; cs->len = (uint32_t)(end - r.pos); if (cs->len) { - cs->data = (uint8_t *)out->heap->alloc(out->heap, cs->len, 1); - if (!cs->data) - wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); + cs->data = (uint8_t*)out->heap->alloc(out->heap, cs->len, 1); + if (!cs->data) wasm_error(c, wasm_loc(0, 0), "wasm: out of memory"); memcpy(cs->data, r.data + r.pos, cs->len); } } @@ -2908,10 +2847,9 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, } if (id == 1) { uint32_t i, count = bin_uleb(&r); - if (count > 64u) - wasm_error(c, wasm_loc(0, 0), "wasm: too many types"); + if (count > 64u) wasm_error(c, wasm_loc(0, 0), "wasm: too many types"); for (i = 0; i < count; ++i) { - WasmFuncType *t = wasm_add_type(c, out); + WasmFuncType* t = wasm_add_type(c, out); uint32_t j, nparam, nresult; if (bin_u8(&r) != 0x60u) wasm_error(c, wasm_loc(0, 0), "wasm: expected function type"); @@ -2919,24 +2857,22 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, if (nparam > 16u) wasm_error(c, wasm_loc(0, 0), "wasm: too many parameters"); t->nparams = nparam; - for (j = 0; j < nparam; ++j) - t->params[j] = bin_val_type(&r, 0); + for (j = 0; j < nparam; ++j) t->params[j] = bin_val_type(&r, 0); nresult = bin_uleb(&r); if (nresult > 1u) wasm_error(c, wasm_loc(0, 0), "wasm: multi-result unsupported"); t->nresults = nresult; - for (j = 0; j < nresult; ++j) - t->results[j] = bin_val_type(&r, 0); + for (j = 0; j < nresult; ++j) t->results[j] = bin_val_type(&r, 0); } } else if (id == 2) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - char *mod = bin_name(&r, out->heap, NULL); - char *name = bin_name(&r, out->heap, NULL); + char* mod = bin_name(&r, out->heap, NULL); + char* name = bin_name(&r, out->heap, NULL); uint8_t kind = bin_u8(&r); if (kind == 0) { uint32_t typeidx = bin_uleb(&r); - WasmFunc *f; + WasmFunc* f; if (typeidx >= out->ntypes) wasm_error(c, wasm_loc(0, 0), "wasm: bad import type index"); f = wasm_add_func(c, out); @@ -2952,7 +2888,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, memcpy(f->results, out->types[typeidx].results, sizeof(f->results[0]) * f->nresults); } else if (kind == 1) { - WasmTable *t = wasm_add_table(c, out); + WasmTable* t = wasm_add_table(c, out); t->is_import = 1; t->import_module = mod; t->import_name = name; @@ -2963,8 +2899,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits"); t->has_max = (flags & 1u) != 0; t->min = bin_uleb(&r); - if (t->has_max) - t->max = bin_uleb(&r); + if (t->has_max) t->max = bin_uleb(&r); } } else if (kind == 2) { uint32_t flags; @@ -2980,10 +2915,9 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: unsupported memory limits"); out->memory.has_max = (flags & 1u) != 0; out->memory.min_pages = bin_uleb(&r); - if (out->memory.has_max) - out->memory.max_pages = bin_uleb(&r); + if (out->memory.has_max) out->memory.max_pages = bin_uleb(&r); } else if (kind == 3) { - WasmGlobal *g = wasm_add_global(c, out); + WasmGlobal* g = wasm_add_global(c, out); g->is_import = 1; g->import_module = mod; g->import_name = name; @@ -3001,7 +2935,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: too many functions"); for (i = 0; i < count; ++i) { uint32_t typeidx = bin_uleb(&r); - WasmFunc *f; + WasmFunc* f; if (typeidx >= out->ntypes) wasm_error(c, wasm_loc(0, 0), "wasm: bad function type index"); f = wasm_add_func(c, out); @@ -3037,7 +2971,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, } else if (id == 4) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - WasmTable *t = wasm_add_table(c, out); + WasmTable* t = wasm_add_table(c, out); uint32_t flags; t->elem_type = bin_val_type(&r, 1); flags = bin_uleb(&r); @@ -3045,13 +2979,12 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: unsupported table limits"); t->has_max = (flags & 1u) != 0; t->min = bin_uleb(&r); - if (t->has_max) - t->max = bin_uleb(&r); + if (t->has_max) t->max = bin_uleb(&r); } } else if (id == 6) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - WasmGlobal *g = wasm_add_global(c, out); + WasmGlobal* g = wasm_add_global(c, out); uint8_t op; g->type = bin_val_type(&r, 0); g->mutable_ = bin_u8(&r); @@ -3059,25 +2992,25 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, wasm_error(c, wasm_loc(0, 0), "wasm: bad global mutability"); op = bin_u8(&r); switch (op) { - case 0x41: - g->init.kind = WASM_INSN_I32_CONST; - g->init.imm = bin_sleb(&r, 32); - break; - case 0x42: - g->init.kind = WASM_INSN_I64_CONST; - g->init.imm = bin_sleb(&r, 64); - break; - case 0x43: - g->init.kind = WASM_INSN_F32_CONST; - g->init.fp = bin_f32(&r); - break; - case 0x44: - g->init.kind = WASM_INSN_F64_CONST; - g->init.fp = bin_f64(&r); - break; - default: - wasm_error(c, wasm_loc(0, 0), - "wasm: unsupported global initializer"); + case 0x41: + g->init.kind = WASM_INSN_I32_CONST; + g->init.imm = bin_sleb(&r, 32); + break; + case 0x42: + g->init.kind = WASM_INSN_I64_CONST; + g->init.imm = bin_sleb(&r, 64); + break; + case 0x43: + g->init.kind = WASM_INSN_F32_CONST; + g->init.fp = bin_f32(&r); + break; + case 0x44: + g->init.kind = WASM_INSN_F64_CONST; + g->init.fp = bin_f64(&r); + break; + default: + wasm_error(c, wasm_loc(0, 0), + "wasm: unsupported global initializer"); } if (bin_u8(&r) != 0x0bu) wasm_error(c, wasm_loc(0, 0), "wasm: malformed global initializer"); @@ -3085,21 +3018,20 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, } else if (id == 7) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - char *name; + char* name; uint8_t kind; uint32_t idx; - WasmExport *ex; + WasmExport* ex; name = bin_name(&r, out->heap, NULL); kind = bin_u8(&r); idx = bin_uleb(&r); - if (kind > 3u) - wasm_error(c, wasm_loc(0, 0), "wasm: bad export kind"); + if (kind > 3u) wasm_error(c, wasm_loc(0, 0), "wasm: bad export kind"); ex = wasm_add_export(c, out); ex->name = name; ex->kind = kind; ex->index = idx; if (kind == 0 && idx < out->nfuncs) { - WasmFunc *f = &out->funcs[idx]; + WasmFunc* f = &out->funcs[idx]; wasm_free_str(out->heap, &f->export_name); f->export_name = wasm_strdup(out->heap, name, strlen(name)); if (!f->export_name) @@ -3123,7 +3055,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, } else if (id == 9) { uint32_t i, count = bin_uleb(&r); for (i = 0; i < count; ++i) { - WasmElemSegment *e = wasm_add_elem(c, out); + WasmElemSegment* e = wasm_add_elem(c, out); uint32_t flags = bin_uleb(&r); uint32_t n; if (flags != 0) @@ -3139,8 +3071,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, n = bin_uleb(&r); if (n > 64u) wasm_error(c, wasm_loc(0, 0), "wasm: too many element functions"); - for (uint32_t k = 0; k < n; ++k) - e->funcs[e->nfuncs++] = bin_uleb(&r); + for (uint32_t k = 0; k < n; ++k) e->funcs[e->nfuncs++] = bin_uleb(&r); } } else if (id == 10) { uint32_t i, count = bin_uleb(&r); @@ -3153,7 +3084,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, uint32_t local_groups, j; uint32_t control_depth = 0; int saw_body_end = 0; - WasmFunc *f; + WasmFunc* f; while (func_index < out->nfuncs && out->funcs[func_index].is_import) func_index++; if (func_index >= out->nfuncs) @@ -3167,8 +3098,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, WasmValType vt = (WasmValType)bin_u8(&r); if (nlocals > 32u || f->nlocals > 32u - nlocals) wasm_error(c, wasm_loc(0, 0), "wasm: too many locals"); - for (k = 0; k < nlocals; ++k) - f->locals[f->nlocals++] = vt; + for (k = 0; k < nlocals; ++k) f->locals[f->nlocals++] = vt; } while (r.pos < body_end) { uint8_t op = bin_u8(&r); @@ -3182,505 +3112,504 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, continue; } switch (op) { - case 0x00: - wasm_func_add_insn(c, out, f, WASM_INSN_UNREACHABLE, 0); - break; - case 0x01: - wasm_func_add_insn(c, out, f, WASM_INSN_NOP, 0); - break; - case 0x02: - if (bin_u8(&r) != 0x40u) - wasm_error(c, wasm_loc(0, 0), - "wasm: block results are unsupported"); - control_depth++; - wasm_func_add_insn(c, out, f, WASM_INSN_BLOCK, 0); - break; - case 0x03: - if (bin_u8(&r) != 0x40u) - wasm_error(c, wasm_loc(0, 0), - "wasm: loop results are unsupported"); - control_depth++; - wasm_func_add_insn(c, out, f, WASM_INSN_LOOP, 0); - break; - case 0x04: - if (bin_u8(&r) != 0x40u) - wasm_error(c, wasm_loc(0, 0), - "wasm: if results are unsupported"); - control_depth++; - wasm_func_add_insn(c, out, f, WASM_INSN_IF, 0); - break; - case 0x05: - wasm_func_add_insn(c, out, f, WASM_INSN_ELSE, 0); - break; - case 0x0c: - wasm_func_add_insn(c, out, f, WASM_INSN_BR, bin_uleb(&r)); - break; - case 0x0d: - wasm_func_add_insn(c, out, f, WASM_INSN_BR_IF, bin_uleb(&r)); - break; - case 0x0e: { - WasmInsn *in; - uint32_t n = bin_uleb(&r); - if (n >= 16u) - wasm_error(c, wasm_loc(0, 0), - "wasm: too many br_table targets"); - wasm_func_add_insn(c, out, f, WASM_INSN_BR_TABLE, 0); - in = &f->insns[f->ninsns - 1u]; - for (uint32_t k = 0; k < n; ++k) - in->targets[k] = bin_uleb(&r); - in->targets[n] = bin_uleb(&r); - in->ntargets = n + 1u; - break; - } - case 0x0f: - wasm_func_add_insn(c, out, f, WASM_INSN_RETURN, 0); - break; - case 0x1a: - wasm_func_add_insn(c, out, f, WASM_INSN_DROP, 0); - break; - case 0x1b: - wasm_func_add_insn(c, out, f, WASM_INSN_SELECT, 0); - break; - case 0x28: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x29: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x2c: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD8_S, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x2d: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD8_U, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x2e: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD16_S, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x2f: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD16_U, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x30: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD8_S, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x31: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD8_U, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x32: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD16_S, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x33: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD16_U, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x34: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD32_S, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x35: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD32_U, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x36: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x37: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3a: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE8, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3b: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE16, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3c: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE8, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3d: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE16, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3e: - wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE32, - bin_uleb(&r), bin_uleb(&r)); - break; - case 0x3f: - if (bin_u8(&r) != 0) - wasm_error(c, wasm_loc(0, 0), "wasm: bad memory.size index"); - wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_SIZE, 0); - break; - case 0x40: - if (bin_u8(&r) != 0) - wasm_error(c, wasm_loc(0, 0), "wasm: bad memory.grow index"); - wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_GROW, 0); - break; - case 0x10: - wasm_func_add_insn(c, out, f, WASM_INSN_CALL, bin_uleb(&r)); - break; - case 0x11: { - WasmInsn *in; - wasm_func_add_insn(c, out, f, WASM_INSN_CALL_INDIRECT, - bin_uleb(&r)); - in = &f->insns[f->ninsns - 1u]; - in->align = bin_uleb(&r); - break; - } - case 0x20: - wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_GET, bin_uleb(&r)); - break; - case 0x21: - wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_SET, bin_uleb(&r)); - break; - case 0x22: - wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_TEE, bin_uleb(&r)); - break; - case 0x23: - wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_GET, bin_uleb(&r)); - break; - case 0x24: - wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_SET, bin_uleb(&r)); - break; - case 0x41: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_CONST, - bin_sleb(&r, 32)); - break; - case 0x42: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_CONST, - bin_sleb(&r, 64)); - break; - case 0x43: - wasm_func_add_fp_insn(c, out, f, WASM_INSN_F32_CONST, - bin_f32(&r)); - break; - case 0x44: - wasm_func_add_fp_insn(c, out, f, WASM_INSN_F64_CONST, - bin_f64(&r)); - break; - case 0x45: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQZ, 0); - break; - case 0x46: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQ, 0); - break; - case 0x47: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_NE, 0); - break; - case 0x48: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_S, 0); - break; - case 0x49: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_U, 0); - break; - case 0x4a: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_S, 0); - break; - case 0x4b: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_U, 0); - break; - case 0x4c: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_S, 0); - break; - case 0x4d: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_U, 0); - break; - case 0x4e: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_S, 0); - break; - case 0x4f: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_U, 0); - break; - case 0x50: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQZ, 0); - break; - case 0x51: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQ, 0); - break; - case 0x52: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_NE, 0); - break; - case 0x53: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_S, 0); - break; - case 0x54: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_U, 0); - break; - case 0x55: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_S, 0); - break; - case 0x56: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_U, 0); - break; - case 0x57: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_S, 0); - break; - case 0x58: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_U, 0); - break; - case 0x59: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_S, 0); - break; - case 0x5a: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_U, 0); - break; - case 0x6a: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_ADD, 0); - break; - case 0x6b: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_SUB, 0); - break; - case 0x6c: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_MUL, 0); - break; - case 0x6d: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_S, 0); - break; - case 0x6e: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_U, 0); - break; - case 0x6f: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_S, 0); - break; - case 0x70: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_U, 0); - break; - case 0x71: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_AND, 0); - break; - case 0x72: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_OR, 0); - break; - case 0x73: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_XOR, 0); - break; - case 0x74: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHL, 0); - break; - case 0x75: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_S, 0); - break; - case 0x76: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_U, 0); - break; - case 0x67: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_CLZ, 0); - break; - case 0x68: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_CTZ, 0); - break; - case 0x69: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_POPCNT, 0); - break; - case 0x77: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTL, 0); - break; - case 0x78: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTR, 0); - break; - case 0x79: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_CLZ, 0); - break; - case 0x7a: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_CTZ, 0); - break; - case 0x7b: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_POPCNT, 0); - break; - case 0x7c: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_ADD, 0); - break; - case 0x7d: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_SUB, 0); - break; - case 0x7e: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_MUL, 0); - break; - case 0x7f: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_S, 0); - break; - case 0x80: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_U, 0); - break; - case 0x81: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_S, 0); - break; - case 0x82: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_U, 0); - break; - case 0x83: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_AND, 0); - break; - case 0x84: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_OR, 0); - break; - case 0x85: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_XOR, 0); - break; - case 0x86: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHL, 0); - break; - case 0x87: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_S, 0); - break; - case 0x88: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_U, 0); - break; - case 0x89: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTL, 0); - break; - case 0x8a: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTR, 0); - break; - case 0x92: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_ADD, 0); - break; - case 0x93: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_SUB, 0); - break; - case 0x94: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_MUL, 0); - break; - case 0x95: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_DIV, 0); - break; - case 0xa0: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_ADD, 0); - break; - case 0xa1: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_SUB, 0); - break; - case 0xa2: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_MUL, 0); - break; - case 0xa3: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_DIV, 0); - break; - case 0x5b: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_EQ, 0); - break; - case 0x5c: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_NE, 0); - break; - case 0x5d: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_LT, 0); - break; - case 0x5e: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_GT, 0); - break; - case 0x5f: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_LE, 0); - break; - case 0x60: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_GE, 0); - break; - case 0x61: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_EQ, 0); - break; - case 0x62: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_NE, 0); - break; - case 0x63: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_LT, 0); - break; - case 0x64: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_GT, 0); - break; - case 0x65: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_LE, 0); - break; - case 0x66: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_GE, 0); - break; - case 0xa7: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_WRAP_I64, 0); - break; - case 0xa8: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_S, 0); - break; - case 0xa9: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_U, 0); - break; - case 0xaa: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_S, 0); - break; - case 0xab: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_U, 0); - break; - case 0xac: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_S, 0); - break; - case 0xad: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_U, 0); - break; - case 0xae: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_S, 0); - break; - case 0xaf: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_U, 0); - break; - case 0xb0: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_S, 0); - break; - case 0xb1: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_U, 0); - break; - case 0xb2: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_S, 0); - break; - case 0xb3: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_U, 0); - break; - case 0xb4: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_S, 0); - break; - case 0xb5: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_U, 0); - break; - case 0xb6: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_DEMOTE_F64, 0); - break; - case 0xb7: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_S, 0); - break; - case 0xb8: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_U, 0); - break; - case 0xb9: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_S, 0); - break; - case 0xba: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_U, 0); - break; - case 0xbb: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_PROMOTE_F32, 0); - break; - case 0xbc: - wasm_func_add_insn(c, out, f, WASM_INSN_I32_REINTERPRET_F32, 0); - break; - case 0xbd: - wasm_func_add_insn(c, out, f, WASM_INSN_I64_REINTERPRET_F64, 0); - break; - case 0xbe: - wasm_func_add_insn(c, out, f, WASM_INSN_F32_REINTERPRET_I32, 0); - break; - case 0xbf: - wasm_func_add_insn(c, out, f, WASM_INSN_F64_REINTERPRET_I64, 0); - break; - default: - wasm_error(c, wasm_loc(0, 0), "wasm: unsupported opcode 0x%02x", - op); + case 0x00: + wasm_func_add_insn(c, out, f, WASM_INSN_UNREACHABLE, 0); + break; + case 0x01: + wasm_func_add_insn(c, out, f, WASM_INSN_NOP, 0); + break; + case 0x02: + if (bin_u8(&r) != 0x40u) + wasm_error(c, wasm_loc(0, 0), + "wasm: block results are unsupported"); + control_depth++; + wasm_func_add_insn(c, out, f, WASM_INSN_BLOCK, 0); + break; + case 0x03: + if (bin_u8(&r) != 0x40u) + wasm_error(c, wasm_loc(0, 0), + "wasm: loop results are unsupported"); + control_depth++; + wasm_func_add_insn(c, out, f, WASM_INSN_LOOP, 0); + break; + case 0x04: + if (bin_u8(&r) != 0x40u) + wasm_error(c, wasm_loc(0, 0), + "wasm: if results are unsupported"); + control_depth++; + wasm_func_add_insn(c, out, f, WASM_INSN_IF, 0); + break; + case 0x05: + wasm_func_add_insn(c, out, f, WASM_INSN_ELSE, 0); + break; + case 0x0c: + wasm_func_add_insn(c, out, f, WASM_INSN_BR, bin_uleb(&r)); + break; + case 0x0d: + wasm_func_add_insn(c, out, f, WASM_INSN_BR_IF, bin_uleb(&r)); + break; + case 0x0e: { + WasmInsn* in; + uint32_t n = bin_uleb(&r); + if (n >= 16u) + wasm_error(c, wasm_loc(0, 0), + "wasm: too many br_table targets"); + wasm_func_add_insn(c, out, f, WASM_INSN_BR_TABLE, 0); + in = &f->insns[f->ninsns - 1u]; + for (uint32_t k = 0; k < n; ++k) in->targets[k] = bin_uleb(&r); + in->targets[n] = bin_uleb(&r); + in->ntargets = n + 1u; + break; + } + case 0x0f: + wasm_func_add_insn(c, out, f, WASM_INSN_RETURN, 0); + break; + case 0x1a: + wasm_func_add_insn(c, out, f, WASM_INSN_DROP, 0); + break; + case 0x1b: + wasm_func_add_insn(c, out, f, WASM_INSN_SELECT, 0); + break; + case 0x28: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x29: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x2c: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD8_S, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x2d: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD8_U, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x2e: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD16_S, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x2f: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_LOAD16_U, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x30: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD8_S, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x31: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD8_U, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x32: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD16_S, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x33: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD16_U, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x34: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD32_S, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x35: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_LOAD32_U, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x36: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x37: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3a: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE8, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3b: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I32_STORE16, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3c: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE8, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3d: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE16, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3e: + wasm_func_add_mem_insn(c, out, f, WASM_INSN_I64_STORE32, + bin_uleb(&r), bin_uleb(&r)); + break; + case 0x3f: + if (bin_u8(&r) != 0) + wasm_error(c, wasm_loc(0, 0), "wasm: bad memory.size index"); + wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_SIZE, 0); + break; + case 0x40: + if (bin_u8(&r) != 0) + wasm_error(c, wasm_loc(0, 0), "wasm: bad memory.grow index"); + wasm_func_add_insn(c, out, f, WASM_INSN_MEMORY_GROW, 0); + break; + case 0x10: + wasm_func_add_insn(c, out, f, WASM_INSN_CALL, bin_uleb(&r)); + break; + case 0x11: { + WasmInsn* in; + wasm_func_add_insn(c, out, f, WASM_INSN_CALL_INDIRECT, + bin_uleb(&r)); + in = &f->insns[f->ninsns - 1u]; + in->align = bin_uleb(&r); + break; + } + case 0x20: + wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_GET, bin_uleb(&r)); + break; + case 0x21: + wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_SET, bin_uleb(&r)); + break; + case 0x22: + wasm_func_add_insn(c, out, f, WASM_INSN_LOCAL_TEE, bin_uleb(&r)); + break; + case 0x23: + wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_GET, bin_uleb(&r)); + break; + case 0x24: + wasm_func_add_insn(c, out, f, WASM_INSN_GLOBAL_SET, bin_uleb(&r)); + break; + case 0x41: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_CONST, + bin_sleb(&r, 32)); + break; + case 0x42: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_CONST, + bin_sleb(&r, 64)); + break; + case 0x43: + wasm_func_add_fp_insn(c, out, f, WASM_INSN_F32_CONST, + bin_f32(&r)); + break; + case 0x44: + wasm_func_add_fp_insn(c, out, f, WASM_INSN_F64_CONST, + bin_f64(&r)); + break; + case 0x45: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQZ, 0); + break; + case 0x46: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_EQ, 0); + break; + case 0x47: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_NE, 0); + break; + case 0x48: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_S, 0); + break; + case 0x49: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_LT_U, 0); + break; + case 0x4a: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_S, 0); + break; + case 0x4b: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_GT_U, 0); + break; + case 0x4c: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_S, 0); + break; + case 0x4d: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_LE_U, 0); + break; + case 0x4e: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_S, 0); + break; + case 0x4f: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_GE_U, 0); + break; + case 0x50: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQZ, 0); + break; + case 0x51: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_EQ, 0); + break; + case 0x52: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_NE, 0); + break; + case 0x53: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_S, 0); + break; + case 0x54: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_LT_U, 0); + break; + case 0x55: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_S, 0); + break; + case 0x56: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_GT_U, 0); + break; + case 0x57: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_S, 0); + break; + case 0x58: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_LE_U, 0); + break; + case 0x59: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_S, 0); + break; + case 0x5a: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_GE_U, 0); + break; + case 0x6a: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_ADD, 0); + break; + case 0x6b: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_SUB, 0); + break; + case 0x6c: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_MUL, 0); + break; + case 0x6d: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_S, 0); + break; + case 0x6e: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_DIV_U, 0); + break; + case 0x6f: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_S, 0); + break; + case 0x70: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_REM_U, 0); + break; + case 0x71: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_AND, 0); + break; + case 0x72: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_OR, 0); + break; + case 0x73: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_XOR, 0); + break; + case 0x74: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHL, 0); + break; + case 0x75: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_S, 0); + break; + case 0x76: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_SHR_U, 0); + break; + case 0x67: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_CLZ, 0); + break; + case 0x68: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_CTZ, 0); + break; + case 0x69: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_POPCNT, 0); + break; + case 0x77: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTL, 0); + break; + case 0x78: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_ROTR, 0); + break; + case 0x79: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_CLZ, 0); + break; + case 0x7a: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_CTZ, 0); + break; + case 0x7b: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_POPCNT, 0); + break; + case 0x7c: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_ADD, 0); + break; + case 0x7d: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_SUB, 0); + break; + case 0x7e: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_MUL, 0); + break; + case 0x7f: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_S, 0); + break; + case 0x80: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_DIV_U, 0); + break; + case 0x81: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_S, 0); + break; + case 0x82: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_REM_U, 0); + break; + case 0x83: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_AND, 0); + break; + case 0x84: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_OR, 0); + break; + case 0x85: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_XOR, 0); + break; + case 0x86: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHL, 0); + break; + case 0x87: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_S, 0); + break; + case 0x88: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_SHR_U, 0); + break; + case 0x89: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTL, 0); + break; + case 0x8a: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_ROTR, 0); + break; + case 0x92: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_ADD, 0); + break; + case 0x93: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_SUB, 0); + break; + case 0x94: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_MUL, 0); + break; + case 0x95: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_DIV, 0); + break; + case 0xa0: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_ADD, 0); + break; + case 0xa1: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_SUB, 0); + break; + case 0xa2: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_MUL, 0); + break; + case 0xa3: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_DIV, 0); + break; + case 0x5b: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_EQ, 0); + break; + case 0x5c: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_NE, 0); + break; + case 0x5d: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_LT, 0); + break; + case 0x5e: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_GT, 0); + break; + case 0x5f: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_LE, 0); + break; + case 0x60: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_GE, 0); + break; + case 0x61: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_EQ, 0); + break; + case 0x62: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_NE, 0); + break; + case 0x63: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_LT, 0); + break; + case 0x64: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_GT, 0); + break; + case 0x65: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_LE, 0); + break; + case 0x66: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_GE, 0); + break; + case 0xa7: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_WRAP_I64, 0); + break; + case 0xa8: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_S, 0); + break; + case 0xa9: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F32_U, 0); + break; + case 0xaa: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_S, 0); + break; + case 0xab: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_TRUNC_F64_U, 0); + break; + case 0xac: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_S, 0); + break; + case 0xad: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_EXTEND_I32_U, 0); + break; + case 0xae: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_S, 0); + break; + case 0xaf: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F32_U, 0); + break; + case 0xb0: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_S, 0); + break; + case 0xb1: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_TRUNC_F64_U, 0); + break; + case 0xb2: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_S, 0); + break; + case 0xb3: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I32_U, 0); + break; + case 0xb4: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_S, 0); + break; + case 0xb5: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_CONVERT_I64_U, 0); + break; + case 0xb6: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_DEMOTE_F64, 0); + break; + case 0xb7: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_S, 0); + break; + case 0xb8: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I32_U, 0); + break; + case 0xb9: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_S, 0); + break; + case 0xba: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_CONVERT_I64_U, 0); + break; + case 0xbb: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_PROMOTE_F32, 0); + break; + case 0xbc: + wasm_func_add_insn(c, out, f, WASM_INSN_I32_REINTERPRET_F32, 0); + break; + case 0xbd: + wasm_func_add_insn(c, out, f, WASM_INSN_I64_REINTERPRET_F64, 0); + break; + case 0xbe: + wasm_func_add_insn(c, out, f, WASM_INSN_F32_REINTERPRET_I32, 0); + break; + case 0xbf: + wasm_func_add_insn(c, out, f, WASM_INSN_F64_REINTERPRET_I64, 0); + break; + default: + wasm_error(c, wasm_loc(0, 0), "wasm: unsupported opcode 0x%02x", + op); } } if (!saw_body_end) @@ -3719,37 +3648,36 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input, } } -static int wasm_is_binary(const CfreeBytesInput *input) { +static int wasm_is_binary(const CfreeBytesInput* input) { return input->len >= 4u && input->data[0] == 0x00 && input->data[1] == 0x61 && input->data[2] == 0x73 && input->data[3] == 0x6d; } -static CfreeCgTypeId wasm_cg_type(CfreeCompiler *c, CfreeCgBuiltinTypes b, +static CfreeCgTypeId wasm_cg_type(CfreeCompiler* c, CfreeCgBuiltinTypes b, WasmValType vt) { switch (vt) { - case WASM_VAL_I32: - return b.id[CFREE_CG_BUILTIN_I32]; - case WASM_VAL_I64: - return b.id[CFREE_CG_BUILTIN_I64]; - case WASM_VAL_F32: - return b.id[CFREE_CG_BUILTIN_F32]; - case WASM_VAL_F64: - return b.id[CFREE_CG_BUILTIN_F64]; - case WASM_VAL_FUNCREF: - case WASM_VAL_EXTERNREF: - break; + case WASM_VAL_I32: + return b.id[CFREE_CG_BUILTIN_I32]; + case WASM_VAL_I64: + return b.id[CFREE_CG_BUILTIN_I64]; + case WASM_VAL_F32: + return b.id[CFREE_CG_BUILTIN_F32]; + case WASM_VAL_F64: + return b.id[CFREE_CG_BUILTIN_F64]; + case WASM_VAL_FUNCREF: + case WASM_VAL_EXTERNREF: + break; } wasm_error(c, wasm_loc(0, 0), "wasm: unsupported value type"); return b.id[CFREE_CG_BUILTIN_I32]; } -static WasmValType wasm_func_local_type(const WasmFunc *f, uint32_t index) { - if (index < f->nparams) - return f->params[index]; +static WasmValType wasm_func_local_type(const WasmFunc* f, uint32_t index) { + if (index < f->nparams) return f->params[index]; return f->locals[index - f->nparams]; } -static CfreeCgMemAccess wasm_cg_mem(CfreeCompiler *c, CfreeCgBuiltinTypes b, +static CfreeCgMemAccess wasm_cg_mem(CfreeCompiler* c, CfreeCgBuiltinTypes b, WasmValType vt) { CfreeCgMemAccess mem; memset(&mem, 0, sizeof mem); @@ -3764,7 +3692,7 @@ static CfreeCgMemAccess wasm_cg_mem_type(CfreeCgTypeId ty) { return mem; } -static void wasm_cg_push_zero(CfreeCompiler *c, CfreeCg *cg, +static void wasm_cg_push_zero(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, WasmValType vt) { CfreeCgTypeId ty = wasm_cg_type(c, b, vt); if (vt == WASM_VAL_F32 || vt == WASM_VAL_F64) @@ -3776,93 +3704,132 @@ static void wasm_cg_push_zero(CfreeCompiler *c, CfreeCg *cg, static CfreeCgTypeId wasm_load_storage_type(CfreeCgBuiltinTypes b, uint8_t kind) { switch (kind) { - case WASM_INSN_I32_LOAD8_S: - case WASM_INSN_I32_LOAD8_U: - case WASM_INSN_I64_LOAD8_S: - case WASM_INSN_I64_LOAD8_U: - return b.id[CFREE_CG_BUILTIN_I8]; - case WASM_INSN_I32_LOAD16_S: - case WASM_INSN_I32_LOAD16_U: - case WASM_INSN_I64_LOAD16_S: - case WASM_INSN_I64_LOAD16_U: - return b.id[CFREE_CG_BUILTIN_I16]; - case WASM_INSN_I64_LOAD32_S: - case WASM_INSN_I64_LOAD32_U: - case WASM_INSN_I32_LOAD: - return b.id[CFREE_CG_BUILTIN_I32]; - default: - return b.id[CFREE_CG_BUILTIN_I64]; + case WASM_INSN_I32_LOAD8_S: + case WASM_INSN_I32_LOAD8_U: + case WASM_INSN_I64_LOAD8_S: + case WASM_INSN_I64_LOAD8_U: + return b.id[CFREE_CG_BUILTIN_I8]; + case WASM_INSN_I32_LOAD16_S: + case WASM_INSN_I32_LOAD16_U: + case WASM_INSN_I64_LOAD16_S: + case WASM_INSN_I64_LOAD16_U: + return b.id[CFREE_CG_BUILTIN_I16]; + case WASM_INSN_I64_LOAD32_S: + case WASM_INSN_I64_LOAD32_U: + case WASM_INSN_I32_LOAD: + return b.id[CFREE_CG_BUILTIN_I32]; + default: + return b.id[CFREE_CG_BUILTIN_I64]; } } static CfreeCgTypeId wasm_store_storage_type(CfreeCgBuiltinTypes b, uint8_t kind) { switch (kind) { - case WASM_INSN_I32_STORE8: - case WASM_INSN_I64_STORE8: - return b.id[CFREE_CG_BUILTIN_I8]; - case WASM_INSN_I32_STORE16: - case WASM_INSN_I64_STORE16: - return b.id[CFREE_CG_BUILTIN_I16]; - case WASM_INSN_I64_STORE32: - case WASM_INSN_I32_STORE: - return b.id[CFREE_CG_BUILTIN_I32]; - default: - return b.id[CFREE_CG_BUILTIN_I64]; + case WASM_INSN_I32_STORE8: + case WASM_INSN_I64_STORE8: + return b.id[CFREE_CG_BUILTIN_I8]; + case WASM_INSN_I32_STORE16: + case WASM_INSN_I64_STORE16: + return b.id[CFREE_CG_BUILTIN_I16]; + case WASM_INSN_I64_STORE32: + case WASM_INSN_I32_STORE: + return b.id[CFREE_CG_BUILTIN_I32]; + default: + return b.id[CFREE_CG_BUILTIN_I64]; } } static uint32_t wasm_mem_width(uint8_t kind) { switch (kind) { - case WASM_INSN_I32_LOAD8_S: - case WASM_INSN_I32_LOAD8_U: - case WASM_INSN_I64_LOAD8_S: - case WASM_INSN_I64_LOAD8_U: - case WASM_INSN_I32_STORE8: - case WASM_INSN_I64_STORE8: - return 1; - case WASM_INSN_I32_LOAD16_S: - case WASM_INSN_I32_LOAD16_U: - case WASM_INSN_I64_LOAD16_S: - case WASM_INSN_I64_LOAD16_U: - case WASM_INSN_I32_STORE16: - case WASM_INSN_I64_STORE16: - return 2; - case WASM_INSN_I32_LOAD: - case WASM_INSN_I64_LOAD32_S: - case WASM_INSN_I64_LOAD32_U: - case WASM_INSN_I32_STORE: - case WASM_INSN_I64_STORE32: - return 4; - default: - return 8; - } -} - -static void wasm_cg_trap(CfreeCg *cg) { + case WASM_INSN_I32_LOAD8_S: + case WASM_INSN_I32_LOAD8_U: + case WASM_INSN_I64_LOAD8_S: + case WASM_INSN_I64_LOAD8_U: + case WASM_INSN_I32_STORE8: + case WASM_INSN_I64_STORE8: + return 1; + case WASM_INSN_I32_LOAD16_S: + case WASM_INSN_I32_LOAD16_U: + case WASM_INSN_I64_LOAD16_S: + case WASM_INSN_I64_LOAD16_U: + case WASM_INSN_I32_STORE16: + case WASM_INSN_I64_STORE16: + return 2; + case WASM_INSN_I32_LOAD: + case WASM_INSN_I64_LOAD32_S: + case WASM_INSN_I64_LOAD32_U: + case WASM_INSN_I32_STORE: + case WASM_INSN_I64_STORE32: + return 4; + default: + return 8; + } +} + +static void wasm_cg_trap(CfreeCg* cg) { cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_TRAP, 0, CFREE_CG_TYPE_NONE); cfree_cg_unreachable(cg); } +static void wasm_cg_trap_unreachable(CfreeCg* cg) { wasm_cg_trap(cg); } +static void wasm_cg_trap_division(CfreeCg* cg) { wasm_cg_trap(cg); } +static void wasm_cg_trap_bounds(CfreeCg* cg) { wasm_cg_trap(cg); } +static void wasm_cg_trap_table(CfreeCg* cg) { wasm_cg_trap(cg); } +static void wasm_cg_trap_signature(CfreeCg* cg) { wasm_cg_trap(cg); } + typedef struct WasmCgRuntime { CfreeCgTypeId i8_ptr_ty; + CfreeCgTypeId void_ptr_ty; CfreeCgTypeId memory_ty; + CfreeCgTypeId func_import_ty; + CfreeCgTypeId global_import_ty; + CfreeCgTypeId table_entry_ty; + CfreeCgTypeId table_entry_ptr_ty; + CfreeCgTypeId table_ty; CfreeCgTypeId instance_ty; CfreeCgTypeId instance_ptr_ty; uint32_t memory_field; uint32_t memory_data_field; uint32_t memory_pages_field; uint32_t memory_max_pages_field; - uint32_t globals_field0; + uint32_t func_import_field[64]; + uint32_t global_field[64]; + uint32_t global_import_addr_field; + uint32_t table_field[64]; + uint32_t table_entries_field[64]; + uint32_t table_entry_fn_field; + uint32_t table_entry_typeidx_field; + uint32_t table_entries_ptr_field; + uint32_t table_len_field; + uint32_t table_max_field; } WasmCgRuntime; -static void wasm_cg_build_runtime(CfreeCompiler *c, CfreeCgBuiltinTypes b, - const WasmModule *m, WasmCgRuntime *rt) { +static void wasm_indexed_name(char* name, size_t cap, const char* prefix, + uint32_t index) { + size_t pos = 0; + uint32_t n = index, div = 1000000000u; + while (*prefix && pos + 1u < cap) name[pos++] = *prefix++; + while (div > 1u && n / div == 0) div /= 10u; + while (div && pos + 1u < cap) { + name[pos++] = (char)('0' + (n / div) % 10u); + div /= 10u; + } + name[pos] = '\0'; +} + +static void wasm_cg_build_runtime(CfreeCompiler* c, CfreeCgBuiltinTypes b, + const WasmModule* m, WasmCgRuntime* rt) { CfreeCgField memory_fields[3]; - CfreeCgField instance_fields[65]; + CfreeCgField func_import_fields[1]; + CfreeCgField global_import_fields[1]; + CfreeCgField table_entry_fields[2]; + CfreeCgField table_fields[3]; + CfreeCgField instance_fields[256]; uint32_t nfields = 0; memset(rt, 0, sizeof *rt); rt->i8_ptr_ty = cfree_cg_type_ptr(c, b.id[CFREE_CG_BUILTIN_I8], 0); + rt->void_ptr_ty = rt->i8_ptr_ty; memset(memory_fields, 0, sizeof memory_fields); memory_fields[0].name = cfree_sym_intern(c, "data"); memory_fields[0].type = rt->i8_ptr_ty; @@ -3876,29 +3843,83 @@ static void wasm_cg_build_runtime(CfreeCompiler *c, CfreeCgBuiltinTypes b, rt->memory_data_field = 0; rt->memory_pages_field = 1; rt->memory_max_pages_field = 2; + memset(func_import_fields, 0, sizeof func_import_fields); + func_import_fields[0].name = cfree_sym_intern(c, "fn"); + func_import_fields[0].type = rt->void_ptr_ty; + rt->func_import_ty = cfree_cg_type_record( + c, cfree_sym_intern(c, "CfreeWasmFuncImport"), func_import_fields, 1); + memset(global_import_fields, 0, sizeof global_import_fields); + global_import_fields[0].name = cfree_sym_intern(c, "addr"); + global_import_fields[0].type = rt->void_ptr_ty; + rt->global_import_ty = cfree_cg_type_record( + c, cfree_sym_intern(c, "CfreeWasmGlobalImport"), global_import_fields, 1); + memset(table_entry_fields, 0, sizeof table_entry_fields); + table_entry_fields[0].name = cfree_sym_intern(c, "fn"); + table_entry_fields[0].type = rt->void_ptr_ty; + table_entry_fields[1].name = cfree_sym_intern(c, "typeidx"); + table_entry_fields[1].type = b.id[CFREE_CG_BUILTIN_I32]; + rt->table_entry_ty = cfree_cg_type_record( + c, cfree_sym_intern(c, "CfreeWasmTableEntry"), table_entry_fields, 2); + rt->table_entry_ptr_ty = cfree_cg_type_ptr(c, rt->table_entry_ty, 0); + rt->table_entry_fn_field = 0; + rt->table_entry_typeidx_field = 1; + memset(table_fields, 0, sizeof table_fields); + table_fields[0].name = cfree_sym_intern(c, "entries"); + table_fields[0].type = rt->table_entry_ptr_ty; + table_fields[1].name = cfree_sym_intern(c, "len"); + table_fields[1].type = b.id[CFREE_CG_BUILTIN_I32]; + table_fields[2].name = cfree_sym_intern(c, "max"); + table_fields[2].type = b.id[CFREE_CG_BUILTIN_I32]; + rt->table_ty = cfree_cg_type_record(c, cfree_sym_intern(c, "CfreeWasmTable"), + table_fields, 3); + rt->table_entries_ptr_field = 0; + rt->table_len_field = 1; + rt->table_max_field = 2; memset(instance_fields, 0, sizeof instance_fields); - if (m->has_memory) { - instance_fields[nfields].name = cfree_sym_intern(c, "memory"); - instance_fields[nfields].type = rt->memory_ty; + instance_fields[nfields].name = cfree_sym_intern(c, "memory"); + instance_fields[nfields].type = rt->memory_ty; + nfields++; + for (uint32_t i = 0; i < m->nfuncs; ++i) { + char name[40]; + if (!m->funcs[i].is_import) continue; + if (nfields >= 256u) + wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); + wasm_indexed_name(name, sizeof name, "import_func_", i); + rt->func_import_field[i] = nfields; + instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].type = rt->func_import_ty; nfields++; } - rt->globals_field0 = nfields; for (uint32_t i = 0; i < m->nglobals; ++i) { char name[32]; - size_t pos = 0; - uint32_t n = i, div = 1000000000u; - const char prefix[] = "global_"; - memcpy(name, prefix, sizeof(prefix) - 1u); - pos = sizeof(prefix) - 1u; - while (div > 1u && n / div == 0) - div /= 10u; - while (div) { - name[pos++] = (char)('0' + (n / div) % 10u); - div /= 10u; - } - name[pos] = '\0'; + if (nfields >= 256u) + wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); + wasm_indexed_name(name, sizeof name, + m->globals[i].is_import ? "import_global_" : "global_", + i); + rt->global_field[i] = nfields; instance_fields[nfields].name = cfree_sym_intern(c, name); - instance_fields[nfields].type = wasm_cg_type(c, b, m->globals[i].type); + instance_fields[nfields].type = + m->globals[i].is_import ? rt->global_import_ty + : wasm_cg_type(c, b, m->globals[i].type); + nfields++; + } + rt->global_import_addr_field = 0; + for (uint32_t i = 0; i < m->ntables; ++i) { + char name[40]; + uint32_t max = m->tables[i].has_max ? m->tables[i].max : m->tables[i].min; + if (nfields + 2u > 256u) + wasm_error(c, wasm_loc(0, 0), "wasm: instance layout too large"); + wasm_indexed_name(name, sizeof name, "table_", i); + rt->table_field[i] = nfields; + instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].type = rt->table_ty; + nfields++; + wasm_indexed_name(name, sizeof name, "table_entries_", i); + rt->table_entries_field[i] = nfields; + instance_fields[nfields].name = cfree_sym_intern(c, name); + instance_fields[nfields].type = + cfree_cg_type_array(c, rt->table_entry_ty, max ? max : 1u); nfields++; } rt->instance_ty = cfree_cg_type_record( @@ -3906,58 +3927,129 @@ static void wasm_cg_build_runtime(CfreeCompiler *c, CfreeCgBuiltinTypes b, rt->instance_ptr_ty = cfree_cg_type_ptr(c, rt->instance_ty, 0); } -static void wasm_cg_push_instance_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_push_instance_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { cfree_cg_push_local(cg, instance_local); cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty)); cfree_cg_indirect(cg); } -static void wasm_cg_push_memory_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_push_memory_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { wasm_cg_push_instance_lvalue(cg, rt, instance_local); cfree_cg_field(cg, rt->memory_field); } -static void wasm_cg_push_memory_data_ptr(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_push_memory_data_ptr(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { wasm_cg_push_memory_lvalue(cg, rt, instance_local); cfree_cg_field(cg, rt->memory_data_field); cfree_cg_load(cg, wasm_cg_mem_type(rt->i8_ptr_ty)); } -static void wasm_cg_push_memory_pages_lvalue(CfreeCg *cg, - const WasmCgRuntime *rt, +static void wasm_cg_push_memory_pages_lvalue(CfreeCg* cg, + const WasmCgRuntime* rt, CfreeCgLocal instance_local) { wasm_cg_push_memory_lvalue(cg, rt, instance_local); cfree_cg_field(cg, rt->memory_pages_field); } -static void wasm_cg_push_memory_max_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_push_memory_max_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local) { wasm_cg_push_memory_lvalue(cg, rt, instance_local); cfree_cg_field(cg, rt->memory_max_pages_field); } -static void wasm_cg_push_global_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_push_global_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local, uint32_t global_index) { wasm_cg_push_instance_lvalue(cg, rt, instance_local); - cfree_cg_field(cg, rt->globals_field0 + global_index); + cfree_cg_field(cg, rt->global_field[global_index]); +} + +static void wasm_cg_push_import_func_lvalue(CfreeCg* cg, + const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + uint32_t func_index) { + wasm_cg_push_instance_lvalue(cg, rt, instance_local); + cfree_cg_field(cg, rt->func_import_field[func_index]); +} + +static void wasm_cg_push_import_func_ptr(CfreeCg* cg, const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + uint32_t func_index) { + wasm_cg_push_import_func_lvalue(cg, rt, instance_local, func_index); + cfree_cg_field(cg, 0); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); +} + +static void wasm_cg_push_global_value_lvalue(CfreeCompiler* c, CfreeCg* cg, + CfreeCgBuiltinTypes b, + const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + const WasmModule* m, + uint32_t global_index) { + wasm_cg_push_global_lvalue(cg, rt, instance_local, global_index); + if (m->globals[global_index].is_import) { + CfreeCgTypeId ptr_ty = cfree_cg_type_ptr( + c, wasm_cg_type(c, b, m->globals[global_index].type), 0); + cfree_cg_field(cg, rt->global_import_addr_field); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); + cfree_cg_dup(cg); + cfree_cg_push_null(cg, rt->void_ptr_ty); + cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); + { + CfreeCgLabel ok = cfree_cg_label_new(cg); + cfree_cg_branch_true(cg, ok); + wasm_cg_trap_table(cg); + cfree_cg_label_place(cg, ok); + } + cfree_cg_bitcast(cg, ptr_ty); + cfree_cg_indirect(cg); + } +} + +static void wasm_cg_push_table_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + uint32_t table_index) { + wasm_cg_push_instance_lvalue(cg, rt, instance_local); + cfree_cg_field(cg, rt->table_field[table_index]); } -static void wasm_cg_memory_check(CfreeCompiler *c, CfreeCg *cg, - CfreeCgBuiltinTypes b, const WasmModule *m, - const WasmCgRuntime *rt, +static void wasm_cg_push_table_entries_array_lvalue(CfreeCg* cg, + const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + uint32_t table_index) { + wasm_cg_push_instance_lvalue(cg, rt, instance_local); + cfree_cg_field(cg, rt->table_entries_field[table_index]); +} + +static void wasm_cg_push_table_entry_lvalue(CfreeCg* cg, + const WasmCgRuntime* rt, + CfreeCgLocal instance_local, + uint32_t table_index, + CfreeCgLocal index_local, + CfreeCgMemAccess index_mem) { + wasm_cg_push_table_lvalue(cg, rt, instance_local, table_index); + cfree_cg_field(cg, rt->table_entries_ptr_field); + cfree_cg_load(cg, wasm_cg_mem_type(rt->table_entry_ptr_ty)); + cfree_cg_push_local(cg, index_local); + cfree_cg_load(cg, index_mem); + cfree_cg_index(cg, 0); +} + +static void wasm_cg_memory_check(CfreeCompiler* c, CfreeCg* cg, + CfreeCgBuiltinTypes b, const WasmModule* m, + const WasmCgRuntime* rt, CfreeCgLocal instance_local, - const WasmInsn *in) { + const WasmInsn* in) { uint32_t width = wasm_mem_width(in->kind); uint64_t end = (uint64_t)(uint32_t)in->imm + width; CfreeCgLabel ok = cfree_cg_label_new(cg); uint32_t max_pages = m->memory.has_max ? m->memory.max_pages : m->memory.min_pages; if (end > (uint64_t)max_pages * 65536u) { - wasm_cg_trap(cg); + wasm_cg_trap_bounds(cg); return; } (void)c; @@ -3970,11 +4062,11 @@ static void wasm_cg_memory_check(CfreeCompiler *c, CfreeCg *cg, cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); cfree_cg_branch_true(cg, ok); - wasm_cg_trap(cg); + wasm_cg_trap_bounds(cg); cfree_cg_label_place(cg, ok); } -static void wasm_cg_memory_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, +static void wasm_cg_memory_lvalue(CfreeCg* cg, const WasmCgRuntime* rt, CfreeCgLocal instance_local, uint32_t offset) { wasm_cg_push_memory_data_ptr(cg, rt, instance_local); @@ -3982,7 +4074,7 @@ static void wasm_cg_memory_lvalue(CfreeCg *cg, const WasmCgRuntime *rt, cfree_cg_index(cg, offset); } -static void wasm_cg_rotate(CfreeCompiler *c, CfreeCg *cg, CfreeCgBuiltinTypes b, +static void wasm_cg_rotate(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, WasmValType vt, int right) { CfreeCgTypeId ty = wasm_cg_type(c, b, vt); CfreeCgMemAccess mem = wasm_cg_mem(c, b, vt); @@ -4020,7 +4112,7 @@ static void wasm_cg_rotate(CfreeCompiler *c, CfreeCg *cg, CfreeCgBuiltinTypes b, cfree_cg_int_binop(cg, CFREE_CG_INT_OR, 0); } -static void wasm_cg_checked_divrem(CfreeCompiler *c, CfreeCg *cg, +static void wasm_cg_checked_divrem(CfreeCompiler* c, CfreeCg* cg, CfreeCgBuiltinTypes b, WasmValType vt, CfreeCgIntBinOp op) { CfreeCgTypeId ty = wasm_cg_type(c, b, vt); @@ -4043,7 +4135,7 @@ static void wasm_cg_checked_divrem(CfreeCompiler *c, CfreeCg *cg, cfree_cg_push_int(cg, 0, ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, ok); - wasm_cg_trap(cg); + wasm_cg_trap_division(cg); cfree_cg_label_place(cg, ok); if (op == CFREE_CG_INT_SDIV) { CfreeCgLabel no_overflow = cfree_cg_label_new(cg); @@ -4059,7 +4151,7 @@ static void wasm_cg_checked_divrem(CfreeCompiler *c, CfreeCg *cg, cfree_cg_push_int(cg, UINT64_MAX, ty); cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); cfree_cg_branch_true(cg, no_overflow); - wasm_cg_trap(cg); + wasm_cg_trap_division(cg); cfree_cg_label_place(cg, no_overflow); } cfree_cg_push_local(cg, lhs); @@ -4069,135 +4161,135 @@ static void wasm_cg_checked_divrem(CfreeCompiler *c, CfreeCg *cg, cfree_cg_int_binop(cg, op, 0); } -static int wasm_int_cmp_op(uint8_t kind, CfreeCgIntCmpOp *out) { +static int wasm_int_cmp_op(uint8_t kind, CfreeCgIntCmpOp* out) { switch (kind) { - case WASM_INSN_I32_EQ: - case WASM_INSN_I64_EQ: - *out = CFREE_CG_INT_EQ; - return 1; - case WASM_INSN_I32_NE: - case WASM_INSN_I64_NE: - *out = CFREE_CG_INT_NE; - return 1; - case WASM_INSN_I32_LT_S: - case WASM_INSN_I64_LT_S: - *out = CFREE_CG_INT_LT_S; - return 1; - case WASM_INSN_I32_LT_U: - case WASM_INSN_I64_LT_U: - *out = CFREE_CG_INT_LT_U; - return 1; - case WASM_INSN_I32_GT_S: - case WASM_INSN_I64_GT_S: - *out = CFREE_CG_INT_GT_S; - return 1; - case WASM_INSN_I32_GT_U: - case WASM_INSN_I64_GT_U: - *out = CFREE_CG_INT_GT_U; - return 1; - case WASM_INSN_I32_LE_S: - case WASM_INSN_I64_LE_S: - *out = CFREE_CG_INT_LE_S; - return 1; - case WASM_INSN_I32_LE_U: - case WASM_INSN_I64_LE_U: - *out = CFREE_CG_INT_LE_U; - return 1; - case WASM_INSN_I32_GE_S: - case WASM_INSN_I64_GE_S: - *out = CFREE_CG_INT_GE_S; - return 1; - case WASM_INSN_I32_GE_U: - case WASM_INSN_I64_GE_U: - *out = CFREE_CG_INT_GE_U; - return 1; - default: - return 0; + case WASM_INSN_I32_EQ: + case WASM_INSN_I64_EQ: + *out = CFREE_CG_INT_EQ; + return 1; + case WASM_INSN_I32_NE: + case WASM_INSN_I64_NE: + *out = CFREE_CG_INT_NE; + return 1; + case WASM_INSN_I32_LT_S: + case WASM_INSN_I64_LT_S: + *out = CFREE_CG_INT_LT_S; + return 1; + case WASM_INSN_I32_LT_U: + case WASM_INSN_I64_LT_U: + *out = CFREE_CG_INT_LT_U; + return 1; + case WASM_INSN_I32_GT_S: + case WASM_INSN_I64_GT_S: + *out = CFREE_CG_INT_GT_S; + return 1; + case WASM_INSN_I32_GT_U: + case WASM_INSN_I64_GT_U: + *out = CFREE_CG_INT_GT_U; + return 1; + case WASM_INSN_I32_LE_S: + case WASM_INSN_I64_LE_S: + *out = CFREE_CG_INT_LE_S; + return 1; + case WASM_INSN_I32_LE_U: + case WASM_INSN_I64_LE_U: + *out = CFREE_CG_INT_LE_U; + return 1; + case WASM_INSN_I32_GE_S: + case WASM_INSN_I64_GE_S: + *out = CFREE_CG_INT_GE_S; + return 1; + case WASM_INSN_I32_GE_U: + case WASM_INSN_I64_GE_U: + *out = CFREE_CG_INT_GE_U; + return 1; + default: + return 0; } } -static int wasm_fp_binop(uint8_t kind, CfreeCgFpBinOp *out) { +static int wasm_fp_binop(uint8_t kind, CfreeCgFpBinOp* out) { switch (kind) { - case WASM_INSN_F32_ADD: - case WASM_INSN_F64_ADD: - *out = CFREE_CG_FP_ADD; - return 1; - case WASM_INSN_F32_SUB: - case WASM_INSN_F64_SUB: - *out = CFREE_CG_FP_SUB; - return 1; - case WASM_INSN_F32_MUL: - case WASM_INSN_F64_MUL: - *out = CFREE_CG_FP_MUL; - return 1; - case WASM_INSN_F32_DIV: - case WASM_INSN_F64_DIV: - *out = CFREE_CG_FP_DIV; - return 1; - default: - return 0; + case WASM_INSN_F32_ADD: + case WASM_INSN_F64_ADD: + *out = CFREE_CG_FP_ADD; + return 1; + case WASM_INSN_F32_SUB: + case WASM_INSN_F64_SUB: + *out = CFREE_CG_FP_SUB; + return 1; + case WASM_INSN_F32_MUL: + case WASM_INSN_F64_MUL: + *out = CFREE_CG_FP_MUL; + return 1; + case WASM_INSN_F32_DIV: + case WASM_INSN_F64_DIV: + *out = CFREE_CG_FP_DIV; + return 1; + default: + return 0; } } -static int wasm_fp_cmp_op(uint8_t kind, CfreeCgFpCmpOp *out) { +static int wasm_fp_cmp_op(uint8_t kind, CfreeCgFpCmpOp* out) { switch (kind) { - case WASM_INSN_F32_EQ: - case WASM_INSN_F64_EQ: - *out = CFREE_CG_FP_OEQ; - return 1; - case WASM_INSN_F32_NE: - case WASM_INSN_F64_NE: - *out = CFREE_CG_FP_ONE; - return 1; - case WASM_INSN_F32_LT: - case WASM_INSN_F64_LT: - *out = CFREE_CG_FP_OLT; - return 1; - case WASM_INSN_F32_GT: - case WASM_INSN_F64_GT: - *out = CFREE_CG_FP_OGT; - return 1; - case WASM_INSN_F32_LE: - case WASM_INSN_F64_LE: - *out = CFREE_CG_FP_OLE; - return 1; - case WASM_INSN_F32_GE: - case WASM_INSN_F64_GE: - *out = CFREE_CG_FP_OGE; - return 1; - default: - return 0; + case WASM_INSN_F32_EQ: + case WASM_INSN_F64_EQ: + *out = CFREE_CG_FP_OEQ; + return 1; + case WASM_INSN_F32_NE: + case WASM_INSN_F64_NE: + *out = CFREE_CG_FP_ONE; + return 1; + case WASM_INSN_F32_LT: + case WASM_INSN_F64_LT: + *out = CFREE_CG_FP_OLT; + return 1; + case WASM_INSN_F32_GT: + case WASM_INSN_F64_GT: + *out = CFREE_CG_FP_OGT; + return 1; + case WASM_INSN_F32_LE: + case WASM_INSN_F64_LE: + *out = CFREE_CG_FP_OLE; + return 1; + case WASM_INSN_F32_GE: + case WASM_INSN_F64_GE: + *out = CFREE_CG_FP_OGE; + return 1; + default: + return 0; } } static WasmValType wasm_load_result_type(uint8_t kind) { switch (kind) { - case WASM_INSN_I64_LOAD: - case WASM_INSN_I64_LOAD8_S: - case WASM_INSN_I64_LOAD8_U: - case WASM_INSN_I64_LOAD16_S: - case WASM_INSN_I64_LOAD16_U: - case WASM_INSN_I64_LOAD32_S: - case WASM_INSN_I64_LOAD32_U: - return WASM_VAL_I64; - default: - return WASM_VAL_I32; + case WASM_INSN_I64_LOAD: + case WASM_INSN_I64_LOAD8_S: + case WASM_INSN_I64_LOAD8_U: + case WASM_INSN_I64_LOAD16_S: + case WASM_INSN_I64_LOAD16_U: + case WASM_INSN_I64_LOAD32_S: + case WASM_INSN_I64_LOAD32_U: + return WASM_VAL_I64; + default: + return WASM_VAL_I32; } } static WasmValType wasm_store_value_type(uint8_t kind) { switch (kind) { - case WASM_INSN_I64_STORE: - case WASM_INSN_I64_STORE8: - case WASM_INSN_I64_STORE16: - case WASM_INSN_I64_STORE32: - return WASM_VAL_I64; - default: - return WASM_VAL_I32; + case WASM_INSN_I64_STORE: + case WASM_INSN_I64_STORE8: + case WASM_INSN_I64_STORE16: + case WASM_INSN_I64_STORE32: + return WASM_VAL_I64; + default: + return WASM_VAL_I32; } } -static int wasm_int_unop_kind(uint8_t kind, WasmValType *vt) { +static int wasm_int_unop_kind(uint8_t kind, WasmValType* vt) { if (kind == WASM_INSN_I32_CLZ || kind == WASM_INSN_I32_CTZ || kind == WASM_INSN_I32_POPCNT) { *vt = WASM_VAL_I32; @@ -4211,7 +4303,7 @@ static int wasm_int_unop_kind(uint8_t kind, WasmValType *vt) { return 0; } -static int wasm_fp_binop_kind(uint8_t kind, WasmValType *vt) { +static int wasm_fp_binop_kind(uint8_t kind, WasmValType* vt) { if (kind == WASM_INSN_F32_ADD || kind == WASM_INSN_F32_SUB || kind == WASM_INSN_F32_MUL || kind == WASM_INSN_F32_DIV) { *vt = WASM_VAL_F32; @@ -4225,7 +4317,7 @@ static int wasm_fp_binop_kind(uint8_t kind, WasmValType *vt) { return 0; } -static int wasm_fp_cmp_kind(uint8_t kind, WasmValType *vt) { +static int wasm_fp_cmp_kind(uint8_t kind, WasmValType* vt) { if (kind == WASM_INSN_F32_EQ || kind == WASM_INSN_F32_NE || kind == WASM_INSN_F32_LT || kind == WASM_INSN_F32_GT || kind == WASM_INSN_F32_LE || kind == WASM_INSN_F32_GE) { @@ -4241,84 +4333,84 @@ static int wasm_fp_cmp_kind(uint8_t kind, WasmValType *vt) { return 0; } -static int wasm_conversion_kind(uint8_t kind, WasmValType *src, - WasmValType *dst) { +static int wasm_conversion_kind(uint8_t kind, WasmValType* src, + WasmValType* dst) { switch (kind) { - case WASM_INSN_I32_WRAP_I64: - *src = WASM_VAL_I64; - *dst = WASM_VAL_I32; - return 1; - case WASM_INSN_I64_EXTEND_I32_S: - case WASM_INSN_I64_EXTEND_I32_U: - *src = WASM_VAL_I32; - *dst = WASM_VAL_I64; - return 1; - case WASM_INSN_I32_TRUNC_F32_S: - case WASM_INSN_I32_TRUNC_F32_U: - *src = WASM_VAL_F32; - *dst = WASM_VAL_I32; - return 1; - case WASM_INSN_I32_TRUNC_F64_S: - case WASM_INSN_I32_TRUNC_F64_U: - *src = WASM_VAL_F64; - *dst = WASM_VAL_I32; - return 1; - case WASM_INSN_I64_TRUNC_F32_S: - case WASM_INSN_I64_TRUNC_F32_U: - *src = WASM_VAL_F32; - *dst = WASM_VAL_I64; - return 1; - case WASM_INSN_I64_TRUNC_F64_S: - case WASM_INSN_I64_TRUNC_F64_U: - *src = WASM_VAL_F64; - *dst = WASM_VAL_I64; - return 1; - case WASM_INSN_F32_CONVERT_I32_S: - case WASM_INSN_F32_CONVERT_I32_U: - *src = WASM_VAL_I32; - *dst = WASM_VAL_F32; - return 1; - case WASM_INSN_F32_CONVERT_I64_S: - case WASM_INSN_F32_CONVERT_I64_U: - *src = WASM_VAL_I64; - *dst = WASM_VAL_F32; - return 1; - case WASM_INSN_F64_CONVERT_I32_S: - case WASM_INSN_F64_CONVERT_I32_U: - *src = WASM_VAL_I32; - *dst = WASM_VAL_F64; - return 1; - case WASM_INSN_F64_CONVERT_I64_S: - case WASM_INSN_F64_CONVERT_I64_U: - *src = WASM_VAL_I64; - *dst = WASM_VAL_F64; - return 1; - case WASM_INSN_F32_DEMOTE_F64: - *src = WASM_VAL_F64; - *dst = WASM_VAL_F32; - return 1; - case WASM_INSN_F64_PROMOTE_F32: - *src = WASM_VAL_F32; - *dst = WASM_VAL_F64; - return 1; - case WASM_INSN_I32_REINTERPRET_F32: - *src = WASM_VAL_F32; - *dst = WASM_VAL_I32; - return 1; - case WASM_INSN_I64_REINTERPRET_F64: - *src = WASM_VAL_F64; - *dst = WASM_VAL_I64; - return 1; - case WASM_INSN_F32_REINTERPRET_I32: - *src = WASM_VAL_I32; - *dst = WASM_VAL_F32; - return 1; - case WASM_INSN_F64_REINTERPRET_I64: - *src = WASM_VAL_I64; - *dst = WASM_VAL_F64; - return 1; - default: - return 0; + case WASM_INSN_I32_WRAP_I64: + *src = WASM_VAL_I64; + *dst = WASM_VAL_I32; + return 1; + case WASM_INSN_I64_EXTEND_I32_S: + case WASM_INSN_I64_EXTEND_I32_U: + *src = WASM_VAL_I32; + *dst = WASM_VAL_I64; + return 1; + case WASM_INSN_I32_TRUNC_F32_S: + case WASM_INSN_I32_TRUNC_F32_U: + *src = WASM_VAL_F32; + *dst = WASM_VAL_I32; + return 1; + case WASM_INSN_I32_TRUNC_F64_S: + case WASM_INSN_I32_TRUNC_F64_U: + *src = WASM_VAL_F64; + *dst = WASM_VAL_I32; + return 1; + case WASM_INSN_I64_TRUNC_F32_S: + case WASM_INSN_I64_TRUNC_F32_U: + *src = WASM_VAL_F32; + *dst = WASM_VAL_I64; + return 1; + case WASM_INSN_I64_TRUNC_F64_S: + case WASM_INSN_I64_TRUNC_F64_U: + *src = WASM_VAL_F64; + *dst = WASM_VAL_I64; + return 1; + case WASM_INSN_F32_CONVERT_I32_S: + case WASM_INSN_F32_CONVERT_I32_U: + *src = WASM_VAL_I32; + *dst = WASM_VAL_F32; + return 1; + case WASM_INSN_F32_CONVERT_I64_S: + case WASM_INSN_F32_CONVERT_I64_U: + *src = WASM_VAL_I64; + *dst = WASM_VAL_F32; + return 1; + case WASM_INSN_F64_CONVERT_I32_S: + case WASM_INSN_F64_CONVERT_I32_U: + *src = WASM_VAL_I32; + *dst = WASM_VAL_F64; + return 1; + case WASM_INSN_F64_CONVERT_I64_S: + case WASM_INSN_F64_CONVERT_I64_U: + *src = WASM_VAL_I64; + *dst = WASM_VAL_F64; + return 1; + case WASM_INSN_F32_DEMOTE_F64: + *src = WASM_VAL_F64; + *dst = WASM_VAL_F32; + return 1; + case WASM_INSN_F64_PROMOTE_F32: + *src = WASM_VAL_F32; + *dst = WASM_VAL_F64; + return 1; + case WASM_INSN_I32_REINTERPRET_F32: + *src = WASM_VAL_F32; + *dst = WASM_VAL_I32; + return 1; + case WASM_INSN_I64_REINTERPRET_F64: + *src = WASM_VAL_F64; + *dst = WASM_VAL_I64; + return 1; + case WASM_INSN_F32_REINTERPRET_I32: + *src = WASM_VAL_I32; + *dst = WASM_VAL_F32; + return 1; + case WASM_INSN_F64_REINTERPRET_I64: + *src = WASM_VAL_I64; + *dst = WASM_VAL_F64; + return 1; + default: + return 0; } } @@ -4334,34 +4426,33 @@ typedef struct WasmControlFrame { int unreachable; } WasmControlFrame; -static WasmValType wasm_global_init_type(const WasmInsn *in) { +static WasmValType wasm_global_init_type(const WasmInsn* in) { switch (in->kind) { - case WASM_INSN_I32_CONST: - return WASM_VAL_I32; - case WASM_INSN_I64_CONST: - return WASM_VAL_I64; - case WASM_INSN_F32_CONST: - return WASM_VAL_F32; - case WASM_INSN_F64_CONST: - return WASM_VAL_F64; - default: - return 0; + case WASM_INSN_I32_CONST: + return WASM_VAL_I32; + case WASM_INSN_I64_CONST: + return WASM_VAL_I64; + case WASM_INSN_F32_CONST: + return WASM_VAL_F32; + case WASM_INSN_F64_CONST: + return WASM_VAL_F64; + default: + return 0; } } -static void wasm_stack_push(CfreeCompiler *c, WasmValStack *s, WasmValType vt) { +static void wasm_stack_push(CfreeCompiler* c, WasmValStack* s, WasmValType vt) { if (s->depth >= 256u) wasm_error(c, wasm_loc(0, 0), "wasm: operand stack too deep"); s->vals[s->depth++] = vt; } -static int wasm_stack_pop(CfreeCompiler *c, WasmValStack *s, - WasmControlFrame *frames, uint32_t nframes, - WasmValType expected, const char *what) { - WasmControlFrame *top = &frames[nframes - 1u]; +static int wasm_stack_pop(CfreeCompiler* c, WasmValStack* s, + WasmControlFrame* frames, uint32_t nframes, + WasmValType expected, const char* what) { + WasmControlFrame* top = &frames[nframes - 1u]; if (s->depth <= top->height) { - if (top->unreachable) - return 1; + if (top->unreachable) return 1; wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow"); } if (expected && s->vals[s->depth - 1u] != expected) @@ -4370,14 +4461,14 @@ static int wasm_stack_pop(CfreeCompiler *c, WasmValStack *s, return 1; } -static void wasm_mark_unreachable(WasmValStack *s, WasmControlFrame *frames, +static void wasm_mark_unreachable(WasmValStack* s, WasmControlFrame* frames, uint32_t nframes) { - WasmControlFrame *top = &frames[nframes - 1u]; + WasmControlFrame* top = &frames[nframes - 1u]; s->depth = top->height; top->unreachable = 1; } -static void wasm_validate(WasmModule *m, CfreeCompiler *c) { +static void wasm_validate(WasmModule* m, CfreeCompiler* c) { uint32_t i, j; for (i = 0; i < m->ntypes; ++i) { for (j = 0; j < m->types[i].nparams; ++j) @@ -4398,14 +4489,14 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) { wasm_error(c, wasm_loc(0, 0), "wasm: table maximum below minimum"); } for (i = 0; i < m->nglobals; ++i) { - WasmGlobal *g = &m->globals[i]; + WasmGlobal* g = &m->globals[i]; if (!wasm_is_num_type(g->type)) wasm_error(c, wasm_loc(0, 0), "wasm: unsupported global type"); if (!g->is_import && wasm_global_init_type(&g->init) != g->type) wasm_error(c, wasm_loc(0, 0), "wasm: global initializer type mismatch"); } for (i = 0; i < m->nexports; ++i) { - WasmExport *ex = &m->exports[i]; + WasmExport* ex = &m->exports[i]; if ((ex->kind == 0 && ex->index >= m->nfuncs) || (ex->kind == 1 && ex->index >= m->ntables) || (ex->kind == 2 && (!m->has_memory || ex->index != 0)) || @@ -4420,15 +4511,20 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) { "wasm: start function must have no params or results"); } for (i = 0; i < m->nelems; ++i) { + uint32_t table_min; if (m->elems[i].tableidx >= m->ntables) wasm_error(c, wasm_loc(0, 0), "wasm: element table index out of range"); + table_min = m->tables[m->elems[i].tableidx].min; + if (m->elems[i].offset < 0 || + (uint64_t)m->elems[i].offset + m->elems[i].nfuncs > table_min) + wasm_error(c, wasm_loc(0, 0), "wasm: element segment out of range"); for (j = 0; j < m->elems[i].nfuncs; ++j) if (m->elems[i].funcs[j] >= m->nfuncs) wasm_error(c, wasm_loc(0, 0), "wasm: element function index out of range"); } for (i = 0; i < m->nfuncs; ++i) { - WasmFunc *f = &m->funcs[i]; + WasmFunc* f = &m->funcs[i]; WasmValStack stack; WasmControlFrame control[65]; uint32_t ncontrol = 1; @@ -4444,266 +4540,265 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) { if (f->nresults > 1u) wasm_error(c, wasm_loc(0, 0), "wasm: multi-result unsupported"); for (j = 0; j < f->ninsns; ++j) { - WasmInsn *in = &f->insns[j]; + WasmInsn* in = &f->insns[j]; WasmValType vt, src, dst; switch (in->kind) { - case WASM_INSN_F32_CONST: - wasm_stack_push(c, &stack, WASM_VAL_F32); - break; - case WASM_INSN_F64_CONST: - wasm_stack_push(c, &stack, WASM_VAL_F64); - break; - case WASM_INSN_I32_CONST: - wasm_stack_push(c, &stack, WASM_VAL_I32); - break; - case WASM_INSN_I64_CONST: - wasm_stack_push(c, &stack, WASM_VAL_I64); - break; - case WASM_INSN_LOCAL_GET: - if (in->imm < 0 || - (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals) - wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range"); - wasm_stack_push(c, &stack, - wasm_func_local_type(f, (uint32_t)in->imm)); - break; - case WASM_INSN_LOCAL_SET: - case WASM_INSN_LOCAL_TEE: - if (in->imm < 0 || - (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals) - wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range"); - wasm_stack_pop(c, &stack, control, ncontrol, - wasm_func_local_type(f, (uint32_t)in->imm), "local"); - if (in->kind == WASM_INSN_LOCAL_TEE) + case WASM_INSN_F32_CONST: + wasm_stack_push(c, &stack, WASM_VAL_F32); + break; + case WASM_INSN_F64_CONST: + wasm_stack_push(c, &stack, WASM_VAL_F64); + break; + case WASM_INSN_I32_CONST: + wasm_stack_push(c, &stack, WASM_VAL_I32); + break; + case WASM_INSN_I64_CONST: + wasm_stack_push(c, &stack, WASM_VAL_I64); + break; + case WASM_INSN_LOCAL_GET: + if (in->imm < 0 || + (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals) + wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range"); wasm_stack_push(c, &stack, wasm_func_local_type(f, (uint32_t)in->imm)); - break; - case WASM_INSN_CALL: - if (in->imm < 0 || (uint64_t)in->imm >= m->nfuncs) - wasm_error(c, wasm_loc(0, 0), "wasm: call index out of range"); - for (uint32_t k = 0; k < m->funcs[in->imm].nparams; ++k) { - uint32_t param = m->funcs[in->imm].nparams - 1u - k; + break; + case WASM_INSN_LOCAL_SET: + case WASM_INSN_LOCAL_TEE: + if (in->imm < 0 || + (uint64_t)in->imm >= (uint64_t)f->nparams + f->nlocals) + wasm_error(c, wasm_loc(0, 0), "wasm: local index out of range"); wasm_stack_pop(c, &stack, control, ncontrol, - m->funcs[in->imm].params[param], "call argument"); - } - if (m->funcs[in->imm].nresults) - wasm_stack_push(c, &stack, m->funcs[in->imm].results[0]); - break; - case WASM_INSN_CALL_INDIRECT: { - WasmFuncType *t; - if (in->imm < 0 || (uint64_t)in->imm >= m->ntypes) - wasm_error(c, wasm_loc(0, 0), - "wasm: call_indirect type index out of range"); - if (in->align >= m->ntables) - wasm_error(c, wasm_loc(0, 0), - "wasm: call_indirect table index out of range"); - t = &m->types[in->imm]; - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, - "call_indirect index"); - for (uint32_t k = 0; k < t->nparams; ++k) { - uint32_t param = t->nparams - 1u - k; - wasm_stack_pop(c, &stack, control, ncontrol, t->params[param], - "call_indirect argument"); - } - if (t->nresults) - wasm_stack_push(c, &stack, t->results[0]); - break; - } - case WASM_INSN_GLOBAL_GET: - if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals) - wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range"); - wasm_stack_push(c, &stack, m->globals[in->imm].type); - break; - case WASM_INSN_GLOBAL_SET: - if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals) - wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range"); - if (!m->globals[in->imm].mutable_) - wasm_error(c, wasm_loc(0, 0), "wasm: global is immutable"); - wasm_stack_pop(c, &stack, control, ncontrol, m->globals[in->imm].type, - "global"); - break; - case WASM_INSN_RETURN: - if (f->nresults) - wasm_stack_pop(c, &stack, control, ncontrol, f->results[0], - "return"); - wasm_mark_unreachable(&stack, control, ncontrol); - break; - case WASM_INSN_DROP: - wasm_stack_pop(c, &stack, control, ncontrol, 0, "drop"); - break; - case WASM_INSN_I32_EQZ: - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "eqz"); - wasm_stack_push(c, &stack, WASM_VAL_I32); - break; - case WASM_INSN_I64_EQZ: - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I64, "eqz"); - wasm_stack_push(c, &stack, WASM_VAL_I32); - break; - case WASM_INSN_BLOCK: - case WASM_INSN_LOOP: - if (ncontrol >= 65u) - wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); - control[ncontrol].kind = in->kind; - control[ncontrol].height = stack.depth; - control[ncontrol].seen_else = 0; - control[ncontrol].unreachable = 0; - ncontrol++; - break; - case WASM_INSN_IF: - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "if"); - if (ncontrol >= 65u) - wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); - control[ncontrol].kind = in->kind; - control[ncontrol].height = stack.depth; - control[ncontrol].seen_else = 0; - control[ncontrol].unreachable = 0; - ncontrol++; - break; - case WASM_INSN_ELSE: - if (ncontrol <= 1u || control[ncontrol - 1u].kind != WASM_INSN_IF) - wasm_error(c, wasm_loc(0, 0), "wasm: else without if"); - if (!control[ncontrol - 1u].unreachable && - stack.depth != control[ncontrol - 1u].height) - wasm_error(c, wasm_loc(0, 0), "wasm: if branch result mismatch"); - stack.depth = control[ncontrol - 1u].height; - control[ncontrol - 1u].seen_else = 1; - control[ncontrol - 1u].unreachable = 0; - break; - case WASM_INSN_END: - if (ncontrol <= 1u) - wasm_error(c, wasm_loc(0, 0), "wasm: end without block"); - if (!control[ncontrol - 1u].unreachable && - stack.depth != control[ncontrol - 1u].height) - wasm_error(c, wasm_loc(0, 0), "wasm: block result mismatch"); - stack.depth = control[ncontrol - 1u].height; - ncontrol--; - break; - case WASM_INSN_BR: - if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u) - wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - wasm_mark_unreachable(&stack, control, ncontrol); - break; - case WASM_INSN_BR_IF: - if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u) - wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "br_if"); - break; - case WASM_INSN_BR_TABLE: - if (in->ntargets == 0) - wasm_error(c, wasm_loc(0, 0), "wasm: br_table without targets"); - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, - "br_table selector"); - for (uint32_t k = 0; k < in->ntargets; ++k) - if (in->targets[k] >= ncontrol - 1u) + wasm_func_local_type(f, (uint32_t)in->imm), "local"); + if (in->kind == WASM_INSN_LOCAL_TEE) + wasm_stack_push(c, &stack, + wasm_func_local_type(f, (uint32_t)in->imm)); + break; + case WASM_INSN_CALL: + if (in->imm < 0 || (uint64_t)in->imm >= m->nfuncs) + wasm_error(c, wasm_loc(0, 0), "wasm: call index out of range"); + for (uint32_t k = 0; k < m->funcs[in->imm].nparams; ++k) { + uint32_t param = m->funcs[in->imm].nparams - 1u - k; + wasm_stack_pop(c, &stack, control, ncontrol, + m->funcs[in->imm].params[param], "call argument"); + } + if (m->funcs[in->imm].nresults) + wasm_stack_push(c, &stack, m->funcs[in->imm].results[0]); + break; + case WASM_INSN_CALL_INDIRECT: { + WasmFuncType* t; + if (in->imm < 0 || (uint64_t)in->imm >= m->ntypes) wasm_error(c, wasm_loc(0, 0), - "wasm: br_table depth out of range"); - wasm_mark_unreachable(&stack, control, ncontrol); - break; - case WASM_INSN_SELECT: { - WasmValType rhs, lhs; - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "select"); - if (stack.depth <= control[ncontrol - 1u].height && - control[ncontrol - 1u].unreachable) { - in->type = WASM_VAL_I32; + "wasm: call_indirect type index out of range"); + if (in->align >= m->ntables) + wasm_error(c, wasm_loc(0, 0), + "wasm: call_indirect table index out of range"); + t = &m->types[in->imm]; + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, + "call_indirect index"); + for (uint32_t k = 0; k < t->nparams; ++k) { + uint32_t param = t->nparams - 1u - k; + wasm_stack_pop(c, &stack, control, ncontrol, t->params[param], + "call_indirect argument"); + } + if (t->nresults) wasm_stack_push(c, &stack, t->results[0]); break; } - if (stack.depth < control[ncontrol - 1u].height + 2u) - wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow"); - rhs = stack.vals[--stack.depth]; - lhs = stack.vals[--stack.depth]; - if (lhs != rhs) - wasm_error(c, wasm_loc(0, 0), "wasm: select type mismatch"); - in->type = (uint8_t)lhs; - wasm_stack_push(c, &stack, lhs); - break; - } - case WASM_INSN_MEMORY_SIZE: - if (!m->has_memory) - wasm_error(c, wasm_loc(0, 0), "wasm: memory.size without memory"); - wasm_stack_push(c, &stack, WASM_VAL_I32); - break; - case WASM_INSN_MEMORY_GROW: - if (!m->has_memory) - wasm_error(c, wasm_loc(0, 0), "wasm: memory.grow without memory"); - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, - "memory.grow"); - wasm_stack_push(c, &stack, WASM_VAL_I32); - break; - case WASM_INSN_I32_LOAD: - case WASM_INSN_I64_LOAD: - case WASM_INSN_I32_LOAD8_S: - case WASM_INSN_I32_LOAD8_U: - case WASM_INSN_I32_LOAD16_S: - case WASM_INSN_I32_LOAD16_U: - case WASM_INSN_I64_LOAD8_S: - case WASM_INSN_I64_LOAD8_U: - case WASM_INSN_I64_LOAD16_S: - case WASM_INSN_I64_LOAD16_U: - case WASM_INSN_I64_LOAD32_S: - case WASM_INSN_I64_LOAD32_U: - if (!m->has_memory) - wasm_error(c, wasm_loc(0, 0), "wasm: load without memory"); - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "load"); - wasm_stack_push(c, &stack, wasm_load_result_type(in->kind)); - break; - case WASM_INSN_I32_STORE: - case WASM_INSN_I64_STORE: - case WASM_INSN_I32_STORE8: - case WASM_INSN_I32_STORE16: - case WASM_INSN_I64_STORE8: - case WASM_INSN_I64_STORE16: - case WASM_INSN_I64_STORE32: - if (!m->has_memory) - wasm_error(c, wasm_loc(0, 0), "wasm: store without memory"); - wasm_stack_pop(c, &stack, control, ncontrol, - wasm_store_value_type(in->kind), "store"); - wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "store"); - break; - case WASM_INSN_UNREACHABLE: - wasm_mark_unreachable(&stack, control, ncontrol); - break; - case WASM_INSN_NOP: - break; - default: - if (wasm_int_unop_kind(in->kind, &vt)) { - wasm_stack_pop(c, &stack, control, ncontrol, vt, "unary operand"); - wasm_stack_push(c, &stack, vt); + case WASM_INSN_GLOBAL_GET: + if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals) + wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range"); + wasm_stack_push(c, &stack, m->globals[in->imm].type); break; - } - if (wasm_fp_binop_kind(in->kind, &vt)) { - wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand"); - wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand"); - wasm_stack_push(c, &stack, vt); + case WASM_INSN_GLOBAL_SET: + if (in->imm < 0 || (uint64_t)in->imm >= m->nglobals) + wasm_error(c, wasm_loc(0, 0), "wasm: global index out of range"); + if (!m->globals[in->imm].mutable_) + wasm_error(c, wasm_loc(0, 0), "wasm: global is immutable"); + wasm_stack_pop(c, &stack, control, ncontrol, m->globals[in->imm].type, + "global"); + break; + case WASM_INSN_RETURN: + if (f->nresults) + wasm_stack_pop(c, &stack, control, ncontrol, f->results[0], + "return"); + wasm_mark_unreachable(&stack, control, ncontrol); + break; + case WASM_INSN_DROP: + wasm_stack_pop(c, &stack, control, ncontrol, 0, "drop"); + break; + case WASM_INSN_I32_EQZ: + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "eqz"); + wasm_stack_push(c, &stack, WASM_VAL_I32); + break; + case WASM_INSN_I64_EQZ: + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I64, "eqz"); + wasm_stack_push(c, &stack, WASM_VAL_I32); + break; + case WASM_INSN_BLOCK: + case WASM_INSN_LOOP: + if (ncontrol >= 65u) + wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); + control[ncontrol].kind = in->kind; + control[ncontrol].height = stack.depth; + control[ncontrol].seen_else = 0; + control[ncontrol].unreachable = 0; + ncontrol++; + break; + case WASM_INSN_IF: + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "if"); + if (ncontrol >= 65u) + wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); + control[ncontrol].kind = in->kind; + control[ncontrol].height = stack.depth; + control[ncontrol].seen_else = 0; + control[ncontrol].unreachable = 0; + ncontrol++; + break; + case WASM_INSN_ELSE: + if (ncontrol <= 1u || control[ncontrol - 1u].kind != WASM_INSN_IF) + wasm_error(c, wasm_loc(0, 0), "wasm: else without if"); + if (!control[ncontrol - 1u].unreachable && + stack.depth != control[ncontrol - 1u].height) + wasm_error(c, wasm_loc(0, 0), "wasm: if branch result mismatch"); + stack.depth = control[ncontrol - 1u].height; + control[ncontrol - 1u].seen_else = 1; + control[ncontrol - 1u].unreachable = 0; + break; + case WASM_INSN_END: + if (ncontrol <= 1u) + wasm_error(c, wasm_loc(0, 0), "wasm: end without block"); + if (!control[ncontrol - 1u].unreachable && + stack.depth != control[ncontrol - 1u].height) + wasm_error(c, wasm_loc(0, 0), "wasm: block result mismatch"); + stack.depth = control[ncontrol - 1u].height; + ncontrol--; + break; + case WASM_INSN_BR: + if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u) + wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); + wasm_mark_unreachable(&stack, control, ncontrol); + break; + case WASM_INSN_BR_IF: + if (in->imm < 0 || (uint64_t)in->imm >= ncontrol - 1u) + wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "br_if"); + break; + case WASM_INSN_BR_TABLE: + if (in->ntargets == 0) + wasm_error(c, wasm_loc(0, 0), "wasm: br_table without targets"); + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, + "br_table selector"); + for (uint32_t k = 0; k < in->ntargets; ++k) + if (in->targets[k] >= ncontrol - 1u) + wasm_error(c, wasm_loc(0, 0), + "wasm: br_table depth out of range"); + wasm_mark_unreachable(&stack, control, ncontrol); + break; + case WASM_INSN_SELECT: { + WasmValType rhs, lhs; + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "select"); + if (stack.depth <= control[ncontrol - 1u].height && + control[ncontrol - 1u].unreachable) { + in->type = WASM_VAL_I32; + break; + } + if (stack.depth < control[ncontrol - 1u].height + 2u) + wasm_error(c, wasm_loc(0, 0), "wasm: operand stack underflow"); + rhs = stack.vals[--stack.depth]; + lhs = stack.vals[--stack.depth]; + if (lhs != rhs) + wasm_error(c, wasm_loc(0, 0), "wasm: select type mismatch"); + in->type = (uint8_t)lhs; + wasm_stack_push(c, &stack, lhs); break; } - if (wasm_fp_cmp_kind(in->kind, &vt)) { - wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare"); - wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare"); + case WASM_INSN_MEMORY_SIZE: + if (!m->has_memory) + wasm_error(c, wasm_loc(0, 0), "wasm: memory.size without memory"); wasm_stack_push(c, &stack, WASM_VAL_I32); break; - } - if (wasm_conversion_kind(in->kind, &src, &dst)) { - wasm_stack_pop(c, &stack, control, ncontrol, src, "conversion"); - wasm_stack_push(c, &stack, dst); + case WASM_INSN_MEMORY_GROW: + if (!m->has_memory) + wasm_error(c, wasm_loc(0, 0), "wasm: memory.grow without memory"); + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, + "memory.grow"); + wasm_stack_push(c, &stack, WASM_VAL_I32); + break; + case WASM_INSN_I32_LOAD: + case WASM_INSN_I64_LOAD: + case WASM_INSN_I32_LOAD8_S: + case WASM_INSN_I32_LOAD8_U: + case WASM_INSN_I32_LOAD16_S: + case WASM_INSN_I32_LOAD16_U: + case WASM_INSN_I64_LOAD8_S: + case WASM_INSN_I64_LOAD8_U: + case WASM_INSN_I64_LOAD16_S: + case WASM_INSN_I64_LOAD16_U: + case WASM_INSN_I64_LOAD32_S: + case WASM_INSN_I64_LOAD32_U: + if (!m->has_memory) + wasm_error(c, wasm_loc(0, 0), "wasm: load without memory"); + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "load"); + wasm_stack_push(c, &stack, wasm_load_result_type(in->kind)); + break; + case WASM_INSN_I32_STORE: + case WASM_INSN_I64_STORE: + case WASM_INSN_I32_STORE8: + case WASM_INSN_I32_STORE16: + case WASM_INSN_I64_STORE8: + case WASM_INSN_I64_STORE16: + case WASM_INSN_I64_STORE32: + if (!m->has_memory) + wasm_error(c, wasm_loc(0, 0), "wasm: store without memory"); + wasm_stack_pop(c, &stack, control, ncontrol, + wasm_store_value_type(in->kind), "store"); + wasm_stack_pop(c, &stack, control, ncontrol, WASM_VAL_I32, "store"); + break; + case WASM_INSN_UNREACHABLE: + wasm_mark_unreachable(&stack, control, ncontrol); break; - } - { - CfreeCgIntCmpOp cmp; - WasmValType rhs, lhs; - rhs = stack.depth > control[ncontrol - 1u].height - ? stack.vals[stack.depth - 1u] - : WASM_VAL_I32; - wasm_stack_pop(c, &stack, control, ncontrol, 0, "operand"); - lhs = stack.depth > control[ncontrol - 1u].height - ? stack.vals[stack.depth - 1u] - : rhs; - wasm_stack_pop(c, &stack, control, ncontrol, rhs, "operand"); - if (lhs != rhs) - wasm_error(c, wasm_loc(0, 0), "wasm: operand type mismatch"); - wasm_stack_push( - c, &stack, - wasm_int_cmp_op(in->kind, &cmp) ? WASM_VAL_I32 : lhs); + case WASM_INSN_NOP: break; - } + default: + if (wasm_int_unop_kind(in->kind, &vt)) { + wasm_stack_pop(c, &stack, control, ncontrol, vt, "unary operand"); + wasm_stack_push(c, &stack, vt); + break; + } + if (wasm_fp_binop_kind(in->kind, &vt)) { + wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand"); + wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp operand"); + wasm_stack_push(c, &stack, vt); + break; + } + if (wasm_fp_cmp_kind(in->kind, &vt)) { + wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare"); + wasm_stack_pop(c, &stack, control, ncontrol, vt, "fp compare"); + wasm_stack_push(c, &stack, WASM_VAL_I32); + break; + } + if (wasm_conversion_kind(in->kind, &src, &dst)) { + wasm_stack_pop(c, &stack, control, ncontrol, src, "conversion"); + wasm_stack_push(c, &stack, dst); + break; + } + { + CfreeCgIntCmpOp cmp; + WasmValType rhs, lhs; + rhs = stack.depth > control[ncontrol - 1u].height + ? stack.vals[stack.depth - 1u] + : WASM_VAL_I32; + wasm_stack_pop(c, &stack, control, ncontrol, 0, "operand"); + lhs = stack.depth > control[ncontrol - 1u].height + ? stack.vals[stack.depth - 1u] + : rhs; + wasm_stack_pop(c, &stack, control, ncontrol, rhs, "operand"); + if (lhs != rhs) + wasm_error(c, wasm_loc(0, 0), "wasm: operand type mismatch"); + wasm_stack_push( + c, &stack, + wasm_int_cmp_op(in->kind, &cmp) ? WASM_VAL_I32 : lhs); + break; + } } } if (ncontrol != 1u) @@ -4719,12 +4814,15 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) { } } -static void wasm_cg_call_func(CfreeCompiler *c, CfreeCg *cg, - CfreeCgBuiltinTypes b, const WasmFunc *f, - const WasmCgRuntime *rt, CfreeCgSym sym, - CfreeCgLocal instance_local) { +static void wasm_cg_call_func(CfreeCompiler* c, CfreeCg* cg, + CfreeCgBuiltinTypes b, const WasmFunc* f, + const WasmCgRuntime* rt, CfreeCgSym sym, + CfreeCgTypeId func_type, + CfreeCgLocal instance_local, + uint32_t func_index) { CfreeCgLocalAttrs attrs; CfreeCgLocal args[16]; + CfreeCgLocal callee = CFREE_CG_LOCAL_NONE; memset(&attrs, 0, sizeof attrs); attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; if (f->nparams > 16u) @@ -4737,18 +4835,38 @@ static void wasm_cg_call_func(CfreeCompiler *c, CfreeCg *cg, cfree_cg_swap(cg); cfree_cg_store(cg, wasm_cg_mem(c, b, f->params[param])); } + if (f->is_import) { + CfreeCgLabel ok = cfree_cg_label_new(cg); + callee = cfree_cg_local(cg, rt->void_ptr_ty, attrs); + cfree_cg_push_local(cg, callee); + wasm_cg_push_import_func_ptr(cg, rt, instance_local, func_index); + cfree_cg_store(cg, wasm_cg_mem_type(rt->void_ptr_ty)); + cfree_cg_push_local(cg, callee); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); + cfree_cg_push_null(cg, rt->void_ptr_ty); + cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); + cfree_cg_branch_true(cg, ok); + wasm_cg_trap_table(cg); + cfree_cg_label_place(cg, ok); + cfree_cg_push_local(cg, callee); + cfree_cg_load(cg, wasm_cg_mem_type(rt->void_ptr_ty)); + cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, func_type, 0)); + } cfree_cg_push_local(cg, instance_local); cfree_cg_load(cg, wasm_cg_mem_type(rt->instance_ptr_ty)); for (uint32_t p = 0; p < f->nparams; ++p) { cfree_cg_push_local(cg, args[p]); cfree_cg_load(cg, wasm_cg_mem(c, b, f->params[p])); } - cfree_cg_call_symbol(cg, sym, f->nparams + 1u, (CfreeCgCallAttrs){0}); + if (f->is_import) + cfree_cg_call(cg, f->nparams + 1u, func_type, (CfreeCgCallAttrs){0}); + else + cfree_cg_call_symbol(cg, sym, f->nparams + 1u, (CfreeCgCallAttrs){0}); } -static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, - CfreeObjBuilder *out, const WasmModule *m) { - CfreeCg *cg = cfree_cg_new(c, out, opts); +static void wasm_emit_cg(CfreeCompiler* c, const CfreeCompileOptions* opts, + CfreeObjBuilder* out, const WasmModule* m) { + CfreeCg* cg = cfree_cg_new(c, out, opts); CfreeCgBuiltinTypes b = cfree_cg_builtin_types(c); WasmCgRuntime rt; CfreeCgSym syms[64]; @@ -4756,8 +4874,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, CfreeCgTypeId func_types[64]; CfreeCgLocal locals[48]; uint32_t i, j; - if (!cg) - wasm_error(c, wasm_loc(0, 0), "wasm: failed to initialize codegen"); + if (!cg) wasm_error(c, wasm_loc(0, 0), "wasm: failed to initialize codegen"); if (m->nfuncs > 64u) wasm_error(c, wasm_loc(0, 0), "wasm: too many functions"); if (m->nglobals > 64u) @@ -4786,7 +4903,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, init_sym = cfree_cg_decl(cg, decl); } for (i = 0; i < m->nfuncs; ++i) { - const WasmFunc *f = &m->funcs[i]; + const WasmFunc* f = &m->funcs[i]; CfreeCgFuncParam cg_params[17]; CfreeCgFuncSig sig; CfreeCgDecl decl; @@ -4807,9 +4924,11 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, func_types[i] = cfree_cg_type_func(c, sig); if (!func_types[i]) wasm_error(c, wasm_loc(0, 0), "wasm: failed to create function type"); - if (f->is_import && f->import_name) { - source_name = cfree_sym_intern(c, f->import_name); - } else if (f->export_name) { + if (f->is_import) { + syms[i] = CFREE_CG_SYM_NONE; + continue; + } + if (f->export_name) { source_name = cfree_sym_intern(c, f->export_name); } else { size_t pos = 0; @@ -4817,8 +4936,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, uint32_t n = i, div = 1000000000u; memcpy(local_name, prefix, sizeof(prefix) - 1u); pos = sizeof(prefix) - 1u; - while (div > 1u && n / div == 0) - div /= 10u; + while (div > 1u && n / div == 0) div /= 10u; while (div) { local_name[pos++] = (char)('0' + (n / div) % 10u); div /= 10u; @@ -4831,8 +4949,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, decl.linkage_name = cfree_cg_c_linkage_name(c, source_name); decl.display_name = source_name; decl.type = func_types[i]; - decl.sym.bind = - (f->export_name || f->is_import) ? CFREE_SB_GLOBAL : CFREE_SB_LOCAL; + decl.sym.bind = f->export_name ? CFREE_SB_GLOBAL : CFREE_SB_LOCAL; syms[i] = cfree_cg_decl(cg, decl); if (!syms[i]) wasm_error(c, wasm_loc(0, 0), "wasm: failed to declare function"); @@ -4862,10 +4979,61 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, cfree_cg_memcpy(cg, m->memory.data_init_len, mem, mem); } } + for (i = 0; i < m->ntables; ++i) { + const WasmTable* t = &m->tables[i]; + uint32_t max = t->has_max ? t->max : t->min; + wasm_cg_push_table_lvalue(cg, &rt, instance_local, i); + cfree_cg_field(cg, rt.table_entries_ptr_field); + wasm_cg_push_table_entries_array_lvalue(cg, &rt, instance_local, i); + cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_index(cg, 0); + cfree_cg_addr(cg); + cfree_cg_store(cg, wasm_cg_mem_type(rt.table_entry_ptr_ty)); + wasm_cg_push_table_lvalue(cg, &rt, instance_local, i); + cfree_cg_field(cg, rt.table_len_field); + cfree_cg_push_int(cg, t->min, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + wasm_cg_push_table_lvalue(cg, &rt, instance_local, i); + cfree_cg_field(cg, rt.table_max_field); + cfree_cg_push_int(cg, max, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + } + for (i = 0; i < m->nelems; ++i) { + const WasmElemSegment* seg = &m->elems[i]; + for (j = 0; j < seg->nfuncs; ++j) { + uint32_t slot = (uint32_t)(seg->offset + j); + uint32_t funcidx = seg->funcs[j]; + CfreeCgLocalAttrs tmp_attrs; + CfreeCgLocal slot_local; + memset(&tmp_attrs, 0, sizeof tmp_attrs); + tmp_attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; + slot_local = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], tmp_attrs); + cfree_cg_push_local(cg, slot_local); + cfree_cg_push_int(cg, slot, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, seg->tableidx, + slot_local, + wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_field(cg, rt.table_entry_fn_field); + if (m->funcs[funcidx].is_import) { + wasm_cg_push_import_func_ptr(cg, &rt, instance_local, funcidx); + } else { + cfree_cg_push_symbol_addr(cg, syms[funcidx], 0); + cfree_cg_bitcast(cg, rt.void_ptr_ty); + } + cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty)); + wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, seg->tableidx, + slot_local, + wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_field(cg, rt.table_entry_typeidx_field); + cfree_cg_push_int(cg, m->funcs[funcidx].typeidx, + b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + } + } for (i = 0; i < m->nglobals; ++i) { - const WasmGlobal *g = &m->globals[i]; - if (g->is_import) - continue; + const WasmGlobal* g = &m->globals[i]; + if (g->is_import) continue; wasm_cg_push_global_lvalue(cg, &rt, instance_local, i); if (g->type == WASM_VAL_F32 || g->type == WASM_VAL_F64) cfree_cg_push_float(cg, g->init.fp, wasm_cg_type(c, b, g->type)); @@ -4876,12 +5044,13 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, } if (m->has_start) wasm_cg_call_func(c, cg, b, &m->funcs[m->start_func], &rt, - syms[m->start_func], instance_local); + syms[m->start_func], func_types[m->start_func], + instance_local, m->start_func); cfree_cg_ret_void(cg); cfree_cg_func_end(cg); } for (i = 0; i < m->nfuncs; ++i) { - const WasmFunc *f = &m->funcs[i]; + const WasmFunc* f = &m->funcs[i]; struct { uint8_t kind; int seen_else; @@ -4891,8 +5060,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, } control[64]; uint32_t ncontrol = 0; CfreeCgLocal instance_local; - if (f->is_import) - continue; + if (f->is_import) continue; cfree_cg_func_begin(cg, syms[i]); { CfreeCgLocalAttrs attrs; @@ -4918,637 +5086,621 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, for (j = 0; j < f->ninsns; ++j) { WasmInsn in = f->insns[j]; switch (in.kind) { - case WASM_INSN_UNREACHABLE: - cfree_cg_unreachable(cg); - break; - case WASM_INSN_NOP: - break; - case WASM_INSN_BLOCK: - if (ncontrol >= 64u) - wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); - memset(&control[ncontrol], 0, sizeof control[ncontrol]); - control[ncontrol].kind = WASM_INSN_BLOCK; - control[ncontrol].end = cfree_cg_label_new(cg); - ncontrol++; - break; - case WASM_INSN_LOOP: - if (ncontrol >= 64u) - wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); - memset(&control[ncontrol], 0, sizeof control[ncontrol]); - control[ncontrol].kind = WASM_INSN_LOOP; - control[ncontrol].start = cfree_cg_label_new(cg); - control[ncontrol].end = cfree_cg_label_new(cg); - cfree_cg_label_place(cg, control[ncontrol].start); - ncontrol++; - break; - case WASM_INSN_IF: - if (ncontrol >= 64u) - wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); - memset(&control[ncontrol], 0, sizeof control[ncontrol]); - control[ncontrol].kind = WASM_INSN_IF; - control[ncontrol].else_label = cfree_cg_label_new(cg); - control[ncontrol].end = cfree_cg_label_new(cg); - cfree_cg_branch_false(cg, control[ncontrol].else_label); - ncontrol++; - break; - case WASM_INSN_ELSE: - if (!ncontrol || control[ncontrol - 1u].kind != WASM_INSN_IF) - wasm_error(c, wasm_loc(0, 0), "wasm: else without if"); - cfree_cg_jump(cg, control[ncontrol - 1u].end); - cfree_cg_label_place(cg, control[ncontrol - 1u].else_label); - control[ncontrol - 1u].seen_else = 1; - break; - case WASM_INSN_END: - if (!ncontrol) - wasm_error(c, wasm_loc(0, 0), "wasm: end without block"); - ncontrol--; - if (control[ncontrol].kind == WASM_INSN_IF && - !control[ncontrol].seen_else) - cfree_cg_label_place(cg, control[ncontrol].else_label); - cfree_cg_label_place(cg, control[ncontrol].end); - break; - case WASM_INSN_BR: { - uint32_t depth = (uint32_t)in.imm; - uint32_t idx; - if (depth >= ncontrol) - wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - idx = ncontrol - 1u - depth; - cfree_cg_jump(cg, control[idx].kind == WASM_INSN_LOOP - ? control[idx].start - : control[idx].end); - break; - } - case WASM_INSN_BR_IF: { - uint32_t depth = (uint32_t)in.imm; - uint32_t idx; - if (depth >= ncontrol) - wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - idx = ncontrol - 1u - depth; - cfree_cg_branch_true(cg, control[idx].kind == WASM_INSN_LOOP - ? control[idx].start - : control[idx].end); - break; - } - case WASM_INSN_BR_TABLE: { - CfreeCgSwitchCase cases[15]; - CfreeCgSwitch sw; - memset(cases, 0, sizeof cases); - if (in.ntargets == 0 || in.ntargets > 16u) - wasm_error(c, wasm_loc(0, 0), "wasm: bad br_table target count"); - for (uint32_t k = 0; k + 1u < in.ntargets; ++k) { + case WASM_INSN_UNREACHABLE: + wasm_cg_trap_unreachable(cg); + break; + case WASM_INSN_NOP: + break; + case WASM_INSN_BLOCK: + if (ncontrol >= 64u) + wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); + memset(&control[ncontrol], 0, sizeof control[ncontrol]); + control[ncontrol].kind = WASM_INSN_BLOCK; + control[ncontrol].end = cfree_cg_label_new(cg); + ncontrol++; + break; + case WASM_INSN_LOOP: + if (ncontrol >= 64u) + wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); + memset(&control[ncontrol], 0, sizeof control[ncontrol]); + control[ncontrol].kind = WASM_INSN_LOOP; + control[ncontrol].start = cfree_cg_label_new(cg); + control[ncontrol].end = cfree_cg_label_new(cg); + cfree_cg_label_place(cg, control[ncontrol].start); + ncontrol++; + break; + case WASM_INSN_IF: + if (ncontrol >= 64u) + wasm_error(c, wasm_loc(0, 0), "wasm: control stack too deep"); + memset(&control[ncontrol], 0, sizeof control[ncontrol]); + control[ncontrol].kind = WASM_INSN_IF; + control[ncontrol].else_label = cfree_cg_label_new(cg); + control[ncontrol].end = cfree_cg_label_new(cg); + cfree_cg_branch_false(cg, control[ncontrol].else_label); + ncontrol++; + break; + case WASM_INSN_ELSE: + if (!ncontrol || control[ncontrol - 1u].kind != WASM_INSN_IF) + wasm_error(c, wasm_loc(0, 0), "wasm: else without if"); + cfree_cg_jump(cg, control[ncontrol - 1u].end); + cfree_cg_label_place(cg, control[ncontrol - 1u].else_label); + control[ncontrol - 1u].seen_else = 1; + break; + case WASM_INSN_END: + if (!ncontrol) + wasm_error(c, wasm_loc(0, 0), "wasm: end without block"); + ncontrol--; + if (control[ncontrol].kind == WASM_INSN_IF && + !control[ncontrol].seen_else) + cfree_cg_label_place(cg, control[ncontrol].else_label); + cfree_cg_label_place(cg, control[ncontrol].end); + break; + case WASM_INSN_BR: { + uint32_t depth = (uint32_t)in.imm; uint32_t idx; - if (in.targets[k] >= ncontrol) + if (depth >= ncontrol) wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - idx = ncontrol - 1u - in.targets[k]; - cases[k].value = k; - cases[k].label = control[idx].kind == WASM_INSN_LOOP - ? control[idx].start - : control[idx].end; - } - if (in.targets[in.ntargets - 1u] >= ncontrol) - wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); - memset(&sw, 0, sizeof sw); - sw.selector_type = b.id[CFREE_CG_BUILTIN_I32]; - sw.cases = cases; - sw.ncases = in.ntargets - 1u; - sw.default_label = - control[ncontrol - 1u - in.targets[in.ntargets - 1u]].kind == - WASM_INSN_LOOP - ? control[ncontrol - 1u - in.targets[in.ntargets - 1u]].start - : control[ncontrol - 1u - in.targets[in.ntargets - 1u]].end; - sw.hint = CFREE_CG_SWITCH_BRANCH_CHAIN; - cfree_cg_switch(cg, sw); - break; - } - case WASM_INSN_SELECT: { - CfreeCgTypeId ty = wasm_cg_type(c, b, (WasmValType)in.type); - CfreeCgMemAccess mem = wasm_cg_mem(c, b, (WasmValType)in.type); - CfreeCgLocalAttrs attrs; - CfreeCgLocal lhs, rhs, cond, result; - CfreeCgLabel else_label = cfree_cg_label_new(cg); - CfreeCgLabel end_label = cfree_cg_label_new(cg); - memset(&attrs, 0, sizeof attrs); - attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; - lhs = cfree_cg_local(cg, ty, attrs); - rhs = cfree_cg_local(cg, ty, attrs); - result = cfree_cg_local(cg, ty, attrs); - cond = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); - - cfree_cg_push_local(cg, cond); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, rhs); - cfree_cg_swap(cg); - cfree_cg_store(cg, mem); - cfree_cg_push_local(cg, lhs); - cfree_cg_swap(cg); - cfree_cg_store(cg, mem); - - cfree_cg_push_local(cg, cond); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_branch_false(cg, else_label); - cfree_cg_push_local(cg, result); - cfree_cg_push_local(cg, lhs); - cfree_cg_load(cg, mem); - cfree_cg_store(cg, mem); - cfree_cg_jump(cg, end_label); - cfree_cg_label_place(cg, else_label); - cfree_cg_push_local(cg, result); - cfree_cg_push_local(cg, rhs); - cfree_cg_load(cg, mem); - cfree_cg_store(cg, mem); - cfree_cg_label_place(cg, end_label); - cfree_cg_push_local(cg, result); - cfree_cg_load(cg, mem); - } break; - case WASM_INSN_I32_CONST: - cfree_cg_push_int(cg, (uint64_t)(uint32_t)in.imm, - b.id[CFREE_CG_BUILTIN_I32]); - break; - case WASM_INSN_I64_CONST: - cfree_cg_push_int(cg, (uint64_t)in.imm, b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_F32_CONST: - cfree_cg_push_float(cg, in.fp, b.id[CFREE_CG_BUILTIN_F32]); - break; - case WASM_INSN_F64_CONST: - cfree_cg_push_float(cg, in.fp, b.id[CFREE_CG_BUILTIN_F64]); - break; - case WASM_INSN_LOCAL_GET: { - uint32_t index = (uint32_t)in.imm; - cfree_cg_push_local(cg, locals[index]); - cfree_cg_load(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); - break; - } - case WASM_INSN_LOCAL_SET: { - uint32_t index = (uint32_t)in.imm; - cfree_cg_push_local(cg, locals[index]); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); - break; - } - case WASM_INSN_LOCAL_TEE: { - uint32_t index = (uint32_t)in.imm; - cfree_cg_dup(cg); - cfree_cg_push_local(cg, locals[index]); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); - break; - } - case WASM_INSN_CALL: - wasm_cg_call_func(c, cg, b, &m->funcs[in.imm], &rt, syms[in.imm], - instance_local); - break; - case WASM_INSN_CALL_INDIRECT: { - const WasmFuncType *t = &m->types[in.imm]; - CfreeCgLocalAttrs attrs; - CfreeCgLocal selector, args[16], result = CFREE_CG_LOCAL_NONE; - CfreeCgSwitchCase cases[64]; - CfreeCgLabel labels[64], trap_label, done_label; - CfreeCgSwitch sw; - uint32_t ncases = 0; - CfreeCgMemAccess i32_mem = wasm_cg_mem(c, b, WASM_VAL_I32); - memset(&attrs, 0, sizeof attrs); - attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; - if (t->nparams > 16u) - wasm_error(c, wasm_loc(0, 0), "wasm: too many call_indirect args"); - selector = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); - if (t->nresults) - result = - cfree_cg_local(cg, wasm_cg_type(c, b, t->results[0]), attrs); - cfree_cg_push_local(cg, selector); - cfree_cg_swap(cg); - cfree_cg_store(cg, i32_mem); - for (uint32_t p = 0; p < t->nparams; ++p) { - uint32_t param = t->nparams - 1u - p; - args[param] = - cfree_cg_local(cg, wasm_cg_type(c, b, t->params[param]), attrs); - cfree_cg_push_local(cg, args[param]); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param])); + idx = ncontrol - 1u - depth; + cfree_cg_jump(cg, control[idx].kind == WASM_INSN_LOOP + ? control[idx].start + : control[idx].end); + break; } - memset(cases, 0, sizeof cases); - memset(labels, 0, sizeof labels); - trap_label = cfree_cg_label_new(cg); - done_label = cfree_cg_label_new(cg); - for (uint32_t e = 0; e < m->nelems; ++e) { - const WasmElemSegment *seg = &m->elems[e]; - if (seg->tableidx != in.align) - continue; - for (uint32_t k = 0; k < seg->nfuncs; ++k) { - uint32_t funcidx = seg->funcs[k]; - if (funcidx >= m->nfuncs) - continue; - if (m->funcs[funcidx].nparams != t->nparams || - m->funcs[funcidx].nresults != t->nresults || - memcmp(m->funcs[funcidx].params, t->params, - sizeof(t->params[0]) * t->nparams) != 0 || - memcmp(m->funcs[funcidx].results, t->results, - sizeof(t->results[0]) * t->nresults) != 0) - continue; - if (ncases >= 64u) - wasm_error(c, wasm_loc(0, 0), - "wasm: too many call_indirect table entries"); - labels[ncases] = cfree_cg_label_new(cg); - cases[ncases].value = (uint64_t)(seg->offset + k); - cases[ncases].label = labels[ncases]; - ncases++; - } + case WASM_INSN_BR_IF: { + uint32_t depth = (uint32_t)in.imm; + uint32_t idx; + if (depth >= ncontrol) + wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); + idx = ncontrol - 1u - depth; + cfree_cg_branch_true(cg, control[idx].kind == WASM_INSN_LOOP + ? control[idx].start + : control[idx].end); + break; } - cfree_cg_push_local(cg, selector); - cfree_cg_load(cg, i32_mem); - memset(&sw, 0, sizeof sw); - sw.selector_type = b.id[CFREE_CG_BUILTIN_I32]; - sw.default_label = trap_label; - sw.cases = cases; - sw.ncases = ncases; - sw.hint = CFREE_CG_SWITCH_BRANCH_CHAIN; - cfree_cg_switch(cg, sw); - for (uint32_t e = 0; e < m->nelems; ++e) { - const WasmElemSegment *seg = &m->elems[e]; - if (seg->tableidx != in.align) - continue; - for (uint32_t k = 0; k < seg->nfuncs; ++k) { - uint32_t funcidx = seg->funcs[k]; - const WasmFunc *callee; - int matched; - CfreeCgLabel label = CFREE_CG_LABEL_NONE; - for (uint32_t ci = 0; ci < ncases; ++ci) - if (cases[ci].value == (uint64_t)(seg->offset + k)) - label = labels[ci]; - if (!label) - continue; - callee = &m->funcs[funcidx]; - matched = callee->nparams == t->nparams && - callee->nresults == t->nresults && - memcmp(callee->params, t->params, - sizeof(t->params[0]) * t->nparams) == 0 && - memcmp(callee->results, t->results, - sizeof(t->results[0]) * t->nresults) == 0; - cfree_cg_label_place(cg, label); - if (!matched) { - wasm_cg_trap(cg); - continue; - } - cfree_cg_push_local(cg, instance_local); - cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty)); - for (uint32_t p = 0; p < t->nparams; ++p) { - cfree_cg_push_local(cg, args[p]); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p])); - } - cfree_cg_call_symbol(cg, syms[funcidx], t->nparams + 1u, - (CfreeCgCallAttrs){0}); - if (t->nresults) { - cfree_cg_push_local(cg, result); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0])); - } - cfree_cg_jump(cg, done_label); + case WASM_INSN_BR_TABLE: { + CfreeCgSwitchCase cases[15]; + CfreeCgSwitch sw; + memset(cases, 0, sizeof cases); + if (in.ntargets == 0 || in.ntargets > 16u) + wasm_error(c, wasm_loc(0, 0), "wasm: bad br_table target count"); + for (uint32_t k = 0; k + 1u < in.ntargets; ++k) { + uint32_t idx; + if (in.targets[k] >= ncontrol) + wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); + idx = ncontrol - 1u - in.targets[k]; + cases[k].value = k; + cases[k].label = control[idx].kind == WASM_INSN_LOOP + ? control[idx].start + : control[idx].end; } + if (in.targets[in.ntargets - 1u] >= ncontrol) + wasm_error(c, wasm_loc(0, 0), "wasm: branch depth out of range"); + memset(&sw, 0, sizeof sw); + sw.selector_type = b.id[CFREE_CG_BUILTIN_I32]; + sw.cases = cases; + sw.ncases = in.ntargets - 1u; + sw.default_label = + control[ncontrol - 1u - in.targets[in.ntargets - 1u]].kind == + WASM_INSN_LOOP + ? control[ncontrol - 1u - in.targets[in.ntargets - 1u]].start + : control[ncontrol - 1u - in.targets[in.ntargets - 1u]].end; + sw.hint = CFREE_CG_SWITCH_BRANCH_CHAIN; + cfree_cg_switch(cg, sw); + break; } - cfree_cg_label_place(cg, trap_label); - wasm_cg_trap(cg); - cfree_cg_label_place(cg, done_label); - if (t->nresults) { + case WASM_INSN_SELECT: { + CfreeCgTypeId ty = wasm_cg_type(c, b, (WasmValType)in.type); + CfreeCgMemAccess mem = wasm_cg_mem(c, b, (WasmValType)in.type); + CfreeCgLocalAttrs attrs; + CfreeCgLocal lhs, rhs, cond, result; + CfreeCgLabel else_label = cfree_cg_label_new(cg); + CfreeCgLabel end_label = cfree_cg_label_new(cg); + memset(&attrs, 0, sizeof attrs); + attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; + lhs = cfree_cg_local(cg, ty, attrs); + rhs = cfree_cg_local(cg, ty, attrs); + result = cfree_cg_local(cg, ty, attrs); + cond = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); + + cfree_cg_push_local(cg, cond); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, rhs); + cfree_cg_swap(cg); + cfree_cg_store(cg, mem); + cfree_cg_push_local(cg, lhs); + cfree_cg_swap(cg); + cfree_cg_store(cg, mem); + + cfree_cg_push_local(cg, cond); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_branch_false(cg, else_label); cfree_cg_push_local(cg, result); - cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0])); + cfree_cg_push_local(cg, lhs); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); + cfree_cg_jump(cg, end_label); + cfree_cg_label_place(cg, else_label); + cfree_cg_push_local(cg, result); + cfree_cg_push_local(cg, rhs); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); + cfree_cg_label_place(cg, end_label); + cfree_cg_push_local(cg, result); + cfree_cg_load(cg, mem); + } break; + case WASM_INSN_I32_CONST: + cfree_cg_push_int(cg, (uint64_t)(uint32_t)in.imm, + b.id[CFREE_CG_BUILTIN_I32]); + break; + case WASM_INSN_I64_CONST: + cfree_cg_push_int(cg, (uint64_t)in.imm, b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_F32_CONST: + cfree_cg_push_float(cg, in.fp, b.id[CFREE_CG_BUILTIN_F32]); + break; + case WASM_INSN_F64_CONST: + cfree_cg_push_float(cg, in.fp, b.id[CFREE_CG_BUILTIN_F64]); + break; + case WASM_INSN_LOCAL_GET: { + uint32_t index = (uint32_t)in.imm; + cfree_cg_push_local(cg, locals[index]); + cfree_cg_load(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); + break; } - break; - } - case WASM_INSN_GLOBAL_GET: { - uint32_t index = (uint32_t)in.imm; - wasm_cg_push_global_lvalue(cg, &rt, instance_local, index); - cfree_cg_load(cg, wasm_cg_mem(c, b, m->globals[index].type)); - break; - } - case WASM_INSN_GLOBAL_SET: { - uint32_t index = (uint32_t)in.imm; - wasm_cg_push_global_lvalue(cg, &rt, instance_local, index); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, m->globals[index].type)); - break; - } - case WASM_INSN_RETURN: - if (f->nresults) - cfree_cg_ret(cg); - else - cfree_cg_ret_void(cg); - break; - case WASM_INSN_DROP: - cfree_cg_drop(cg); - break; - case WASM_INSN_MEMORY_SIZE: - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - break; - case WASM_INSN_MEMORY_GROW: { - CfreeCgLocalAttrs attrs; - CfreeCgLocal delta, old_pages, grow_result; - CfreeCgLabel fail = cfree_cg_label_new(cg); - CfreeCgLabel done = cfree_cg_label_new(cg); - CfreeCgTypeId i32 = b.id[CFREE_CG_BUILTIN_I32]; - memset(&attrs, 0, sizeof attrs); - attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; - delta = cfree_cg_local(cg, i32, attrs); - old_pages = cfree_cg_local(cg, i32, attrs); - grow_result = cfree_cg_local(cg, i32, attrs); - cfree_cg_push_local(cg, delta); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, old_pages); - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + case WASM_INSN_LOCAL_SET: { + uint32_t index = (uint32_t)in.imm; + cfree_cg_push_local(cg, locals[index]); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); + break; + } + case WASM_INSN_LOCAL_TEE: { + uint32_t index = (uint32_t)in.imm; + cfree_cg_dup(cg); + cfree_cg_push_local(cg, locals[index]); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index))); + break; + } + case WASM_INSN_CALL: + wasm_cg_call_func(c, cg, b, &m->funcs[in.imm], &rt, syms[in.imm], + func_types[in.imm], instance_local, + (uint32_t)in.imm); + break; + case WASM_INSN_CALL_INDIRECT: { + const WasmFuncType* t = &m->types[in.imm]; + CfreeCgLocalAttrs attrs; + CfreeCgLocal selector, callee, args[16], result = CFREE_CG_LOCAL_NONE; + CfreeCgLabel ok; + CfreeCgMemAccess i32_mem = wasm_cg_mem(c, b, WASM_VAL_I32); + CfreeCgFuncParam indirect_params[17]; + CfreeCgFuncSig indirect_sig; + CfreeCgTypeId indirect_func_type; + memset(&attrs, 0, sizeof attrs); + attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; + if (t->nparams > 16u) + wasm_error(c, wasm_loc(0, 0), "wasm: too many call_indirect args"); + memset(indirect_params, 0, sizeof indirect_params); + indirect_params[0].type = rt.instance_ptr_ty; + for (uint32_t p = 0; p < t->nparams; ++p) + indirect_params[p + 1u].type = wasm_cg_type(c, b, t->params[p]); + memset(&indirect_sig, 0, sizeof indirect_sig); + indirect_sig.ret = t->nresults ? wasm_cg_type(c, b, t->results[0]) + : b.id[CFREE_CG_BUILTIN_VOID]; + indirect_sig.params = indirect_params; + indirect_sig.nparams = t->nparams + 1u; + indirect_sig.call_conv = CFREE_CG_CC_TARGET_C; + indirect_func_type = cfree_cg_type_func(c, indirect_sig); + selector = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); + callee = cfree_cg_local(cg, rt.void_ptr_ty, attrs); + if (t->nresults) + result = + cfree_cg_local(cg, wasm_cg_type(c, b, t->results[0]), attrs); + cfree_cg_push_local(cg, selector); + cfree_cg_swap(cg); + cfree_cg_store(cg, i32_mem); + for (uint32_t p = 0; p < t->nparams; ++p) { + uint32_t param = t->nparams - 1u - p; + args[param] = + cfree_cg_local(cg, wasm_cg_type(c, b, t->params[param]), attrs); + cfree_cg_push_local(cg, args[param]); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->params[param])); + } - cfree_cg_push_local(cg, delta); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - wasm_cg_push_memory_max_lvalue(cg, &rt, instance_local); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); - cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); - cfree_cg_branch_false(cg, fail); - - wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); - cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, delta); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, grow_result); - cfree_cg_push_local(cg, old_pages); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_jump(cg, done); - cfree_cg_label_place(cg, fail); - cfree_cg_push_local(cg, grow_result); - cfree_cg_push_int(cg, UINT64_C(0xffffffff), i32); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_label_place(cg, done); - cfree_cg_push_local(cg, grow_result); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - break; - } - case WASM_INSN_I32_LOAD: - case WASM_INSN_I64_LOAD: - case WASM_INSN_I32_LOAD8_S: - case WASM_INSN_I32_LOAD8_U: - case WASM_INSN_I32_LOAD16_S: - case WASM_INSN_I32_LOAD16_U: - case WASM_INSN_I64_LOAD8_S: - case WASM_INSN_I64_LOAD8_U: - case WASM_INSN_I64_LOAD16_S: - case WASM_INSN_I64_LOAD16_U: - case WASM_INSN_I64_LOAD32_S: - case WASM_INSN_I64_LOAD32_U: { - CfreeCgTypeId storage = wasm_load_storage_type(b, in.kind); - CfreeCgTypeId result = - wasm_cg_type(c, b, wasm_load_result_type(in.kind)); - CfreeCgMemAccess mem; - memset(&mem, 0, sizeof mem); - mem.type = storage; - mem.align = in.align; - wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); - wasm_cg_memory_lvalue(cg, &rt, instance_local, (uint32_t)in.imm); - cfree_cg_load(cg, mem); - if (storage != result) { - if (in.kind == WASM_INSN_I32_LOAD8_S || - in.kind == WASM_INSN_I32_LOAD16_S || - in.kind == WASM_INSN_I64_LOAD8_S || - in.kind == WASM_INSN_I64_LOAD16_S || - in.kind == WASM_INSN_I64_LOAD32_S) - cfree_cg_sext(cg, result); + ok = cfree_cg_label_new(cg); + cfree_cg_push_local(cg, selector); + cfree_cg_load(cg, i32_mem); + wasm_cg_push_table_lvalue(cg, &rt, instance_local, in.align); + cfree_cg_field(cg, rt.table_len_field); + cfree_cg_load(cg, i32_mem); + cfree_cg_int_cmp(cg, CFREE_CG_INT_LT_U); + cfree_cg_branch_true(cg, ok); + wasm_cg_trap_table(cg); + cfree_cg_label_place(cg, ok); + + ok = cfree_cg_label_new(cg); + cfree_cg_push_local(cg, callee); + wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, in.align, + selector, i32_mem); + cfree_cg_field(cg, rt.table_entry_fn_field); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); + cfree_cg_store(cg, wasm_cg_mem_type(rt.void_ptr_ty)); + cfree_cg_push_local(cg, callee); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); + cfree_cg_push_null(cg, rt.void_ptr_ty); + cfree_cg_int_cmp(cg, CFREE_CG_INT_NE); + cfree_cg_branch_true(cg, ok); + wasm_cg_trap_table(cg); + cfree_cg_label_place(cg, ok); + + ok = cfree_cg_label_new(cg); + wasm_cg_push_table_entry_lvalue(cg, &rt, instance_local, in.align, + selector, i32_mem); + cfree_cg_field(cg, rt.table_entry_typeidx_field); + cfree_cg_load(cg, i32_mem); + cfree_cg_push_int(cg, (uint32_t)in.imm, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); + cfree_cg_branch_true(cg, ok); + wasm_cg_trap_signature(cg); + cfree_cg_label_place(cg, ok); + + cfree_cg_push_local(cg, callee); + cfree_cg_load(cg, wasm_cg_mem_type(rt.void_ptr_ty)); + cfree_cg_bitcast(cg, cfree_cg_type_ptr(c, indirect_func_type, 0)); + cfree_cg_push_local(cg, instance_local); + cfree_cg_load(cg, wasm_cg_mem_type(rt.instance_ptr_ty)); + for (uint32_t p = 0; p < t->nparams; ++p) { + cfree_cg_push_local(cg, args[p]); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->params[p])); + } + cfree_cg_call(cg, t->nparams + 1u, indirect_func_type, + (CfreeCgCallAttrs){0}); + if (t->nresults) { + cfree_cg_push_local(cg, result); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, t->results[0])); + cfree_cg_push_local(cg, result); + cfree_cg_load(cg, wasm_cg_mem(c, b, t->results[0])); + } + break; + } + case WASM_INSN_GLOBAL_GET: { + uint32_t index = (uint32_t)in.imm; + wasm_cg_push_global_value_lvalue(c, cg, b, &rt, instance_local, m, + index); + cfree_cg_load(cg, wasm_cg_mem(c, b, m->globals[index].type)); + break; + } + case WASM_INSN_GLOBAL_SET: { + uint32_t index = (uint32_t)in.imm; + wasm_cg_push_global_value_lvalue(c, cg, b, &rt, instance_local, m, + index); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, m->globals[index].type)); + break; + } + case WASM_INSN_RETURN: + if (f->nresults) + cfree_cg_ret(cg); else - cfree_cg_zext(cg, result); + cfree_cg_ret_void(cg); + break; + case WASM_INSN_DROP: + cfree_cg_drop(cg); + break; + case WASM_INSN_MEMORY_SIZE: + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + break; + case WASM_INSN_MEMORY_GROW: { + CfreeCgLocalAttrs attrs; + CfreeCgLocal delta, old_pages, grow_result; + CfreeCgLabel fail = cfree_cg_label_new(cg); + CfreeCgLabel done = cfree_cg_label_new(cg); + CfreeCgTypeId i32 = b.id[CFREE_CG_BUILTIN_I32]; + memset(&attrs, 0, sizeof attrs); + attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; + delta = cfree_cg_local(cg, i32, attrs); + old_pages = cfree_cg_local(cg, i32, attrs); + grow_result = cfree_cg_local(cg, i32, attrs); + cfree_cg_push_local(cg, delta); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, old_pages); + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + + cfree_cg_push_local(cg, delta); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + wasm_cg_push_memory_max_lvalue(cg, &rt, instance_local); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, old_pages); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); + cfree_cg_int_cmp(cg, CFREE_CG_INT_LE_U); + cfree_cg_branch_false(cg, fail); + + wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local); + cfree_cg_push_local(cg, old_pages); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, delta); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, grow_result); + cfree_cg_push_local(cg, old_pages); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_jump(cg, done); + cfree_cg_label_place(cg, fail); + cfree_cg_push_local(cg, grow_result); + cfree_cg_push_int(cg, UINT64_C(0xffffffff), i32); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_label_place(cg, done); + cfree_cg_push_local(cg, grow_result); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + break; } - break; - } - case WASM_INSN_I32_STORE: - case WASM_INSN_I64_STORE: - case WASM_INSN_I32_STORE8: - case WASM_INSN_I32_STORE16: - case WASM_INSN_I64_STORE8: - case WASM_INSN_I64_STORE16: - case WASM_INSN_I64_STORE32: { - CfreeCgTypeId storage = wasm_store_storage_type(b, in.kind); - CfreeCgTypeId value_type = - wasm_cg_type(c, b, wasm_store_value_type(in.kind)); - CfreeCgMemAccess mem; - CfreeCgLocalAttrs attrs; - CfreeCgLocal addr_tmp, value_tmp; - memset(&mem, 0, sizeof mem); - mem.type = storage; - mem.align = in.align; - if (storage != value_type) - cfree_cg_trunc(cg, storage); - memset(&attrs, 0, sizeof attrs); - attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; - value_tmp = cfree_cg_local(cg, storage, attrs); - addr_tmp = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); - cfree_cg_push_local(cg, value_tmp); - cfree_cg_swap(cg); - cfree_cg_store(cg, mem); - wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); - cfree_cg_push_local(cg, addr_tmp); - cfree_cg_swap(cg); - cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - cfree_cg_push_local(cg, addr_tmp); - cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); - wasm_cg_memory_lvalue(cg, &rt, instance_local, (uint32_t)in.imm); - cfree_cg_push_local(cg, value_tmp); - cfree_cg_load(cg, mem); - cfree_cg_store(cg, mem); - break; - } - case WASM_INSN_I32_ADD: - case WASM_INSN_I64_ADD: - cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); - break; - case WASM_INSN_I32_SUB: - case WASM_INSN_I64_SUB: - cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); - break; - case WASM_INSN_I32_MUL: - case WASM_INSN_I64_MUL: - cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); - break; - case WASM_INSN_I32_DIV_S: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_SDIV); - break; - case WASM_INSN_I32_DIV_U: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_UDIV); - break; - case WASM_INSN_I32_REM_S: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_SREM); - break; - case WASM_INSN_I32_REM_U: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_UREM); - break; - case WASM_INSN_I64_DIV_S: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_SDIV); - break; - case WASM_INSN_I64_DIV_U: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_UDIV); - break; - case WASM_INSN_I64_REM_S: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_SREM); - break; - case WASM_INSN_I64_REM_U: - wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_UREM); - break; - case WASM_INSN_I32_AND: - case WASM_INSN_I64_AND: - cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); - break; - case WASM_INSN_I32_OR: - case WASM_INSN_I64_OR: - cfree_cg_int_binop(cg, CFREE_CG_INT_OR, 0); - break; - case WASM_INSN_I32_XOR: - case WASM_INSN_I64_XOR: - cfree_cg_int_binop(cg, CFREE_CG_INT_XOR, 0); - break; - case WASM_INSN_I32_SHL: - case WASM_INSN_I64_SHL: - cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, 0); - break; - case WASM_INSN_I32_SHR_S: - case WASM_INSN_I64_SHR_S: - cfree_cg_int_binop(cg, CFREE_CG_INT_ASHR, 0); - break; - case WASM_INSN_I32_SHR_U: - case WASM_INSN_I64_SHR_U: - cfree_cg_int_binop(cg, CFREE_CG_INT_LSHR, 0); - break; - case WASM_INSN_I32_ROTL: - wasm_cg_rotate(c, cg, b, WASM_VAL_I32, 0); - break; - case WASM_INSN_I32_ROTR: - wasm_cg_rotate(c, cg, b, WASM_VAL_I32, 1); - break; - case WASM_INSN_I64_ROTL: - wasm_cg_rotate(c, cg, b, WASM_VAL_I64, 0); - break; - case WASM_INSN_I64_ROTR: - wasm_cg_rotate(c, cg, b, WASM_VAL_I64, 1); - break; - case WASM_INSN_I32_CLZ: - case WASM_INSN_I64_CLZ: - cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_CLZ, 1, - in.kind == WASM_INSN_I32_CLZ - ? b.id[CFREE_CG_BUILTIN_I32] - : b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_I32_CTZ: - case WASM_INSN_I64_CTZ: - cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_CTZ, 1, - in.kind == WASM_INSN_I32_CTZ - ? b.id[CFREE_CG_BUILTIN_I32] - : b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_I32_POPCNT: - case WASM_INSN_I64_POPCNT: - cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_POPCOUNT, 1, - in.kind == WASM_INSN_I32_POPCNT - ? b.id[CFREE_CG_BUILTIN_I32] - : b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_I32_EQZ: - cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); - cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); - cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); - break; - case WASM_INSN_I64_EQZ: - cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); - cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); - cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); - break; - case WASM_INSN_I32_WRAP_I64: - cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I32]); - break; - case WASM_INSN_I64_EXTEND_I32_S: - cfree_cg_sext(cg, b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_I64_EXTEND_I32_U: - cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_I32_TRUNC_F32_S: - case WASM_INSN_I32_TRUNC_F64_S: - cfree_cg_float_to_sint(cg, b.id[CFREE_CG_BUILTIN_I32], - CFREE_CG_ROUND_TOWARD_ZERO); - break; - case WASM_INSN_I32_TRUNC_F32_U: - case WASM_INSN_I32_TRUNC_F64_U: - cfree_cg_float_to_uint(cg, b.id[CFREE_CG_BUILTIN_I32], - CFREE_CG_ROUND_TOWARD_ZERO); - break; - case WASM_INSN_I64_TRUNC_F32_S: - case WASM_INSN_I64_TRUNC_F64_S: - cfree_cg_float_to_sint(cg, b.id[CFREE_CG_BUILTIN_I64], - CFREE_CG_ROUND_TOWARD_ZERO); - break; - case WASM_INSN_I64_TRUNC_F32_U: - case WASM_INSN_I64_TRUNC_F64_U: - cfree_cg_float_to_uint(cg, b.id[CFREE_CG_BUILTIN_I64], - CFREE_CG_ROUND_TOWARD_ZERO); - break; - case WASM_INSN_F32_CONVERT_I32_S: - case WASM_INSN_F32_CONVERT_I64_S: - cfree_cg_sint_to_float(cg, b.id[CFREE_CG_BUILTIN_F32], - CFREE_CG_ROUND_DEFAULT); - break; - case WASM_INSN_F32_CONVERT_I32_U: - case WASM_INSN_F32_CONVERT_I64_U: - cfree_cg_uint_to_float(cg, b.id[CFREE_CG_BUILTIN_F32], - CFREE_CG_ROUND_DEFAULT); - break; - case WASM_INSN_F64_CONVERT_I32_S: - case WASM_INSN_F64_CONVERT_I64_S: - cfree_cg_sint_to_float(cg, b.id[CFREE_CG_BUILTIN_F64], - CFREE_CG_ROUND_DEFAULT); - break; - case WASM_INSN_F64_CONVERT_I32_U: - case WASM_INSN_F64_CONVERT_I64_U: - cfree_cg_uint_to_float(cg, b.id[CFREE_CG_BUILTIN_F64], - CFREE_CG_ROUND_DEFAULT); - break; - case WASM_INSN_F32_DEMOTE_F64: - cfree_cg_fptrunc(cg, b.id[CFREE_CG_BUILTIN_F32]); - break; - case WASM_INSN_F64_PROMOTE_F32: - cfree_cg_fpext(cg, b.id[CFREE_CG_BUILTIN_F64]); - break; - case WASM_INSN_I32_REINTERPRET_F32: - cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_I32]); - break; - case WASM_INSN_I64_REINTERPRET_F64: - cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_I64]); - break; - case WASM_INSN_F32_REINTERPRET_I32: - cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_F32]); - break; - case WASM_INSN_F64_REINTERPRET_I64: - cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_F64]); - break; - default: { - CfreeCgIntCmpOp cmp; - CfreeCgFpBinOp fp_bin; - CfreeCgFpCmpOp fp_cmp; - if (wasm_int_cmp_op(in.kind, &cmp)) { - cfree_cg_int_cmp(cg, cmp); + case WASM_INSN_I32_LOAD: + case WASM_INSN_I64_LOAD: + case WASM_INSN_I32_LOAD8_S: + case WASM_INSN_I32_LOAD8_U: + case WASM_INSN_I32_LOAD16_S: + case WASM_INSN_I32_LOAD16_U: + case WASM_INSN_I64_LOAD8_S: + case WASM_INSN_I64_LOAD8_U: + case WASM_INSN_I64_LOAD16_S: + case WASM_INSN_I64_LOAD16_U: + case WASM_INSN_I64_LOAD32_S: + case WASM_INSN_I64_LOAD32_U: { + CfreeCgTypeId storage = wasm_load_storage_type(b, in.kind); + CfreeCgTypeId result = + wasm_cg_type(c, b, wasm_load_result_type(in.kind)); + CfreeCgMemAccess mem; + memset(&mem, 0, sizeof mem); + mem.type = storage; + mem.align = in.align; + wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); + wasm_cg_memory_lvalue(cg, &rt, instance_local, (uint32_t)in.imm); + cfree_cg_load(cg, mem); + if (storage != result) { + if (in.kind == WASM_INSN_I32_LOAD8_S || + in.kind == WASM_INSN_I32_LOAD16_S || + in.kind == WASM_INSN_I64_LOAD8_S || + in.kind == WASM_INSN_I64_LOAD16_S || + in.kind == WASM_INSN_I64_LOAD32_S) + cfree_cg_sext(cg, result); + else + cfree_cg_zext(cg, result); + } + break; + } + case WASM_INSN_I32_STORE: + case WASM_INSN_I64_STORE: + case WASM_INSN_I32_STORE8: + case WASM_INSN_I32_STORE16: + case WASM_INSN_I64_STORE8: + case WASM_INSN_I64_STORE16: + case WASM_INSN_I64_STORE32: { + CfreeCgTypeId storage = wasm_store_storage_type(b, in.kind); + CfreeCgTypeId value_type = + wasm_cg_type(c, b, wasm_store_value_type(in.kind)); + CfreeCgMemAccess mem; + CfreeCgLocalAttrs attrs; + CfreeCgLocal addr_tmp, value_tmp; + memset(&mem, 0, sizeof mem); + mem.type = storage; + mem.align = in.align; + if (storage != value_type) cfree_cg_trunc(cg, storage); + memset(&attrs, 0, sizeof attrs); + attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP; + value_tmp = cfree_cg_local(cg, storage, attrs); + addr_tmp = cfree_cg_local(cg, b.id[CFREE_CG_BUILTIN_I32], attrs); + cfree_cg_push_local(cg, value_tmp); + cfree_cg_swap(cg); + cfree_cg_store(cg, mem); + wasm_cg_memory_check(c, cg, b, m, &rt, instance_local, &in); + cfree_cg_push_local(cg, addr_tmp); + cfree_cg_swap(cg); + cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + cfree_cg_push_local(cg, addr_tmp); + cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32)); + wasm_cg_memory_lvalue(cg, &rt, instance_local, (uint32_t)in.imm); + cfree_cg_push_local(cg, value_tmp); + cfree_cg_load(cg, mem); + cfree_cg_store(cg, mem); + break; + } + case WASM_INSN_I32_ADD: + case WASM_INSN_I64_ADD: + cfree_cg_int_binop(cg, CFREE_CG_INT_ADD, 0); + break; + case WASM_INSN_I32_SUB: + case WASM_INSN_I64_SUB: + cfree_cg_int_binop(cg, CFREE_CG_INT_SUB, 0); + break; + case WASM_INSN_I32_MUL: + case WASM_INSN_I64_MUL: + cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0); + break; + case WASM_INSN_I32_DIV_S: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_SDIV); + break; + case WASM_INSN_I32_DIV_U: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_UDIV); + break; + case WASM_INSN_I32_REM_S: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_SREM); + break; + case WASM_INSN_I32_REM_U: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I32, CFREE_CG_INT_UREM); + break; + case WASM_INSN_I64_DIV_S: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_SDIV); + break; + case WASM_INSN_I64_DIV_U: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_UDIV); + break; + case WASM_INSN_I64_REM_S: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_SREM); + break; + case WASM_INSN_I64_REM_U: + wasm_cg_checked_divrem(c, cg, b, WASM_VAL_I64, CFREE_CG_INT_UREM); + break; + case WASM_INSN_I32_AND: + case WASM_INSN_I64_AND: + cfree_cg_int_binop(cg, CFREE_CG_INT_AND, 0); + break; + case WASM_INSN_I32_OR: + case WASM_INSN_I64_OR: + cfree_cg_int_binop(cg, CFREE_CG_INT_OR, 0); + break; + case WASM_INSN_I32_XOR: + case WASM_INSN_I64_XOR: + cfree_cg_int_binop(cg, CFREE_CG_INT_XOR, 0); + break; + case WASM_INSN_I32_SHL: + case WASM_INSN_I64_SHL: + cfree_cg_int_binop(cg, CFREE_CG_INT_SHL, 0); + break; + case WASM_INSN_I32_SHR_S: + case WASM_INSN_I64_SHR_S: + cfree_cg_int_binop(cg, CFREE_CG_INT_ASHR, 0); + break; + case WASM_INSN_I32_SHR_U: + case WASM_INSN_I64_SHR_U: + cfree_cg_int_binop(cg, CFREE_CG_INT_LSHR, 0); + break; + case WASM_INSN_I32_ROTL: + wasm_cg_rotate(c, cg, b, WASM_VAL_I32, 0); + break; + case WASM_INSN_I32_ROTR: + wasm_cg_rotate(c, cg, b, WASM_VAL_I32, 1); + break; + case WASM_INSN_I64_ROTL: + wasm_cg_rotate(c, cg, b, WASM_VAL_I64, 0); + break; + case WASM_INSN_I64_ROTR: + wasm_cg_rotate(c, cg, b, WASM_VAL_I64, 1); + break; + case WASM_INSN_I32_CLZ: + case WASM_INSN_I64_CLZ: + cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_CLZ, 1, + in.kind == WASM_INSN_I32_CLZ + ? b.id[CFREE_CG_BUILTIN_I32] + : b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_I32_CTZ: + case WASM_INSN_I64_CTZ: + cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_CTZ, 1, + in.kind == WASM_INSN_I32_CTZ + ? b.id[CFREE_CG_BUILTIN_I32] + : b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_I32_POPCNT: + case WASM_INSN_I64_POPCNT: + cfree_cg_intrinsic(cg, CFREE_CG_INTRIN_POPCOUNT, 1, + in.kind == WASM_INSN_I32_POPCNT + ? b.id[CFREE_CG_BUILTIN_I32] + : b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_I32_EQZ: + cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]); + cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); - } else if (wasm_fp_binop(in.kind, &fp_bin)) { - cfree_cg_fp_binop(cg, fp_bin, CFREE_CG_FP_NONE); - } else if (wasm_fp_cmp_op(in.kind, &fp_cmp)) { - cfree_cg_fp_cmp(cg, fp_cmp); + break; + case WASM_INSN_I64_EQZ: + cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I64]); + cfree_cg_int_cmp(cg, CFREE_CG_INT_EQ); cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); - } else { - wasm_error(c, wasm_loc(0, 0), "wasm: unsupported instruction"); + break; + case WASM_INSN_I32_WRAP_I64: + cfree_cg_trunc(cg, b.id[CFREE_CG_BUILTIN_I32]); + break; + case WASM_INSN_I64_EXTEND_I32_S: + cfree_cg_sext(cg, b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_I64_EXTEND_I32_U: + cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_I32_TRUNC_F32_S: + case WASM_INSN_I32_TRUNC_F64_S: + cfree_cg_float_to_sint(cg, b.id[CFREE_CG_BUILTIN_I32], + CFREE_CG_ROUND_TOWARD_ZERO); + break; + case WASM_INSN_I32_TRUNC_F32_U: + case WASM_INSN_I32_TRUNC_F64_U: + cfree_cg_float_to_uint(cg, b.id[CFREE_CG_BUILTIN_I32], + CFREE_CG_ROUND_TOWARD_ZERO); + break; + case WASM_INSN_I64_TRUNC_F32_S: + case WASM_INSN_I64_TRUNC_F64_S: + cfree_cg_float_to_sint(cg, b.id[CFREE_CG_BUILTIN_I64], + CFREE_CG_ROUND_TOWARD_ZERO); + break; + case WASM_INSN_I64_TRUNC_F32_U: + case WASM_INSN_I64_TRUNC_F64_U: + cfree_cg_float_to_uint(cg, b.id[CFREE_CG_BUILTIN_I64], + CFREE_CG_ROUND_TOWARD_ZERO); + break; + case WASM_INSN_F32_CONVERT_I32_S: + case WASM_INSN_F32_CONVERT_I64_S: + cfree_cg_sint_to_float(cg, b.id[CFREE_CG_BUILTIN_F32], + CFREE_CG_ROUND_DEFAULT); + break; + case WASM_INSN_F32_CONVERT_I32_U: + case WASM_INSN_F32_CONVERT_I64_U: + cfree_cg_uint_to_float(cg, b.id[CFREE_CG_BUILTIN_F32], + CFREE_CG_ROUND_DEFAULT); + break; + case WASM_INSN_F64_CONVERT_I32_S: + case WASM_INSN_F64_CONVERT_I64_S: + cfree_cg_sint_to_float(cg, b.id[CFREE_CG_BUILTIN_F64], + CFREE_CG_ROUND_DEFAULT); + break; + case WASM_INSN_F64_CONVERT_I32_U: + case WASM_INSN_F64_CONVERT_I64_U: + cfree_cg_uint_to_float(cg, b.id[CFREE_CG_BUILTIN_F64], + CFREE_CG_ROUND_DEFAULT); + break; + case WASM_INSN_F32_DEMOTE_F64: + cfree_cg_fptrunc(cg, b.id[CFREE_CG_BUILTIN_F32]); + break; + case WASM_INSN_F64_PROMOTE_F32: + cfree_cg_fpext(cg, b.id[CFREE_CG_BUILTIN_F64]); + break; + case WASM_INSN_I32_REINTERPRET_F32: + cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_I32]); + break; + case WASM_INSN_I64_REINTERPRET_F64: + cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_I64]); + break; + case WASM_INSN_F32_REINTERPRET_I32: + cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_F32]); + break; + case WASM_INSN_F64_REINTERPRET_I64: + cfree_cg_bitcast(cg, b.id[CFREE_CG_BUILTIN_F64]); + break; + default: { + CfreeCgIntCmpOp cmp; + CfreeCgFpBinOp fp_bin; + CfreeCgFpCmpOp fp_cmp; + if (wasm_int_cmp_op(in.kind, &cmp)) { + cfree_cg_int_cmp(cg, cmp); + cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); + } else if (wasm_fp_binop(in.kind, &fp_bin)) { + cfree_cg_fp_binop(cg, fp_bin, CFREE_CG_FP_NONE); + } else if (wasm_fp_cmp_op(in.kind, &fp_cmp)) { + cfree_cg_fp_cmp(cg, fp_cmp); + cfree_cg_zext(cg, b.id[CFREE_CG_BUILTIN_I32]); + } else { + wasm_error(c, wasm_loc(0, 0), "wasm: unsupported instruction"); + } + break; } - break; - } } } if (f->nresults) @@ -5560,21 +5712,18 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts, cfree_cg_free(cg); } -static void write_byte(CfreeWriter *w, uint8_t b) { - w->write(w, &b, 1); -} +static void write_byte(CfreeWriter* w, uint8_t b) { w->write(w, &b, 1); } -static void write_uleb(CfreeWriter *w, uint64_t v) { +static void write_uleb(CfreeWriter* w, uint64_t v) { do { uint8_t b = (uint8_t)(v & 0x7fu); v >>= 7u; - if (v) - b |= 0x80u; + if (v) b |= 0x80u; write_byte(w, b); } while (v); } -static void write_sleb(CfreeWriter *w, int64_t v) { +static void write_sleb(CfreeWriter* w, int64_t v) { int more = 1; while (more) { uint8_t b = (uint8_t)(v & 0x7f); @@ -5588,35 +5737,32 @@ static void write_sleb(CfreeWriter *w, int64_t v) { } } -static void write_f32(CfreeWriter *w, double value) { +static void write_f32(CfreeWriter* w, double value) { float f = (float)value; uint32_t bits; memcpy(&bits, &f, sizeof bits); - for (uint32_t i = 0; i < 4u; ++i) - write_byte(w, (uint8_t)(bits >> (i * 8u))); + for (uint32_t i = 0; i < 4u; ++i) write_byte(w, (uint8_t)(bits >> (i * 8u))); } -static void write_f64(CfreeWriter *w, double value) { +static void write_f64(CfreeWriter* w, double value) { uint64_t bits; memcpy(&bits, &value, sizeof bits); - for (uint32_t i = 0; i < 8u; ++i) - write_byte(w, (uint8_t)(bits >> (i * 8u))); + for (uint32_t i = 0; i < 8u; ++i) write_byte(w, (uint8_t)(bits >> (i * 8u))); } -static void write_name(CfreeWriter *w, const char *s) { +static void write_name(CfreeWriter* w, const char* s) { size_t n = strlen(s); write_uleb(w, n); w->write(w, s, n); } -static void encode_section(CfreeHeap *h, CfreeWriter *out, uint8_t id, - void (*fn)(CfreeWriter *, const WasmModule *), - const WasmModule *m) { - CfreeWriter *tmp = cfree_writer_mem(h); +static void encode_section(CfreeHeap* h, CfreeWriter* out, uint8_t id, + void (*fn)(CfreeWriter*, const WasmModule*), + const WasmModule* m) { + CfreeWriter* tmp = cfree_writer_mem(h); size_t len; - const uint8_t *bytes; - if (!tmp) - return; + const uint8_t* bytes; + if (!tmp) return; fn(tmp, m); bytes = cfree_writer_mem_bytes(tmp, &len); write_byte(out, id); @@ -5625,56 +5771,47 @@ static void encode_section(CfreeHeap *h, CfreeWriter *out, uint8_t id, cfree_writer_close(tmp); } -static void enc_type(CfreeWriter *w, const WasmModule *m) { +static void enc_type(CfreeWriter* w, const WasmModule* m) { uint32_t i, j; write_uleb(w, m->ntypes); for (i = 0; i < m->ntypes; ++i) { - const WasmFuncType *f = &m->types[i]; + const WasmFuncType* f = &m->types[i]; write_byte(w, 0x60); write_uleb(w, f->nparams); - for (j = 0; j < f->nparams; ++j) - write_byte(w, (uint8_t)f->params[j]); + for (j = 0; j < f->nparams; ++j) write_byte(w, (uint8_t)f->params[j]); write_uleb(w, f->nresults); - for (j = 0; j < f->nresults; ++j) - write_byte(w, (uint8_t)f->results[j]); + for (j = 0; j < f->nresults; ++j) write_byte(w, (uint8_t)f->results[j]); } } -static void write_limits(CfreeWriter *w, uint32_t min, uint32_t max, +static void write_limits(CfreeWriter* w, uint32_t min, uint32_t max, int has_max) { write_byte(w, has_max ? 1 : 0); write_uleb(w, min); - if (has_max) - write_uleb(w, max); + if (has_max) write_uleb(w, max); } -static void enc_import(CfreeWriter *w, const WasmModule *m) { +static void enc_import(CfreeWriter* w, const WasmModule* m) { uint32_t i, n = 0; for (i = 0; i < m->nfuncs; ++i) - if (m->funcs[i].is_import) - n++; + if (m->funcs[i].is_import) n++; for (i = 0; i < m->ntables; ++i) - if (m->tables[i].is_import) - n++; - if (m->has_memory && m->memory.is_import) - n++; + if (m->tables[i].is_import) n++; + if (m->has_memory && m->memory.is_import) n++; for (i = 0; i < m->nglobals; ++i) - if (m->globals[i].is_import) - n++; + if (m->globals[i].is_import) n++; write_uleb(w, n); for (i = 0; i < m->nfuncs; ++i) { - const WasmFunc *f = &m->funcs[i]; - if (!f->is_import) - continue; + const WasmFunc* f = &m->funcs[i]; + if (!f->is_import) continue; write_name(w, f->import_module ? f->import_module : ""); write_name(w, f->import_name ? f->import_name : ""); write_byte(w, 0); write_uleb(w, f->typeidx); } for (i = 0; i < m->ntables; ++i) { - const WasmTable *t = &m->tables[i]; - if (!t->is_import) - continue; + const WasmTable* t = &m->tables[i]; + if (!t->is_import) continue; write_name(w, t->import_module ? t->import_module : ""); write_name(w, t->import_name ? t->import_name : ""); write_byte(w, 1); @@ -5689,9 +5826,8 @@ static void enc_import(CfreeWriter *w, const WasmModule *m) { m->memory.has_max); } for (i = 0; i < m->nglobals; ++i) { - const WasmGlobal *g = &m->globals[i]; - if (!g->is_import) - continue; + const WasmGlobal* g = &m->globals[i]; + if (!g->is_import) continue; write_name(w, g->import_module ? g->import_module : ""); write_name(w, g->import_name ? g->import_name : ""); write_byte(w, 3); @@ -5700,35 +5836,29 @@ static void enc_import(CfreeWriter *w, const WasmModule *m) { } } -static int wasm_module_has_imports(const WasmModule *m) { +static int wasm_module_has_imports(const WasmModule* m) { uint32_t i; for (i = 0; i < m->nfuncs; ++i) - if (m->funcs[i].is_import) - return 1; + if (m->funcs[i].is_import) return 1; for (i = 0; i < m->ntables; ++i) - if (m->tables[i].is_import) - return 1; - if (m->has_memory && m->memory.is_import) - return 1; + if (m->tables[i].is_import) return 1; + if (m->has_memory && m->memory.is_import) return 1; for (i = 0; i < m->nglobals; ++i) - if (m->globals[i].is_import) - return 1; + if (m->globals[i].is_import) return 1; return 0; } -static void enc_func(CfreeWriter *w, const WasmModule *m) { +static void enc_func(CfreeWriter* w, const WasmModule* m) { uint32_t i; uint32_t n = 0; for (i = 0; i < m->nfuncs; ++i) - if (!m->funcs[i].is_import) - n++; + if (!m->funcs[i].is_import) n++; write_uleb(w, n); for (i = 0; i < m->nfuncs; ++i) - if (!m->funcs[i].is_import) - write_uleb(w, m->funcs[i].typeidx); + if (!m->funcs[i].is_import) write_uleb(w, m->funcs[i].typeidx); } -static void enc_export(CfreeWriter *w, const WasmModule *m) { +static void enc_export(CfreeWriter* w, const WasmModule* m) { uint32_t i; write_uleb(w, m->nexports); for (i = 0; i < m->nexports; ++i) { @@ -5738,7 +5868,7 @@ static void enc_export(CfreeWriter *w, const WasmModule *m) { } } -static void enc_memory(CfreeWriter *w, const WasmModule *m) { +static void enc_memory(CfreeWriter* w, const WasmModule* m) { if (!m->has_memory) { write_uleb(w, 0); return; @@ -5746,37 +5876,32 @@ static void enc_memory(CfreeWriter *w, const WasmModule *m) { write_uleb(w, 1); write_byte(w, m->memory.has_max ? 1 : 0); write_uleb(w, m->memory.min_pages); - if (m->memory.has_max) - write_uleb(w, m->memory.max_pages); + if (m->memory.has_max) write_uleb(w, m->memory.max_pages); } static uint8_t wasm_opcode(uint8_t kind); -static void enc_table(CfreeWriter *w, const WasmModule *m) { +static void enc_table(CfreeWriter* w, const WasmModule* m) { uint32_t i, n = 0; for (i = 0; i < m->ntables; ++i) - if (!m->tables[i].is_import) - n++; + if (!m->tables[i].is_import) n++; write_uleb(w, n); for (i = 0; i < m->ntables; ++i) { - const WasmTable *t = &m->tables[i]; - if (t->is_import) - continue; + const WasmTable* t = &m->tables[i]; + if (t->is_import) continue; write_byte(w, (uint8_t)t->elem_type); write_limits(w, t->min, t->max, t->has_max); } } -static void enc_global(CfreeWriter *w, const WasmModule *m) { +static void enc_global(CfreeWriter* w, const WasmModule* m) { uint32_t i, n = 0; for (i = 0; i < m->nglobals; ++i) - if (!m->globals[i].is_import) - n++; + if (!m->globals[i].is_import) n++; write_uleb(w, n); for (i = 0; i < m->nglobals; ++i) { - const WasmGlobal *g = &m->globals[i]; - if (g->is_import) - continue; + const WasmGlobal* g = &m->globals[i]; + if (g->is_import) continue; write_byte(w, (uint8_t)g->type); write_byte(w, g->mutable_); write_byte(w, wasm_opcode(g->init.kind)); @@ -5793,317 +5918,316 @@ static void enc_global(CfreeWriter *w, const WasmModule *m) { static uint8_t wasm_opcode(uint8_t kind) { switch (kind) { - case WASM_INSN_UNREACHABLE: - return 0x00; - case WASM_INSN_NOP: - return 0x01; - case WASM_INSN_BLOCK: - return 0x02; - case WASM_INSN_LOOP: - return 0x03; - case WASM_INSN_IF: - return 0x04; - case WASM_INSN_ELSE: - return 0x05; - case WASM_INSN_END: - return 0x0b; - case WASM_INSN_BR: - return 0x0c; - case WASM_INSN_BR_IF: - return 0x0d; - case WASM_INSN_BR_TABLE: - return 0x0e; - case WASM_INSN_I32_CONST: - return 0x41; - case WASM_INSN_I64_CONST: - return 0x42; - case WASM_INSN_F32_CONST: - return 0x43; - case WASM_INSN_F64_CONST: - return 0x44; - case WASM_INSN_LOCAL_GET: - return 0x20; - case WASM_INSN_LOCAL_SET: - return 0x21; - case WASM_INSN_LOCAL_TEE: - return 0x22; - case WASM_INSN_CALL: - return 0x10; - case WASM_INSN_CALL_INDIRECT: - return 0x11; - case WASM_INSN_GLOBAL_GET: - return 0x23; - case WASM_INSN_GLOBAL_SET: - return 0x24; - case WASM_INSN_RETURN: - return 0x0f; - case WASM_INSN_DROP: - return 0x1a; - case WASM_INSN_SELECT: - return 0x1b; - case WASM_INSN_I32_LOAD: - return 0x28; - case WASM_INSN_I64_LOAD: - return 0x29; - case WASM_INSN_I32_LOAD8_S: - return 0x2c; - case WASM_INSN_I32_LOAD8_U: - return 0x2d; - case WASM_INSN_I32_LOAD16_S: - return 0x2e; - case WASM_INSN_I32_LOAD16_U: - return 0x2f; - case WASM_INSN_I64_LOAD8_S: - return 0x30; - case WASM_INSN_I64_LOAD8_U: - return 0x31; - case WASM_INSN_I64_LOAD16_S: - return 0x32; - case WASM_INSN_I64_LOAD16_U: - return 0x33; - case WASM_INSN_I64_LOAD32_S: - return 0x34; - case WASM_INSN_I64_LOAD32_U: - return 0x35; - case WASM_INSN_I32_STORE: - return 0x36; - case WASM_INSN_I64_STORE: - return 0x37; - case WASM_INSN_I32_STORE8: - return 0x3a; - case WASM_INSN_I32_STORE16: - return 0x3b; - case WASM_INSN_I64_STORE8: - return 0x3c; - case WASM_INSN_I64_STORE16: - return 0x3d; - case WASM_INSN_I64_STORE32: - return 0x3e; - case WASM_INSN_MEMORY_SIZE: - return 0x3f; - case WASM_INSN_MEMORY_GROW: - return 0x40; - case WASM_INSN_I32_EQZ: - return 0x45; - case WASM_INSN_I32_EQ: - return 0x46; - case WASM_INSN_I32_NE: - return 0x47; - case WASM_INSN_I32_LT_S: - return 0x48; - case WASM_INSN_I32_LT_U: - return 0x49; - case WASM_INSN_I32_GT_S: - return 0x4a; - case WASM_INSN_I32_GT_U: - return 0x4b; - case WASM_INSN_I32_LE_S: - return 0x4c; - case WASM_INSN_I32_LE_U: - return 0x4d; - case WASM_INSN_I32_GE_S: - return 0x4e; - case WASM_INSN_I32_GE_U: - return 0x4f; - case WASM_INSN_I64_EQZ: - return 0x50; - case WASM_INSN_I64_EQ: - return 0x51; - case WASM_INSN_I64_NE: - return 0x52; - case WASM_INSN_I64_LT_S: - return 0x53; - case WASM_INSN_I64_LT_U: - return 0x54; - case WASM_INSN_I64_GT_S: - return 0x55; - case WASM_INSN_I64_GT_U: - return 0x56; - case WASM_INSN_I64_LE_S: - return 0x57; - case WASM_INSN_I64_LE_U: - return 0x58; - case WASM_INSN_I64_GE_S: - return 0x59; - case WASM_INSN_I64_GE_U: - return 0x5a; - case WASM_INSN_I32_ADD: - return 0x6a; - case WASM_INSN_I32_SUB: - return 0x6b; - case WASM_INSN_I32_MUL: - return 0x6c; - case WASM_INSN_I32_DIV_S: - return 0x6d; - case WASM_INSN_I32_DIV_U: - return 0x6e; - case WASM_INSN_I32_REM_S: - return 0x6f; - case WASM_INSN_I32_REM_U: - return 0x70; - case WASM_INSN_I32_AND: - return 0x71; - case WASM_INSN_I32_OR: - return 0x72; - case WASM_INSN_I32_XOR: - return 0x73; - case WASM_INSN_I32_SHL: - return 0x74; - case WASM_INSN_I32_SHR_S: - return 0x75; - case WASM_INSN_I32_SHR_U: - return 0x76; - case WASM_INSN_I32_CLZ: - return 0x67; - case WASM_INSN_I32_CTZ: - return 0x68; - case WASM_INSN_I32_POPCNT: - return 0x69; - case WASM_INSN_I32_ROTL: - return 0x77; - case WASM_INSN_I32_ROTR: - return 0x78; - case WASM_INSN_I64_CLZ: - return 0x79; - case WASM_INSN_I64_CTZ: - return 0x7a; - case WASM_INSN_I64_POPCNT: - return 0x7b; - case WASM_INSN_I64_ADD: - return 0x7c; - case WASM_INSN_I64_SUB: - return 0x7d; - case WASM_INSN_I64_MUL: - return 0x7e; - case WASM_INSN_I64_DIV_S: - return 0x7f; - case WASM_INSN_I64_DIV_U: - return 0x80; - case WASM_INSN_I64_REM_S: - return 0x81; - case WASM_INSN_I64_REM_U: - return 0x82; - case WASM_INSN_I64_AND: - return 0x83; - case WASM_INSN_I64_OR: - return 0x84; - case WASM_INSN_I64_XOR: - return 0x85; - case WASM_INSN_I64_SHL: - return 0x86; - case WASM_INSN_I64_SHR_S: - return 0x87; - case WASM_INSN_I64_SHR_U: - return 0x88; - case WASM_INSN_I64_ROTL: - return 0x89; - case WASM_INSN_I64_ROTR: - return 0x8a; - case WASM_INSN_F32_ADD: - return 0x92; - case WASM_INSN_F32_SUB: - return 0x93; - case WASM_INSN_F32_MUL: - return 0x94; - case WASM_INSN_F32_DIV: - return 0x95; - case WASM_INSN_F64_ADD: - return 0xa0; - case WASM_INSN_F64_SUB: - return 0xa1; - case WASM_INSN_F64_MUL: - return 0xa2; - case WASM_INSN_F64_DIV: - return 0xa3; - case WASM_INSN_F32_EQ: - return 0x5b; - case WASM_INSN_F32_NE: - return 0x5c; - case WASM_INSN_F32_LT: - return 0x5d; - case WASM_INSN_F32_GT: - return 0x5e; - case WASM_INSN_F32_LE: - return 0x5f; - case WASM_INSN_F32_GE: - return 0x60; - case WASM_INSN_F64_EQ: - return 0x61; - case WASM_INSN_F64_NE: - return 0x62; - case WASM_INSN_F64_LT: - return 0x63; - case WASM_INSN_F64_GT: - return 0x64; - case WASM_INSN_F64_LE: - return 0x65; - case WASM_INSN_F64_GE: - return 0x66; - case WASM_INSN_I32_WRAP_I64: - return 0xa7; - case WASM_INSN_I32_TRUNC_F32_S: - return 0xa8; - case WASM_INSN_I32_TRUNC_F32_U: - return 0xa9; - case WASM_INSN_I32_TRUNC_F64_S: - return 0xaa; - case WASM_INSN_I32_TRUNC_F64_U: - return 0xab; - case WASM_INSN_I64_EXTEND_I32_S: - return 0xac; - case WASM_INSN_I64_EXTEND_I32_U: - return 0xad; - case WASM_INSN_I64_TRUNC_F32_S: - return 0xae; - case WASM_INSN_I64_TRUNC_F32_U: - return 0xaf; - case WASM_INSN_I64_TRUNC_F64_S: - return 0xb0; - case WASM_INSN_I64_TRUNC_F64_U: - return 0xb1; - case WASM_INSN_F32_CONVERT_I32_S: - return 0xb2; - case WASM_INSN_F32_CONVERT_I32_U: - return 0xb3; - case WASM_INSN_F32_CONVERT_I64_S: - return 0xb4; - case WASM_INSN_F32_CONVERT_I64_U: - return 0xb5; - case WASM_INSN_F32_DEMOTE_F64: - return 0xb6; - case WASM_INSN_F64_CONVERT_I32_S: - return 0xb7; - case WASM_INSN_F64_CONVERT_I32_U: - return 0xb8; - case WASM_INSN_F64_CONVERT_I64_S: - return 0xb9; - case WASM_INSN_F64_CONVERT_I64_U: - return 0xba; - case WASM_INSN_F64_PROMOTE_F32: - return 0xbb; - case WASM_INSN_I32_REINTERPRET_F32: - return 0xbc; - case WASM_INSN_I64_REINTERPRET_F64: - return 0xbd; - case WASM_INSN_F32_REINTERPRET_I32: - return 0xbe; - case WASM_INSN_F64_REINTERPRET_I64: - return 0xbf; + case WASM_INSN_UNREACHABLE: + return 0x00; + case WASM_INSN_NOP: + return 0x01; + case WASM_INSN_BLOCK: + return 0x02; + case WASM_INSN_LOOP: + return 0x03; + case WASM_INSN_IF: + return 0x04; + case WASM_INSN_ELSE: + return 0x05; + case WASM_INSN_END: + return 0x0b; + case WASM_INSN_BR: + return 0x0c; + case WASM_INSN_BR_IF: + return 0x0d; + case WASM_INSN_BR_TABLE: + return 0x0e; + case WASM_INSN_I32_CONST: + return 0x41; + case WASM_INSN_I64_CONST: + return 0x42; + case WASM_INSN_F32_CONST: + return 0x43; + case WASM_INSN_F64_CONST: + return 0x44; + case WASM_INSN_LOCAL_GET: + return 0x20; + case WASM_INSN_LOCAL_SET: + return 0x21; + case WASM_INSN_LOCAL_TEE: + return 0x22; + case WASM_INSN_CALL: + return 0x10; + case WASM_INSN_CALL_INDIRECT: + return 0x11; + case WASM_INSN_GLOBAL_GET: + return 0x23; + case WASM_INSN_GLOBAL_SET: + return 0x24; + case WASM_INSN_RETURN: + return 0x0f; + case WASM_INSN_DROP: + return 0x1a; + case WASM_INSN_SELECT: + return 0x1b; + case WASM_INSN_I32_LOAD: + return 0x28; + case WASM_INSN_I64_LOAD: + return 0x29; + case WASM_INSN_I32_LOAD8_S: + return 0x2c; + case WASM_INSN_I32_LOAD8_U: + return 0x2d; + case WASM_INSN_I32_LOAD16_S: + return 0x2e; + case WASM_INSN_I32_LOAD16_U: + return 0x2f; + case WASM_INSN_I64_LOAD8_S: + return 0x30; + case WASM_INSN_I64_LOAD8_U: + return 0x31; + case WASM_INSN_I64_LOAD16_S: + return 0x32; + case WASM_INSN_I64_LOAD16_U: + return 0x33; + case WASM_INSN_I64_LOAD32_S: + return 0x34; + case WASM_INSN_I64_LOAD32_U: + return 0x35; + case WASM_INSN_I32_STORE: + return 0x36; + case WASM_INSN_I64_STORE: + return 0x37; + case WASM_INSN_I32_STORE8: + return 0x3a; + case WASM_INSN_I32_STORE16: + return 0x3b; + case WASM_INSN_I64_STORE8: + return 0x3c; + case WASM_INSN_I64_STORE16: + return 0x3d; + case WASM_INSN_I64_STORE32: + return 0x3e; + case WASM_INSN_MEMORY_SIZE: + return 0x3f; + case WASM_INSN_MEMORY_GROW: + return 0x40; + case WASM_INSN_I32_EQZ: + return 0x45; + case WASM_INSN_I32_EQ: + return 0x46; + case WASM_INSN_I32_NE: + return 0x47; + case WASM_INSN_I32_LT_S: + return 0x48; + case WASM_INSN_I32_LT_U: + return 0x49; + case WASM_INSN_I32_GT_S: + return 0x4a; + case WASM_INSN_I32_GT_U: + return 0x4b; + case WASM_INSN_I32_LE_S: + return 0x4c; + case WASM_INSN_I32_LE_U: + return 0x4d; + case WASM_INSN_I32_GE_S: + return 0x4e; + case WASM_INSN_I32_GE_U: + return 0x4f; + case WASM_INSN_I64_EQZ: + return 0x50; + case WASM_INSN_I64_EQ: + return 0x51; + case WASM_INSN_I64_NE: + return 0x52; + case WASM_INSN_I64_LT_S: + return 0x53; + case WASM_INSN_I64_LT_U: + return 0x54; + case WASM_INSN_I64_GT_S: + return 0x55; + case WASM_INSN_I64_GT_U: + return 0x56; + case WASM_INSN_I64_LE_S: + return 0x57; + case WASM_INSN_I64_LE_U: + return 0x58; + case WASM_INSN_I64_GE_S: + return 0x59; + case WASM_INSN_I64_GE_U: + return 0x5a; + case WASM_INSN_I32_ADD: + return 0x6a; + case WASM_INSN_I32_SUB: + return 0x6b; + case WASM_INSN_I32_MUL: + return 0x6c; + case WASM_INSN_I32_DIV_S: + return 0x6d; + case WASM_INSN_I32_DIV_U: + return 0x6e; + case WASM_INSN_I32_REM_S: + return 0x6f; + case WASM_INSN_I32_REM_U: + return 0x70; + case WASM_INSN_I32_AND: + return 0x71; + case WASM_INSN_I32_OR: + return 0x72; + case WASM_INSN_I32_XOR: + return 0x73; + case WASM_INSN_I32_SHL: + return 0x74; + case WASM_INSN_I32_SHR_S: + return 0x75; + case WASM_INSN_I32_SHR_U: + return 0x76; + case WASM_INSN_I32_CLZ: + return 0x67; + case WASM_INSN_I32_CTZ: + return 0x68; + case WASM_INSN_I32_POPCNT: + return 0x69; + case WASM_INSN_I32_ROTL: + return 0x77; + case WASM_INSN_I32_ROTR: + return 0x78; + case WASM_INSN_I64_CLZ: + return 0x79; + case WASM_INSN_I64_CTZ: + return 0x7a; + case WASM_INSN_I64_POPCNT: + return 0x7b; + case WASM_INSN_I64_ADD: + return 0x7c; + case WASM_INSN_I64_SUB: + return 0x7d; + case WASM_INSN_I64_MUL: + return 0x7e; + case WASM_INSN_I64_DIV_S: + return 0x7f; + case WASM_INSN_I64_DIV_U: + return 0x80; + case WASM_INSN_I64_REM_S: + return 0x81; + case WASM_INSN_I64_REM_U: + return 0x82; + case WASM_INSN_I64_AND: + return 0x83; + case WASM_INSN_I64_OR: + return 0x84; + case WASM_INSN_I64_XOR: + return 0x85; + case WASM_INSN_I64_SHL: + return 0x86; + case WASM_INSN_I64_SHR_S: + return 0x87; + case WASM_INSN_I64_SHR_U: + return 0x88; + case WASM_INSN_I64_ROTL: + return 0x89; + case WASM_INSN_I64_ROTR: + return 0x8a; + case WASM_INSN_F32_ADD: + return 0x92; + case WASM_INSN_F32_SUB: + return 0x93; + case WASM_INSN_F32_MUL: + return 0x94; + case WASM_INSN_F32_DIV: + return 0x95; + case WASM_INSN_F64_ADD: + return 0xa0; + case WASM_INSN_F64_SUB: + return 0xa1; + case WASM_INSN_F64_MUL: + return 0xa2; + case WASM_INSN_F64_DIV: + return 0xa3; + case WASM_INSN_F32_EQ: + return 0x5b; + case WASM_INSN_F32_NE: + return 0x5c; + case WASM_INSN_F32_LT: + return 0x5d; + case WASM_INSN_F32_GT: + return 0x5e; + case WASM_INSN_F32_LE: + return 0x5f; + case WASM_INSN_F32_GE: + return 0x60; + case WASM_INSN_F64_EQ: + return 0x61; + case WASM_INSN_F64_NE: + return 0x62; + case WASM_INSN_F64_LT: + return 0x63; + case WASM_INSN_F64_GT: + return 0x64; + case WASM_INSN_F64_LE: + return 0x65; + case WASM_INSN_F64_GE: + return 0x66; + case WASM_INSN_I32_WRAP_I64: + return 0xa7; + case WASM_INSN_I32_TRUNC_F32_S: + return 0xa8; + case WASM_INSN_I32_TRUNC_F32_U: + return 0xa9; + case WASM_INSN_I32_TRUNC_F64_S: + return 0xaa; + case WASM_INSN_I32_TRUNC_F64_U: + return 0xab; + case WASM_INSN_I64_EXTEND_I32_S: + return 0xac; + case WASM_INSN_I64_EXTEND_I32_U: + return 0xad; + case WASM_INSN_I64_TRUNC_F32_S: + return 0xae; + case WASM_INSN_I64_TRUNC_F32_U: + return 0xaf; + case WASM_INSN_I64_TRUNC_F64_S: + return 0xb0; + case WASM_INSN_I64_TRUNC_F64_U: + return 0xb1; + case WASM_INSN_F32_CONVERT_I32_S: + return 0xb2; + case WASM_INSN_F32_CONVERT_I32_U: + return 0xb3; + case WASM_INSN_F32_CONVERT_I64_S: + return 0xb4; + case WASM_INSN_F32_CONVERT_I64_U: + return 0xb5; + case WASM_INSN_F32_DEMOTE_F64: + return 0xb6; + case WASM_INSN_F64_CONVERT_I32_S: + return 0xb7; + case WASM_INSN_F64_CONVERT_I32_U: + return 0xb8; + case WASM_INSN_F64_CONVERT_I64_S: + return 0xb9; + case WASM_INSN_F64_CONVERT_I64_U: + return 0xba; + case WASM_INSN_F64_PROMOTE_F32: + return 0xbb; + case WASM_INSN_I32_REINTERPRET_F32: + return 0xbc; + case WASM_INSN_I64_REINTERPRET_F64: + return 0xbd; + case WASM_INSN_F32_REINTERPRET_I32: + return 0xbe; + case WASM_INSN_F64_REINTERPRET_I64: + return 0xbf; } return 0; } -static void enc_code(CfreeWriter *w, const WasmModule *m) { +static void enc_code(CfreeWriter* w, const WasmModule* m) { uint32_t i, j; uint32_t n = 0; for (i = 0; i < m->nfuncs; ++i) - if (!m->funcs[i].is_import) - n++; + if (!m->funcs[i].is_import) n++; write_uleb(w, n); for (i = 0; i < m->nfuncs; ++i) { - CfreeWriter *body = cfree_writer_mem(m->heap); + CfreeWriter* body = cfree_writer_mem(m->heap); size_t len; - const uint8_t *bytes; + const uint8_t* bytes; if (m->funcs[i].is_import) { cfree_writer_close(body); continue; @@ -6173,7 +6297,7 @@ static void enc_code(CfreeWriter *w, const WasmModule *m) { } } -static void enc_data(CfreeWriter *w, const WasmModule *m) { +static void enc_data(CfreeWriter* w, const WasmModule* m) { if (!m->has_memory || !m->memory.data_init_len) { write_uleb(w, 0); return; @@ -6187,35 +6311,32 @@ static void enc_data(CfreeWriter *w, const WasmModule *m) { w->write(w, m->memory.data, m->memory.data_init_len); } -static void enc_elem(CfreeWriter *w, const WasmModule *m) { +static void enc_elem(CfreeWriter* w, const WasmModule* m) { uint32_t i, j; write_uleb(w, m->nelems); for (i = 0; i < m->nelems; ++i) { - const WasmElemSegment *e = &m->elems[i]; + const WasmElemSegment* e = &m->elems[i]; write_uleb(w, 0); write_byte(w, 0x41); write_sleb(w, e->offset); write_byte(w, 0x0b); write_uleb(w, e->nfuncs); - for (j = 0; j < e->nfuncs; ++j) - write_uleb(w, e->funcs[j]); + for (j = 0; j < e->nfuncs; ++j) write_uleb(w, e->funcs[j]); } } -static void enc_start(CfreeWriter *w, const WasmModule *m) { +static void enc_start(CfreeWriter* w, const WasmModule* m) { write_uleb(w, m->start_func); } -static void encode_custom(CfreeHeap *h, CfreeWriter *out, - const WasmCustom *cs) { - CfreeWriter *tmp = cfree_writer_mem(h); +static void encode_custom(CfreeHeap* h, CfreeWriter* out, + const WasmCustom* cs) { + CfreeWriter* tmp = cfree_writer_mem(h); size_t len; - const uint8_t *bytes; - if (!tmp) - return; + const uint8_t* bytes; + if (!tmp) return; write_name(tmp, cs->name ? cs->name : ""); - if (cs->len) - tmp->write(tmp, cs->data, cs->len); + if (cs->len) tmp->write(tmp, cs->data, cs->len); bytes = cfree_writer_mem_bytes(tmp, &len); write_byte(out, 0); write_uleb(out, len); @@ -6223,36 +6344,31 @@ static void encode_custom(CfreeHeap *h, CfreeWriter *out, cfree_writer_close(tmp); } -static void wasm_encode(CfreeCompiler *c, const WasmModule *m, - CfreeWriter *out) { +static void wasm_encode(CfreeCompiler* c, const WasmModule* m, + CfreeWriter* out) { static const uint8_t magic[] = {0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}; - CfreeHeap *h = cfree_compiler_heap(c); + CfreeHeap* h = cfree_compiler_heap(c); out->write(out, magic, sizeof magic); for (uint32_t i = 0; i < m->ncustoms; ++i) encode_custom(h, out, &m->customs[i]); encode_section(h, out, 1, enc_type, m); - if (wasm_module_has_imports(m)) - encode_section(h, out, 2, enc_import, m); + if (wasm_module_has_imports(m)) encode_section(h, out, 2, enc_import, m); encode_section(h, out, 3, enc_func, m); - if (m->ntables) - encode_section(h, out, 4, enc_table, m); + if (m->ntables) encode_section(h, out, 4, enc_table, m); if (m->has_memory && !m->memory.is_import) encode_section(h, out, 5, enc_memory, m); - if (m->nglobals) - encode_section(h, out, 6, enc_global, m); + if (m->nglobals) encode_section(h, out, 6, enc_global, m); encode_section(h, out, 7, enc_export, m); - if (m->has_start) - encode_section(h, out, 8, enc_start, m); - if (m->nelems) - encode_section(h, out, 9, enc_elem, m); + if (m->has_start) encode_section(h, out, 8, enc_start, m); + if (m->nelems) encode_section(h, out, 9, enc_elem, m); encode_section(h, out, 10, enc_code, m); if (m->has_memory && m->memory.data_init_len) encode_section(h, out, 11, enc_data, m); } -static void wasm_parse_any(CfreeCompiler *c, const CfreeBytesInput *input, - WasmModule *m) { +static void wasm_parse_any(CfreeCompiler* c, const CfreeBytesInput* input, + WasmModule* m) { if (wasm_is_binary(input)) wasm_decode_binary(c, input, m); else @@ -6260,8 +6376,8 @@ static void wasm_parse_any(CfreeCompiler *c, const CfreeBytesInput *input, wasm_validate(m, c); } -int cfree_wasm_compile(CfreeCompiler *c, const CfreeCompileOptions *opts, - const CfreeBytesInput *input, CfreeObjBuilder *out) { +int cfree_wasm_compile(CfreeCompiler* c, const CfreeCompileOptions* opts, + const CfreeBytesInput* input, CfreeObjBuilder* out) { WasmModule m; wasm_module_init(&m, cfree_compiler_heap(c)); wasm_parse_any(c, input, &m); @@ -6270,12 +6386,12 @@ int cfree_wasm_compile(CfreeCompiler *c, const CfreeCompileOptions *opts, return 0; } -void cfree_wasm_register(CfreeCompiler *c) { +void cfree_wasm_register(CfreeCompiler* c) { (void)cfree_register_frontend(c, CFREE_LANG_WASM, cfree_wasm_compile); } -int cfree_wasm_wat_to_wasm(CfreeCompiler *c, const CfreeBytesInput *input, - CfreeWriter *out) { +int cfree_wasm_wat_to_wasm(CfreeCompiler* c, const CfreeBytesInput* input, + CfreeWriter* out) { WasmModule m; wasm_module_init(&m, cfree_compiler_heap(c)); wat_parse_module(c, input, &m); diff --git a/test/wasm/cases/import_slot_unused.expect b/test/wasm/cases/import_slot_unused.expect @@ -0,0 +1 @@ +42 diff --git a/test/wasm/cases/import_slot_unused.wat b/test/wasm/cases/import_slot_unused.wat @@ -0,0 +1,4 @@ +(module + (import "host" "unused" (func $unused (param i32) (result i32))) + (func (export "test_main") (result i32) + i32.const 42)) diff --git a/test/wasm/cases/table_offset.expect b/test/wasm/cases/table_offset.expect @@ -0,0 +1 @@ +42 diff --git a/test/wasm/cases/table_offset.wat b/test/wasm/cases/table_offset.wat @@ -0,0 +1,9 @@ +(module + (type $ret_i32 (func (result i32))) + (func $target (type $ret_i32) + i32.const 42) + (table 3 funcref) + (elem (i32.const 2) func $target) + (func (export "test_main") (result i32) + i32.const 2 + call_indirect (type $ret_i32)))