wasm.c (6144B)
1 #include "wasm/wasm.h" 2 3 #include <stdarg.h> 4 #include <string.h> 5 6 /* Every KitWasmFeature bit — the frontend's default when no -mfeature flags 7 * narrow it (and what wasm_module_init seeds, kept in sync). */ 8 #define WASM_FEATURES_ALL \ 9 (KIT_WASM_FEATURE_THREADS | KIT_WASM_FEATURE_TYPED_FUNC_REFS | \ 10 KIT_WASM_FEATURE_TAIL_CALLS | KIT_WASM_FEATURE_MULTI_MEMORY | \ 11 KIT_WASM_FEATURE_MEMORY64 | KIT_WASM_FEATURE_BULK_MEMORY | \ 12 KIT_WASM_FEATURE_NONTRAPPING_FTOI) 13 14 static void wasm_parse_any(KitCompiler* c, KitSlice name, const KitSlice* input, 15 WasmModule* m) { 16 if (wasm_is_binary(input)) 17 wasm_decode_binary(c, input, m); 18 else 19 wasm_parse_wat(c, name, input, m); 20 wasm_validate(m, c); 21 } 22 23 typedef struct WasmFrontend { 24 KitCompiler* c; 25 } WasmFrontend; 26 27 static KitFrontendState* wasm_frontend_new(KitCompiler* c) { 28 KitHeap* h; 29 WasmFrontend* fe; 30 if (!c) return NULL; 31 h = kit_compiler_context(c)->heap; 32 fe = (WasmFrontend*)h->alloc(h, sizeof(*fe), _Alignof(WasmFrontend)); 33 if (!fe) return NULL; 34 fe->c = c; 35 return (KitFrontendState*)fe; 36 } 37 38 static void wasm_opt_errf(KitCompiler* c, const char* fmt, ...) { 39 const KitContext* ctx = kit_compiler_context(c); 40 va_list ap; 41 KitSrcLoc loc; 42 if (!ctx || !ctx->diag || !ctx->diag->emit) return; 43 loc.file_id = 0; 44 loc.line = 0; 45 loc.col = 0; 46 va_start(ap, fmt); 47 ctx->diag->emit(ctx->diag, KIT_DIAG_ERROR, loc, fmt, ap); 48 va_end(ap); 49 } 50 51 /* Map a feature name (`tail-calls`, `memory64`, ...) to its KitWasmFeature 52 * bit. Returns 0 for an unknown name. */ 53 static uint32_t wasm_feature_bit(const char* name) { 54 static const struct { 55 const char* name; 56 uint32_t bit; 57 } table[] = { 58 {"threads", KIT_WASM_FEATURE_THREADS}, 59 {"typed-func-refs", KIT_WASM_FEATURE_TYPED_FUNC_REFS}, 60 {"tail-calls", KIT_WASM_FEATURE_TAIL_CALLS}, 61 {"multi-memory", KIT_WASM_FEATURE_MULTI_MEMORY}, 62 {"memory64", KIT_WASM_FEATURE_MEMORY64}, 63 {"bulk-memory", KIT_WASM_FEATURE_BULK_MEMORY}, 64 {"nontrapping-ftoi", KIT_WASM_FEATURE_NONTRAPPING_FTOI}, 65 }; 66 size_t i; 67 for (i = 0; i < sizeof table / sizeof table[0]; ++i) { 68 if (strcmp(name, table[i].name) == 0) return table[i].bit; 69 } 70 return 0; 71 } 72 73 /* Parse the wasm frontend flags `kit compile` did not consume: 74 * -mfeature=NAME enable a proposal feature 75 * -mno-feature=NAME disable one 76 * Repeatable; starts from the full default set. */ 77 static KitStatus wasm_parse_options(KitCompiler* c, int argc, char** argv, 78 void** out_opts) { 79 KitHeap* h = kit_compiler_context(c)->heap; 80 KitWasmCompileOptions* o; 81 int i; 82 *out_opts = NULL; 83 o = (KitWasmCompileOptions*)h->alloc(h, sizeof(*o), 84 _Alignof(KitWasmCompileOptions)); 85 if (!o) return KIT_NOMEM; 86 o->features = WASM_FEATURES_ALL; 87 for (i = 0; i < argc; ++i) { 88 const char* a = argv[i]; 89 const char* name; 90 int enable; 91 uint32_t bit; 92 if (strncmp(a, "-mfeature=", 10) == 0) { 93 enable = 1; 94 name = a + 10; 95 } else if (strncmp(a, "-mno-feature=", 13) == 0) { 96 enable = 0; 97 name = a + 13; 98 } else { 99 wasm_opt_errf(c, "wasm: unknown option: %s", a); 100 h->free(h, o, sizeof(*o)); 101 return KIT_INVALID; 102 } 103 bit = wasm_feature_bit(name); 104 if (!bit) { 105 wasm_opt_errf(c, "wasm: unknown feature: %s", name); 106 h->free(h, o, sizeof(*o)); 107 return KIT_INVALID; 108 } 109 if (enable) 110 o->features |= bit; 111 else 112 o->features &= ~bit; 113 } 114 *out_opts = o; 115 return KIT_OK; 116 } 117 118 static void wasm_free_options(KitCompiler* c, void* opts) { 119 KitHeap* h = kit_compiler_context(c)->heap; 120 if (opts) h->free(h, opts, sizeof(KitWasmCompileOptions)); 121 } 122 123 static KitStatus wasm_frontend_compile_cg(KitFrontendState* frontend, 124 const KitFrontendCompileOptions* opts, 125 const KitSourceInput* input, 126 KitCg* cg) { 127 WasmFrontend* fe = (WasmFrontend*)frontend; 128 KitCompiler* c; 129 WasmModule m; 130 const KitWasmCompileOptions* wopts; 131 if (!fe || !fe->c || !opts || !input || !cg) return KIT_INVALID; 132 c = fe->c; 133 wopts = (const KitWasmCompileOptions*)opts->language_options; 134 wasm_module_init(&m, kit_compiler_context(c)->heap); 135 /* wasm_module_init seeds the full feature set; narrow it when the driver 136 * supplied parsed options. NULL keeps the default (run/dbg/cc paths). */ 137 if (wopts) m.features = wopts->features; 138 wasm_parse_any(c, input->name, &input->bytes, &m); 139 wasm_emit_cg_into(c, cg, &m); 140 wasm_module_free(&m); 141 return KIT_OK; 142 } 143 144 static void wasm_frontend_free(KitFrontendState* frontend) { 145 WasmFrontend* fe = (WasmFrontend*)frontend; 146 KitHeap* h; 147 if (!fe) return; 148 h = kit_compiler_context(fe->c)->heap; 149 h->free(h, fe, sizeof(*fe)); 150 } 151 152 static const KitSlice wasm_extensions[] = {KIT_SLICE_LIT("wat"), 153 KIT_SLICE_LIT("wasm")}; 154 /* Canonical `-x` name plus alias; mirrors the driver's "wasm"/"wat" spellings. */ 155 static const KitSlice wasm_names[] = {KIT_SLICE_LIT("wasm"), 156 KIT_SLICE_LIT("wat")}; 157 158 const KitFrontendVTable kit_wasm_frontend_vtable = { 159 wasm_frontend_new, 160 wasm_frontend_compile_cg, 161 NULL, /* compile_obj: semantic frontends are wrapped by compile session */ 162 wasm_frontend_free, 163 wasm_extensions, 164 (uint32_t)(sizeof wasm_extensions / sizeof wasm_extensions[0]), 165 wasm_names, 166 (uint32_t)(sizeof wasm_names / sizeof wasm_names[0]), 167 NULL, /* commit: wasm has no durable cross-compile state */ 168 NULL, /* abort */ 169 {false, KIT_FRONTEND_LTO_CG, false}, 170 wasm_parse_options, 171 wasm_free_options, 172 }; 173 174 KIT_API int kit_wasm_wat_to_wasm(KitCompiler* c, const KitSlice* input, 175 KitWriter* out) { 176 WasmModule m; 177 wasm_module_init(&m, kit_compiler_context(c)->heap); 178 wasm_parse_wat(c, KIT_SLICE_NULL, input, &m); 179 wasm_validate(&m, c); 180 wasm_encode(c, &m, out); 181 wasm_module_free(&m); 182 return 0; 183 }