host_imports.c (8594B)
1 /* Host-import binder: walks the per-module __kit_wasm_imports metadata 2 * emitted by lang/wasm/cg.c and writes resolved function pointers into the 3 * matching slots of a freshly-allocated KitWasmInstance. 4 * 5 * The metadata wire format is defined in lang/wasm/runtime_abi.h alongside 6 * the rest of the kit-instance ABI. The public-API surface is in 7 * include/kit/wasm.h. */ 8 9 #include <kit/core.h> 10 #include <kit/jit.h> 11 #include <kit/wasm.h> 12 #include <stdint.h> 13 #include <string.h> 14 15 #include "runtime_abi.h" 16 17 /* Raw wasm WasmValType byte encoding (mirrored from src/wasm/wasm.h so this 18 * module stays free of internal wasm-core dependencies; if either side 19 * changes these, the binder/metadata pair breaks together). */ 20 enum { 21 WASM_ABI_VAL_I32 = 0x7f, 22 WASM_ABI_VAL_I64 = 0x7e, 23 WASM_ABI_VAL_F32 = 0x7d, 24 WASM_ABI_VAL_F64 = 0x7c, 25 WASM_ABI_VAL_FUNCREF = 0x70, 26 WASM_ABI_VAL_EXTERNREF = 0x6f, 27 }; 28 29 static int host_imports_streq(const char* a, const char* b) { 30 if (a == b) return 1; 31 if (!a || !b) return 0; 32 return strcmp(a, b) == 0; 33 } 34 35 static int host_imports_map_valtype(uint8_t raw, KitWasmValType* out) { 36 switch (raw) { 37 case WASM_ABI_VAL_I32: 38 *out = KIT_WASM_VAL_I32; 39 return 1; 40 case WASM_ABI_VAL_I64: 41 *out = KIT_WASM_VAL_I64; 42 return 1; 43 case WASM_ABI_VAL_F32: 44 *out = KIT_WASM_VAL_F32; 45 return 1; 46 case WASM_ABI_VAL_F64: 47 *out = KIT_WASM_VAL_F64; 48 return 1; 49 case WASM_ABI_VAL_FUNCREF: 50 *out = KIT_WASM_VAL_FUNCREF; 51 return 1; 52 case WASM_ABI_VAL_EXTERNREF: 53 *out = KIT_WASM_VAL_EXTERNREF; 54 return 1; 55 default: 56 return 0; 57 } 58 } 59 60 /* Translate an nparams/nresults raw-byte type description into the public 61 * KitWasmImportType. Returns 0 on unsupported value-type byte. The 62 * arrays are written into caller-provided storage. */ 63 static int host_imports_build_type(const KitWasmTypeDesc* src, 64 KitWasmValType* pbuf, uint32_t pcap, 65 KitWasmValType* rbuf, uint32_t rcap, 66 KitWasmImportType* out) { 67 uint32_t i; 68 if (src->nparams > pcap || src->nresults > rcap) return 0; 69 for (i = 0; i < src->nparams; ++i) 70 if (!host_imports_map_valtype(src->params[i], &pbuf[i])) return 0; 71 for (i = 0; i < src->nresults; ++i) 72 if (!host_imports_map_valtype(src->results[i], &rbuf[i])) return 0; 73 out->params = pbuf; 74 out->nparams = src->nparams; 75 out->results = rbuf; 76 out->nresults = src->nresults; 77 return 1; 78 } 79 80 /* Conservative cap on per-import param/result count for the on-stack 81 * translation buffer in kit_wasm_bind_host_imports. Wasm allows arbitrary 82 * counts in principle, but real modules cap well below this; tests use at 83 * most a few. If a module exceeds this the binder returns an error rather 84 * than silently truncating. */ 85 #define KIT_WASM_BIND_MAX_VALTYPES 32u 86 87 KIT_API KitStatus kit_wasm_get_runtime_layout(KitJit* jit, 88 KitWasmRuntimeLayout* out) { 89 const uint64_t* instance_size; 90 const uint32_t* nmemories; 91 const KitWasmMemoryLayout* memories = NULL; 92 KitWasmRuntimeLayout z = {0}; 93 if (!jit || !out) return KIT_INVALID; 94 instance_size = (const uint64_t*)kit_jit_lookup( 95 jit, KIT_SLICE_LIT("__kit_wasm_instance_size")); 96 nmemories = (const uint32_t*)kit_jit_lookup( 97 jit, KIT_SLICE_LIT("__kit_wasm_nmemories")); 98 if (!instance_size && !nmemories) return KIT_NOT_FOUND; 99 if (!instance_size || !nmemories) return KIT_MALFORMED; 100 if (*nmemories) { 101 memories = (const KitWasmMemoryLayout*)kit_jit_lookup( 102 jit, KIT_SLICE_LIT("__kit_wasm_memory_layouts")); 103 if (!memories) return KIT_MALFORMED; 104 } 105 z.instance_size = *instance_size; 106 z.memories = memories; 107 z.nmemories = *nmemories; 108 *out = z; 109 return KIT_OK; 110 } 111 112 KIT_API KitStatus kit_wasm_bind_host_imports(KitCompiler* compiler, KitJit* jit, 113 KitWasmInstance* inst, 114 const KitWasmHostImport* imports, 115 size_t nimports, 116 KitWasmResolveFn resolve, 117 void* user) { 118 const uint32_t* nimports_meta; 119 const uint32_t* nfunc_import_types_meta = NULL; 120 const KitWasmImportDesc* import_descs; 121 const KitWasmTypeDesc* type_descs = NULL; 122 const KitWasmMemoryImportDesc* memory_descs = NULL; 123 const KitWasmTableImportDesc* table_descs = NULL; 124 const KitWasmGlobalImportDesc* global_descs = NULL; 125 uint32_t n; 126 uint32_t i; 127 uint32_t nfunc_descs = 0; 128 uint32_t nmemory_descs = 0; 129 uint32_t ntable_descs = 0; 130 uint32_t nglobal_descs = 0; 131 uint32_t nfunc_import_types = 0; 132 (void)compiler; 133 if (!jit || !inst) return KIT_INVALID; 134 135 nimports_meta = (const uint32_t*)kit_jit_lookup( 136 jit, KIT_SLICE_LIT("__kit_wasm_nimports")); 137 if (!nimports_meta) { 138 /* Module wasn't built through kit's wasm frontend, or it has no 139 * imports at all. Nothing to bind. */ 140 return KIT_OK; 141 } 142 n = *nimports_meta; 143 if (n == 0) return KIT_OK; 144 import_descs = (const KitWasmImportDesc*)kit_jit_lookup( 145 jit, KIT_SLICE_LIT("__kit_wasm_imports")); 146 if (!import_descs) return KIT_MALFORMED; 147 148 for (i = 0; i < n; ++i) { 149 switch (import_descs[i].kind) { 150 case KIT_WASM_IMPORT_FUNC: 151 nfunc_descs++; 152 break; 153 case KIT_WASM_IMPORT_MEMORY: 154 nmemory_descs++; 155 break; 156 case KIT_WASM_IMPORT_TABLE: 157 ntable_descs++; 158 break; 159 case KIT_WASM_IMPORT_GLOBAL: 160 nglobal_descs++; 161 break; 162 default: 163 return KIT_MALFORMED; 164 } 165 } 166 if (nfunc_descs) { 167 nfunc_import_types_meta = (const uint32_t*)kit_jit_lookup( 168 jit, KIT_SLICE_LIT("__kit_wasm_nfunc_import_types")); 169 type_descs = (const KitWasmTypeDesc*)kit_jit_lookup( 170 jit, KIT_SLICE_LIT("__kit_wasm_types")); 171 if (!nfunc_import_types_meta || !type_descs) return KIT_MALFORMED; 172 nfunc_import_types = *nfunc_import_types_meta; 173 if (nfunc_import_types == 0 || nfunc_import_types > nfunc_descs) 174 return KIT_MALFORMED; 175 } 176 177 for (i = 0; i < n; ++i) { 178 const KitWasmImportDesc* d = &import_descs[i]; 179 void* fn = NULL; 180 KitWasmValType pbuf[KIT_WASM_BIND_MAX_VALTYPES]; 181 KitWasmValType rbuf[KIT_WASM_BIND_MAX_VALTYPES]; 182 KitWasmImportType type; 183 switch (d->kind) { 184 case KIT_WASM_IMPORT_FUNC: 185 if (d->desc_index >= nfunc_import_types) return KIT_MALFORMED; 186 break; 187 case KIT_WASM_IMPORT_MEMORY: 188 if (d->desc_index >= nmemory_descs) return KIT_MALFORMED; 189 if (!memory_descs) 190 memory_descs = (const KitWasmMemoryImportDesc*)kit_jit_lookup( 191 jit, KIT_SLICE_LIT("__kit_wasm_memory_import_types")); 192 if (!memory_descs) return KIT_MALFORMED; 193 return KIT_UNSUPPORTED; 194 case KIT_WASM_IMPORT_TABLE: 195 if (d->desc_index >= ntable_descs) return KIT_MALFORMED; 196 if (!table_descs) 197 table_descs = (const KitWasmTableImportDesc*)kit_jit_lookup( 198 jit, KIT_SLICE_LIT("__kit_wasm_table_import_types")); 199 if (!table_descs) return KIT_MALFORMED; 200 return KIT_UNSUPPORTED; 201 case KIT_WASM_IMPORT_GLOBAL: 202 if (d->desc_index >= nglobal_descs) return KIT_MALFORMED; 203 if (!global_descs) 204 global_descs = (const KitWasmGlobalImportDesc*)kit_jit_lookup( 205 jit, KIT_SLICE_LIT("__kit_wasm_global_import_types")); 206 if (!global_descs) return KIT_MALFORMED; 207 return KIT_UNSUPPORTED; 208 default: 209 return KIT_MALFORMED; 210 } 211 /* Static table first. */ 212 for (size_t k = 0; imports && k < nimports; ++k) { 213 if (host_imports_streq(imports[k].module, d->module) && 214 host_imports_streq(imports[k].field, d->field)) { 215 fn = imports[k].func; 216 break; 217 } 218 } 219 /* Resolver fallback. */ 220 if (!fn && resolve) { 221 const KitWasmTypeDesc* td; 222 td = &type_descs[d->desc_index]; 223 if (!host_imports_build_type(td, pbuf, KIT_WASM_BIND_MAX_VALTYPES, rbuf, 224 KIT_WASM_BIND_MAX_VALTYPES, &type)) 225 return KIT_MALFORMED; 226 fn = resolve(user, d->module, d->field, &type); 227 } 228 if (!fn) return KIT_NOT_FOUND; 229 /* Slot is a void* at byte offset slot_offset inside the instance struct. 230 * The KitWasmFuncImport record is { void* fn; } so the offset of the 231 * field is also the offset of the fn pointer. */ 232 *(void**)((unsigned char*)inst + d->slot_offset) = fn; 233 } 234 return KIT_OK; 235 }