From 1c7dce6ae11b4ec7ccb0f0c592f048750dfb24f6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 8 Mar 2024 13:36:40 -0600 Subject: [PATCH] Add back in resources destructors to Rust exports (#888) * Add back in resources destructors to Rust exports This was accidentally left out of my refactoring from #871 meaning that exported Rust resources never actually got their destructors run because the `export!` macro forgot to drop things. Closes #887 * Get test passing for Go --- crates/rust/src/interface.rs | 31 +++++++++++++++++++++++++++++++ tests/runtime/resources.rs | 7 +++++++ tests/runtime/resources/wasm.c | 7 +++++++ tests/runtime/resources/wasm.go | 4 ++++ tests/runtime/resources/wasm.rs | 14 ++++++++++++++ tests/runtime/resources/world.wit | 2 ++ 6 files changed, 65 insertions(+) diff --git a/crates/rust/src/interface.rs b/crates/rust/src/interface.rs index 5dc4851f7..216114d3d 100644 --- a/crates/rust/src/interface.rs +++ b/crates/rust/src/interface.rs @@ -133,6 +133,7 @@ impl InterfaceGenerator<'_> { ) -> Result { let mut traits = BTreeMap::new(); let mut funcs_to_export = Vec::new(); + let mut resources_to_drop = Vec::new(); traits.insert(None, ("Guest".to_string(), Vec::new())); @@ -142,6 +143,7 @@ impl InterfaceGenerator<'_> { TypeDefKind::Resource => {} _ => continue, } + resources_to_drop.push(name); let camel = name.to_upper_camel_case(); traits.insert(Some(*id), (format!("Guest{camel}"), Vec::new())); } @@ -296,6 +298,29 @@ macro_rules! {macro_name} {{ }; self.generate_raw_cabi_export(func, &ty, "$($path_to_types)*"); } + let export_prefix = self.gen.opts.export_prefix.as_deref().unwrap_or(""); + for name in resources_to_drop { + let module = match self.identifier { + Identifier::Interface(_, key) => self.resolve.name_world_key(key), + Identifier::World(_) => unreachable!(), + }; + let camel = name.to_upper_camel_case(); + uwriteln!( + self.src, + r#" + const _: () = {{ + #[doc(hidden)] + #[export_name = "{export_prefix}{module}#[dtor]{name}"] + #[allow(non_snake_case)] + unsafe extern "C" fn dtor(rep: *mut u8) {{ + $($path_to_types)*::{camel}::dtor::< + <$ty as $($path_to_types)*::Guest>::{camel} + >(rep) + }} + }}; + "# + ); + } uwriteln!(self.src, "}};);"); uwriteln!(self.src, "}}"); uwriteln!(self.src, "#[doc(hidden)]"); @@ -2054,6 +2079,12 @@ impl {camel} {{ }} }} + #[doc(hidden)] + pub unsafe fn dtor(handle: *mut u8) {{ + Self::type_guard::(); + let _ = {box_path}::from_raw(handle as *mut _{camel}Rep); + }} + fn as_ptr(&self) -> *mut _{camel}Rep {{ {camel}::type_guard::(); unsafe {{ T::_resource_rep(self.handle()).cast() }} diff --git a/tests/runtime/resources.rs b/tests/runtime/resources.rs index a1bd3b209..627430469 100644 --- a/tests/runtime/resources.rs +++ b/tests/runtime/resources.rs @@ -92,9 +92,16 @@ fn run_test(exports: Exports, store: &mut Store>) -> Resu let z_add = exports.call_add(&mut *store, z_instance_1, z_instance_2)?; assert_eq!(z.call_get_a(&mut *store, z_add)?, 30); + let dropped_zs_start = z.call_num_dropped(&mut *store)?; + ResourceAny::resource_drop(x_instance, &mut *store)?; ResourceAny::resource_drop(z_instance_1, &mut *store)?; ResourceAny::resource_drop(z_instance_2, &mut *store)?; + let dropped_zs_end = z.call_num_dropped(&mut *store)?; + if dropped_zs_start != 0 { + assert_eq!(dropped_zs_end, dropped_zs_start + 2); + } + Ok(()) } diff --git a/tests/runtime/resources/wasm.c b/tests/runtime/resources/wasm.c index 7c012d6a1..3051f2496 100644 --- a/tests/runtime/resources/wasm.c +++ b/tests/runtime/resources/wasm.c @@ -57,10 +57,17 @@ void exports_x_destructor(exports_x_t* x) { free(x); } +static uint32_t NUM_Z_DROPPED = 0; + void exports_z_destructor(exports_z_t* z) { + NUM_Z_DROPPED += 1; free(z); } +uint32_t exports_static_z_num_dropped() { + return NUM_Z_DROPPED + 1; +} + exports_own_kebab_case_t exports_constructor_kebab_case(uint32_t a) { exports_kebab_case_t* kc_instance = (exports_kebab_case_t*)malloc(sizeof(exports_kebab_case_t)); kc_instance->a = a; diff --git a/tests/runtime/resources/wasm.go b/tests/runtime/resources/wasm.go index d257b4704..a94b319fd 100644 --- a/tests/runtime/resources/wasm.go +++ b/tests/runtime/resources/wasm.go @@ -52,6 +52,10 @@ func (z *MyZ) MethodZGetA() int32 { return z.a } +func (e ExportsImpl) StaticZNumDropped() uint32 { + return 0 +} + func (e ExportsImpl) Add(z ExportsZ, b ExportsZ) ExportsZ { return &MyZ{a: z.MethodZGetA() + b.MethodZGetA()} } diff --git a/tests/runtime/resources/wasm.rs b/tests/runtime/resources/wasm.rs index e88fd4ede..a7c06d106 100644 --- a/tests/runtime/resources/wasm.rs +++ b/tests/runtime/resources/wasm.rs @@ -79,6 +79,8 @@ impl exports::exports::GuestX for ComponentX { } } +static mut NUM_DROPPED_ZS: u32 = 0; + impl exports::exports::GuestZ for ComponentZ { fn new(a: i32) -> Self { Self { val: a } @@ -86,6 +88,18 @@ impl exports::exports::GuestZ for ComponentZ { fn get_a(&self) -> i32 { self.val } + + fn num_dropped() -> u32 { + unsafe { NUM_DROPPED_ZS + 1 } + } +} + +impl Drop for ComponentZ { + fn drop(&mut self) { + unsafe { + NUM_DROPPED_ZS += 1; + } + } } impl exports::exports::GuestKebabCase for ComponentKebabCase { diff --git a/tests/runtime/resources/world.wit b/tests/runtime/resources/world.wit index 637a95175..e9f3bb08b 100644 --- a/tests/runtime/resources/world.wit +++ b/tests/runtime/resources/world.wit @@ -21,6 +21,8 @@ world resources { resource z { constructor(a: s32); get-a: func() -> s32; + + num-dropped: static func() -> u32; } add: func(a: borrow, b: borrow) -> own;