diff --git a/Cargo.lock b/Cargo.lock index ab6eb70422..d9e83e364a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5267,7 +5267,7 @@ dependencies = [ [[package]] name = "wit-bindgen" version = "0.41.0" -source = "git+https://github.com/bytecodealliance/witx-bindgen#ef8647453a7bc5f1c1ec1876fb2d5554214c124d" +source = "git+https://github.com/bytecodealliance/witx-bindgen#adbeb1bdadea0b85754fefef79a28198f6fdfd6c" dependencies = [ "wit-bindgen-rt 0.41.0", "wit-bindgen-rust-macro", @@ -5276,7 +5276,7 @@ dependencies = [ [[package]] name = "wit-bindgen-core" version = "0.41.0" -source = "git+https://github.com/bytecodealliance/witx-bindgen#ef8647453a7bc5f1c1ec1876fb2d5554214c124d" +source = "git+https://github.com/bytecodealliance/witx-bindgen#adbeb1bdadea0b85754fefef79a28198f6fdfd6c" dependencies = [ "anyhow", "heck 0.5.0", @@ -5295,7 +5295,7 @@ dependencies = [ [[package]] name = "wit-bindgen-rt" version = "0.41.0" -source = "git+https://github.com/bytecodealliance/witx-bindgen#ef8647453a7bc5f1c1ec1876fb2d5554214c124d" +source = "git+https://github.com/bytecodealliance/witx-bindgen#adbeb1bdadea0b85754fefef79a28198f6fdfd6c" dependencies = [ "bitflags 2.6.0", "futures", @@ -5305,7 +5305,7 @@ dependencies = [ [[package]] name = "wit-bindgen-rust" version = "0.41.0" -source = "git+https://github.com/bytecodealliance/witx-bindgen#ef8647453a7bc5f1c1ec1876fb2d5554214c124d" +source = "git+https://github.com/bytecodealliance/witx-bindgen#adbeb1bdadea0b85754fefef79a28198f6fdfd6c" dependencies = [ "anyhow", "heck 0.5.0", @@ -5320,7 +5320,7 @@ dependencies = [ [[package]] name = "wit-bindgen-rust-macro" version = "0.41.0" -source = "git+https://github.com/bytecodealliance/witx-bindgen#ef8647453a7bc5f1c1ec1876fb2d5554214c124d" +source = "git+https://github.com/bytecodealliance/witx-bindgen#adbeb1bdadea0b85754fefef79a28198f6fdfd6c" dependencies = [ "anyhow", "prettyplease", diff --git a/crates/environ/src/component/info.rs b/crates/environ/src/component/info.rs index 41e9e717ef..318e941ae1 100644 --- a/crates/environ/src/component/info.rs +++ b/crates/environ/src/component/info.rs @@ -643,6 +643,7 @@ pub struct Resource { /// /// Note that this type does not implement `Serialize` or `Deserialize` and /// that's intentional as this isn't stored in the final compilation artifact. +#[derive(Debug)] pub enum Trampoline { /// Description of a lowered import used in conjunction with /// `GlobalInitializer::LowerImport`. diff --git a/crates/test-programs/src/bin/async_poll_stackless.rs b/crates/test-programs/src/bin/async_poll_stackless.rs index 8798308700..580798c3fb 100644 --- a/crates/test-programs/src/bin/async_poll_stackless.rs +++ b/crates/test-programs/src/bin/async_poll_stackless.rs @@ -79,8 +79,8 @@ unsafe extern "C" fn callback_run(event0: u32, event1: u32, _event2: u32) -> u32 let set = *set; let result = async_when_ready(); - let status = result >> 30; - let call = result & !(0b11 << 30); + let status = result & 0xf; + let call = result >> 4; assert!(status != STATUS_RETURNED); waitable_join(call, set); @@ -117,7 +117,7 @@ unsafe extern "C" fn callback_run(event0: u32, event1: u32, _event2: u32) -> u32 assert_eq!(event0, EVENT_NONE); let set = *set; - assert!(async_when_ready() == STATUS_RETURNED << 30); + assert!(async_when_ready() == STATUS_RETURNED); *state = State::S5 { set }; diff --git a/crates/test-programs/src/bin/async_poll_synchronous.rs b/crates/test-programs/src/bin/async_poll_synchronous.rs index c8539b6026..267b216331 100644 --- a/crates/test-programs/src/bin/async_poll_synchronous.rs +++ b/crates/test-programs/src/bin/async_poll_synchronous.rs @@ -45,8 +45,8 @@ impl Guest for Component { assert!(waitable_set_poll(set).is_none()); let result = async_when_ready(); - let status = result >> 30; - let call = result & !(0b11 << 30); + let status = result & 0xf; + let call = result >> 4; assert!(status != STATUS_RETURNED); waitable_join(call, set); @@ -64,7 +64,7 @@ impl Guest for Component { assert!(waitable_set_poll(set).is_none()); - assert!(async_when_ready() == STATUS_RETURNED << 30); + assert!(async_when_ready() == STATUS_RETURNED); assert!(waitable_set_poll(set).is_none()); diff --git a/crates/test-programs/src/bin/async_round_trip_many_stackful.rs b/crates/test-programs/src/bin/async_round_trip_many_stackful.rs index da8ba0661a..d997bec3c5 100644 --- a/crates/test-programs/src/bin/async_round_trip_many_stackful.rs +++ b/crates/test-programs/src/bin/async_round_trip_many_stackful.rs @@ -86,8 +86,8 @@ unsafe extern "C" fn export_foo(args: *mut u8) { let results = alloc::alloc(layout); let result = import_foo(params, results); - let mut status = result >> 30; - let call = result & !(0b11 << 30); + let mut status = result & 0xf; + let call = result >> 4; let set = waitable_set_new(); if call != 0 { waitable_join(call, set); diff --git a/crates/test-programs/src/bin/async_round_trip_stackful.rs b/crates/test-programs/src/bin/async_round_trip_stackful.rs index 318940c5e6..b01c53d1f0 100644 --- a/crates/test-programs/src/bin/async_round_trip_stackful.rs +++ b/crates/test-programs/src/bin/async_round_trip_stackful.rs @@ -72,8 +72,8 @@ unsafe extern "C" fn export_foo(ptr: *mut u8, len: usize) { let results = alloc::alloc(layout); let result = import_foo(params, results); - let mut status = result >> 30; - let call = result & !(0b11 << 30); + let mut status = result & 0xf; + let call = result >> 4; let set = waitable_set_new(); if call != 0 { waitable_join(call, set); diff --git a/crates/wasmtime/src/runtime/component/concurrent.rs b/crates/wasmtime/src/runtime/component/concurrent.rs index 3c27f76c31..cac500071e 100644 --- a/crates/wasmtime/src/runtime/component/concurrent.rs +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -70,12 +70,26 @@ mod ready_chunks; mod states; mod table; +/// Corresponds to `CallState` in the upstream spec. #[derive(Clone, Copy, Eq, PartialEq, Debug)] -#[repr(u32)] -enum Status { +pub enum Status { Starting = 1, - Started, - Returned, + Started = 2, + Returned = 3, +} + +impl Status { + /// Packs this status and the optional `waitable` provided into a 32-bit + /// result that the canonical ABI requires. + /// + /// The low 4 bits are reserved for the status while the upper 28 bits are + /// the waitable, if present. + pub fn pack(self, waitable: Option) -> u32 { + assert!(matches!(self, Status::Returned) == waitable.is_none()); + let waitable = waitable.unwrap_or(0); + assert!(waitable < (1 << 28)); + (waitable << 4) | (self as u32) + } } #[derive(Clone, Copy, Debug)] @@ -1602,12 +1616,14 @@ impl ComponentInstance { log::trace!("status {status:?} for {}", guest_task.rep()); - let call = if status != Status::Returned { + let waitable = if status != Status::Returned { if async_caller { self.get_mut(guest_task)?.has_suspended = true; - self.waitable_tables()[caller_instance] - .insert(guest_task.rep(), WaitableState::GuestTask)? + Some( + self.waitable_tables()[caller_instance] + .insert(guest_task.rep(), WaitableState::GuestTask)?, + ) } else { let caller = if let Caller::Guest { task, .. } = &self.get(guest_task)?.caller { *task @@ -1621,10 +1637,10 @@ impl ComponentInstance { self.poll_for_result(guest_task)?; status = Status::Returned; - 0 + None } } else { - 0 + None }; if let Some(storage) = storage { @@ -1635,10 +1651,8 @@ impl ComponentInstance { } else { return Err(anyhow!(crate::Trap::NoAsyncResult)); } - Ok(0) - } else { - Ok(((status as u32) << 30) | call) } + Ok(status.pack(waitable)) } pub(crate) fn wrap_call( diff --git a/crates/wasmtime/src/runtime/component/func/host.rs b/crates/wasmtime/src/runtime/component/func/host.rs index 796eb12d8b..dc9620e7af 100644 --- a/crates/wasmtime/src/runtime/component/func/host.rs +++ b/crates/wasmtime/src/runtime/component/func/host.rs @@ -1,5 +1,5 @@ #[cfg(feature = "component-model-async")] -use crate::component::concurrent::Accessor; +use crate::component::concurrent::{Accessor, Status}; use crate::component::func::{LiftContext, LowerContext, Options}; use crate::component::matching::InstanceType; use crate::component::storage::slice_to_storage_mut; @@ -23,11 +23,6 @@ use wasmtime_environ::component::{ TypeFuncIndex, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, }; -#[cfg(feature = "component-model-async")] -const STATUS_PARAMS_READ: u32 = 1; -#[cfg(feature = "component-model-async")] -const STATUS_DONE: u32 = 3; - pub struct HostFunc { entrypoint: VMLoweringCallee, typecheck: Box) -> Result<()>) + Send + Sync>, @@ -335,9 +330,9 @@ where })?; let status = if let Some(task) = task { - (STATUS_PARAMS_READ << 30) | task + Status::Started.pack(Some(task)) } else { - STATUS_DONE << 30 + Status::Returned.pack(None) }; storage[0] = MaybeUninit::new(ValRaw::i32(status as i32)); @@ -591,9 +586,9 @@ where })?; let status = if let Some(task) = task { - (STATUS_PARAMS_READ << 30) | task + Status::Started.pack(Some(task)) } else { - STATUS_DONE << 30 + Status::Returned.pack(None) }; storage[0] = MaybeUninit::new(ValRaw::i32(status as i32));