kit

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

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 }