commit de7b25ff43c391fe820d41f84e1b0bca8ba9d360
parent e8e6581c9b695d8e265a180dc64d27e73938815f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 17 May 2026 23:43:34 -0700
wasm: add instance runtime runner path
Diffstat:
7 files changed, 859 insertions(+), 364 deletions(-)
diff --git a/driver/run.c b/driver/run.c
@@ -1,4 +1,5 @@
#include <stdint.h>
+#include <stdlib.h>
#include "cflags.h"
#include "driver.h"
@@ -404,6 +405,47 @@ static int run_compile_and_jit(RunOptions* o, CfreePipeline* pipe,
}
typedef int (*MainFn)(int, char**);
+typedef void (*WasmInitFn)(void*);
+typedef int (*WasmMainFn)(void*);
+
+typedef struct RunWasmMemoryPrefix {
+ uint8_t* data;
+ uint32_t pages;
+ uint32_t max_pages;
+} RunWasmMemoryPrefix;
+
+static int run_call_wasm_entry(RunOptions* ro, CfreeJit* jit, void* entry,
+ int* rc_out) {
+ void* init_sym = cfree_jit_lookup(jit, "__cfree_wasm_init");
+ uint8_t* instance;
+ uint8_t* memory;
+ union {
+ void* p;
+ WasmInitFn fn;
+ } init_u;
+ union {
+ void* p;
+ WasmMainFn fn;
+ } entry_u;
+ if (!init_sym) return 0;
+ instance = (uint8_t*)driver_alloc_zeroed(ro->env, 64u * 1024u);
+ memory = (uint8_t*)driver_alloc_zeroed(ro->env, 16u * 1024u * 1024u);
+ if (!instance || !memory) {
+ driver_errf(RUN_TOOL, "out of memory");
+ driver_free(ro->env, memory, 16u * 1024u * 1024u);
+ driver_free(ro->env, instance, 64u * 1024u);
+ *rc_out = 1;
+ return 1;
+ }
+ ((RunWasmMemoryPrefix*)instance)->data = memory;
+ init_u.p = init_sym;
+ entry_u.p = entry;
+ init_u.fn(instance);
+ *rc_out = entry_u.fn(instance);
+ driver_free(ro->env, memory, 16u * 1024u * 1024u);
+ driver_free(ro->env, instance, 64u * 1024u);
+ return 1;
+}
int driver_run(int argc, char** argv) {
DriverEnv env;
@@ -490,7 +532,8 @@ int driver_run(int argc, char** argv) {
}
run_metrics_begin(metrics, "run.entry_call");
- rc = entry_fn((int)ro.prog_argc, ro.prog_argv);
+ if (!run_call_wasm_entry(&ro, jit, sym, &rc))
+ rc = entry_fn((int)ro.prog_argc, ro.prog_argv);
run_metrics_end(metrics, "run.entry_call");
cfree_jit_free(jit);
diff --git a/lang/wasm/runtime_abi.h b/lang/wasm/runtime_abi.h
@@ -0,0 +1,19 @@
+#ifndef CFREE_LANG_WASM_RUNTIME_ABI_H
+#define CFREE_LANG_WASM_RUNTIME_ABI_H
+
+#include <stdint.h>
+
+typedef struct CfreeWasmMemory {
+ uint8_t *data;
+ uint32_t pages;
+ uint32_t max_pages;
+} CfreeWasmMemory;
+
+/* 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. */
+typedef struct CfreeWasmInstance CfreeWasmInstance;
+
+typedef void (*CfreeWasmInitFn)(CfreeWasmInstance *);
+
+#endif
diff --git a/lang/wasm/wasm.c b/lang/wasm/wasm.c
@@ -217,6 +217,7 @@ typedef struct WasmMemory {
char *export_name;
uint8_t *data;
uint32_t data_len;
+ uint32_t data_init_len;
} WasmMemory;
typedef struct WasmTable {
@@ -493,8 +494,8 @@ static uint32_t wasm_intern_func_type(CfreeCompiler *c, WasmModule *m,
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) == 0)
+ memcmp(t->results, f->results, sizeof(t->results[0]) * t->nresults) ==
+ 0)
return i;
}
{
@@ -511,9 +512,9 @@ 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 = wasm_realloc(m->heap, m->tables,
- sizeof(*m->tables) * m->cap_tables,
- sizeof(*m->tables) * new_cap);
+ 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;
@@ -530,9 +531,9 @@ 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 = wasm_realloc(m->heap, m->globals,
- sizeof(*m->globals) * m->cap_globals,
- sizeof(*m->globals) * new_cap);
+ 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;
@@ -567,9 +568,9 @@ 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 = wasm_realloc(m->heap, m->exports,
- sizeof(*m->exports) * m->cap_exports,
- sizeof(*m->exports) * new_cap);
+ 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;
@@ -586,9 +587,9 @@ 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 = wasm_realloc(m->heap, m->customs,
- sizeof(*m->customs) * m->cap_customs,
- sizeof(*m->customs) * new_cap);
+ 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;
@@ -621,16 +622,15 @@ 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, WasmInsnKind kind,
- uint32_t align, uint32_t offset) {
+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, WasmInsnKind kind,
- double value) {
+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;
}
@@ -823,8 +823,8 @@ static void wat_next(WatParser *p) {
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);
+ wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col), "wasm wat: expected %s",
+ what);
wat_next(p);
}
@@ -1356,51 +1356,186 @@ static int wat_instr_kind(WasmTok t, WasmInsnKind *out, int *has_imm) {
*out = WASM_INSN_I64_GE_U;
return 1;
}
- if (tok_is(t, "f32.add")) { *out = WASM_INSN_F32_ADD; return 1; }
- if (tok_is(t, "f32.sub")) { *out = WASM_INSN_F32_SUB; return 1; }
- if (tok_is(t, "f32.mul")) { *out = WASM_INSN_F32_MUL; return 1; }
- if (tok_is(t, "f32.div")) { *out = WASM_INSN_F32_DIV; return 1; }
- if (tok_is(t, "f32.eq")) { *out = WASM_INSN_F32_EQ; return 1; }
- if (tok_is(t, "f32.ne")) { *out = WASM_INSN_F32_NE; return 1; }
- if (tok_is(t, "f32.lt")) { *out = WASM_INSN_F32_LT; return 1; }
- if (tok_is(t, "f32.gt")) { *out = WASM_INSN_F32_GT; return 1; }
- if (tok_is(t, "f32.le")) { *out = WASM_INSN_F32_LE; return 1; }
- if (tok_is(t, "f32.ge")) { *out = WASM_INSN_F32_GE; return 1; }
- if (tok_is(t, "f64.add")) { *out = WASM_INSN_F64_ADD; return 1; }
- if (tok_is(t, "f64.sub")) { *out = WASM_INSN_F64_SUB; return 1; }
- if (tok_is(t, "f64.mul")) { *out = WASM_INSN_F64_MUL; return 1; }
- if (tok_is(t, "f64.div")) { *out = WASM_INSN_F64_DIV; return 1; }
- if (tok_is(t, "f64.eq")) { *out = WASM_INSN_F64_EQ; return 1; }
- if (tok_is(t, "f64.ne")) { *out = WASM_INSN_F64_NE; return 1; }
- if (tok_is(t, "f64.lt")) { *out = WASM_INSN_F64_LT; return 1; }
- if (tok_is(t, "f64.gt")) { *out = WASM_INSN_F64_GT; return 1; }
- if (tok_is(t, "f64.le")) { *out = WASM_INSN_F64_LE; return 1; }
- if (tok_is(t, "f64.ge")) { *out = WASM_INSN_F64_GE; return 1; }
- if (tok_is(t, "i32.wrap_i64")) { *out = WASM_INSN_I32_WRAP_I64; return 1; }
- if (tok_is(t, "i32.trunc_f32_s")) { *out = WASM_INSN_I32_TRUNC_F32_S; return 1; }
- if (tok_is(t, "i32.trunc_f32_u")) { *out = WASM_INSN_I32_TRUNC_F32_U; return 1; }
- if (tok_is(t, "i32.trunc_f64_s")) { *out = WASM_INSN_I32_TRUNC_F64_S; return 1; }
- if (tok_is(t, "i32.trunc_f64_u")) { *out = WASM_INSN_I32_TRUNC_F64_U; return 1; }
- if (tok_is(t, "i64.extend_i32_s")) { *out = WASM_INSN_I64_EXTEND_I32_S; return 1; }
- if (tok_is(t, "i64.extend_i32_u")) { *out = WASM_INSN_I64_EXTEND_I32_U; return 1; }
- if (tok_is(t, "i64.trunc_f32_s")) { *out = WASM_INSN_I64_TRUNC_F32_S; return 1; }
- if (tok_is(t, "i64.trunc_f32_u")) { *out = WASM_INSN_I64_TRUNC_F32_U; return 1; }
- if (tok_is(t, "i64.trunc_f64_s")) { *out = WASM_INSN_I64_TRUNC_F64_S; return 1; }
- if (tok_is(t, "i64.trunc_f64_u")) { *out = WASM_INSN_I64_TRUNC_F64_U; return 1; }
- if (tok_is(t, "f32.convert_i32_s")) { *out = WASM_INSN_F32_CONVERT_I32_S; return 1; }
- if (tok_is(t, "f32.convert_i32_u")) { *out = WASM_INSN_F32_CONVERT_I32_U; return 1; }
- if (tok_is(t, "f32.convert_i64_s")) { *out = WASM_INSN_F32_CONVERT_I64_S; return 1; }
- if (tok_is(t, "f32.convert_i64_u")) { *out = WASM_INSN_F32_CONVERT_I64_U; return 1; }
- if (tok_is(t, "f32.demote_f64")) { *out = WASM_INSN_F32_DEMOTE_F64; return 1; }
- if (tok_is(t, "f64.convert_i32_s")) { *out = WASM_INSN_F64_CONVERT_I32_S; return 1; }
- if (tok_is(t, "f64.convert_i32_u")) { *out = WASM_INSN_F64_CONVERT_I32_U; return 1; }
- if (tok_is(t, "f64.convert_i64_s")) { *out = WASM_INSN_F64_CONVERT_I64_S; return 1; }
- if (tok_is(t, "f64.convert_i64_u")) { *out = WASM_INSN_F64_CONVERT_I64_U; return 1; }
- if (tok_is(t, "f64.promote_f32")) { *out = WASM_INSN_F64_PROMOTE_F32; return 1; }
- if (tok_is(t, "i32.reinterpret_f32")) { *out = WASM_INSN_I32_REINTERPRET_F32; return 1; }
- if (tok_is(t, "i64.reinterpret_f64")) { *out = WASM_INSN_I64_REINTERPRET_F64; return 1; }
- if (tok_is(t, "f32.reinterpret_i32")) { *out = WASM_INSN_F32_REINTERPRET_I32; return 1; }
- if (tok_is(t, "f64.reinterpret_i64")) { *out = WASM_INSN_F64_REINTERPRET_I64; return 1; }
+ if (tok_is(t, "f32.add")) {
+ *out = WASM_INSN_F32_ADD;
+ return 1;
+ }
+ if (tok_is(t, "f32.sub")) {
+ *out = WASM_INSN_F32_SUB;
+ return 1;
+ }
+ if (tok_is(t, "f32.mul")) {
+ *out = WASM_INSN_F32_MUL;
+ return 1;
+ }
+ if (tok_is(t, "f32.div")) {
+ *out = WASM_INSN_F32_DIV;
+ return 1;
+ }
+ if (tok_is(t, "f32.eq")) {
+ *out = WASM_INSN_F32_EQ;
+ return 1;
+ }
+ if (tok_is(t, "f32.ne")) {
+ *out = WASM_INSN_F32_NE;
+ return 1;
+ }
+ if (tok_is(t, "f32.lt")) {
+ *out = WASM_INSN_F32_LT;
+ return 1;
+ }
+ if (tok_is(t, "f32.gt")) {
+ *out = WASM_INSN_F32_GT;
+ return 1;
+ }
+ if (tok_is(t, "f32.le")) {
+ *out = WASM_INSN_F32_LE;
+ return 1;
+ }
+ if (tok_is(t, "f32.ge")) {
+ *out = WASM_INSN_F32_GE;
+ return 1;
+ }
+ if (tok_is(t, "f64.add")) {
+ *out = WASM_INSN_F64_ADD;
+ return 1;
+ }
+ if (tok_is(t, "f64.sub")) {
+ *out = WASM_INSN_F64_SUB;
+ return 1;
+ }
+ if (tok_is(t, "f64.mul")) {
+ *out = WASM_INSN_F64_MUL;
+ return 1;
+ }
+ if (tok_is(t, "f64.div")) {
+ *out = WASM_INSN_F64_DIV;
+ return 1;
+ }
+ if (tok_is(t, "f64.eq")) {
+ *out = WASM_INSN_F64_EQ;
+ return 1;
+ }
+ if (tok_is(t, "f64.ne")) {
+ *out = WASM_INSN_F64_NE;
+ return 1;
+ }
+ if (tok_is(t, "f64.lt")) {
+ *out = WASM_INSN_F64_LT;
+ return 1;
+ }
+ if (tok_is(t, "f64.gt")) {
+ *out = WASM_INSN_F64_GT;
+ return 1;
+ }
+ if (tok_is(t, "f64.le")) {
+ *out = WASM_INSN_F64_LE;
+ return 1;
+ }
+ if (tok_is(t, "f64.ge")) {
+ *out = WASM_INSN_F64_GE;
+ return 1;
+ }
+ if (tok_is(t, "i32.wrap_i64")) {
+ *out = WASM_INSN_I32_WRAP_I64;
+ return 1;
+ }
+ if (tok_is(t, "i32.trunc_f32_s")) {
+ *out = WASM_INSN_I32_TRUNC_F32_S;
+ return 1;
+ }
+ if (tok_is(t, "i32.trunc_f32_u")) {
+ *out = WASM_INSN_I32_TRUNC_F32_U;
+ return 1;
+ }
+ if (tok_is(t, "i32.trunc_f64_s")) {
+ *out = WASM_INSN_I32_TRUNC_F64_S;
+ return 1;
+ }
+ if (tok_is(t, "i32.trunc_f64_u")) {
+ *out = WASM_INSN_I32_TRUNC_F64_U;
+ return 1;
+ }
+ if (tok_is(t, "i64.extend_i32_s")) {
+ *out = WASM_INSN_I64_EXTEND_I32_S;
+ return 1;
+ }
+ if (tok_is(t, "i64.extend_i32_u")) {
+ *out = WASM_INSN_I64_EXTEND_I32_U;
+ return 1;
+ }
+ if (tok_is(t, "i64.trunc_f32_s")) {
+ *out = WASM_INSN_I64_TRUNC_F32_S;
+ return 1;
+ }
+ if (tok_is(t, "i64.trunc_f32_u")) {
+ *out = WASM_INSN_I64_TRUNC_F32_U;
+ return 1;
+ }
+ if (tok_is(t, "i64.trunc_f64_s")) {
+ *out = WASM_INSN_I64_TRUNC_F64_S;
+ return 1;
+ }
+ if (tok_is(t, "i64.trunc_f64_u")) {
+ *out = WASM_INSN_I64_TRUNC_F64_U;
+ return 1;
+ }
+ if (tok_is(t, "f32.convert_i32_s")) {
+ *out = WASM_INSN_F32_CONVERT_I32_S;
+ return 1;
+ }
+ if (tok_is(t, "f32.convert_i32_u")) {
+ *out = WASM_INSN_F32_CONVERT_I32_U;
+ return 1;
+ }
+ if (tok_is(t, "f32.convert_i64_s")) {
+ *out = WASM_INSN_F32_CONVERT_I64_S;
+ return 1;
+ }
+ if (tok_is(t, "f32.convert_i64_u")) {
+ *out = WASM_INSN_F32_CONVERT_I64_U;
+ return 1;
+ }
+ if (tok_is(t, "f32.demote_f64")) {
+ *out = WASM_INSN_F32_DEMOTE_F64;
+ return 1;
+ }
+ if (tok_is(t, "f64.convert_i32_s")) {
+ *out = WASM_INSN_F64_CONVERT_I32_S;
+ return 1;
+ }
+ if (tok_is(t, "f64.convert_i32_u")) {
+ *out = WASM_INSN_F64_CONVERT_I32_U;
+ return 1;
+ }
+ if (tok_is(t, "f64.convert_i64_s")) {
+ *out = WASM_INSN_F64_CONVERT_I64_S;
+ return 1;
+ }
+ if (tok_is(t, "f64.convert_i64_u")) {
+ *out = WASM_INSN_F64_CONVERT_I64_U;
+ return 1;
+ }
+ if (tok_is(t, "f64.promote_f32")) {
+ *out = WASM_INSN_F64_PROMOTE_F32;
+ return 1;
+ }
+ if (tok_is(t, "i32.reinterpret_f32")) {
+ *out = WASM_INSN_I32_REINTERPRET_F32;
+ return 1;
+ }
+ if (tok_is(t, "i64.reinterpret_f64")) {
+ *out = WASM_INSN_I64_REINTERPRET_F64;
+ return 1;
+ }
+ if (tok_is(t, "f32.reinterpret_i32")) {
+ *out = WASM_INSN_F32_REINTERPRET_I32;
+ return 1;
+ }
+ if (tok_is(t, "f64.reinterpret_i64")) {
+ *out = WASM_INSN_F64_REINTERPRET_I64;
+ return 1;
+ }
return 0;
}
@@ -1720,9 +1855,8 @@ static void wat_parse_instr_list(WatParser *p, WasmFunc *f) {
if (!wat_parse_i64(p, &target) || target < 0 || target > UINT32_MAX)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm wat: bad br_table target");
- wasm_func_add_insn(p->c, p->module, f, n ? WASM_INSN_NOP
- : WASM_INSN_BR_TABLE,
- 0);
+ wasm_func_add_insn(p->c, p->module, f,
+ n ? WASM_INSN_NOP : WASM_INSN_BR_TABLE, 0);
in = &f->insns[f->ninsns - 1u - n];
in->targets[n++] = (uint32_t)target;
wat_next(p);
@@ -1909,9 +2043,8 @@ static void wat_parse_func(WatParser *p) {
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm wat: parameter does not match type");
if (have_name) {
- f->local_names[checked_params] =
- wasm_strdup(p->module->heap, pending_name.p,
- pending_name.len);
+ f->local_names[checked_params] = wasm_strdup(
+ p->module->heap, pending_name.p, pending_name.len);
if (!f->local_names[checked_params])
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm: out of memory");
@@ -1946,7 +2079,8 @@ static void wat_parse_func(WatParser *p) {
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm wat: unsupported result type");
if (f->has_typeidx) {
- if (checked_results >= f->nresults || f->results[checked_results] != vt)
+ if (checked_results >= f->nresults ||
+ f->results[checked_results] != vt)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm wat: result does not match type");
checked_results++;
@@ -2098,29 +2232,29 @@ static void wat_parse_export_field(WatParser *p) {
}
if (kind == 0 && (uint64_t)idx < p->module->nfuncs) {
wasm_free_str(p->module->heap, &p->module->funcs[idx].export_name);
- p->module->funcs[idx].export_name = wasm_strdup(p->module->heap, name,
- strlen(name));
+ p->module->funcs[idx].export_name =
+ wasm_strdup(p->module->heap, name, strlen(name));
if (!p->module->funcs[idx].export_name)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm: out of memory");
} else if (kind == 2 && idx == 0 && p->module->has_memory) {
wasm_free_str(p->module->heap, &p->module->memory.export_name);
- p->module->memory.export_name = wasm_strdup(p->module->heap, name,
- strlen(name));
+ p->module->memory.export_name =
+ wasm_strdup(p->module->heap, name, strlen(name));
if (!p->module->memory.export_name)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm: out of memory");
} else if (kind == 1 && (uint64_t)idx < p->module->ntables) {
wasm_free_str(p->module->heap, &p->module->tables[idx].export_name);
- p->module->tables[idx].export_name = wasm_strdup(p->module->heap, name,
- strlen(name));
+ p->module->tables[idx].export_name =
+ wasm_strdup(p->module->heap, name, strlen(name));
if (!p->module->tables[idx].export_name)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm: out of memory");
} else if (kind == 3 && (uint64_t)idx < p->module->nglobals) {
wasm_free_str(p->module->heap, &p->module->globals[idx].export_name);
- p->module->globals[idx].export_name = wasm_strdup(p->module->heap, name,
- strlen(name));
+ p->module->globals[idx].export_name =
+ wasm_strdup(p->module->heap, name, strlen(name));
if (!p->module->globals[idx].export_name)
wasm_error(p->c, wasm_loc(p->tok.line, p->tok.col),
"wasm: out of memory");
@@ -2137,8 +2271,7 @@ static void wat_parse_memory_field(WatParser *p) {
"wasm wat: multiple memories are unsupported");
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)
+ 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");
p->module->has_memory = 1;
@@ -2299,8 +2432,8 @@ static void wat_parse_import_field(WatParser *p) {
wat_next(p);
}
wat_parse_limits(p, &p->module->memory.min_pages,
- &p->module->memory.max_pages,
- &p->module->memory.has_max, "memory");
+ &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);
t->is_import = 1;
@@ -2510,7 +2643,8 @@ 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");
@@ -2549,6 +2683,9 @@ static void wat_parse_data_field(WatParser *p) {
"wasm wat: data segment too large");
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->heap->free(p->module->heap, bytes, alloc_len);
wat_next(p);
wat_expect(p, WT_RPAREN, "')'");
@@ -2750,8 +2887,8 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
"wasm: relocatable object metadata is not frontend input");
{
WasmCustom *cs = wasm_add_custom(c, out);
- cs->name = wasm_strdup(out->heap, (const char *)(r.data + r.pos),
- name_len);
+ 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");
r.pos += name_len;
@@ -2832,7 +2969,8 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
} else if (kind == 2) {
uint32_t flags;
if (out->has_memory)
- wasm_error(c, wasm_loc(0, 0), "wasm: multiple memories unsupported");
+ wasm_error(c, wasm_loc(0, 0),
+ "wasm: multiple memories unsupported");
out->has_memory = 1;
out->memory.is_import = 1;
out->memory.import_module = mod;
@@ -2938,7 +3076,8 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
g->init.fp = bin_f64(&r);
break;
default:
- wasm_error(c, wasm_loc(0, 0), "wasm: unsupported global initializer");
+ 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");
@@ -2967,15 +3106,15 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
wasm_error(c, wasm_loc(0, 0), "wasm: out of memory");
} else if (kind == 1 && idx < out->ntables) {
wasm_free_str(out->heap, &out->tables[idx].export_name);
- out->tables[idx].export_name = wasm_strdup(out->heap, name,
- strlen(name));
+ out->tables[idx].export_name =
+ wasm_strdup(out->heap, name, strlen(name));
} else if (kind == 2 && idx == 0 && out->has_memory) {
wasm_free_str(out->heap, &out->memory.export_name);
out->memory.export_name = wasm_strdup(out->heap, name, strlen(name));
} else if (kind == 3 && idx < out->nglobals) {
wasm_free_str(out->heap, &out->globals[idx].export_name);
- out->globals[idx].export_name = wasm_strdup(out->heap, name,
- strlen(name));
+ out->globals[idx].export_name =
+ wasm_strdup(out->heap, name, strlen(name));
}
}
} else if (id == 8) {
@@ -3034,8 +3173,7 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
while (r.pos < body_end) {
uint8_t op = bin_u8(&r);
if (op == 0x0bu) {
- if (!control_depth)
- {
+ if (!control_depth) {
saw_body_end = 1;
break;
}
@@ -3084,7 +3222,8 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
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_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)
@@ -3565,10 +3704,13 @@ static void wasm_decode_binary(CfreeCompiler *c, const CfreeBytesInput *input,
bin_need(&r, n);
wasm_memory_ensure(c, out, (uint32_t)offset + n);
memcpy(out->memory.data + (uint32_t)offset, r.data + r.pos, n);
+ if ((uint64_t)offset + n > out->memory.data_init_len)
+ out->memory.data_init_len = (uint32_t)((uint64_t)offset + n);
r.pos += n;
}
} else if (id == 12) {
- wasm_error(c, wasm_loc(0, 0), "wasm: data count sections are unsupported");
+ wasm_error(c, wasm_loc(0, 0),
+ "wasm: data count sections are unsupported");
} else {
r.pos = end;
}
@@ -3615,6 +3757,13 @@ static CfreeCgMemAccess wasm_cg_mem(CfreeCompiler *c, CfreeCgBuiltinTypes b,
return mem;
}
+static CfreeCgMemAccess wasm_cg_mem_type(CfreeCgTypeId ty) {
+ CfreeCgMemAccess mem;
+ memset(&mem, 0, sizeof mem);
+ mem.type = ty;
+ return mem;
+}
+
static void wasm_cg_push_zero(CfreeCompiler *c, CfreeCg *cg,
CfreeCgBuiltinTypes b, WasmValType vt) {
CfreeCgTypeId ty = wasm_cg_type(c, b, vt);
@@ -3695,22 +3844,125 @@ static void wasm_cg_trap(CfreeCg *cg) {
cfree_cg_unreachable(cg);
}
+typedef struct WasmCgRuntime {
+ CfreeCgTypeId i8_ptr_ty;
+ CfreeCgTypeId memory_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;
+} WasmCgRuntime;
+
+static void wasm_cg_build_runtime(CfreeCompiler *c, CfreeCgBuiltinTypes b,
+ const WasmModule *m, WasmCgRuntime *rt) {
+ CfreeCgField memory_fields[3];
+ CfreeCgField instance_fields[65];
+ 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);
+ memset(memory_fields, 0, sizeof memory_fields);
+ memory_fields[0].name = cfree_sym_intern(c, "data");
+ memory_fields[0].type = rt->i8_ptr_ty;
+ memory_fields[1].name = cfree_sym_intern(c, "pages");
+ memory_fields[1].type = b.id[CFREE_CG_BUILTIN_I32];
+ memory_fields[2].name = cfree_sym_intern(c, "max_pages");
+ memory_fields[2].type = b.id[CFREE_CG_BUILTIN_I32];
+ rt->memory_ty = cfree_cg_type_record(
+ c, cfree_sym_intern(c, "CfreeWasmMemory"), memory_fields, 3);
+ rt->memory_field = 0;
+ rt->memory_data_field = 0;
+ rt->memory_pages_field = 1;
+ rt->memory_max_pages_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;
+ 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';
+ instance_fields[nfields].name = cfree_sym_intern(c, name);
+ instance_fields[nfields].type = wasm_cg_type(c, b, m->globals[i].type);
+ nfields++;
+ }
+ rt->instance_ty = cfree_cg_type_record(
+ c, cfree_sym_intern(c, "CfreeWasmInstance"), instance_fields, nfields);
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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);
+}
+
static void wasm_cg_memory_check(CfreeCompiler *c, CfreeCg *cg,
CfreeCgBuiltinTypes b, const WasmModule *m,
- CfreeCgSym memory_pages_sym,
+ const WasmCgRuntime *rt,
+ CfreeCgLocal instance_local,
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;
+ 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);
return;
}
(void)c;
cfree_cg_dup(cg);
- cfree_cg_push_symbol_lvalue(cg, memory_pages_sym, 0);
+ wasm_cg_push_memory_pages_lvalue(cg, rt, instance_local);
cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
cfree_cg_push_int(cg, 65536u, b.id[CFREE_CG_BUILTIN_I32]);
cfree_cg_int_binop(cg, CFREE_CG_INT_MUL, 0);
@@ -3722,9 +3974,10 @@ static void wasm_cg_memory_check(CfreeCompiler *c, CfreeCg *cg,
cfree_cg_label_place(cg, ok);
}
-static void wasm_cg_memory_lvalue(CfreeCg *cg, CfreeCgSym memory_sym,
+static void wasm_cg_memory_lvalue(CfreeCg *cg, const WasmCgRuntime *rt,
+ CfreeCgLocal instance_local,
uint32_t offset) {
- cfree_cg_push_symbol_lvalue(cg, memory_sym, 0);
+ wasm_cg_push_memory_data_ptr(cg, rt, instance_local);
cfree_cg_swap(cg);
cfree_cg_index(cg, offset);
}
@@ -3867,16 +4120,20 @@ 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;
+ *out = CFREE_CG_FP_ADD;
+ return 1;
case WASM_INSN_F32_SUB:
case WASM_INSN_F64_SUB:
- *out = CFREE_CG_FP_SUB; return 1;
+ *out = CFREE_CG_FP_SUB;
+ return 1;
case WASM_INSN_F32_MUL:
case WASM_INSN_F64_MUL:
- *out = CFREE_CG_FP_MUL; return 1;
+ *out = CFREE_CG_FP_MUL;
+ return 1;
case WASM_INSN_F32_DIV:
case WASM_INSN_F64_DIV:
- *out = CFREE_CG_FP_DIV; return 1;
+ *out = CFREE_CG_FP_DIV;
+ return 1;
default:
return 0;
}
@@ -3886,22 +4143,28 @@ 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;
+ *out = CFREE_CG_FP_OEQ;
+ return 1;
case WASM_INSN_F32_NE:
case WASM_INSN_F64_NE:
- *out = CFREE_CG_FP_ONE; return 1;
+ *out = CFREE_CG_FP_ONE;
+ return 1;
case WASM_INSN_F32_LT:
case WASM_INSN_F64_LT:
- *out = CFREE_CG_FP_OLT; return 1;
+ *out = CFREE_CG_FP_OLT;
+ return 1;
case WASM_INSN_F32_GT:
case WASM_INSN_F64_GT:
- *out = CFREE_CG_FP_OGT; return 1;
+ *out = CFREE_CG_FP_OGT;
+ return 1;
case WASM_INSN_F32_LE:
case WASM_INSN_F64_LE:
- *out = CFREE_CG_FP_OLE; return 1;
+ *out = CFREE_CG_FP_OLE;
+ return 1;
case WASM_INSN_F32_GE:
case WASM_INSN_F64_GE:
- *out = CFREE_CG_FP_OGE; return 1;
+ *out = CFREE_CG_FP_OGE;
+ return 1;
default:
return 0;
}
@@ -3982,46 +4245,78 @@ 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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *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;
+ *src = WASM_VAL_I64;
+ *dst = WASM_VAL_F64;
+ return 1;
default:
return 0;
}
@@ -4054,8 +4349,7 @@ static WasmValType wasm_global_init_type(const WasmInsn *in) {
}
}
-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;
@@ -4153,15 +4447,24 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) {
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_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));
+ 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:
@@ -4171,7 +4474,8 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) {
wasm_stack_pop(c, &stack, control, ncontrol,
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));
+ 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)
@@ -4290,7 +4594,8 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) {
"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_error(c, wasm_loc(0, 0),
+ "wasm: br_table depth out of range");
wasm_mark_unreachable(&stack, control, ncontrol);
break;
case WASM_INSN_SELECT: {
@@ -4394,9 +4699,9 @@ static void wasm_validate(WasmModule *m, CfreeCompiler *c) {
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);
+ wasm_stack_push(
+ c, &stack,
+ wasm_int_cmp_op(in->kind, &cmp) ? WASM_VAL_I32 : lhs);
break;
}
}
@@ -4414,17 +4719,42 @@ 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) {
+ CfreeCgLocalAttrs attrs;
+ CfreeCgLocal args[16];
+ memset(&attrs, 0, sizeof attrs);
+ attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP;
+ if (f->nparams > 16u)
+ wasm_error(c, wasm_loc(0, 0), "wasm: too many call arguments");
+ for (uint32_t p = 0; p < f->nparams; ++p) {
+ uint32_t param = f->nparams - 1u - p;
+ args[param] =
+ cfree_cg_local(cg, wasm_cg_type(c, b, f->params[param]), attrs);
+ cfree_cg_push_local(cg, args[param]);
+ cfree_cg_swap(cg);
+ cfree_cg_store(cg, wasm_cg_mem(c, b, f->params[param]));
+ }
+ 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});
+}
+
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];
+ CfreeCgSym init_sym = CFREE_CG_SYM_NONE;
CfreeCgTypeId func_types[64];
- CfreeCgSym global_syms[64];
CfreeCgLocal locals[48];
- CfreeCgSym memory_sym = CFREE_CG_SYM_NONE;
- CfreeCgSym memory_pages_sym = CFREE_CG_SYM_NONE;
- CfreeCgSym start_flag_sym = CFREE_CG_SYM_NONE;
uint32_t i, j;
if (!cg)
wasm_error(c, wasm_loc(0, 0), "wasm: failed to initialize codegen");
@@ -4432,129 +4762,47 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
wasm_error(c, wasm_loc(0, 0), "wasm: too many functions");
if (m->nglobals > 64u)
wasm_error(c, wasm_loc(0, 0), "wasm: too many globals");
- if (m->has_memory && m->memory.is_import)
- wasm_error(c, wasm_loc(0, 0),
- "wasm: imported memories are not lowered yet");
+ wasm_cg_build_runtime(c, b, m, &rt);
memset(syms, 0, sizeof syms);
memset(func_types, 0, sizeof func_types);
- memset(global_syms, 0, sizeof global_syms);
- if (m->has_memory) {
- CfreeCgDecl decl;
- CfreeCgDataDefAttrs attrs;
- uint32_t max_pages = m->memory.has_max ? m->memory.max_pages
- : m->memory.min_pages;
- uint32_t memory_len = max_pages ? max_pages * 65536u : 1u;
- CfreeCgTypeId mem_ty =
- cfree_cg_type_array(c, b.id[CFREE_CG_BUILTIN_I8], memory_len);
- memset(&decl, 0, sizeof decl);
- decl.kind = CFREE_CG_DECL_OBJECT;
- decl.linkage_name = cfree_sym_intern(c, "__cfree_wasm_memory");
- decl.display_name = decl.linkage_name;
- decl.type = mem_ty;
- decl.sym.bind = CFREE_SB_LOCAL;
- decl.as.object.align = 16;
- memory_sym = cfree_cg_decl(cg, decl);
- memset(&attrs, 0, sizeof attrs);
- attrs.align = 16;
- cfree_cg_data_begin(cg, memory_sym, attrs);
- if (m->memory.data_len) {
- cfree_cg_data_bytes(cg, m->memory.data, m->memory.data_len);
- if (memory_len > m->memory.data_len)
- cfree_cg_data_zero(cg, memory_len - m->memory.data_len);
- } else {
- cfree_cg_data_zero(cg, memory_len);
- }
- cfree_cg_data_end(cg);
-
- memset(&decl, 0, sizeof decl);
- decl.kind = CFREE_CG_DECL_OBJECT;
- decl.linkage_name = cfree_sym_intern(c, "__cfree_wasm_memory_pages");
- decl.display_name = decl.linkage_name;
- decl.type = b.id[CFREE_CG_BUILTIN_I32];
- decl.sym.bind = CFREE_SB_LOCAL;
- decl.as.object.align = 4;
- memory_pages_sym = cfree_cg_decl(cg, decl);
- memset(&attrs, 0, sizeof attrs);
- attrs.align = 4;
- cfree_cg_data_begin(cg, memory_pages_sym, attrs);
- cfree_cg_data_int(cg, m->memory.min_pages, b.id[CFREE_CG_BUILTIN_I32]);
- cfree_cg_data_end(cg);
- }
- for (i = 0; i < m->nglobals; ++i) {
- const WasmGlobal *g = &m->globals[i];
- CfreeCgDecl decl;
- CfreeCgDataDefAttrs attrs;
- CfreeSym name;
- char local_name[40];
- if (g->is_import && g->import_name) {
- name = cfree_sym_intern(c, g->import_name);
- } else {
- size_t pos = 0;
- const char prefix[] = "__cfree_wasm_global_";
- 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) {
- local_name[pos++] = (char)('0' + (n / div) % 10u);
- div /= 10u;
- }
- local_name[pos] = '\0';
- name = cfree_sym_intern(c, local_name);
- }
- memset(&decl, 0, sizeof decl);
- decl.kind = CFREE_CG_DECL_OBJECT;
- decl.linkage_name = g->is_import ? cfree_cg_c_linkage_name(c, name) : name;
- decl.display_name = name;
- decl.type = wasm_cg_type(c, b, g->type);
- decl.sym.bind = g->is_import ? CFREE_SB_GLOBAL : CFREE_SB_LOCAL;
- decl.as.object.align = cfree_cg_type_align(c, decl.type);
- global_syms[i] = cfree_cg_decl(cg, decl);
- if (g->is_import)
- continue;
- memset(&attrs, 0, sizeof attrs);
- attrs.align = decl.as.object.align;
- cfree_cg_data_begin(cg, global_syms[i], attrs);
- if (g->type == WASM_VAL_F32 || g->type == WASM_VAL_F64)
- cfree_cg_data_float(cg, g->init.fp, decl.type);
- else
- cfree_cg_data_int(cg, (uint64_t)g->init.imm, decl.type);
- cfree_cg_data_end(cg);
- }
- if (m->has_start) {
+ {
CfreeCgDecl decl;
- CfreeCgDataDefAttrs attrs;
+ CfreeCgFuncParam init_param;
+ CfreeCgFuncSig sig;
+ memset(&init_param, 0, sizeof init_param);
+ init_param.type = rt.instance_ptr_ty;
+ memset(&sig, 0, sizeof sig);
+ sig.ret = b.id[CFREE_CG_BUILTIN_VOID];
+ sig.params = &init_param;
+ sig.nparams = 1;
+ sig.call_conv = CFREE_CG_CC_TARGET_C;
memset(&decl, 0, sizeof decl);
- decl.kind = CFREE_CG_DECL_OBJECT;
- decl.linkage_name = cfree_sym_intern(c, "__cfree_wasm_start_ran");
+ decl.kind = CFREE_CG_DECL_FUNC;
+ decl.linkage_name =
+ cfree_cg_c_linkage_name(c, cfree_sym_intern(c, "__cfree_wasm_init"));
decl.display_name = decl.linkage_name;
- decl.type = b.id[CFREE_CG_BUILTIN_I32];
- decl.sym.bind = CFREE_SB_LOCAL;
- decl.as.object.align = 4;
- start_flag_sym = cfree_cg_decl(cg, decl);
- memset(&attrs, 0, sizeof attrs);
- attrs.align = 4;
- cfree_cg_data_begin(cg, start_flag_sym, attrs);
- cfree_cg_data_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]);
- cfree_cg_data_end(cg);
+ decl.type = cfree_cg_type_func(c, sig);
+ decl.sym.bind = CFREE_SB_GLOBAL;
+ init_sym = cfree_cg_decl(cg, decl);
}
for (i = 0; i < m->nfuncs; ++i) {
const WasmFunc *f = &m->funcs[i];
- CfreeCgFuncParam cg_params[16];
+ CfreeCgFuncParam cg_params[17];
CfreeCgFuncSig sig;
CfreeCgDecl decl;
char local_name[40];
CfreeSym source_name;
+ memset(&cg_params[0], 0, sizeof cg_params[0]);
+ cg_params[0].type = rt.instance_ptr_ty;
for (j = 0; j < f->nparams; ++j) {
- memset(&cg_params[j], 0, sizeof cg_params[j]);
- cg_params[j].type = wasm_cg_type(c, b, f->params[j]);
+ memset(&cg_params[j + 1u], 0, sizeof cg_params[j + 1u]);
+ cg_params[j + 1u].type = wasm_cg_type(c, b, f->params[j]);
}
memset(&sig, 0, sizeof sig);
sig.ret = f->nresults ? wasm_cg_type(c, b, f->results[0])
: b.id[CFREE_CG_BUILTIN_VOID];
sig.params = cg_params;
- sig.nparams = f->nparams;
+ sig.nparams = f->nparams + 1u;
sig.call_conv = CFREE_CG_CC_TARGET_C;
func_types[i] = cfree_cg_type_func(c, sig);
if (!func_types[i])
@@ -4583,12 +4831,55 @@ 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 || f->is_import) ? 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");
}
+ if (init_sym) {
+ CfreeCgLocalAttrs attrs;
+ CfreeCgLocal instance_local;
+ memset(&attrs, 0, sizeof attrs);
+ cfree_cg_func_begin(cg, init_sym);
+ instance_local = cfree_cg_param(cg, 0, rt.instance_ptr_ty, attrs);
+ if (m->has_memory) {
+ uint32_t max_pages =
+ m->memory.has_max ? m->memory.max_pages : m->memory.min_pages;
+ wasm_cg_push_memory_pages_lvalue(cg, &rt, instance_local);
+ cfree_cg_push_int(cg, m->memory.min_pages, b.id[CFREE_CG_BUILTIN_I32]);
+ cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
+ wasm_cg_push_memory_max_lvalue(cg, &rt, instance_local);
+ cfree_cg_push_int(cg, max_pages, b.id[CFREE_CG_BUILTIN_I32]);
+ cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
+ if (m->memory.data_init_len) {
+ CfreeCgSym data_sym =
+ cfree_cg_const_data(cg, m->memory.data, m->memory.data_init_len, 16,
+ b.id[CFREE_CG_BUILTIN_I8]);
+ CfreeCgMemAccess mem = wasm_cg_mem_type(b.id[CFREE_CG_BUILTIN_I8]);
+ wasm_cg_push_memory_data_ptr(cg, &rt, instance_local);
+ cfree_cg_push_symbol_addr(cg, data_sym, 0);
+ cfree_cg_memcpy(cg, m->memory.data_init_len, mem, mem);
+ }
+ }
+ for (i = 0; i < m->nglobals; ++i) {
+ 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));
+ else
+ cfree_cg_push_int(cg, (uint64_t)g->init.imm,
+ wasm_cg_type(c, b, g->type));
+ cfree_cg_store(cg, wasm_cg_mem(c, b, g->type));
+ }
+ if (m->has_start)
+ wasm_cg_call_func(c, cg, b, &m->funcs[m->start_func], &rt,
+ syms[m->start_func], instance_local);
+ cfree_cg_ret_void(cg);
+ cfree_cg_func_end(cg);
+ }
for (i = 0; i < m->nfuncs; ++i) {
const WasmFunc *f = &m->funcs[i];
struct {
@@ -4599,14 +4890,20 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
CfreeCgLabel else_label;
} control[64];
uint32_t ncontrol = 0;
+ CfreeCgLocal instance_local;
if (f->is_import)
continue;
cfree_cg_func_begin(cg, syms[i]);
+ {
+ CfreeCgLocalAttrs attrs;
+ memset(&attrs, 0, sizeof attrs);
+ instance_local = cfree_cg_param(cg, 0, rt.instance_ptr_ty, attrs);
+ }
for (j = 0; j < f->nparams; ++j) {
CfreeCgLocalAttrs attrs;
memset(&attrs, 0, sizeof attrs);
- locals[j] = cfree_cg_param(cg, j, wasm_cg_type(c, b, f->params[j]),
- attrs);
+ locals[j] =
+ cfree_cg_param(cg, j + 1u, wasm_cg_type(c, b, f->params[j]), attrs);
}
for (j = 0; j < f->nlocals; ++j) {
CfreeCgLocalAttrs attrs;
@@ -4618,19 +4915,6 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
wasm_cg_push_zero(c, cg, b, f->locals[j]);
cfree_cg_store(cg, wasm_cg_mem(c, b, f->locals[j]));
}
- if (m->has_start && f->export_name && i != m->start_func) {
- CfreeCgLabel started = cfree_cg_label_new(cg);
- cfree_cg_push_symbol_lvalue(cg, start_flag_sym, 0);
- cfree_cg_load(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
- cfree_cg_push_int(cg, 0, b.id[CFREE_CG_BUILTIN_I32]);
- cfree_cg_int_cmp(cg, CFREE_CG_INT_NE);
- cfree_cg_branch_true(cg, started);
- cfree_cg_push_symbol_lvalue(cg, start_flag_sym, 0);
- cfree_cg_push_int(cg, 1, b.id[CFREE_CG_BUILTIN_I32]);
- cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
- cfree_cg_call_symbol(cg, syms[m->start_func], 0, (CfreeCgCallAttrs){0});
- cfree_cg_label_place(cg, started);
- }
for (j = 0; j < f->ninsns; ++j) {
WasmInsn in = f->insns[j];
switch (in.kind) {
@@ -4736,49 +5020,47 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
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);
+ 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_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;
+ 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]);
@@ -4795,16 +5077,14 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
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)));
+ 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)));
+ cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index)));
break;
}
case WASM_INSN_LOCAL_TEE: {
@@ -4812,13 +5092,12 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
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)));
+ cfree_cg_store(cg, wasm_cg_mem(c, b, wasm_func_local_type(f, index)));
break;
}
case WASM_INSN_CALL:
- cfree_cg_call_symbol(cg, syms[in.imm], m->funcs[in.imm].nparams,
- (CfreeCgCallAttrs){0});
+ 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];
@@ -4835,15 +5114,15 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
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);
+ 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);
+ 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]));
@@ -4911,11 +5190,13 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
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,
+ cfree_cg_call_symbol(cg, syms[funcidx], t->nparams + 1u,
(CfreeCgCallAttrs){0});
if (t->nresults) {
cfree_cg_push_local(cg, result);
@@ -4936,13 +5217,13 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
}
case WASM_INSN_GLOBAL_GET: {
uint32_t index = (uint32_t)in.imm;
- cfree_cg_push_symbol_lvalue(cg, global_syms[index], 0);
+ 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;
- cfree_cg_push_symbol_lvalue(cg, global_syms[index], 0);
+ 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;
@@ -4957,7 +5238,7 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
cfree_cg_drop(cg);
break;
case WASM_INSN_MEMORY_SIZE:
- cfree_cg_push_symbol_lvalue(cg, memory_pages_sym, 0);
+ 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: {
@@ -4966,8 +5247,6 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
CfreeCgLabel fail = cfree_cg_label_new(cg);
CfreeCgLabel done = cfree_cg_label_new(cg);
CfreeCgTypeId i32 = b.id[CFREE_CG_BUILTIN_I32];
- uint32_t max_pages = m->memory.has_max ? m->memory.max_pages
- : m->memory.min_pages;
memset(&attrs, 0, sizeof attrs);
attrs.flags = CFREE_CG_LOCAL_COMPILER_TEMP;
delta = cfree_cg_local(cg, i32, attrs);
@@ -4977,20 +5256,21 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
cfree_cg_swap(cg);
cfree_cg_store(cg, wasm_cg_mem(c, b, WASM_VAL_I32));
cfree_cg_push_local(cg, old_pages);
- cfree_cg_push_symbol_lvalue(cg, memory_pages_sym, 0);
+ 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));
- cfree_cg_push_int(cg, max_pages, 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);
- cfree_cg_push_symbol_lvalue(cg, memory_pages_sym, 0);
+ 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);
@@ -5030,8 +5310,8 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
memset(&mem, 0, sizeof mem);
mem.type = storage;
mem.align = in.align;
- wasm_cg_memory_check(c, cg, b, m, memory_pages_sym, &in);
- wasm_cg_memory_lvalue(cg, memory_sym, (uint32_t)in.imm);
+ 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 ||
@@ -5070,18 +5350,15 @@ static void wasm_emit_cg(CfreeCompiler *c, const CfreeCompileOptions *opts,
cfree_cg_push_local(cg, value_tmp);
cfree_cg_swap(cg);
cfree_cg_store(cg, mem);
- wasm_cg_memory_check(c, cg, b, m, memory_pages_sym, &in);
+ 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_push_symbol_lvalue(cg, memory_sym, 0);
- cfree_cg_rot3(cg);
- cfree_cg_index(cg, (uint32_t)in.imm);
- cfree_cg_swap(cg);
cfree_cg_store(cg, mem);
break;
}
@@ -5283,7 +5560,9 @@ 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) {
do {
@@ -5868,21 +6147,17 @@ static void enc_code(CfreeWriter *w, const WasmModule *m) {
in.kind == WASM_INSN_LOCAL_SET ||
in.kind == WASM_INSN_LOCAL_TEE ||
in.kind == WASM_INSN_GLOBAL_GET ||
- in.kind == WASM_INSN_GLOBAL_SET ||
- in.kind == WASM_INSN_CALL ||
- in.kind == WASM_INSN_BR ||
- in.kind == WASM_INSN_BR_IF)
+ in.kind == WASM_INSN_GLOBAL_SET || in.kind == WASM_INSN_CALL ||
+ in.kind == WASM_INSN_BR || in.kind == WASM_INSN_BR_IF)
write_uleb(body, (uint64_t)in.imm);
else if (in.kind == WASM_INSN_CALL_INDIRECT) {
write_uleb(body, (uint64_t)in.imm);
write_uleb(body, in.align);
- }
- else if (in.kind == WASM_INSN_BR_TABLE) {
+ } else if (in.kind == WASM_INSN_BR_TABLE) {
write_uleb(body, in.ntargets ? in.ntargets - 1u : 0u);
for (uint32_t k = 0; k < in.ntargets; ++k)
write_uleb(body, in.targets[k]);
- }
- else if (wasm_insn_is_mem(in.kind)) {
+ } else if (wasm_insn_is_mem(in.kind)) {
write_uleb(body, in.align);
write_uleb(body, (uint64_t)in.imm);
} else if (in.kind == WASM_INSN_MEMORY_SIZE ||
@@ -5899,7 +6174,7 @@ static void enc_code(CfreeWriter *w, const WasmModule *m) {
}
static void enc_data(CfreeWriter *w, const WasmModule *m) {
- if (!m->has_memory || !m->memory.data_len) {
+ if (!m->has_memory || !m->memory.data_init_len) {
write_uleb(w, 0);
return;
}
@@ -5908,8 +6183,8 @@ static void enc_data(CfreeWriter *w, const WasmModule *m) {
write_byte(w, 0x41);
write_sleb(w, 0);
write_byte(w, 0x0b);
- write_uleb(w, m->memory.data_len);
- w->write(w, m->memory.data, m->memory.data_len);
+ write_uleb(w, m->memory.data_init_len);
+ w->write(w, m->memory.data, m->memory.data_init_len);
}
static void enc_elem(CfreeWriter *w, const WasmModule *m) {
@@ -5972,7 +6247,7 @@ static void wasm_encode(CfreeCompiler *c, const WasmModule *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_len)
+ if (m->has_memory && m->memory.data_init_len)
encode_section(h, out, 11, enc_data, m);
}
diff --git a/lang/wasm/wasm.h b/lang/wasm/wasm.h
@@ -3,6 +3,8 @@
#include <cfree.h>
+#include "runtime_abi.h"
+
int cfree_wasm_compile(CfreeCompiler*, const CfreeCompileOptions*,
const CfreeBytesInput* input, CfreeObjBuilder* out);
void cfree_wasm_register(CfreeCompiler*);
diff --git a/test/link/harness/jit_runner.c b/test/link/harness/jit_runner.c
@@ -332,6 +332,15 @@ static void jit_tls_ctx_destroy(void* user, void* ctx_v) {
}
static CfreeJitTls g_jit_tls = {jit_tls_ctx_new, jit_tls_ctx_destroy, NULL};
+typedef struct WasmRunnerMemoryPrefix {
+ uint8_t* data;
+ uint32_t pages;
+ uint32_t max_pages;
+} WasmRunnerMemoryPrefix;
+
+typedef void (*WasmRunnerInitFn)(void*);
+typedef int (*WasmRunnerMainFn)(void*);
+
int main(int argc, char** argv) {
{
long ps = sysconf(_SC_PAGESIZE);
@@ -490,7 +499,9 @@ int main(int argc, char** argv) {
return present_ok ? 0 : 1;
}
- int (*fn)(void) = cfree_jit_lookup(jit, "test_main");
+ void* wasm_init = cfree_jit_lookup(jit, "__cfree_wasm_init");
+ void* entry = cfree_jit_lookup(jit, "test_main");
+ int (*fn)(void) = entry;
/* AArch64 TLS local-exec setup. Build a thread-local image —
* 16-byte TCB + .tdata copy + .tbss zero-fill — and point
@@ -517,7 +528,23 @@ int main(int argc, char** argv) {
#endif
int result;
- if (fn) {
+ if (wasm_init && entry) {
+ uint8_t* instance = calloc(1, 64u * 1024u);
+ uint8_t* memory = calloc(1, 16u * 1024u * 1024u);
+ if (!instance || !memory) {
+ free(memory);
+ free(instance);
+ cfree_jit_run_dtors(jit);
+ cfree_jit_free(jit);
+ cfree_compiler_free(c);
+ return 1;
+ }
+ ((WasmRunnerMemoryPrefix*)instance)->data = memory;
+ ((WasmRunnerInitFn)wasm_init)(instance);
+ result = ((WasmRunnerMainFn)entry)(instance);
+ free(memory);
+ free(instance);
+ } else if (fn) {
#if defined(__aarch64__) || defined(__arm64__)
/* msr + blr in immediate succession; the compiler must not
* insert anything between. `volatile` and the "memory"
diff --git a/test/wasm/harness/start_wasm.c b/test/wasm/harness/start_wasm.c
@@ -0,0 +1,129 @@
+/* Freestanding _start for Wasm-input native executable tests.
+ *
+ * Wasm frontend exports use the internal instance ABI:
+ * __cfree_wasm_init(instance)
+ * test_main(instance)
+ */
+
+extern void __cfree_wasm_init(void *);
+extern int test_main(void *);
+
+typedef struct WasmStartMemoryPrefix {
+ unsigned char *data;
+ unsigned int pages;
+ unsigned int max_pages;
+} WasmStartMemoryPrefix;
+
+#define WASM_START_INSTANCE_SIZE (64u * 1024u)
+#define WASM_START_MEMORY_SIZE (16u * 1024u * 1024u)
+#define WASM_START_PROT_READ 1
+#define WASM_START_PROT_WRITE 2
+#define WASM_START_MAP_PRIVATE 2
+#if defined(__APPLE__)
+#define WASM_START_MAP_ANON 0x1000
+#else
+#define WASM_START_MAP_ANON 0x20
+#endif
+
+#if defined(__APPLE__)
+extern void exit(int) __attribute__((noreturn));
+extern void *mmap(void *, unsigned long, int, int, int, long);
+#endif
+
+__attribute__((noreturn)) static void do_exit(int code) {
+#if defined(__APPLE__)
+ exit(code);
+ __builtin_unreachable();
+#elif defined(__aarch64__)
+ register long x8 __asm__("x8") = 94;
+ register long x0 __asm__("x0") = code;
+ __asm__ volatile("svc #0" ::"r"(x8), "r"(x0) : "memory");
+#elif defined(__x86_64__)
+ register long rax __asm__("rax") = 231;
+ register long rdi __asm__("rdi") = code;
+ __asm__ volatile("syscall" ::"r"(rax), "r"(rdi) : "rcx", "r11", "memory");
+#elif defined(__riscv) && __riscv_xlen == 64
+ register long a7 __asm__("a7") = 94;
+ register long a0 __asm__("a0") = code;
+ __asm__ volatile("ecall" ::"r"(a7), "r"(a0) : "memory");
+#else
+#error "start_wasm.c: unsupported architecture"
+#endif
+ __builtin_unreachable();
+}
+
+static void *start_mmap(unsigned long size) {
+#if defined(__APPLE__)
+ void *p = mmap((void *)0, size, WASM_START_PROT_READ | WASM_START_PROT_WRITE,
+ WASM_START_MAP_PRIVATE | WASM_START_MAP_ANON, -1, 0);
+ if ((long)p == -1)
+ return (void *)0;
+ return p;
+#elif defined(__aarch64__)
+ register long x8 __asm__("x8") = 222;
+ register long x0 __asm__("x0") = 0;
+ register long x1 __asm__("x1") = (long)size;
+ register long x2 __asm__("x2") =
+ WASM_START_PROT_READ | WASM_START_PROT_WRITE;
+ register long x3 __asm__("x3") =
+ WASM_START_MAP_PRIVATE | WASM_START_MAP_ANON;
+ register long x4 __asm__("x4") = -1;
+ register long x5 __asm__("x5") = 0;
+ __asm__ volatile("svc #0"
+ : "+r"(x0)
+ : "r"(x8), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5)
+ : "memory");
+ if (x0 < 0 && x0 > -4096)
+ return (void *)0;
+ return (void *)x0;
+#elif defined(__x86_64__)
+ register long rax __asm__("rax") = 9;
+ register long rdi __asm__("rdi") = 0;
+ register long rsi __asm__("rsi") = (long)size;
+ register long rdx __asm__("rdx") =
+ WASM_START_PROT_READ | WASM_START_PROT_WRITE;
+ register long r10 __asm__("r10") =
+ WASM_START_MAP_PRIVATE | WASM_START_MAP_ANON;
+ register long r8 __asm__("r8") = -1;
+ register long r9 __asm__("r9") = 0;
+ __asm__ volatile("syscall"
+ : "+r"(rax)
+ : "r"(rdi), "r"(rsi), "r"(rdx), "r"(r10), "r"(r8), "r"(r9)
+ : "rcx", "r11", "memory");
+ if (rax < 0 && rax > -4096)
+ return (void *)0;
+ return (void *)rax;
+#elif defined(__riscv) && __riscv_xlen == 64
+ register long a7 __asm__("a7") = 222;
+ register long a0 __asm__("a0") = 0;
+ register long a1 __asm__("a1") = (long)size;
+ register long a2 __asm__("a2") =
+ WASM_START_PROT_READ | WASM_START_PROT_WRITE;
+ register long a3 __asm__("a3") =
+ WASM_START_MAP_PRIVATE | WASM_START_MAP_ANON;
+ register long a4 __asm__("a4") = -1;
+ register long a5 __asm__("a5") = 0;
+ __asm__ volatile("ecall"
+ : "+r"(a0)
+ : "r"(a7), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5)
+ : "memory");
+ if (a0 < 0 && a0 > -4096)
+ return (void *)0;
+ return (void *)a0;
+#else
+#error "start_wasm.c: unsupported architecture"
+#endif
+}
+
+#if defined(__x86_64__)
+__attribute__((force_align_arg_pointer))
+#endif
+void _start(void) {
+ void *instance = start_mmap(WASM_START_INSTANCE_SIZE);
+ void *memory = start_mmap(WASM_START_MEMORY_SIZE);
+ if (!instance || !memory)
+ do_exit(1);
+ ((WasmStartMemoryPrefix *)instance)->data = (unsigned char *)memory;
+ __cfree_wasm_init(instance);
+ do_exit(test_main(instance));
+}
diff --git a/test/wasm/run.sh b/test/wasm/run.sh
@@ -10,7 +10,6 @@ CFREE_BIN="${CFREE:-$ROOT/build/cfree}"
WASM_TOOL="$ROOT/build/test/wasm-tool"
JIT_RUNNER="$ROOT/build/test/jit-runner"
LINK_EXE_RUNNER="$ROOT/build/test/link-exe-runner"
-LINK_TEST_DIR="$ROOT/test/link"
TEST_ARCH="${CFREE_TEST_ARCH:-aa64}"
TEST_OBJ="${CFREE_TEST_OBJ:-macho}"
@@ -88,12 +87,13 @@ EXEC_TARGET_MOUNT_ROOT="$BUILD_DIR"
# shellcheck source=../lib/exec_target.sh
source "$ROOT/test/lib/exec_target.sh"
-START_OBJ="$BUILD_DIR/start.o"
-have_start_obj=0
+WASM_START_OBJ="$BUILD_DIR/start-wasm.o"
+have_wasm_start_obj=0
if clang --target="$clang_triple" -ffreestanding -fno-stack-protector \
- -fno-builtin -nostdlib -c "$LINK_TEST_DIR/harness/start.c" \
- -o "$START_OBJ" >"$BUILD_DIR/start.out" 2>"$BUILD_DIR/start.err"; then
- have_start_obj=1
+ -fno-builtin -nostdlib -c "$ROOT/test/wasm/harness/start_wasm.c" \
+ -o "$WASM_START_OBJ" >"$BUILD_DIR/start-wasm.out" \
+ 2>"$BUILD_DIR/start-wasm.err"; then
+ have_wasm_start_obj=1
fi
MACHO_DSO_ARGS=()
@@ -173,9 +173,9 @@ for wat in "$CASES_DIR"/*.wat; do
note_skip "$name/J" "host arch does not match target or no jit-runner"
fi
- if [ "$have_link_runner" -eq 1 ] && [ "$have_start_obj" -eq 1 ]; then
+ if [ "$have_link_runner" -eq 1 ] && [ "$have_wasm_start_obj" -eq 1 ]; then
exe="$work/$name.exe"
- if "$LINK_EXE_RUNNER" -o "$exe" "${MACHO_DSO_ARGS[@]}" "$wat_obj" "$START_OBJ" \
+ if "$LINK_EXE_RUNNER" -o "$exe" "${MACHO_DSO_ARGS[@]}" "$wat_obj" "$WASM_START_OBJ" \
>"$work/link.out" 2>"$work/link.err"; then
if exec_target_supported "$EXEC_TAG"; then
exec_target_run "$EXEC_TAG" "$exe" "$work/exec.out" "$work/exec.err"
@@ -192,7 +192,7 @@ for wat in "$CASES_DIR"/*.wat; do
note_fail "$name/E link failed"
fi
else
- note_skip "$name/E" "requires link runner and start.o"
+ note_skip "$name/E" "requires link runner and wasm start.o"
fi
done