Skip to content

Commit 6796bc6

Browse files
committed
Communicate exceptions through global memory
Instead of allocating space on the stack and returning a pointer we should be able to use a single global memory location to communicate this error payload information. This shouldn't run into any reentrancy issues since it's only stored just before returning to wasm and it's always read just after returning from wasm.
1 parent 535aa31 commit 6796bc6

File tree

4 files changed

+35
-39
lines changed

4 files changed

+35
-39
lines changed

crates/backend/src/codegen.rs

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -974,28 +974,12 @@ impl TryToTokens for ast::ImportFunction {
974974
}
975975

976976
let mut exceptional_ret = quote!();
977-
let exn_data = if self.catch {
978-
let exn_data = Ident::new("exn_data", Span::call_site());
979-
let exn_data_ptr = Ident::new("exn_data_ptr", Span::call_site());
980-
abi_argument_names.push(exn_data_ptr.clone());
981-
abi_arguments.push(quote! { #exn_data_ptr: *mut u32 });
977+
if self.catch {
982978
convert_ret = quote! { Ok(#convert_ret) };
983979
exceptional_ret = quote! {
984-
if #exn_data[0] == 1 {
985-
return Err(
986-
<
987-
wasm_bindgen::JsValue as wasm_bindgen::convert::FromWasmAbi
988-
>::from_abi(#exn_data[1], &mut wasm_bindgen::convert::GlobalStack::new())
989-
)
990-
}
980+
wasm_bindgen::__rt::take_last_exception()?;
991981
};
992-
quote! {
993-
let mut #exn_data = [0; 2];
994-
let #exn_data_ptr = #exn_data.as_mut_ptr();
995-
}
996-
} else {
997-
quote!()
998-
};
982+
}
999983

1000984
let rust_name = &self.rust_name;
1001985
let import_name = &self.shim;
@@ -1055,7 +1039,6 @@ impl TryToTokens for ast::ImportFunction {
10551039
#extern_fn
10561040

10571041
unsafe {
1058-
#exn_data
10591042
let #ret_ident = {
10601043
let mut __stack = wasm_bindgen::convert::GlobalStack::new();
10611044
#(#arg_conversions)*

crates/cli-support/src/js/mod.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,27 +1419,23 @@ impl<'a> Context<'a> {
14191419
if !self.should_write_global("handle_error") {
14201420
return Ok(());
14211421
}
1422-
self.expose_uint32_memory();
1422+
self.require_internal_export("__wbindgen_exn_store")?;
14231423
if self.config.anyref {
14241424
self.expose_add_to_anyref_table()?;
14251425
self.global(
14261426
"
1427-
function handleError(exnptr, e) {
1427+
function handleError(e) {
14281428
const idx = addToAnyrefTable(e);
1429-
const view = getUint32Memory();
1430-
view[exnptr / 4] = 1;
1431-
view[exnptr / 4 + 1] = idx;
1429+
wasm.__wbindgen_exn_store(idx);
14321430
}
14331431
",
14341432
);
14351433
} else {
14361434
self.expose_add_heap_object();
14371435
self.global(
14381436
"
1439-
function handleError(exnptr, e) {
1440-
const view = getUint32Memory();
1441-
view[exnptr / 4] = 1;
1442-
view[exnptr / 4 + 1] = addHeapObject(e);
1437+
function handleError(e) {
1438+
wasm.__wbindgen_exn_store(addHeapObject(e));
14431439
}
14441440
",
14451441
);
@@ -2115,7 +2111,7 @@ impl<'a> Context<'a> {
21152111

21162112
fn export_function_table(&mut self) -> Result<(), Error> {
21172113
if !self.should_write_global("wbg-function-table") {
2118-
return Ok(())
2114+
return Ok(());
21192115
}
21202116
let id = match self.module.tables.main_function_table()? {
21212117
Some(id) => id,
@@ -2192,7 +2188,7 @@ impl ExportedClass {
21922188
field: &str,
21932189
js: &str,
21942190
prefix: &str,
2195-
ret_ty: &str
2191+
ret_ty: &str,
21962192
) -> &mut bool {
21972193
self.contents.push_str(docs);
21982194
self.contents.push_str(prefix);
@@ -2215,7 +2211,8 @@ impl ExportedClass {
22152211
/// generated output is deterministic and we do so by ensuring that iteration of
22162212
/// hash maps is consistently sorted.
22172213
fn sorted_iter<K, V>(map: &HashMap<K, V>) -> impl Iterator<Item = (&K, &V)>
2218-
where K: Ord,
2214+
where
2215+
K: Ord,
22192216
{
22202217
let mut pairs = map.iter().collect::<Vec<_>>();
22212218
pairs.sort_by_key(|(k, _)| *k);

crates/cli-support/src/js/rust2js.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -928,7 +928,7 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
928928
try {{\n\
929929
{}
930930
}} catch (e) {{\n\
931-
handleError(exnptr, e);\n\
931+
handleError(e);\n\
932932
}}\
933933
",
934934
&invoc
@@ -973,12 +973,6 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
973973
let mut ret = String::new();
974974
ret.push_str("function(");
975975
ret.push_str(&self.shim_arguments.join(", "));
976-
if self.catch {
977-
if self.shim_arguments.len() > 0 {
978-
ret.push_str(", ")
979-
}
980-
ret.push_str("exnptr");
981-
}
982976
ret.push_str(") {\n");
983977
ret.push_str(&self.prelude);
984978

src/lib.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,28 @@ pub mod __rt {
10671067
pub fn link_mem_intrinsics() {
10681068
crate::anyref::link_intrinsics();
10691069
}
1070+
1071+
static mut GLOBAL_EXNDATA: [u32; 2] = [0; 2];
1072+
1073+
#[no_mangle]
1074+
pub unsafe extern "C" fn __wbindgen_exn_store(idx: u32) {
1075+
assert_eq!(GLOBAL_EXNDATA[0], 0);
1076+
GLOBAL_EXNDATA[0] = 1;
1077+
GLOBAL_EXNDATA[1] = idx;
1078+
}
1079+
1080+
pub fn take_last_exception() -> Result<(), super::JsValue> {
1081+
unsafe {
1082+
let ret = if GLOBAL_EXNDATA[0] == 1 {
1083+
Err(super::JsValue:: _new(GLOBAL_EXNDATA[1]))
1084+
} else {
1085+
Ok(())
1086+
};
1087+
GLOBAL_EXNDATA[0] = 0;
1088+
GLOBAL_EXNDATA[1] = 0;
1089+
return ret;
1090+
}
1091+
}
10701092
}
10711093

10721094
/// A wrapper type around slices and vectors for binding the `Uint8ClampedArray`

0 commit comments

Comments
 (0)