Skip to content

Commit 1c7dce6

Browse files
authored
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
1 parent 046ddcb commit 1c7dce6

File tree

6 files changed

+65
-0
lines changed

6 files changed

+65
-0
lines changed

crates/rust/src/interface.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ impl InterfaceGenerator<'_> {
133133
) -> Result<String> {
134134
let mut traits = BTreeMap::new();
135135
let mut funcs_to_export = Vec::new();
136+
let mut resources_to_drop = Vec::new();
136137

137138
traits.insert(None, ("Guest".to_string(), Vec::new()));
138139

@@ -142,6 +143,7 @@ impl InterfaceGenerator<'_> {
142143
TypeDefKind::Resource => {}
143144
_ => continue,
144145
}
146+
resources_to_drop.push(name);
145147
let camel = name.to_upper_camel_case();
146148
traits.insert(Some(*id), (format!("Guest{camel}"), Vec::new()));
147149
}
@@ -296,6 +298,29 @@ macro_rules! {macro_name} {{
296298
};
297299
self.generate_raw_cabi_export(func, &ty, "$($path_to_types)*");
298300
}
301+
let export_prefix = self.gen.opts.export_prefix.as_deref().unwrap_or("");
302+
for name in resources_to_drop {
303+
let module = match self.identifier {
304+
Identifier::Interface(_, key) => self.resolve.name_world_key(key),
305+
Identifier::World(_) => unreachable!(),
306+
};
307+
let camel = name.to_upper_camel_case();
308+
uwriteln!(
309+
self.src,
310+
r#"
311+
const _: () = {{
312+
#[doc(hidden)]
313+
#[export_name = "{export_prefix}{module}#[dtor]{name}"]
314+
#[allow(non_snake_case)]
315+
unsafe extern "C" fn dtor(rep: *mut u8) {{
316+
$($path_to_types)*::{camel}::dtor::<
317+
<$ty as $($path_to_types)*::Guest>::{camel}
318+
>(rep)
319+
}}
320+
}};
321+
"#
322+
);
323+
}
299324
uwriteln!(self.src, "}};);");
300325
uwriteln!(self.src, "}}");
301326
uwriteln!(self.src, "#[doc(hidden)]");
@@ -2054,6 +2079,12 @@ impl {camel} {{
20542079
}}
20552080
}}
20562081
2082+
#[doc(hidden)]
2083+
pub unsafe fn dtor<T: 'static>(handle: *mut u8) {{
2084+
Self::type_guard::<T>();
2085+
let _ = {box_path}::from_raw(handle as *mut _{camel}Rep<T>);
2086+
}}
2087+
20572088
fn as_ptr<T: Guest{camel}>(&self) -> *mut _{camel}Rep<T> {{
20582089
{camel}::type_guard::<T>();
20592090
unsafe {{ T::_resource_rep(self.handle()).cast() }}

tests/runtime/resources.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,16 @@ fn run_test(exports: Exports, store: &mut Store<crate::Wasi<MyImports>>) -> Resu
9292
let z_add = exports.call_add(&mut *store, z_instance_1, z_instance_2)?;
9393
assert_eq!(z.call_get_a(&mut *store, z_add)?, 30);
9494

95+
let dropped_zs_start = z.call_num_dropped(&mut *store)?;
96+
9597
ResourceAny::resource_drop(x_instance, &mut *store)?;
9698
ResourceAny::resource_drop(z_instance_1, &mut *store)?;
9799
ResourceAny::resource_drop(z_instance_2, &mut *store)?;
98100

101+
let dropped_zs_end = z.call_num_dropped(&mut *store)?;
102+
if dropped_zs_start != 0 {
103+
assert_eq!(dropped_zs_end, dropped_zs_start + 2);
104+
}
105+
99106
Ok(())
100107
}

tests/runtime/resources/wasm.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,17 @@ void exports_x_destructor(exports_x_t* x) {
5757
free(x);
5858
}
5959

60+
static uint32_t NUM_Z_DROPPED = 0;
61+
6062
void exports_z_destructor(exports_z_t* z) {
63+
NUM_Z_DROPPED += 1;
6164
free(z);
6265
}
6366

67+
uint32_t exports_static_z_num_dropped() {
68+
return NUM_Z_DROPPED + 1;
69+
}
70+
6471
exports_own_kebab_case_t exports_constructor_kebab_case(uint32_t a) {
6572
exports_kebab_case_t* kc_instance = (exports_kebab_case_t*)malloc(sizeof(exports_kebab_case_t));
6673
kc_instance->a = a;

tests/runtime/resources/wasm.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ func (z *MyZ) MethodZGetA() int32 {
5252
return z.a
5353
}
5454

55+
func (e ExportsImpl) StaticZNumDropped() uint32 {
56+
return 0
57+
}
58+
5559
func (e ExportsImpl) Add(z ExportsZ, b ExportsZ) ExportsZ {
5660
return &MyZ{a: z.MethodZGetA() + b.MethodZGetA()}
5761
}

tests/runtime/resources/wasm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,27 @@ impl exports::exports::GuestX for ComponentX {
7979
}
8080
}
8181

82+
static mut NUM_DROPPED_ZS: u32 = 0;
83+
8284
impl exports::exports::GuestZ for ComponentZ {
8385
fn new(a: i32) -> Self {
8486
Self { val: a }
8587
}
8688
fn get_a(&self) -> i32 {
8789
self.val
8890
}
91+
92+
fn num_dropped() -> u32 {
93+
unsafe { NUM_DROPPED_ZS + 1 }
94+
}
95+
}
96+
97+
impl Drop for ComponentZ {
98+
fn drop(&mut self) {
99+
unsafe {
100+
NUM_DROPPED_ZS += 1;
101+
}
102+
}
89103
}
90104

91105
impl exports::exports::GuestKebabCase for ComponentKebabCase {

tests/runtime/resources/world.wit

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ world resources {
2121
resource z {
2222
constructor(a: s32);
2323
get-a: func() -> s32;
24+
25+
num-dropped: static func() -> u32;
2426
}
2527

2628
add: func(a: borrow<z>, b: borrow<z>) -> own<z>;

0 commit comments

Comments
 (0)