Skip to content

Commit

Permalink
Add back in resources destructors to Rust exports (bytecodealliance#888)
Browse files Browse the repository at this point in the history
* Add back in resources destructors to Rust exports

This was accidentally left out of my refactoring from bytecodealliance#871 meaning that
exported Rust resources never actually got their destructors run because
the `export!` macro forgot to drop things.

Closes bytecodealliance#887

* Get test passing for Go
  • Loading branch information
alexcrichton authored Mar 8, 2024
1 parent 046ddcb commit 1c7dce6
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 0 deletions.
31 changes: 31 additions & 0 deletions crates/rust/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ impl InterfaceGenerator<'_> {
) -> Result<String> {
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()));

Expand All @@ -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()));
}
Expand Down Expand Up @@ -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)]");
Expand Down Expand Up @@ -2054,6 +2079,12 @@ impl {camel} {{
}}
}}
#[doc(hidden)]
pub unsafe fn dtor<T: 'static>(handle: *mut u8) {{
Self::type_guard::<T>();
let _ = {box_path}::from_raw(handle as *mut _{camel}Rep<T>);
}}
fn as_ptr<T: Guest{camel}>(&self) -> *mut _{camel}Rep<T> {{
{camel}::type_guard::<T>();
unsafe {{ T::_resource_rep(self.handle()).cast() }}
Expand Down
7 changes: 7 additions & 0 deletions tests/runtime/resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,16 @@ fn run_test(exports: Exports, store: &mut Store<crate::Wasi<MyImports>>) -> 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(())
}
7 changes: 7 additions & 0 deletions tests/runtime/resources/wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions tests/runtime/resources/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()}
}
Expand Down
14 changes: 14 additions & 0 deletions tests/runtime/resources/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,27 @@ 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 }
}
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 {
Expand Down
2 changes: 2 additions & 0 deletions tests/runtime/resources/world.wit
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ world resources {
resource z {
constructor(a: s32);
get-a: func() -> s32;

num-dropped: static func() -> u32;
}

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

0 comments on commit 1c7dce6

Please sign in to comment.