MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at mir/inline-method 1466 lines 54 kB view raw
1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <inttypes.h> 5#include <wasm_c_api.h> 6#include <wasm_export.h> 7 8#pragma clang diagnostic push 9#pragma clang diagnostic ignored "-Wundef" 10#pragma clang diagnostic ignored "-Wimplicit-int-conversion" 11#include <wasm_c_api_internal.h> 12#include <wasm_runtime.h> 13#pragma clang diagnostic pop 14 15#include "ant.h" 16#include "ptr.h" 17#include "errors.h" 18#include "runtime.h" 19#include "internal.h" 20#include "descriptors.h" 21 22#include "gc/modules.h" 23#include "silver/engine.h" 24#include "modules/buffer.h" 25#include "modules/wasm.h" 26#include "modules/wasi.h" 27 28typedef struct { 29 wasm_store_t *store; 30 wasm_module_t *module; 31} wasm_module_handle_t; 32 33typedef struct { 34 wasm_instance_t *instance; 35 wasm_extern_vec_t exports; 36 wasm_func_t **host_funcs; 37 size_t host_func_count; 38} wasm_instance_handle_t; 39 40typedef enum { 41 WASM_EXTERN_WRAP_GLOBAL = 1, 42 WASM_EXTERN_WRAP_MEMORY, 43 WASM_EXTERN_WRAP_TABLE, 44} wasm_extern_wrap_kind_t; 45 46typedef struct { 47 wasm_extern_wrap_kind_t kind; 48 wasm_store_t *store; 49 bool own_handle; 50 bool use_cached_value; 51 wasm_val_t cached_value; 52 union { 53 wasm_global_t *global; 54 wasm_memory_t *memory; 55 wasm_table_t *table; 56 } as; 57} wasm_extern_handle_t; 58 59typedef struct { 60 ant_t *js; 61 wasm_store_t *store; 62 ant_value_t owner; 63 ant_value_t fn; 64} wasm_import_func_env_t; 65 66typedef struct { 67 wasm_func_t *func; 68 bool own_func; 69} wasm_func_handle_t; 70 71enum { WASM_FUNC_STATE_TAG = 0x57465354u }; // WFST 72 73static size_t g_wasm_import_env_count = 0; 74static size_t g_wasm_import_env_cap = 0; 75 76static ant_value_t g_wasm_module_proto = 0; 77static ant_value_t g_wasm_instance_proto = 0; 78static ant_value_t g_wasm_global_proto = 0; 79static ant_value_t g_wasm_memory_proto = 0; 80static ant_value_t g_wasm_table_proto = 0; 81static ant_value_t g_wasm_tag_proto = 0; 82static ant_value_t g_wasm_exception_proto = 0; 83 84static ant_value_t g_wasm_compileerror_proto = 0; 85static ant_value_t g_wasm_linkerror_proto = 0; 86static ant_value_t g_wasm_runtimeerror_proto = 0; 87static ant_value_t g_wasm_pending_import_throw = 0; 88 89static wasm_engine_t *g_wasm_engine = NULL; 90static wasm_import_func_env_t **g_wasm_import_envs = NULL; 91static bool g_wasm_pending_import_throw_exists = false; 92 93static void wasm_clear_pending_import_throw(void) { 94 g_wasm_pending_import_throw_exists = false; 95 g_wasm_pending_import_throw = js_mkundef(); 96} 97 98static void wasm_set_pending_import_throw(ant_value_t value) { 99 g_wasm_pending_import_throw_exists = true; 100 g_wasm_pending_import_throw = value; 101} 102 103static ant_value_t wasm_consume_pending_import_throw(void) { 104 ant_value_t value = g_wasm_pending_import_throw_exists 105 ? g_wasm_pending_import_throw 106 : js_mkundef(); 107 wasm_clear_pending_import_throw(); 108 return value; 109} 110 111static void wasm_register_import_env(wasm_import_func_env_t *env) { 112 if (g_wasm_import_env_count == g_wasm_import_env_cap) { 113 size_t new_cap = g_wasm_import_env_cap ? g_wasm_import_env_cap * 2 : 16; 114 wasm_import_func_env_t **new_arr = realloc(g_wasm_import_envs, new_cap * sizeof(*new_arr)); 115 if (!new_arr) return; 116 g_wasm_import_envs = new_arr; 117 g_wasm_import_env_cap = new_cap; 118 } 119 g_wasm_import_envs[g_wasm_import_env_count++] = env; 120} 121 122static void wasm_unregister_import_env(wasm_import_func_env_t *env) { 123 for (size_t i = 0; i < g_wasm_import_env_count; i++) { 124 if (g_wasm_import_envs[i] != env) continue; 125 g_wasm_import_envs[i] = g_wasm_import_envs[--g_wasm_import_env_count]; 126 return; 127 } 128} 129 130static void wasm_import_func_env_finalizer(void *env_ptr) { 131 wasm_import_func_env_t *env = (wasm_import_func_env_t *)env_ptr; 132 wasm_unregister_import_env(env); 133 free(env); 134} 135 136static ant_value_t wasm_wrap_func( 137 ant_t *js, wasm_func_t *func, 138 ant_value_t owner, bool own_func 139); 140 141static bool ensure_wasm_engine(void) { 142 if (g_wasm_engine) return true; 143 g_wasm_engine = wasm_engine_new(); 144 return g_wasm_engine != NULL; 145} 146 147static size_t wasm_name_len(const wasm_name_t *name) { 148 if (!name || !name->data) return 0; 149 if (name->size > 0 && name->data[name->size - 1] == '\0') return name->size - 1; 150 return name->size; 151} 152 153static const char *wasm_extern_kind_name(wasm_externkind_t kind) { 154switch (kind) { 155 case WASM_EXTERN_FUNC: return "function"; 156 case WASM_EXTERN_GLOBAL: return "global"; 157 case WASM_EXTERN_TABLE: return "table"; 158 case WASM_EXTERN_MEMORY: return "memory"; 159 default: return "unknown"; 160}} 161 162static wasm_valkind_t wasm_valkind_from_string(const char *name, size_t len, bool *ok) { 163 *ok = true; 164 if (len == 3 && !memcmp(name, "i32", 3)) return WASM_I32; 165 if (len == 3 && !memcmp(name, "i64", 3)) return WASM_I64; 166 if (len == 3 && !memcmp(name, "f32", 3)) return WASM_F32; 167 if (len == 3 && !memcmp(name, "f64", 3)) return WASM_F64; 168 if (len == 9 && !memcmp(name, "externref", 9)) return WASM_EXTERNREF; 169 if (len == 7 && !memcmp(name, "funcref", 7)) return WASM_FUNCREF; 170 *ok = false; 171 return WASM_I32; 172} 173 174static wasm_module_handle_t *wasm_module_handle(ant_value_t value) { 175 if (!js_check_brand(value, BRAND_WASM_MODULE)) return NULL; 176 ant_value_t slot = js_get_slot(value, SLOT_DATA); 177 if (vtype(slot) != T_NUM) return NULL; 178 return (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(slot); 179} 180 181static wasm_instance_handle_t *wasm_instance_handle(ant_value_t value) { 182 if (!js_check_brand(value, BRAND_WASM_INSTANCE)) return NULL; 183 ant_value_t slot = js_get_slot(value, SLOT_DATA); 184 if (vtype(slot) != T_NUM) return NULL; 185 return (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(slot); 186} 187 188static wasm_extern_handle_t *wasm_extern_handle(ant_value_t value, wasm_extern_wrap_kind_t kind) { 189 if ((kind == WASM_EXTERN_WRAP_GLOBAL && !js_check_brand(value, BRAND_WASM_GLOBAL)) 190 || (kind == WASM_EXTERN_WRAP_MEMORY && !js_check_brand(value, BRAND_WASM_MEMORY)) 191 || (kind == WASM_EXTERN_WRAP_TABLE && !js_check_brand(value, BRAND_WASM_TABLE))) { 192 return NULL; 193 } 194 195 ant_value_t slot = js_get_slot(value, SLOT_DATA); 196 if (vtype(slot) != T_NUM) return NULL; 197 wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(slot); 198 return handle && handle->kind == kind ? handle : NULL; 199} 200 201static ant_value_t wasm_make_error(ant_t *js, ant_value_t proto, const char *name, const char *message) { 202 ant_value_t err = js_make_error_silent(js, JS_ERR_TYPE, message ? message : ""); 203 if (vtype(err) != T_OBJ) return err; 204 js_set(js, err, "name", js_mkstr(js, name, strlen(name))); 205 if (is_object_type(proto)) js_set_proto_init(err, proto); 206 return err; 207} 208 209static ant_value_t wasm_make_compile_error(ant_t *js, const char *message) { 210 return wasm_make_error(js, g_wasm_compileerror_proto, "CompileError", message); 211} 212 213static ant_value_t wasm_make_link_error(ant_t *js, const char *message) { 214 return wasm_make_error(js, g_wasm_linkerror_proto, "LinkError", message); 215} 216 217static ant_value_t wasm_make_runtime_error(ant_t *js, const char *message) { 218 return wasm_make_error(js, g_wasm_runtimeerror_proto, "RuntimeError", message); 219} 220 221static ant_value_t wasm_error_value(ant_t *js, ant_value_t value) { 222 if (is_err(value) && js->thrown_exists) 223 return js->thrown_value; 224 return value; 225} 226 227static void wasm_reject_with_error(ant_t *js, ant_value_t promise, ant_value_t error) { 228 js_reject_promise(js, promise, error); 229} 230 231static bool wasm_buffer_source_to_vec(ant_t *js, ant_value_t value, wasm_byte_vec_t *out, char *error_buf, size_t error_buf_len) { 232 const uint8_t *bytes = NULL; 233 size_t len = 0; 234 memset(out, 0, sizeof(*out)); 235 236 if (!buffer_source_get_bytes(js, value, &bytes, &len)) { 237 snprintf(error_buf, error_buf_len, "Expected a BufferSource"); 238 return false; 239 } 240 241 wasm_byte_vec_new_uninitialized(out, len); 242 if (len > 0 && !out->data) { 243 snprintf(error_buf, error_buf_len, "Out of memory"); 244 return false; 245 } 246 247 if (len > 0) memcpy(out->data, bytes, len); 248 return true; 249} 250 251static ant_value_t wasm_value_from_i64(ant_t *js, int64_t value) { 252 char buf[64]; 253 int n = snprintf(buf, sizeof(buf), "%" PRId64, value); 254 if (n < 0) return js_mkerr(js, "Failed to convert i64"); 255 return js_mkbigint(js, buf, (size_t)n, value < 0); 256} 257 258static ant_value_t wasm_value_to_js(ant_t *js, const wasm_val_t *value) { 259 switch (value->kind) { 260 case WASM_I32: return js_mknum((double)value->of.i32); 261 case WASM_I64: return wasm_value_from_i64(js, value->of.i64); 262 case WASM_F32: return js_mknum((double)value->of.f32); 263 case WASM_F64: return js_mknum(value->of.f64); 264 case WASM_EXTERNREF: 265 return value->of.ref ? js_mkundef() : js_mknull(); 266 case WASM_FUNCREF: { 267 wasm_func_t *func; 268 if (!value->of.ref) return js_mknull(); 269 func = wasm_ref_as_func(value->of.ref); 270 if (!func) return js_mkundef(); 271 return wasm_wrap_func(js, func, js_mkundef(), true); 272 } 273 default: return js_mkundef(); 274 } 275} 276 277static bool js_value_to_i64(ant_t *js, ant_value_t value, int64_t *out) { 278 if (vtype(value) == T_BIGINT) { 279 ant_value_t str_val = js_tostring_val(js, value); 280 if (is_err(str_val) || vtype(str_val) != T_STR) return false; 281 const char *str = js_str(js, str_val); 282 if (!str) return false; 283 char *end = NULL; 284 long long parsed = strtoll(str, &end, 10); 285 if (!end || *end != '\0') return false; 286 *out = (int64_t)parsed; 287 return true; 288 } 289 290 double d = js_to_number(js, value); 291 if (!isfinite(d)) return false; 292 *out = (int64_t)d; 293 return true; 294} 295 296static bool js_value_to_wasm(ant_t *js, ant_value_t value, wasm_valkind_t kind, wasm_val_t *out) { 297 memset(out, 0, sizeof(*out)); 298 out->kind = kind; 299 300 switch (kind) { 301 case WASM_I32: 302 out->of.i32 = (int32_t)js_to_number(js, value); 303 return true; 304 case WASM_I64: 305 return js_value_to_i64(js, value, &out->of.i64); 306 case WASM_F32: 307 out->of.f32 = (float)js_to_number(js, value); 308 return true; 309 case WASM_F64: 310 out->of.f64 = js_to_number(js, value); 311 return true; 312 case WASM_EXTERNREF: 313 out->of.ref = NULL; 314 return vtype(value) == T_NULL || vtype(value) == T_UNDEF; 315 case WASM_FUNCREF: { 316 ant_value_t state; 317 wasm_func_handle_t *handle; 318 if (vtype(value) == T_NULL || vtype(value) == T_UNDEF) { 319 out->of.ref = NULL; 320 return true; 321 } 322 if (!is_callable(value)) return false; 323 state = js_get_slot(value, SLOT_DATA); 324 if (!is_object_type(state) || !js_check_native_tag(state, WASM_FUNC_STATE_TAG)) 325 return false; 326 handle = (wasm_func_handle_t *)js_get_native_ptr(state); 327 if (!handle || !handle->func) return false; 328 out->of.ref = wasm_func_as_ref(handle->func); 329 return out->of.ref != NULL; 330 } 331 default: return false; 332 } 333} 334 335static ant_value_t wasm_js_from_result_vec(ant_t *js, wasm_val_vec_t *results) { 336 if (!results || results->size == 0) return js_mkundef(); 337 if (results->size == 1) return wasm_value_to_js(js, &results->data[0]); 338 339 ant_value_t arr = js_mkarr(js); 340 for (size_t i = 0; i < results->size; i++) { 341 js_arr_push(js, arr, wasm_value_to_js(js, &results->data[i])); 342 } 343 return arr; 344} 345 346static ant_value_t wasm_trap_to_error(ant_t *js, wasm_trap_t *trap) { 347 wasm_message_t message = WASM_EMPTY_VEC; 348 wasm_trap_message(trap, &message); 349 350 ant_value_t err = wasm_make_runtime_error(js, message.data ? message.data : "WebAssembly trap"); 351 352 wasm_byte_vec_delete(&message); 353 wasm_trap_delete(trap); 354 return err; 355} 356 357static ant_value_t wasm_wrap_module(ant_t *js, wasm_store_t *store, wasm_module_t *module) { 358 wasm_module_handle_t *handle = calloc(1, sizeof(*handle)); 359 if (!handle) { 360 if (module) wasm_module_delete(module); 361 if (store) wasm_store_delete(store); 362 return js_mkerr(js, "out of memory"); 363 } 364 365 handle->store = store; 366 handle->module = module; 367 368 ant_value_t obj = js_mkobj(js); 369 js_set_proto_init(obj, g_wasm_module_proto); 370 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_WASM_MODULE)); 371 js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); 372 return obj; 373} 374 375static void wasm_module_finalize(ant_t *js, ant_object_t *obj) { 376 if (!obj->extra_slots) return; 377 378 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 379 for (uint8_t i = 0; i < obj->extra_count; i++) { 380 if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 381 wasm_module_handle_t *handle = (wasm_module_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 382 if (!handle) return; 383 if (handle->module) wasm_module_delete(handle->module); 384 if (handle->store) wasm_store_delete(handle->store); 385 free(handle); 386 return; 387 } 388} 389 390static ant_value_t wasm_wrap_instance(ant_t *js, wasm_instance_handle_t *handle, ant_value_t module_ref) { 391 ant_value_t obj = js_mkobj(js); 392 js_set_proto_init(obj, g_wasm_instance_proto); 393 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_WASM_INSTANCE)); 394 js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); 395 js_set_slot_wb(js, obj, SLOT_CTOR, module_ref); 396 return obj; 397} 398 399static void wasm_instance_finalize(ant_t *js, ant_object_t *obj) { 400 if (!obj->extra_slots) return; 401 402 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 403 for (uint8_t i = 0; i < obj->extra_count; i++) { 404 if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 405 wasm_instance_handle_t *handle = (wasm_instance_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 406 if (!handle) return; 407 for (size_t j = 0; j < handle->host_func_count; j++) { 408 if (handle->host_funcs[j]) wasm_func_delete(handle->host_funcs[j]); 409 } 410 free(handle->host_funcs); 411 wasm_extern_vec_delete(&handle->exports); 412 free(handle); 413 return; 414 } 415} 416 417static ant_value_t wasm_wrap_extern_object(ant_t *js, wasm_extern_wrap_kind_t kind, ant_value_t proto, int brand, wasm_store_t *store, bool own_handle, void *ptr, ant_value_t owner) { 418 wasm_extern_handle_t *handle = calloc(1, sizeof(*handle)); 419 if (!handle) return js_mkerr(js, "out of memory"); 420 421 handle->kind = kind; 422 handle->store = store; 423 handle->own_handle = own_handle; 424 handle->cached_value = (wasm_val_t)WASM_INIT_VAL; 425 426 switch (kind) { 427 case WASM_EXTERN_WRAP_GLOBAL: handle->as.global = (wasm_global_t *)ptr; break; 428 case WASM_EXTERN_WRAP_MEMORY: handle->as.memory = (wasm_memory_t *)ptr; break; 429 case WASM_EXTERN_WRAP_TABLE: handle->as.table = (wasm_table_t *)ptr; break; 430 } 431 432 ant_value_t obj = js_mkobj(js); 433 js_set_proto_init(obj, proto); 434 js_set_slot(obj, SLOT_BRAND, js_mknum(brand)); 435 js_set_slot(obj, SLOT_DATA, ANT_PTR(handle)); 436 if (is_object_type(owner)) js_set_slot_wb(js, obj, SLOT_ENTRIES, owner); 437 return obj; 438} 439 440static void wasm_extern_finalize(ant_t *js, ant_object_t *obj) { 441 if (!obj->extra_slots) return; 442 443 ant_extra_slot_t *entries = (ant_extra_slot_t *)obj->extra_slots; 444 for (uint8_t i = 0; i < obj->extra_count; i++) { 445 if (entries[i].slot != SLOT_DATA || vtype(entries[i].value) != T_NUM) continue; 446 wasm_extern_handle_t *handle = (wasm_extern_handle_t *)(uintptr_t)(size_t)js_getnum(entries[i].value); 447 if (!handle) return; 448 449 if (handle->own_handle) { 450 switch (handle->kind) { 451 case WASM_EXTERN_WRAP_GLOBAL: 452 if (handle->as.global) wasm_global_delete(handle->as.global); 453 break; 454 case WASM_EXTERN_WRAP_MEMORY: 455 if (handle->as.memory) wasm_memory_delete(handle->as.memory); 456 break; 457 case WASM_EXTERN_WRAP_TABLE: 458 if (handle->as.table) wasm_table_delete(handle->as.table); 459 break; 460 } 461 if (handle->store) wasm_store_delete(handle->store); 462 } 463 464 free(handle); 465 return; 466 } 467} 468 469static ant_value_t js_wasm_exported_func_call(ant_t *js, ant_value_t *args, int nargs) { 470 ant_value_t state = js_get_slot(js->current_func, SLOT_DATA); 471 wasm_func_handle_t *handle; 472 wasm_func_t *func; 473 474 if (!is_object_type(state) || !js_check_native_tag(state, WASM_FUNC_STATE_TAG)) 475 return js_mkerr(js, "Invalid WebAssembly function"); 476 477 handle = (wasm_func_handle_t *)js_get_native_ptr(state); 478 func = handle ? handle->func : NULL; 479 if (!func) return js_mkerr(js, "Invalid WebAssembly function"); 480 481 wasm_functype_t *type = wasm_func_type(func); 482 if (!type) return js_mkerr(js, "Failed to inspect WebAssembly function"); 483 484 const wasm_valtype_vec_t *params = wasm_functype_params(type); 485 const wasm_valtype_vec_t *results_t = wasm_functype_results(type); 486 487 wasm_val_vec_t wasm_args = WASM_EMPTY_VEC; 488 wasm_val_vec_t wasm_results = WASM_EMPTY_VEC; 489 wasm_trap_t *trap = NULL; 490 ant_value_t result = js_mkundef(); 491 492 wasm_val_vec_new_uninitialized(&wasm_args, params ? params->size : 0); 493 wasm_val_vec_new_uninitialized(&wasm_results, results_t ? results_t->size : 0); 494 495 for (size_t i = 0; params && i < params->size; i++) { 496 if ((int)i >= nargs) { 497 wasm_val_vec_delete(&wasm_args); 498 wasm_val_vec_delete(&wasm_results); 499 wasm_functype_delete(type); 500 return js_mkerr_typed(js, JS_ERR_TYPE, "Missing WebAssembly argument"); 501 } 502 503 if (!js_value_to_wasm(js, args[i], wasm_valtype_kind(params->data[i]), &wasm_args.data[i])) { 504 wasm_val_vec_delete(&wasm_args); 505 wasm_val_vec_delete(&wasm_results); 506 wasm_functype_delete(type); 507 return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly argument type"); 508 } 509 } 510 511 wasm_clear_pending_import_throw(); 512 trap = wasm_func_call(func, &wasm_args, &wasm_results); 513 514 if (trap) { 515 if (g_wasm_pending_import_throw_exists) { 516 result = wasm_consume_pending_import_throw(); 517 js_mark_errorlike_no_stack(js, result); 518 wasm_val_vec_delete(&wasm_args); 519 wasm_val_vec_delete(&wasm_results); 520 wasm_functype_delete(type); 521 wasm_trap_delete(trap); 522 return js_throw(js, result); 523 } 524 525 result = wasm_trap_to_error(js, trap); 526 wasm_val_vec_delete(&wasm_args); 527 wasm_val_vec_delete(&wasm_results); 528 wasm_functype_delete(type); 529 return js_throw(js, result); 530 } 531 532 wasm_clear_pending_import_throw(); 533 result = wasm_js_from_result_vec(js, &wasm_results); 534 535 wasm_val_vec_delete(&wasm_args); 536 wasm_val_vec_delete(&wasm_results); 537 wasm_functype_delete(type); 538 539 return result; 540} 541 542static void wasm_func_state_finalize(ant_t *js, ant_object_t *obj) { 543 if (obj->native.tag != WASM_FUNC_STATE_TAG) return; 544 545 wasm_func_handle_t *handle = (wasm_func_handle_t *)obj->native.ptr; 546 if (!handle) return; 547 548 if (handle->own_func && handle->func) wasm_func_delete(handle->func); 549 free(handle); 550 obj->native.ptr = NULL; 551 obj->native.tag = 0; 552} 553 554static ant_value_t wasm_wrap_func(ant_t *js, wasm_func_t *func, ant_value_t owner, bool own_func) { 555 wasm_func_handle_t *handle; 556 ant_value_t state; 557 558 if (!func) return js_mkundef(); 559 560 handle = calloc(1, sizeof(*handle)); 561 if (!handle) { 562 if (own_func) wasm_func_delete(func); 563 return js_mkerr(js, "out of memory"); 564 } 565 566 handle->func = func; 567 handle->own_func = own_func; 568 569 state = js_mkobj(js); 570 js_set_native_ptr(state, handle); 571 js_set_native_tag(state, WASM_FUNC_STATE_TAG); 572 573 if (is_object_type(owner)) js_set_slot_wb(js, state, SLOT_ENTRIES, owner); 574 js_set_finalizer(state, wasm_func_state_finalize); 575 576 return js_heavy_mkfun(js, js_wasm_exported_func_call, state); 577} 578 579static ant_value_t wasm_wrap_export_value(ant_t *js, ant_value_t instance_obj, const wasm_exporttype_t *export_type, wasm_extern_t *external) { 580 switch (wasm_extern_kind(external)) { 581 case WASM_EXTERN_FUNC: { 582 return wasm_wrap_func(js, wasm_extern_as_func(external), instance_obj, false); 583 } 584 case WASM_EXTERN_GLOBAL: { 585 ant_value_t obj = wasm_wrap_extern_object( 586 js, WASM_EXTERN_WRAP_GLOBAL, g_wasm_global_proto, BRAND_WASM_GLOBAL, 587 NULL, false, wasm_extern_as_global(external), instance_obj 588 ); 589 if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); 590 return obj; 591 } 592 case WASM_EXTERN_MEMORY: { 593 ant_value_t obj = wasm_wrap_extern_object( 594 js, WASM_EXTERN_WRAP_MEMORY, g_wasm_memory_proto, BRAND_WASM_MEMORY, 595 NULL, false, wasm_extern_as_memory(external), instance_obj 596 ); 597 if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); 598 return obj; 599 } 600 case WASM_EXTERN_TABLE: { 601 ant_value_t obj = wasm_wrap_extern_object( 602 js, WASM_EXTERN_WRAP_TABLE, g_wasm_table_proto, BRAND_WASM_TABLE, 603 NULL, false, wasm_extern_as_table(external), instance_obj 604 ); 605 if (vtype(obj) == T_OBJ) js_set_finalizer(obj, wasm_extern_finalize); 606 return obj; 607 } 608 default: 609 (void)export_type; 610 return js_mkundef(); 611 } 612} 613 614static ant_value_t wasm_module_from_bytes(ant_t *js, ant_value_t value, ant_value_t *out_module) { 615 wasm_byte_vec_t binary = WASM_EMPTY_VEC; 616 wasm_store_t *store = NULL; 617 wasm_module_t *module = NULL; 618 619 char error_buf[128] = {0}; 620 bool suppress_wasi_warning = false; 621 622 *out_module = js_mkundef(); 623 624 if (!ensure_wasm_engine()) return js_mkerr(js, "Failed to initialize WebAssembly engine"); 625 if (!(store = wasm_store_new(g_wasm_engine))) return js_mkerr(js, "Failed to create WebAssembly store"); 626 627 if (!wasm_buffer_source_to_vec(js, value, &binary, error_buf, sizeof(error_buf))) { 628 wasm_store_delete(store); 629 return js_mkerr_typed(js, JS_ERR_TYPE, "%s", error_buf); 630 } 631 632 suppress_wasi_warning = wasi_bytes_need_wasi_command_warning_suppression( 633 (const uint8_t *)binary.data, binary.size 634 ); 635 636 if (suppress_wasi_warning) wasm_runtime_set_log_level(WASM_LOG_LEVEL_ERROR); 637 module = wasm_module_new(store, &binary); 638 639 if (suppress_wasi_warning) wasm_runtime_set_log_level(WASM_LOG_LEVEL_WARNING); 640 wasm_byte_vec_delete(&binary); 641 642 if (!module) { 643 wasm_store_delete(store); 644 return wasm_make_compile_error(js, "Failed to compile WebAssembly module"); 645 } 646 647 *out_module = wasm_wrap_module(js, store, module); 648 if (vtype(*out_module) == T_OBJ) { 649 js_set_finalizer(*out_module, wasm_module_finalize); 650 js_set_slot_wb(js, *out_module, SLOT_MAP, value); 651 } 652 return js_mkundef(); 653} 654 655static ant_value_t js_wasm_module_ctor(ant_t *js, ant_value_t *args, int nargs) { 656 ant_value_t module = js_mkundef(); 657 ant_value_t err; 658 659 if (vtype(js->new_target) == T_UNDEF) 660 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module constructor requires 'new'"); 661 if (nargs < 1) 662 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module requires a BufferSource"); 663 664 err = wasm_module_from_bytes(js, args[0], &module); 665 if (is_err(err)) return err; 666 if (vtype(module) != T_OBJ) return js_throw(js, wasm_error_value(js, err)); 667 return module; 668} 669 670static ant_value_t wasm_module_type_descriptors(ant_t *js, ant_value_t module_obj, bool imports) { 671 wasm_module_handle_t *handle = wasm_module_handle(module_obj); 672 if (!handle) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Module"); 673 674 ant_value_t arr = js_mkarr(js); 675 if (imports) { 676 wasm_importtype_vec_t vec = WASM_EMPTY_VEC; 677 wasm_module_imports(handle->module, &vec); 678 for (size_t i = 0; i < vec.size; i++) { 679 const wasm_importtype_t *entry = vec.data[i]; 680 const wasm_name_t *module_name = wasm_importtype_module(entry); 681 const wasm_name_t *name = wasm_importtype_name(entry); 682 const wasm_externtype_t *type = wasm_importtype_type(entry); 683 684 ant_value_t item = js_mkobj(js); 685 js_set(js, item, "module", js_mkstr(js, module_name->data, wasm_name_len(module_name))); 686 js_set(js, item, "name", js_mkstr(js, name->data, wasm_name_len(name))); 687 js_set(js, item, "kind", js_mkstr(js, wasm_extern_kind_name(wasm_externtype_kind(type)), strlen(wasm_extern_kind_name(wasm_externtype_kind(type))))); 688 js_arr_push(js, arr, item); 689 } 690 wasm_importtype_vec_delete(&vec); 691 } else { 692 wasm_exporttype_vec_t vec = WASM_EMPTY_VEC; 693 wasm_module_exports(handle->module, &vec); 694 for (size_t i = 0; i < vec.size; i++) { 695 const wasm_exporttype_t *entry = vec.data[i]; 696 const wasm_name_t *name = wasm_exporttype_name(entry); 697 const wasm_externtype_t *type = wasm_exporttype_type(entry); 698 699 ant_value_t item = js_mkobj(js); 700 js_set(js, item, "name", js_mkstr(js, name->data, wasm_name_len(name))); 701 js_set(js, item, "kind", js_mkstr(js, wasm_extern_kind_name(wasm_externtype_kind(type)), strlen(wasm_extern_kind_name(wasm_externtype_kind(type))))); 702 js_arr_push(js, arr, item); 703 } 704 wasm_exporttype_vec_delete(&vec); 705 } 706 707 return arr; 708} 709 710static ant_value_t js_wasm_module_imports(ant_t *js, ant_value_t *args, int nargs) { 711 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module.imports requires 1 argument"); 712 return wasm_module_type_descriptors(js, args[0], true); 713} 714 715static ant_value_t js_wasm_module_exports(ant_t *js, ant_value_t *args, int nargs) { 716 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Module.exports requires 1 argument"); 717 return wasm_module_type_descriptors(js, args[0], false); 718} 719 720static ant_value_t js_wasm_instance_exports_getter(ant_t *js, ant_value_t *args, int nargs) { 721 if (!js_check_brand(js->this_val, BRAND_WASM_INSTANCE)) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Instance"); 722 return js_get_slot(js->this_val, SLOT_ENTRIES); 723} 724 725static ant_value_t wasm_property_get_nested(ant_t *js, ant_value_t base, const wasm_name_t *name) { 726 if (!is_object_type(base)) return js_mkundef(); 727 return js_getprop_fallback(js, base, name && name->data ? name->data : ""); 728} 729 730static wasm_trap_t *wasm_import_func_callback(void *env_ptr, const wasm_val_vec_t *args, wasm_val_vec_t *results) { 731 wasm_import_func_env_t *env = (wasm_import_func_env_t *)env_ptr; 732 ant_t *js = env->js; 733 734 ant_value_t *js_args = NULL; 735 ant_value_t result = js_mkundef(); 736 wasm_message_t trap_msg = WASM_EMPTY_VEC; 737 738 if (args && args->size > 0) { 739 js_args = calloc(args->size, sizeof(*js_args)); 740 if (!js_args) { 741 wasm_name_new_from_string_nt(&trap_msg, "Out of memory"); 742 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 743 wasm_byte_vec_delete(&trap_msg); 744 return trap; 745 } 746 } 747 748 for (size_t i = 0; args && i < args->size; i++) { 749 js_args[i] = wasm_value_to_js(js, &args->data[i]); 750 } 751 752 result = sv_vm_call( 753 js->vm, js, env->fn, js_mkundef(), 754 js_args, args ? (int)args->size : 0, NULL, false 755 ); 756 free(js_args); 757 758 if (is_err(result)) { 759 ant_value_t thrown = js->thrown_exists ? js->thrown_value : result; 760 wasm_set_pending_import_throw(thrown); 761 762 const char *msg = "WebAssembly import threw"; 763 if (vtype(js->thrown_value) == T_OBJ) { 764 const char *message = get_str_prop(js, js->thrown_value, "message", 7, NULL); 765 if (message && *message) msg = message; 766 } 767 768 wasm_name_new_from_string_nt(&trap_msg, msg); 769 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 770 wasm_byte_vec_delete(&trap_msg); 771 772 return trap; 773 } 774 775 if (results && results->size > 0) { 776 if (results->size == 1) { 777 if (!js_value_to_wasm(js, result, results->data[0].kind, &results->data[0])) { 778 wasm_name_new_from_string_nt(&trap_msg, "Unsupported import return value"); 779 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 780 wasm_byte_vec_delete(&trap_msg); 781 return trap; 782 } 783 } else { 784 if (vtype(result) != T_ARR) { 785 wasm_name_new_from_string_nt(&trap_msg, "Expected an array for multi-value return"); 786 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 787 wasm_byte_vec_delete(&trap_msg); 788 return trap; 789 } 790 791 for (size_t i = 0; i < results->size; i++) { 792 ant_value_t item = js_arr_get(js, result, (ant_offset_t)i); 793 if (!js_value_to_wasm(js, item, results->data[i].kind, &results->data[i])) { 794 wasm_name_new_from_string_nt(&trap_msg, "Unsupported import return value"); 795 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 796 wasm_byte_vec_delete(&trap_msg); 797 return trap; 798 } 799 } 800 }} 801 802 return NULL; 803} 804 805static ant_value_t wasm_instantiate_module(ant_t *js, ant_value_t module_obj, ant_value_t import_obj, ant_value_t *out_instance) { 806 wasm_module_handle_t *module_handle = wasm_module_handle(module_obj); 807 wasm_importtype_vec_t import_types = WASM_EMPTY_VEC; 808 wasm_exporttype_vec_t export_types = WASM_EMPTY_VEC; 809 810 wasm_extern_t **imports = NULL; 811 wasm_func_t **owned_host_funcs = NULL; 812 813 size_t owned_host_func_count = 0; 814 wasm_extern_vec_t exports = WASM_EMPTY_VEC; 815 816 wasm_trap_t *trap = NULL; 817 wasm_instance_t *instance = NULL; 818 ant_value_t instance_obj = js_mkundef(); 819 ant_value_t exports_obj = js_mkobj(js); 820 *out_instance = js_mkundef(); 821 822 if (!module_handle) 823 return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Module"); 824 825 if (wasi_module_has_wasi_imports(module_handle->module) 826 && wasi_module_is_command_or_reactor(module_handle->module)) { 827 ant_value_t wasi_opts = is_object_type(import_obj) ? js_get(js, import_obj, "wasi") : js_mkundef(); 828 if (!is_object_type(import_obj) || is_object_type(wasi_opts)) { 829 ant_value_t bytes_src = js_get_slot(module_obj, SLOT_MAP); 830 wasm_byte_vec_t binary = WASM_EMPTY_VEC; 831 char wasi_err[128] = {0}; 832 if (!wasm_buffer_source_to_vec(js, bytes_src, &binary, wasi_err, sizeof(wasi_err))) { 833 return js_mkerr(js, "WASI: cannot extract module bytes"); 834 } 835 *out_instance = wasi_instantiate(js, (const uint8_t *)binary.data, binary.size, module_obj, wasi_opts); 836 wasm_byte_vec_delete(&binary); 837 return is_err(*out_instance) ? *out_instance : js_mkundef(); 838 } 839 } 840 841 wasm_module_imports(module_handle->module, &import_types); 842 if (import_types.size > 0) { 843 imports = calloc(import_types.size, sizeof(*imports)); 844 owned_host_funcs = calloc(import_types.size, sizeof(*owned_host_funcs)); 845 if (!imports || !owned_host_funcs) { 846 free(imports); 847 free(owned_host_funcs); 848 wasm_importtype_vec_delete(&import_types); 849 return js_mkerr(js, "out of memory"); 850 } 851 } 852 853 for (size_t i = 0; i < import_types.size; i++) { 854 const wasm_importtype_t *import_type = import_types.data[i]; 855 const wasm_name_t *module_name = wasm_importtype_module(import_type); 856 const wasm_name_t *field_name = wasm_importtype_name(import_type); 857 const wasm_externtype_t *extern_type = wasm_importtype_type(import_type); 858 859 ant_value_t namespace_obj = wasm_property_get_nested(js, import_obj, module_name); 860 ant_value_t value = wasm_property_get_nested(js, namespace_obj, field_name); 861 wasm_externkind_t kind = wasm_externtype_kind(extern_type); 862 863 if (kind == WASM_EXTERN_MEMORY || kind == WASM_EXTERN_TABLE) { 864 free(imports); 865 free(owned_host_funcs); 866 wasm_importtype_vec_delete(&import_types); 867 return wasm_make_link_error(js, "The current WAMR backend does not support memory/table imports"); 868 } 869 870 if (kind == WASM_EXTERN_FUNC) { 871 const wasm_functype_t *func_type = wasm_externtype_as_functype_const(extern_type); 872 wasm_import_func_env_t *env = NULL; 873 874 if (!is_callable(value)) { 875 free(imports); 876 free(owned_host_funcs); 877 wasm_importtype_vec_delete(&import_types); 878 return wasm_make_link_error(js, "Missing function import"); 879 } 880 881 env = calloc(1, sizeof(*env)); 882 if (!env) { 883 free(imports); 884 free(owned_host_funcs); 885 wasm_importtype_vec_delete(&import_types); 886 return js_mkerr(js, "out of memory"); 887 } 888 889 env->js = js; 890 env->store = module_handle->store; 891 env->owner = module_obj; 892 env->fn = value; 893 wasm_register_import_env(env); 894 895 896 owned_host_funcs[owned_host_func_count] = wasm_func_new_with_env( 897 module_handle->store, 898 func_type, 899 wasm_import_func_callback, 900 env, 901 wasm_import_func_env_finalizer 902 ); 903 904 if (!owned_host_funcs[owned_host_func_count]) { 905 free(env); 906 free(imports); 907 free(owned_host_funcs); 908 wasm_importtype_vec_delete(&import_types); 909 return wasm_make_link_error(js, "Failed to create function import"); 910 } 911 912 imports[i] = wasm_func_as_extern(owned_host_funcs[owned_host_func_count]); 913 owned_host_func_count++; 914 continue; 915 } 916 917 if (kind == WASM_EXTERN_GLOBAL) { 918 wasm_extern_handle_t *handle = wasm_extern_handle(value, WASM_EXTERN_WRAP_GLOBAL); 919 if (!handle || !handle->as.global) { 920 free(imports); 921 free(owned_host_funcs); 922 wasm_importtype_vec_delete(&import_types); 923 return wasm_make_link_error(js, "Missing global import"); 924 } 925 imports[i] = wasm_global_as_extern(handle->as.global); 926 continue; 927 } 928 } 929 930 { 931 wasm_extern_vec_t import_vec = WASM_EMPTY_VEC; 932 if (imports && import_types.size > 0) 933 import_vec = (wasm_extern_vec_t){ import_types.size, imports, import_types.size, sizeof(*imports), NULL }; 934 935 wasm_clear_pending_import_throw(); 936 instance = wasm_instance_new_with_args(module_handle->store, module_handle->module, &import_vec, &trap, KILOBYTE(32), 0); 937 } 938 939 free(imports); 940 wasm_importtype_vec_delete(&import_types); 941 942 if (!instance) { 943 for (size_t i = 0; i < owned_host_func_count; i++) { 944 if (owned_host_funcs[i]) wasm_func_delete(owned_host_funcs[i]); 945 } 946 free(owned_host_funcs); 947 948 if (trap) { 949 if (g_wasm_pending_import_throw_exists) { 950 ant_value_t thrown = wasm_consume_pending_import_throw(); 951 js_mark_errorlike_no_stack(js, thrown); 952 wasm_trap_delete(trap); 953 return js_throw(js, thrown); 954 } 955 return wasm_trap_to_error(js, trap); 956 } 957 958 return wasm_make_link_error(js, "Failed to instantiate WebAssembly module"); 959 } 960 961 wasm_clear_pending_import_throw(); 962 wasm_instance_exports(instance, &exports); 963 wasm_module_exports(module_handle->module, &export_types); 964 965 { 966 wasm_instance_handle_t *inst_handle = calloc(1, sizeof(*inst_handle)); 967 if (!inst_handle) { 968 wasm_extern_vec_delete(&exports); 969 wasm_exporttype_vec_delete(&export_types); 970 return js_mkerr(js, "out of memory"); 971 } 972 inst_handle->instance = instance; 973 inst_handle->exports = exports; 974 inst_handle->host_funcs = owned_host_funcs; 975 inst_handle->host_func_count = owned_host_func_count; 976 977 instance_obj = wasm_wrap_instance(js, inst_handle, module_obj); 978 } 979 if (vtype(instance_obj) != T_OBJ) { 980 wasm_exporttype_vec_delete(&export_types); 981 return instance_obj; 982 } 983 js_set_finalizer(instance_obj, wasm_instance_finalize); 984 985 for (size_t i = 0; i < export_types.size && i < exports.size; i++) { 986 const wasm_exporttype_t *export_type = export_types.data[i]; 987 const wasm_name_t *name = wasm_exporttype_name(export_type); 988 ant_value_t export_value = wasm_wrap_export_value(js, instance_obj, export_type, exports.data[i]); 989 js_setprop(js, exports_obj, js_mkstr(js, name->data, wasm_name_len(name)), export_value); 990 } 991 992 wasm_exporttype_vec_delete(&export_types); 993 js_set_slot_wb(js, instance_obj, SLOT_ENTRIES, exports_obj); 994 if (is_object_type(import_obj)) js_set_slot_wb(js, instance_obj, SLOT_MAP, import_obj); 995 996 *out_instance = instance_obj; 997 return js_mkundef(); 998} 999 1000static ant_value_t js_wasm_instance_ctor(ant_t *js, ant_value_t *args, int nargs) { 1001 ant_value_t instance = js_mkundef(); 1002 ant_value_t import_obj = (nargs >= 2 && is_object_type(args[1])) ? args[1] : js_mkundef(); 1003 ant_value_t err; 1004 1005 if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Instance constructor requires 'new'"); 1006 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Instance requires a module"); 1007 1008 err = wasm_instantiate_module(js, args[0], import_obj, &instance); 1009 if (is_err(err)) return err; 1010 if (vtype(instance) != T_OBJ) return js_throw(js, wasm_error_value(js, err)); 1011 1012 return instance; 1013} 1014 1015static ant_value_t js_wasm_global_value_getter(ant_t *js, ant_value_t *args, int nargs) { 1016 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_GLOBAL); 1017 wasm_val_t value = WASM_INIT_VAL; 1018 1019 if (!handle || !handle->as.global) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Global"); 1020 if (handle->use_cached_value) return wasm_value_to_js(js, &handle->cached_value); 1021 1022 wasm_global_get(handle->as.global, &value); 1023 return wasm_value_to_js(js, &value); 1024} 1025 1026static ant_value_t js_wasm_global_value_setter(ant_t *js, ant_value_t *args, int nargs) { 1027 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_GLOBAL); 1028 wasm_globaltype_t *type = NULL; 1029 1030 const wasm_valtype_t *content = NULL; 1031 wasm_val_t value = WASM_INIT_VAL; 1032 1033 if (!handle || !handle->as.global) 1034 return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Global"); 1035 if (nargs < 1) return js_mkundef(); 1036 1037 type = wasm_global_type(handle->as.global); 1038 if (!type) return js_mkerr(js, "Failed to inspect WebAssembly.Global"); 1039 if (wasm_globaltype_mutability(type) != WASM_VAR) { 1040 wasm_globaltype_delete(type); 1041 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global is immutable"); 1042 } 1043 1044 content = wasm_globaltype_content(type); 1045 if (!js_value_to_wasm(js, args[0], wasm_valtype_kind(content), &value)) { 1046 wasm_globaltype_delete(type); 1047 return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported global value"); 1048 } 1049 1050 if (handle->use_cached_value) handle->cached_value = value; 1051 else wasm_global_set(handle->as.global, &value); 1052 wasm_globaltype_delete(type); 1053 1054 return js_mkundef(); 1055} 1056 1057static ant_value_t js_wasm_global_value_of(ant_t *js, ant_value_t *args, int nargs) { 1058 return js_wasm_global_value_getter(js, NULL, 0); 1059} 1060 1061static ant_value_t js_wasm_global_ctor(ant_t *js, ant_value_t *args, int nargs) { 1062 ant_value_t descriptor; 1063 ant_value_t mutable_val; 1064 1065 const char *value_type; 1066 ant_offset_t value_type_len = 0; 1067 bool ok = false; 1068 1069 wasm_valkind_t kind; 1070 wasm_store_t *store = NULL; 1071 wasm_valtype_t *valtype = NULL; 1072 wasm_globaltype_t *globaltype = NULL; 1073 wasm_global_t *global = NULL; 1074 wasm_val_t initial = WASM_INIT_VAL; 1075 ant_value_t result; 1076 1077 if (vtype(js->new_target) == T_UNDEF) 1078 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global constructor requires 'new'"); 1079 if (nargs < 1 || !is_object_type(args[0])) 1080 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global requires a descriptor object"); 1081 if (!ensure_wasm_engine()) 1082 return js_mkerr(js, "Failed to initialize WebAssembly engine"); 1083 1084 descriptor = args[0]; 1085 value_type = get_str_prop(js, descriptor, "value", 5, &value_type_len); 1086 if (!value_type) 1087 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Global descriptor requires a value type"); 1088 1089 kind = wasm_valkind_from_string(value_type, value_type_len, &ok); 1090 if (!ok) 1091 return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly.Global value type"); 1092 1093 if (!js_value_to_wasm(js, nargs >= 2 ? args[1] : js_mknum(0), kind, &initial)) 1094 return js_mkerr_typed(js, JS_ERR_TYPE, "Unsupported WebAssembly.Global initial value"); 1095 1096 mutable_val = js_get(js, descriptor, "mutable"); 1097 store = wasm_store_new(g_wasm_engine); 1098 if (!store) return js_mkerr(js, "Failed to create WebAssembly store"); 1099 1100 valtype = wasm_valtype_new(kind); 1101 globaltype = wasm_globaltype_new(valtype, js_truthy(js, mutable_val) ? WASM_VAR : WASM_CONST); 1102 global = globaltype ? wasm_global_new(store, globaltype, &initial) : NULL; 1103 1104 wasm_globaltype_delete(globaltype); 1105 1106 if (!global) { 1107 wasm_store_delete(store); 1108 return js_throw(js, wasm_make_runtime_error(js, "Failed to create WebAssembly.Global")); 1109 } 1110 1111 result = wasm_wrap_extern_object( 1112 js, WASM_EXTERN_WRAP_GLOBAL, g_wasm_global_proto, BRAND_WASM_GLOBAL, 1113 store, true, global, js_mkundef() 1114 ); 1115 if (vtype(result) == T_OBJ) { 1116 wasm_extern_handle_t *handle = wasm_extern_handle(result, WASM_EXTERN_WRAP_GLOBAL); 1117 if (handle) { 1118 handle->use_cached_value = true; 1119 handle->cached_value = initial; 1120 } 1121 js_set_finalizer(result, wasm_extern_finalize); 1122 } 1123 return result; 1124} 1125 1126static ant_value_t js_wasm_memory_buffer_getter(ant_t *js, ant_value_t *args, int nargs) { 1127 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_MEMORY); 1128 byte_t *data; size_t len; ArrayBufferData *buffer; 1129 1130 if (!handle || !handle->as.memory) 1131 return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Memory"); 1132 1133 data = wasm_memory_data(handle->as.memory); 1134 len = wasm_memory_data_size(handle->as.memory); 1135 buffer = calloc(1, sizeof(ArrayBufferData)); 1136 1137 if (!buffer) return js_mkerr(js, "out of memory"); 1138 buffer->data = (uint8_t *)data; 1139 buffer->length = len; 1140 buffer->capacity = len; 1141 buffer->ref_count = 1; 1142 1143 return create_arraybuffer_obj(js, buffer); 1144} 1145 1146static ant_value_t js_wasm_memory_grow(ant_t *js, ant_value_t *args, int nargs) { 1147 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_MEMORY); 1148 wasm_memory_pages_t old_size; 1149 uint32_t delta; 1150 1151 if (!handle || !handle->as.memory) 1152 return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Memory"); 1153 1154 delta = (uint32_t)(nargs > 0 ? js_to_number(js, args[0]) : 0); 1155 old_size = wasm_memory_size(handle->as.memory); 1156 1157 if (delta == 0) return js_mknum((double)old_size); 1158 1159 wasm_module_inst_t inst = (wasm_module_inst_t)handle->as.memory->inst_comm_rt; 1160 if (!inst) 1161 return js_mkerr_typed(js, JS_ERR_RANGE, "Memory instance not available"); 1162 1163 if (inst->module_type == Wasm_Module_Bytecode) { 1164 WASMModuleInstance *wasm_inst = (WASMModuleInstance *)inst; 1165 WASMMemoryInstance *mem_inst = wasm_inst->memories[handle->as.memory->memory_idx_rt]; 1166 uint32_t needed = mem_inst->cur_page_count + delta; 1167 if (needed > mem_inst->max_page_count) mem_inst->max_page_count = needed; 1168 } 1169 1170 if (!wasm_runtime_enlarge_memory(inst, (uint64_t)delta)) 1171 return js_mkerr_typed(js, JS_ERR_RANGE, "Failed to grow memory by %u pages", delta); 1172 1173 return js_mknum((double)old_size); 1174} 1175 1176static ant_value_t js_wasm_memory_ctor(ant_t *js, ant_value_t *args, int nargs) { 1177 if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Memory constructor requires 'new'"); 1178 return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support standalone WebAssembly.Memory"); 1179} 1180 1181static ant_value_t js_wasm_table_length_getter(ant_t *js, ant_value_t *args, int nargs) { 1182 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); 1183 if (!handle || !handle->as.table) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); 1184 return js_mknum((double)wasm_table_size(handle->as.table)); 1185} 1186 1187static ant_value_t js_wasm_table_get(ant_t *js, ant_value_t *args, int nargs) { 1188 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); 1189 wasm_ref_t *ref; 1190 wasm_func_t *func; 1191 uint32_t index; 1192 1193 if (!handle || !handle->as.table) 1194 return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); 1195 1196 index = (uint32_t)(nargs > 0 ? js_to_number(js, args[0]) : 0); 1197 ref = wasm_table_get(handle->as.table, index); 1198 1199 if (!ref) return js_mknull(); 1200 func = wasm_ref_as_func(ref); 1201 1202 if (func) { 1203 ant_value_t owner = js_get_slot(js->this_val, SLOT_ENTRIES); 1204 ant_value_t wrapped = wasm_wrap_func(js, func, owner, true); 1205 wasm_ref_delete(ref); 1206 return wrapped; 1207 } 1208 1209 wasm_ref_delete(ref); 1210 return js_mknull(); 1211} 1212 1213static ant_value_t js_wasm_table_set(ant_t *js, ant_value_t *args, int nargs) { 1214 wasm_extern_handle_t *handle = wasm_extern_handle(js->this_val, WASM_EXTERN_WRAP_TABLE); 1215 wasm_ref_t *ref = NULL; 1216 uint32_t index; 1217 1218 if (!handle || !handle->as.table) return js_mkerr_typed(js, JS_ERR_TYPE, "Expected a WebAssembly.Table"); 1219 if (nargs < 2) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table.set requires 2 arguments"); 1220 1221 index = (uint32_t)js_to_number(js, args[0]); 1222 if (!(vtype(args[1]) == T_NULL || vtype(args[1]) == T_UNDEF)) { 1223 ant_value_t state; 1224 wasm_func_handle_t *func_handle; 1225 1226 if (!is_callable(args[1])) 1227 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table.set expects a WebAssembly function or null"); 1228 1229 state = js_get_slot(args[1], SLOT_DATA); 1230 if (!is_object_type(state) || !js_check_native_tag(state, WASM_FUNC_STATE_TAG)) 1231 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table.set expects a WebAssembly function or null"); 1232 1233 func_handle = (wasm_func_handle_t *)js_get_native_ptr(state); 1234 if (!func_handle || !func_handle->func) 1235 return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table.set expects a WebAssembly function or null"); 1236 1237 ref = wasm_func_as_ref(func_handle->func); 1238 if (!ref) return js_mkerr_typed(js, JS_ERR_TYPE, "Failed to materialize WebAssembly function reference"); 1239 } 1240 1241 if (!wasm_table_set(handle->as.table, index, ref)) { 1242 if (ref) wasm_ref_delete(ref); 1243 return js_mkerr_typed(js, JS_ERR_TYPE, "Failed to update WebAssembly.Table"); 1244 } 1245 1246 return js_mkundef(); 1247} 1248 1249static ant_value_t js_wasm_table_grow(ant_t *js, ant_value_t *args, int nargs) { 1250 return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support host-side table.grow"); 1251} 1252 1253static ant_value_t js_wasm_table_ctor(ant_t *js, ant_value_t *args, int nargs) { 1254 if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.Table constructor requires 'new'"); 1255 return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not support standalone WebAssembly.Table"); 1256} 1257 1258static ant_value_t js_wasm_tag_ctor(ant_t *js, ant_value_t *args, int nargs) { 1259 return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not expose WebAssembly.Tag"); 1260} 1261 1262static ant_value_t js_wasm_exception_ctor(ant_t *js, ant_value_t *args, int nargs) { 1263 return js_mkerr_typed(js, JS_ERR_TYPE, "The current WAMR backend does not expose WebAssembly.Exception"); 1264} 1265 1266static ant_value_t js_wasm_validate(ant_t *js, ant_value_t *args, int nargs) { 1267 wasm_byte_vec_t binary = WASM_EMPTY_VEC; 1268 wasm_store_t *store; 1269 1270 bool ok; 1271 char error_buf[128] = {0}; 1272 bool suppress_wasi_warning = false; 1273 1274 if (nargs < 1) return js_false; 1275 if (!ensure_wasm_engine()) return js_false; 1276 if (!(store = wasm_store_new(g_wasm_engine))) return js_false; 1277 1278 if (!wasm_buffer_source_to_vec(js, args[0], &binary, error_buf, sizeof(error_buf))) { 1279 wasm_store_delete(store); 1280 return js_false; 1281 } 1282 1283 suppress_wasi_warning = wasi_bytes_need_wasi_command_warning_suppression( 1284 (const uint8_t *)binary.data, binary.size 1285 ); 1286 1287 if (suppress_wasi_warning) wasm_runtime_set_log_level(WASM_LOG_LEVEL_ERROR); 1288 ok = wasm_module_validate(store, &binary); 1289 1290 if (suppress_wasi_warning) wasm_runtime_set_log_level(WASM_LOG_LEVEL_WARNING); 1291 wasm_byte_vec_delete(&binary); 1292 wasm_store_delete(store); 1293 1294 return js_bool(ok); 1295} 1296 1297static ant_value_t js_wasm_compile(ant_t *js, ant_value_t *args, int nargs) { 1298 ant_value_t promise = js_mkpromise(js); 1299 ant_value_t module = js_mkundef(); 1300 ant_value_t err; 1301 1302 if (nargs < 1) { 1303 wasm_reject_with_error(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.compile requires 1 argument")); 1304 return promise; 1305 } 1306 1307 err = wasm_module_from_bytes(js, args[0], &module); 1308 if (is_err(err) || vtype(module) != T_OBJ) { 1309 wasm_reject_with_error(js, promise, wasm_error_value(js, err)); 1310 return promise; 1311 } 1312 1313 js_resolve_promise(js, promise, module); 1314 return promise; 1315} 1316 1317static ant_value_t js_wasm_instantiate(ant_t *js, ant_value_t *args, int nargs) { 1318 ant_value_t promise = js_mkpromise(js); 1319 ant_value_t module = js_mkundef(); 1320 ant_value_t instance = js_mkundef(); 1321 ant_value_t import_obj = (nargs >= 2 && is_object_type(args[1])) ? args[1] : js_mkundef(); 1322 ant_value_t err; 1323 1324 if (nargs < 1) { 1325 wasm_reject_with_error(js, promise, js_mkerr_typed(js, JS_ERR_TYPE, "WebAssembly.instantiate requires 1 argument")); 1326 return promise; 1327 } 1328 1329 if (wasm_module_handle(args[0])) { 1330 err = wasm_instantiate_module(js, args[0], import_obj, &instance); 1331 if (is_err(err) || vtype(instance) != T_OBJ) { 1332 wasm_reject_with_error(js, promise, wasm_error_value(js, err)); 1333 return promise; 1334 } 1335 js_resolve_promise(js, promise, instance); 1336 return promise; 1337 } 1338 1339 err = wasm_module_from_bytes(js, args[0], &module); 1340 if (is_err(err) || vtype(module) != T_OBJ) { 1341 wasm_reject_with_error(js, promise, wasm_error_value(js, err)); 1342 return promise; 1343 } 1344 1345 err = wasm_instantiate_module(js, module, import_obj, &instance); 1346 if (is_err(err) || vtype(instance) != T_OBJ) { 1347 wasm_reject_with_error(js, promise, wasm_error_value(js, err)); 1348 return promise; 1349 } 1350 1351 ant_value_t result = js_mkobj(js); 1352 js_set(js, result, "module", module); 1353 js_set(js, result, "instance", instance); 1354 js_resolve_promise(js, promise, result); 1355 1356 return promise; 1357} 1358 1359static ant_value_t js_wasm_compile_error_ctor(ant_t *js, ant_value_t *args, int nargs) { 1360 ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 1361 if (is_err(msg)) return msg; 1362 return wasm_make_error(js, g_wasm_compileerror_proto, "CompileError", js_str(js, msg)); 1363} 1364 1365static ant_value_t js_wasm_link_error_ctor(ant_t *js, ant_value_t *args, int nargs) { 1366 ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 1367 if (is_err(msg)) return msg; 1368 return wasm_make_error(js, g_wasm_linkerror_proto, "LinkError", js_str(js, msg)); 1369} 1370 1371static ant_value_t js_wasm_runtime_error_ctor(ant_t *js, ant_value_t *args, int nargs) { 1372 ant_value_t msg = (nargs > 0) ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0); 1373 if (is_err(msg)) return msg; 1374 return wasm_make_error(js, g_wasm_runtimeerror_proto, "RuntimeError", js_str(js, msg)); 1375} 1376 1377void gc_mark_wasm(ant_t *js, gc_mark_fn mark) { 1378 for (size_t i = 0; i < g_wasm_import_env_count; i++) { 1379 wasm_import_func_env_t *env = g_wasm_import_envs[i]; 1380 mark(js, env->fn); 1381 mark(js, env->owner); 1382 } 1383 1384 if (g_wasm_pending_import_throw_exists) 1385 mark(js, g_wasm_pending_import_throw); 1386} 1387 1388void init_wasm_module(void) { 1389 ant_t *js = rt->js; 1390 ant_value_t global = js_glob(js); 1391 1392 ant_value_t error_proto = js_get_ctor_proto(js, "Error", 5); 1393 ant_value_t ns = js_mkobj(js); 1394 1395 if (!ensure_wasm_engine()) return; 1396 1397 g_wasm_module_proto = js_mkobj(js); 1398 g_wasm_instance_proto = js_mkobj(js); 1399 g_wasm_global_proto = js_mkobj(js); 1400 g_wasm_memory_proto = js_mkobj(js); 1401 g_wasm_table_proto = js_mkobj(js); 1402 g_wasm_tag_proto = js_mkobj(js); 1403 g_wasm_exception_proto = js_mkobj(js); 1404 1405 g_wasm_compileerror_proto = js_mkobj(js); 1406 g_wasm_linkerror_proto = js_mkobj(js); 1407 g_wasm_runtimeerror_proto = js_mkobj(js); 1408 1409 js_set_proto_init(g_wasm_module_proto, js->sym.object_proto); 1410 js_set_proto_init(g_wasm_instance_proto, js->sym.object_proto); 1411 js_set_proto_init(g_wasm_global_proto, js->sym.object_proto); 1412 js_set_proto_init(g_wasm_memory_proto, js->sym.object_proto); 1413 js_set_proto_init(g_wasm_table_proto, js->sym.object_proto); 1414 js_set_proto_init(g_wasm_tag_proto, js->sym.object_proto); 1415 js_set_proto_init(g_wasm_exception_proto, js->sym.object_proto); 1416 1417 js_set_proto_init(g_wasm_compileerror_proto, error_proto); 1418 js_set_proto_init(g_wasm_linkerror_proto, error_proto); 1419 js_set_proto_init(g_wasm_runtimeerror_proto, error_proto); 1420 1421 js_set(js, g_wasm_global_proto, "valueOf", js_mkfun(js_wasm_global_value_of)); 1422 js_set_getter_desc(js, g_wasm_global_proto, "value", 5, js_mkfun(js_wasm_global_value_getter), JS_DESC_C); 1423 js_set_setter_desc(js, g_wasm_global_proto, "value", 5, js_mkfun(js_wasm_global_value_setter), JS_DESC_C); 1424 1425 js_set_getter_desc(js, g_wasm_instance_proto, "exports", 7, js_mkfun(js_wasm_instance_exports_getter), JS_DESC_C); 1426 js_set_getter_desc(js, g_wasm_memory_proto, "buffer", 6, js_mkfun(js_wasm_memory_buffer_getter), JS_DESC_C); 1427 js_set(js, g_wasm_memory_proto, "grow", js_mkfun(js_wasm_memory_grow)); 1428 1429 js_set_getter_desc(js, g_wasm_table_proto, "length", 6, js_mkfun(js_wasm_table_length_getter), JS_DESC_C); 1430 js_set(js, g_wasm_table_proto, "get", js_mkfun(js_wasm_table_get)); 1431 js_set(js, g_wasm_table_proto, "set", js_mkfun(js_wasm_table_set)); 1432 js_set(js, g_wasm_table_proto, "grow", js_mkfun(js_wasm_table_grow)); 1433 1434 ant_value_t module_ctor = js_make_ctor(js, js_wasm_module_ctor, g_wasm_module_proto, "Module", 6); 1435 ant_value_t instance_ctor = js_make_ctor(js, js_wasm_instance_ctor, g_wasm_instance_proto, "Instance", 8); 1436 ant_value_t global_ctor = js_make_ctor(js, js_wasm_global_ctor, g_wasm_global_proto, "Global", 6); 1437 ant_value_t memory_ctor = js_make_ctor(js, js_wasm_memory_ctor, g_wasm_memory_proto, "Memory", 6); 1438 ant_value_t table_ctor = js_make_ctor(js, js_wasm_table_ctor, g_wasm_table_proto, "Table", 5); 1439 ant_value_t tag_ctor = js_make_ctor(js, js_wasm_tag_ctor, g_wasm_tag_proto, "Tag", 3); 1440 ant_value_t exception_ctor = js_make_ctor(js, js_wasm_exception_ctor, g_wasm_exception_proto, "Exception", 9); 1441 1442 ant_value_t compile_error_ctor = js_make_ctor(js, js_wasm_compile_error_ctor, g_wasm_compileerror_proto, "CompileError", 12); 1443 ant_value_t link_error_ctor = js_make_ctor(js, js_wasm_link_error_ctor, g_wasm_linkerror_proto, "LinkError", 9); 1444 ant_value_t runtime_error_ctor = js_make_ctor(js, js_wasm_runtime_error_ctor, g_wasm_runtimeerror_proto, "RuntimeError", 12); 1445 1446 js_set(js, module_ctor, "imports", js_mkfun(js_wasm_module_imports)); 1447 js_set(js, module_ctor, "exports", js_mkfun(js_wasm_module_exports)); 1448 1449 js_set(js, ns, "validate", js_mkfun(js_wasm_validate)); 1450 js_set(js, ns, "compile", js_mkfun(js_wasm_compile)); 1451 js_set(js, ns, "instantiate", js_mkfun(js_wasm_instantiate)); 1452 1453 js_set(js, ns, "Module", module_ctor); 1454 js_set(js, ns, "Instance", instance_ctor); 1455 js_set(js, ns, "Global", global_ctor); 1456 js_set(js, ns, "Memory", memory_ctor); 1457 js_set(js, ns, "Table", table_ctor); 1458 js_set(js, ns, "Tag", tag_ctor); 1459 js_set(js, ns, "Exception", exception_ctor); 1460 js_set(js, ns, "CompileError", compile_error_ctor); 1461 js_set(js, ns, "LinkError", link_error_ctor); 1462 js_set(js, ns, "RuntimeError", runtime_error_ctor); 1463 1464 js_set(js, global, "WebAssembly", ns); 1465 js_set_descriptor(js, global, "WebAssembly", 11, JS_DESC_W | JS_DESC_C); 1466}