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.

handle exit messages in wasm

+105 -12
+68 -12
src/modules/wasm.c
··· 81 81 static ant_value_t g_wasm_tag_proto = 0; 82 82 static ant_value_t g_wasm_exception_proto = 0; 83 83 84 - static ant_value_t g_wasm_compileerror_proto = 0; 85 - static ant_value_t g_wasm_linkerror_proto = 0; 86 - static ant_value_t g_wasm_runtimeerror_proto = 0; 84 + static ant_value_t g_wasm_compileerror_proto = 0; 85 + static ant_value_t g_wasm_linkerror_proto = 0; 86 + static ant_value_t g_wasm_runtimeerror_proto = 0; 87 + static ant_value_t g_wasm_pending_import_throw = 0; 87 88 88 89 static wasm_engine_t *g_wasm_engine = NULL; 89 90 static wasm_import_func_env_t **g_wasm_import_envs = NULL; 91 + static bool g_wasm_pending_import_throw_exists = false; 92 + 93 + static 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 + 98 + static 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 + 103 + static 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 + } 90 110 91 111 static void wasm_register_import_env(wasm_import_func_env_t *env) { 92 112 if (g_wasm_import_env_count == g_wasm_import_env_cap) { ··· 491 511 } 492 512 } 493 513 514 + wasm_clear_pending_import_throw(); 494 515 trap = wasm_func_call(func, &wasm_args, &wasm_results); 516 + 495 517 if (trap) { 518 + if (g_wasm_pending_import_throw_exists) { 519 + result = wasm_consume_pending_import_throw(); 520 + wasm_val_vec_delete(&wasm_args); 521 + wasm_val_vec_delete(&wasm_results); 522 + wasm_functype_delete(type); 523 + wasm_trap_delete(trap); 524 + return js_throw(js, result); 525 + } 526 + 496 527 result = wasm_trap_to_error(js, trap); 497 528 wasm_val_vec_delete(&wasm_args); 498 529 wasm_val_vec_delete(&wasm_results); 499 530 wasm_functype_delete(type); 500 531 return js_throw(js, result); 501 532 } 502 - 533 + 534 + wasm_clear_pending_import_throw(); 503 535 result = wasm_js_from_result_vec(js, &wasm_results); 504 536 505 537 wasm_val_vec_delete(&wasm_args); 506 538 wasm_val_vec_delete(&wasm_results); 507 539 wasm_functype_delete(type); 540 + 508 541 return result; 509 542 } 510 543 ··· 718 751 js_args[i] = wasm_value_to_js(js, &args->data[i]); 719 752 } 720 753 721 - result = sv_vm_call(js->vm, js, env->fn, js_mkundef(), js_args, args ? (int)args->size : 0, NULL, false); 754 + result = sv_vm_call( 755 + js->vm, js, env->fn, js_mkundef(), 756 + js_args, args ? (int)args->size : 0, NULL, false 757 + ); 722 758 free(js_args); 723 759 724 760 if (is_err(result)) { 761 + ant_value_t thrown = js->thrown_exists ? js->thrown_value : result; 762 + wasm_set_pending_import_throw(thrown); 763 + 725 764 const char *msg = "WebAssembly import threw"; 726 765 if (vtype(js->thrown_value) == T_OBJ) { 727 766 const char *message = get_str_prop(js, js->thrown_value, "message", 7, NULL); 728 767 if (message && *message) msg = message; 729 768 } 769 + 730 770 wasm_name_new_from_string_nt(&trap_msg, msg); 731 771 wasm_trap_t *trap = wasm_trap_new(env->store, &trap_msg); 732 772 wasm_byte_vec_delete(&trap_msg); 773 + 733 774 return trap; 734 775 } 735 776 ··· 893 934 if (imports && import_types.size > 0) 894 935 import_vec = (wasm_extern_vec_t){ import_types.size, imports, import_types.size, sizeof(*imports), NULL }; 895 936 937 + wasm_clear_pending_import_throw(); 896 938 instance = wasm_instance_new_with_args(module_handle->store, module_handle->module, &import_vec, &trap, KILOBYTE(32), 0); 897 939 } 898 940 ··· 904 946 if (owned_host_funcs[i]) wasm_func_delete(owned_host_funcs[i]); 905 947 } 906 948 free(owned_host_funcs); 907 - if (trap) return wasm_trap_to_error(js, trap); 949 + 950 + if (trap) { 951 + if (g_wasm_pending_import_throw_exists) { 952 + ant_value_t thrown = wasm_consume_pending_import_throw(); 953 + wasm_trap_delete(trap); 954 + return js_throw(js, thrown); 955 + } 956 + return wasm_trap_to_error(js, trap); 957 + } 958 + 908 959 return wasm_make_link_error(js, "Failed to instantiate WebAssembly module"); 909 960 } 910 - 961 + 962 + wasm_clear_pending_import_throw(); 911 963 wasm_instance_exports(instance, &exports); 912 964 wasm_module_exports(module_handle->module, &export_types); 913 965 ··· 1324 1376 } 1325 1377 1326 1378 void gc_mark_wasm(ant_t *js, gc_mark_fn mark) { 1327 - for (size_t i = 0; i < g_wasm_import_env_count; i++) { 1328 - wasm_import_func_env_t *env = g_wasm_import_envs[i]; 1329 - mark(js, env->fn); 1330 - mark(js, env->owner); 1331 - }} 1379 + for (size_t i = 0; i < g_wasm_import_env_count; i++) { 1380 + wasm_import_func_env_t *env = g_wasm_import_envs[i]; 1381 + mark(js, env->fn); 1382 + mark(js, env->owner); 1383 + } 1384 + 1385 + if (g_wasm_pending_import_throw_exists) 1386 + mark(js, g_wasm_pending_import_throw); 1387 + } 1332 1388 1333 1389 void init_wasm_module(void) { 1334 1390 ant_t *js = rt->js;
+37
tests/test_wasm_webassembly_api.mjs
··· 22 22 4, 110, 105, 110, 101, 0, 1, 5, 116, 97, 98, 108, 101, 1, 0, 9, 8, 1, 0, 65, 0, 11, 2, 0, 1, 10, 11, 2, 4, 0, 65, 7, 11, 4, 0, 65, 9, 11, 0, 21, 4, 23 23 110, 97, 109, 101, 1, 14, 2, 0, 5, 115, 101, 118, 101, 110, 1, 4, 110, 105, 110, 101 24 24 ]); 25 + const throwingImportFixture = new Uint8Array([ 26 + 0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 2, 12, 1, 3, 101, 110, 118, 4, 102, 97, 105, 108, 0, 0, 3, 2, 1, 0, 7, 7, 1, 3, 114, 117, 110, 0, 1, 27 + 10, 6, 1, 4, 0, 16, 0, 11 28 + ]); 25 29 26 30 assert(WebAssembly.validate(incrementer) === true, 'incrementer.wasm should validate'); 27 31 ··· 48 52 assert(secondTableEntry() === 9, 'table.get(1) should invoke the second table function'); 49 53 tableInstance.exports.table.set(0, tableInstance.exports.nine); 50 54 assert(tableInstance.exports.table.get(0)() === 9, 'table.set() should accept wasm-exported functions'); 55 + 56 + const throwingModule = new WebAssembly.Module(throwingImportFixture); 57 + 58 + let sawPrimitiveThrow = false; 59 + try { 60 + new WebAssembly.Instance(throwingModule, { 61 + env: { 62 + fail() { 63 + throw Infinity; 64 + } 65 + } 66 + }).exports.run(); 67 + } catch (error) { 68 + sawPrimitiveThrow = true; 69 + assert(error === Infinity, 'import throws should preserve primitive thrown values'); 70 + } 71 + assert(sawPrimitiveThrow, 'primitive import throws should escape the wasm call'); 72 + 73 + const thrownError = new Error('import boom'); 74 + let sawErrorThrow = false; 75 + try { 76 + new WebAssembly.Instance(throwingModule, { 77 + env: { 78 + fail() { 79 + throw thrownError; 80 + } 81 + } 82 + }).exports.run(); 83 + } catch (error) { 84 + sawErrorThrow = true; 85 + assert(error === thrownError, 'import throws should preserve original Error objects'); 86 + } 87 + assert(sawErrorThrow, 'Error import throws should escape the wasm call'); 51 88 52 89 const compiled = await WebAssembly.compile(incrementer); 53 90 assert(compiled instanceof WebAssembly.Module, 'WebAssembly.compile() should resolve a module');