diff --git a/crates/cli-support/src/js/js2rust.rs b/crates/cli-support/src/js/js2rust.rs index 13a531f8..ed04ae30 100644 --- a/crates/cli-support/src/js/js2rust.rs +++ b/crates/cli-support/src/js/js2rust.rs @@ -488,8 +488,8 @@ impl<'a, 'b> Js2Rust<'a, 'b> { if self.cx.config.weak_refs { self.ret_expr.push_str(&format!( "\ - addCleanup(this, this.ptr, free{}); - ", + {}FinalizationGroup.register(this, this.ptr, this.ptr); + ", name )); } diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 18213433..4cf6cb00 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -1103,35 +1103,6 @@ impl<'a> Context<'a> { let mut dst = format!("class {} {{\n", name); let mut ts_dst = format!("export {}", dst); - let (mkweakref, freeref) = if self.config.weak_refs { - // When weak refs are enabled we use them to automatically free the - // contents of an exported rust class when it's gc'd. Note that a - // manual `free` function still exists for deterministic - // destruction. - // - // This is implemented by using a `WeakRefGroup` to run finalizers - // for all `WeakRef` objects that it creates. Upon construction of - // a new wasm object we use `makeRef` with "holdings" of a thunk to - // free the wasm instance. Once the `this` (the instance we're - // creating) is gc'd then the finalizer will run with the - // `WeakRef`, and we'll pull out the `holdings`, our pointer. - // - // Note, though, that if manual finalization happens we want to - // cancel the `WeakRef`-generated finalization, so we retain the - // `WeakRef` in a global map. This global map is then used to - // `drop()` the `WeakRef` (cancel finalization) whenever it is - // finalized. - self.expose_cleanup_groups(); - let mk = format!("addCleanup(this, this.ptr, free{});", name); - let free = " - CLEANUPS_MAP.get(ptr).drop(); - CLEANUPS_MAP.delete(ptr); - "; - (mk, free) - } else { - (String::new(), "") - }; - if self.config.debug && !class.has_constructor { dst.push_str( " @@ -1165,29 +1136,52 @@ impl<'a> Context<'a> { }} ", name, - mkweakref.replace("this", "obj"), + if self.config.weak_refs { + format!("{}FinalizationGroup.register(obj, obj.ptr, obj.ptr);", name) + } else { + String::new() + }, )); } self.global(&format!( " function free{}(ptr) {{ - {} wasm.{}(ptr); }} ", name, - freeref, wasm_bindgen_shared::free_function(&name) )); + + if self.config.weak_refs { + self.global(&format!( + " + const {}FinalizationGroup = new FinalizationGroup((items) => {{ + for (const ptr of items) {{ + free{}(ptr); + }} + }}); + ", + name, + name, + )); + } + dst.push_str(&format!( " free() {{ const ptr = this.ptr; this.ptr = 0; + {} free{}(ptr); }} ", + if self.config.weak_refs { + format!("{}FinalizationGroup.unregister(ptr);", name) + } else { + String::new() + }, name, )); ts_dst.push_str(" free(): void;"); @@ -2279,23 +2273,6 @@ impl<'a> Context<'a> { ); } - fn expose_cleanup_groups(&mut self) { - if !self.should_write_global("cleanup_groups") { - return; - } - self.global( - " - const CLEANUPS = new WeakRefGroup(x => x.holdings()); - const CLEANUPS_MAP = new Map(); - - function addCleanup(obj, ptr, free) { - const ref = CLEANUPS.makeRef(obj, () => free(ptr)); - CLEANUPS_MAP.set(ptr, ref); - } - ", - ); - } - fn describe(&mut self, name: &str) -> Option { let name = format!("__wbindgen_describe_{}", name); let descriptor = self.interpreter.interpret_descriptor(&name, self.module)?; diff --git a/crates/cli-support/src/lib.rs b/crates/cli-support/src/lib.rs index 53f22d25..ec3dbef0 100755 --- a/crates/cli-support/src/lib.rs +++ b/crates/cli-support/src/lib.rs @@ -25,7 +25,7 @@ pub struct Bindgen { remove_name_section: bool, remove_producers_section: bool, emit_start: bool, - // Experimental support for `WeakRefGroup`, an upcoming ECMAScript feature. + // Experimental support for weakrefs, an upcoming ECMAScript feature. // Currently only enable-able through an env var. weak_refs: bool, // Experimental support for the wasm threads proposal, transforms the wasm