diff --git a/crates/cranelift/src/compiler/component.rs b/crates/cranelift/src/compiler/component.rs index 93795cd6da89..1790e336948a 100644 --- a/crates/cranelift/src/compiler/component.rs +++ b/crates/cranelift/src/compiler/component.rs @@ -784,12 +784,30 @@ impl<'a> TrampolineCompiler<'a> { }, ); } - Trampoline::ThreadSwitchTo { + Trampoline::ThreadSuspendToSuspended { instance, cancellable, } => { self.translate_libcall( - host::thread_switch_to, + host::thread_suspend_to_suspended, + TrapSentinel::NegativeOne, + WasmArgs::InRegisters, + |me, params| { + params.push(me.index_value(*instance)); + params.push( + me.builder + .ins() + .iconst(ir::types::I8, i64::from(*cancellable)), + ); + }, + ); + } + Trampoline::ThreadSuspendTo { + instance, + cancellable, + } => { + self.translate_libcall( + host::thread_suspend_to, TrapSentinel::NegativeOne, WasmArgs::InRegisters, |me, params| { @@ -820,9 +838,9 @@ impl<'a> TrampolineCompiler<'a> { }, ); } - Trampoline::ThreadResumeLater { instance } => { + Trampoline::ThreadUnsuspend { instance } => { self.translate_libcall( - host::thread_resume_later, + host::thread_unsuspend, TrapSentinel::Falsy, WasmArgs::InRegisters, |me, params| { @@ -830,12 +848,12 @@ impl<'a> TrampolineCompiler<'a> { }, ); } - Trampoline::ThreadYieldTo { + Trampoline::ThreadYieldToSuspended { instance, cancellable, } => { self.translate_libcall( - host::thread_yield_to, + host::thread_yield_to_suspended, TrapSentinel::NegativeOne, WasmArgs::InRegisters, |me, params| { diff --git a/crates/environ/src/component.rs b/crates/environ/src/component.rs index edc02acac524..4b18a3737ebd 100644 --- a/crates/environ/src/component.rs +++ b/crates/environ/src/component.rs @@ -198,13 +198,15 @@ macro_rules! foreach_builtin_component_function { #[cfg(feature = "component-model-async")] thread_new_indirect(vmctx: vmctx, caller_instance: u32, func_ty_id: u32, func_table_idx: u32, func_idx: u32, context: u32) -> u64; #[cfg(feature = "component-model-async")] - thread_switch_to(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32; + thread_suspend_to_suspended(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32; + #[cfg(feature = "component-model-async")] + thread_suspend_to(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32; #[cfg(feature = "component-model-async")] thread_suspend(vmctx: vmctx, caller_instance: u32, cancellable: u8) -> u32; #[cfg(feature = "component-model-async")] - thread_resume_later(vmctx: vmctx, caller_instance: u32, thread_idx: u32) -> bool; + thread_unsuspend(vmctx: vmctx, caller_instance: u32, thread_idx: u32) -> bool; #[cfg(feature = "component-model-async")] - thread_yield_to(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32; + thread_yield_to_suspended(vmctx: vmctx, caller_instance: u32, cancellable: u8, thread_idx: u32) -> u32; trap(vmctx: vmctx, code: u32) -> bool; diff --git a/crates/environ/src/component/dfg.rs b/crates/environ/src/component/dfg.rs index f1c4cef3f40f..2a4735e5d4cd 100644 --- a/crates/environ/src/component/dfg.rs +++ b/crates/environ/src/component/dfg.rs @@ -492,7 +492,7 @@ pub enum Trampoline { start_func_ty_idx: ComponentTypeIndex, start_func_table_id: TableId, }, - ThreadSwitchTo { + ThreadSuspendToSuspended { instance: RuntimeComponentInstanceIndex, cancellable: bool, }, @@ -500,10 +500,14 @@ pub enum Trampoline { instance: RuntimeComponentInstanceIndex, cancellable: bool, }, - ThreadResumeLater { + ThreadSuspendTo { + instance: RuntimeComponentInstanceIndex, + cancellable: bool, + }, + ThreadUnsuspend { instance: RuntimeComponentInstanceIndex, }, - ThreadYieldTo { + ThreadYieldToSuspended { instance: RuntimeComponentInstanceIndex, cancellable: bool, }, @@ -1185,10 +1189,17 @@ impl LinearizeDfg<'_> { start_func_ty_idx: *start_func_ty_idx, start_func_table_idx: self.runtime_table(*start_func_table_id), }, - Trampoline::ThreadSwitchTo { + Trampoline::ThreadSuspendToSuspended { + instance, + cancellable, + } => info::Trampoline::ThreadSuspendToSuspended { + instance: *instance, + cancellable: *cancellable, + }, + Trampoline::ThreadSuspendTo { instance, cancellable, - } => info::Trampoline::ThreadSwitchTo { + } => info::Trampoline::ThreadSuspendTo { instance: *instance, cancellable: *cancellable, }, @@ -1199,13 +1210,13 @@ impl LinearizeDfg<'_> { instance: *instance, cancellable: *cancellable, }, - Trampoline::ThreadResumeLater { instance } => info::Trampoline::ThreadResumeLater { + Trampoline::ThreadUnsuspend { instance } => info::Trampoline::ThreadUnsuspend { instance: *instance, }, - Trampoline::ThreadYieldTo { + Trampoline::ThreadYieldToSuspended { instance, cancellable, - } => info::Trampoline::ThreadYieldTo { + } => info::Trampoline::ThreadYieldToSuspended { instance: *instance, cancellable: *cancellable, }, diff --git a/crates/environ/src/component/info.rs b/crates/environ/src/component/info.rs index 2aff54ae68d3..50ec25b56544 100644 --- a/crates/environ/src/component/info.rs +++ b/crates/environ/src/component/info.rs @@ -1154,8 +1154,17 @@ pub enum Trampoline { start_func_table_idx: RuntimeTableIndex, }, - /// Intrinsic used to implement the `thread.switch-to` component model builtin. - ThreadSwitchTo { + /// Intrinsic used to implement the `thread.suspend-to-suspended` component model builtin. + ThreadSuspendToSuspended { + /// The specific component instance which is calling the intrinsic. + instance: RuntimeComponentInstanceIndex, + /// If `true`, indicates the caller instance may receive notification + /// of task cancellation. + cancellable: bool, + }, + + /// Intrinsic used to implement the `thread.suspend-to` component model builtin. + ThreadSuspendTo { /// The specific component instance which is calling the intrinsic. instance: RuntimeComponentInstanceIndex, /// If `true`, indicates the caller instance may receive notification @@ -1172,14 +1181,14 @@ pub enum Trampoline { cancellable: bool, }, - /// Intrinsic used to implement the `thread.resume-later` component model builtin. - ThreadResumeLater { + /// Intrinsic used to implement the `thread.unsuspend` component model builtin. + ThreadUnsuspend { /// The specific component instance which is calling the intrinsic. instance: RuntimeComponentInstanceIndex, }, - /// Intrinsic used to implement the `thread.yield-to` component model builtin. - ThreadYieldTo { + /// Intrinsic used to implement the `thread.yield-to-suspended` component model builtin. + ThreadYieldToSuspended { /// The specific component instance which is calling the intrinsic. instance: RuntimeComponentInstanceIndex, /// If `true`, indicates the caller instance may receive notification @@ -1254,10 +1263,11 @@ impl Trampoline { ContextSet { .. } => format!("context-set"), ThreadIndex => format!("thread-index"), ThreadNewIndirect { .. } => format!("thread-new-indirect"), - ThreadSwitchTo { .. } => format!("thread-switch-to"), + ThreadSuspendToSuspended { .. } => format!("thread-suspend-to-suspended"), + ThreadSuspendTo { .. } => format!("thread-suspend-to"), ThreadSuspend { .. } => format!("thread-suspend"), - ThreadResumeLater { .. } => format!("thread-resume-later"), - ThreadYieldTo { .. } => format!("thread-yield-to"), + ThreadUnsuspend { .. } => format!("thread-unsuspend"), + ThreadYieldToSuspended { .. } => format!("thread-yield-to-suspended"), } } } diff --git a/crates/environ/src/component/translate.rs b/crates/environ/src/component/translate.rs index 78bdb0307ed6..8855a848a660 100644 --- a/crates/environ/src/component/translate.rs +++ b/crates/environ/src/component/translate.rs @@ -319,7 +319,7 @@ enum LocalInitializer<'data> { start_func_ty: ComponentTypeIndex, start_func_table_index: TableIndex, }, - ThreadSwitchTo { + ThreadSuspendToSuspended { func: ModuleInternedTypeIndex, cancellable: bool, }, @@ -327,10 +327,14 @@ enum LocalInitializer<'data> { func: ModuleInternedTypeIndex, cancellable: bool, }, - ThreadResumeLater { + ThreadSuspendTo { + func: ModuleInternedTypeIndex, + cancellable: bool, + }, + ThreadUnsuspend { func: ModuleInternedTypeIndex, }, - ThreadYieldTo { + ThreadYieldToSuspended { func: ModuleInternedTypeIndex, cancellable: bool, }, @@ -1150,25 +1154,30 @@ impl<'a, 'data> Translator<'a, 'data> { start_func_table_index: TableIndex::from_u32(table_index), } } - wasmparser::CanonicalFunction::ThreadSwitchTo { cancellable } => { + wasmparser::CanonicalFunction::ThreadSuspendToSuspended { cancellable } => { let func = self.core_func_signature(core_func_index)?; core_func_index += 1; - LocalInitializer::ThreadSwitchTo { func, cancellable } + LocalInitializer::ThreadSuspendToSuspended { func, cancellable } } wasmparser::CanonicalFunction::ThreadSuspend { cancellable } => { let func = self.core_func_signature(core_func_index)?; core_func_index += 1; LocalInitializer::ThreadSuspend { func, cancellable } } - wasmparser::CanonicalFunction::ThreadResumeLater => { + wasmparser::CanonicalFunction::ThreadSuspendTo { cancellable } => { + let func = self.core_func_signature(core_func_index)?; + core_func_index += 1; + LocalInitializer::ThreadSuspendTo { func, cancellable } + } + wasmparser::CanonicalFunction::ThreadUnsuspend => { let func = self.core_func_signature(core_func_index)?; core_func_index += 1; - LocalInitializer::ThreadResumeLater { func } + LocalInitializer::ThreadUnsuspend { func } } - wasmparser::CanonicalFunction::ThreadYieldTo { cancellable } => { + wasmparser::CanonicalFunction::ThreadYieldToSuspended { cancellable } => { let func = self.core_func_signature(core_func_index)?; core_func_index += 1; - LocalInitializer::ThreadYieldTo { func, cancellable } + LocalInitializer::ThreadYieldToSuspended { func, cancellable } } }; self.result.initializers.push(init); diff --git a/crates/environ/src/component/translate/inline.rs b/crates/environ/src/component/translate/inline.rs index 8492b9e04ae3..94ba5b1723fa 100644 --- a/crates/environ/src/component/translate/inline.rs +++ b/crates/environ/src/component/translate/inline.rs @@ -1123,10 +1123,20 @@ impl<'a> Inliner<'a> { )); frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); } - ThreadSwitchTo { func, cancellable } => { + ThreadSuspendToSuspended { func, cancellable } => { let index = self.result.trampolines.push(( *func, - dfg::Trampoline::ThreadSwitchTo { + dfg::Trampoline::ThreadSuspendToSuspended { + instance: frame.instance, + cancellable: *cancellable, + }, + )); + frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); + } + ThreadSuspendTo { func, cancellable } => { + let index = self.result.trampolines.push(( + *func, + dfg::Trampoline::ThreadSuspendTo { instance: frame.instance, cancellable: *cancellable, }, @@ -1143,19 +1153,19 @@ impl<'a> Inliner<'a> { )); frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); } - ThreadResumeLater { func } => { + ThreadUnsuspend { func } => { let index = self.result.trampolines.push(( *func, - dfg::Trampoline::ThreadResumeLater { + dfg::Trampoline::ThreadUnsuspend { instance: frame.instance, }, )); frame.funcs.push((*func, dfg::CoreDef::Trampoline(index))); } - ThreadYieldTo { func, cancellable } => { + ThreadYieldToSuspended { func, cancellable } => { let index = self.result.trampolines.push(( *func, - dfg::Trampoline::ThreadYieldTo { + dfg::Trampoline::ThreadYieldToSuspended { instance: frame.instance, cancellable: *cancellable, }, diff --git a/crates/environ/src/component/types_builder.rs b/crates/environ/src/component/types_builder.rs index ddfe291b0826..ef082cae4eda 100644 --- a/crates/environ/src/component/types_builder.rs +++ b/crates/environ/src/component/types_builder.rs @@ -458,7 +458,7 @@ impl ComponentTypesBuilder { ComponentDefinedType::Stream(ty) => { InterfaceType::Stream(self.stream_table_type(types, ty)?) } - ComponentDefinedType::FixedSizeList(ty, size) => { + ComponentDefinedType::FixedLengthList(ty, size) => { InterfaceType::FixedLengthList(self.fixed_length_list_type(types, ty, *size)?) } ComponentDefinedType::Map(..) => { diff --git a/crates/wasmtime/src/config.rs b/crates/wasmtime/src/config.rs index 45d01e007e51..6f691e93187a 100644 --- a/crates/wasmtime/src/config.rs +++ b/crates/wasmtime/src/config.rs @@ -1210,7 +1210,7 @@ impl Config { /// incomplete. #[cfg(feature = "component-model")] pub fn wasm_component_model_fixed_length_lists(&mut self, enable: bool) -> &mut Self { - self.wasm_features(WasmFeatures::CM_FIXED_SIZE_LIST, enable); + self.wasm_features(WasmFeatures::CM_FIXED_LENGTH_LISTS, enable); self } @@ -2183,7 +2183,7 @@ impl Config { | WasmFeatures::CM_THREADING | WasmFeatures::CM_ERROR_CONTEXT | WasmFeatures::CM_GC - | WasmFeatures::CM_FIXED_SIZE_LIST; + | WasmFeatures::CM_FIXED_LENGTH_LISTS; #[allow(unused_mut, reason = "easier to avoid #[cfg]")] let mut unsupported = !features_known_to_wasmtime; diff --git a/crates/wasmtime/src/runtime/component/concurrent.rs b/crates/wasmtime/src/runtime/component/concurrent.rs index 113bdda0637d..e0d129b4615a 100644 --- a/crates/wasmtime/src/runtime/component/concurrent.rs +++ b/crates/wasmtime/src/runtime/component/concurrent.rs @@ -634,6 +634,23 @@ impl fmt::Debug for GuestCallKind { } } +/// The target of a suspension intrinsic. +#[derive(Copy, Clone, Debug)] +pub enum SuspensionTarget { + SomeSuspended(u32), + Some(u32), + None, +} + +impl SuspensionTarget { + fn is_none(&self) -> bool { + matches!(self, SuspensionTarget::None) + } + fn is_some(&self) -> bool { + !self.is_none() + } +} + /// Represents a pending call into guest code for a given guest thread. #[derive(Debug)] struct GuestCall { @@ -685,8 +702,10 @@ enum WorkItem { PushFuture(AlwaysMut), /// A fiber to resume. ResumeFiber(StoreFiber<'static>), + /// A thread to resume. + ResumeThread(RuntimeComponentInstanceIndex, QualifiedThreadId), /// A pending call into guest code for a given guest task. - GuestCall(GuestCall), + GuestCall(RuntimeComponentInstanceIndex, GuestCall), /// A job to run on a worker fiber. WorkerFunction(AlwaysMut Result<()> + Send>>), } @@ -696,7 +715,16 @@ impl fmt::Debug for WorkItem { match self { Self::PushFuture(_) => f.debug_tuple("PushFuture").finish(), Self::ResumeFiber(_) => f.debug_tuple("ResumeFiber").finish(), - Self::GuestCall(call) => f.debug_tuple("GuestCall").field(call).finish(), + Self::ResumeThread(instance, thread) => f + .debug_tuple("ResumeThread") + .field(instance) + .field(thread) + .finish(), + Self::GuestCall(instance, call) => f + .debug_tuple("GuestCall") + .field(instance) + .field(call) + .finish(), Self::WorkerFunction(_) => f.debug_tuple("WorkerFunction").finish(), } } @@ -1307,7 +1335,17 @@ impl StoreContextMut<'_, T> { WorkItem::ResumeFiber(fiber) => { self.0.resume_fiber(fiber).await?; } - WorkItem::GuestCall(call) => { + WorkItem::ResumeThread(_, thread) => { + if let GuestThreadState::Ready(fiber) = mem::replace( + &mut self.0.concurrent_state_mut().get_mut(thread.thread)?.state, + GuestThreadState::Running, + ) { + self.0.resume_fiber(fiber).await?; + } else { + bail!("cannot resume non-pending thread {thread:?}"); + } + } + WorkItem::GuestCall(_, call) => { if call.is_ready(self.0)? { self.run_on_worker(WorkerItem::GuestCall(call)).await?; } else { @@ -1673,7 +1711,7 @@ impl StoreOpaque { let call = GuestCall { thread, kind }; if call.is_ready(self)? { self.concurrent_state_mut() - .push_high_priority(WorkItem::GuestCall(call)); + .push_high_priority(WorkItem::GuestCall(instance.index, call)); } else { self.instance_state(instance) .pending @@ -1733,8 +1771,9 @@ impl StoreOpaque { } } SuspendReason::Yielding { thread, .. } => { - state.get_mut(thread.thread)?.state = GuestThreadState::Pending; - state.push_low_priority(WorkItem::ResumeFiber(fiber)); + state.get_mut(thread.thread)?.state = GuestThreadState::Ready(fiber); + let instance = state.get_mut(thread.task)?.instance.index; + state.push_low_priority(WorkItem::ResumeThread(instance, thread)); } SuspendReason::ExplicitlySuspending { thread, .. } => { state.get_mut(thread.thread)?.state = GuestThreadState::Suspended(fiber); @@ -2000,7 +2039,7 @@ impl Instance { if state.may_block(guest_thread.task) { // Push this thread onto the "low priority" queue so it runs // after any other threads have had a chance to run. - state.push_low_priority(WorkItem::GuestCall(call)); + state.push_low_priority(WorkItem::GuestCall(runtime_instance, call)); None } else { // Yielding in a non-blocking context is defined as a no-op @@ -2021,13 +2060,16 @@ impl Instance { || !state.get_mut(set)?.ready.is_empty() { // An event is immediately available; deliver it ASAP. - state.push_high_priority(WorkItem::GuestCall(GuestCall { - thread: guest_thread, - kind: GuestCallKind::DeliverEvent { - instance: self, - set: Some(set), + state.push_high_priority(WorkItem::GuestCall( + runtime_instance, + GuestCall { + thread: guest_thread, + kind: GuestCallKind::DeliverEvent { + instance: self, + set: Some(set), + }, }, - })); + )); } else { // No event is immediately available. // @@ -2353,10 +2395,13 @@ impl Instance { store .0 .concurrent_state_mut() - .push_high_priority(WorkItem::GuestCall(GuestCall { - thread: guest_thread, - kind: GuestCallKind::StartImplicit(fun), - })); + .push_high_priority(WorkItem::GuestCall( + callee_instance.index, + GuestCall { + thread: guest_thread, + kind: GuestCallKind::StartImplicit(fun), + }, + )); Ok(()) } @@ -3383,12 +3428,13 @@ impl Instance { self.add_guest_thread_to_instance_table(thread_id, store.0, runtime_instance) } - pub(crate) fn resume_suspended_thread( + pub(crate) fn resume_thread( self, store: &mut StoreOpaque, runtime_instance: RuntimeComponentInstanceIndex, thread_idx: u32, high_priority: bool, + allow_ready: bool, ) -> Result<()> { let thread_id = GuestThread::from_instance(self.id().get_mut(store), runtime_instance, thread_idx)?; @@ -3399,12 +3445,15 @@ impl Instance { match mem::replace(&mut thread.state, GuestThreadState::Running) { GuestThreadState::NotStartedExplicit(start_func) => { log::trace!("starting thread {guest_thread:?}"); - let guest_call = WorkItem::GuestCall(GuestCall { - thread: guest_thread, - kind: GuestCallKind::StartExplicit(Box::new(move |store| { - start_func(store, guest_thread) - })), - }); + let guest_call = WorkItem::GuestCall( + runtime_instance, + GuestCall { + thread: guest_thread, + kind: GuestCallKind::StartExplicit(Box::new(move |store| { + start_func(store, guest_thread) + })), + }, + ); store .concurrent_state_mut() .push_work_item(guest_call, high_priority); @@ -3415,6 +3464,13 @@ impl Instance { .concurrent_state_mut() .push_work_item(WorkItem::ResumeFiber(fiber), high_priority); } + GuestThreadState::Ready(fiber) if allow_ready => { + log::trace!("resuming thread {thread_id:?} that was ready"); + thread.state = GuestThreadState::Ready(fiber); + store + .concurrent_state_mut() + .promote_thread_work_item(guest_thread); + } _ => { bail!("cannot resume thread which is not suspended"); } @@ -3441,15 +3497,15 @@ impl Instance { Ok(guest_id) } - /// Helper function for the `thread.yield`, `thread.yield-to`, `thread.suspend`, - /// and `thread.switch-to` intrinsics. + /// Helper function for the `thread.yield`, `thread.yield-to-suspended`, `thread.suspend`, + /// `thread.suspend-to`, and `thread.suspend-to-suspended` intrinsics. pub(crate) fn suspension_intrinsic( self, store: &mut StoreOpaque, caller: RuntimeComponentInstanceIndex, cancellable: bool, yielding: bool, - to_thread: Option, + to_thread: SuspensionTarget, ) -> Result { self.check_may_leave(store, caller)?; @@ -3458,10 +3514,12 @@ impl Instance { if yielding { // This is a `thread.yield` call if !state.may_block(state.guest_thread.unwrap().task) { - // The spec defines `thread.yield` to be a no-op in a - // non-blocking context, so we return immediately without giving - // any other thread a chance to run. - return Ok(WaitResult::Completed); + // In a non-blocking context, a `thread.yield` may trigger + // other threads in the same component instance to run. + if !state.promote_instance_local_thread_work_item(caller) { + // No other threads are runnable, so just return + return Ok(WaitResult::Completed); + } } } else { // The caller may only call `thread.suspend` from an async task @@ -3476,8 +3534,14 @@ impl Instance { return Ok(WaitResult::Cancelled); } - if let Some(thread) = to_thread { - self.resume_suspended_thread(store, caller, thread, true)?; + match to_thread { + SuspensionTarget::SomeSuspended(thread) => { + self.resume_thread(store, caller, thread, true, false)? + } + SuspensionTarget::Some(thread) => { + self.resume_thread(store, caller, thread, true, true)? + } + SuspensionTarget::None => { /* nothing to do */ } } let state = store.concurrent_state_mut(); @@ -3486,7 +3550,7 @@ impl Instance { SuspendReason::Yielding { thread: guest_thread, // Tell `StoreOpaque::suspend` it's okay to suspend here since - // we're handling a `thread.yield-to` call; otherwise it would + // we're handling a `thread.yield-to-suspended` call; otherwise it would // panic if we called it in a non-blocking context. skip_may_block_check: to_thread.is_some(), } @@ -3494,7 +3558,7 @@ impl Instance { SuspendReason::ExplicitlySuspending { thread: guest_thread, // Tell `StoreOpaque::suspend` it's okay to suspend here since - // we're handling a `thread.switch-to` call; otherwise it would + // we're handling a `thread.suspend-to(-suspended)` call; otherwise it would // panic if we called it in a non-blocking context. skip_may_block_check: to_thread.is_some(), } @@ -3691,6 +3755,7 @@ impl Instance { // `Event::Cancelled` if it was already cancelled), but that's // okay -- this should supersede the previous state. task.event = Some(Event::Cancelled); + let runtime_instance = task.instance.index; for thread in task.threads.clone() { let thread = QualifiedThreadId { task: guest_task, @@ -3709,13 +3774,16 @@ impl Instance { .unwrap() { WaitMode::Fiber(fiber) => WorkItem::ResumeFiber(fiber), - WaitMode::Callback(instance) => WorkItem::GuestCall(GuestCall { - thread, - kind: GuestCallKind::DeliverEvent { - instance, - set: None, + WaitMode::Callback(instance) => WorkItem::GuestCall( + runtime_instance, + GuestCall { + thread, + kind: GuestCallKind::DeliverEvent { + instance, + set: None, + }, }, - }), + ), }; concurrent_state.push_high_priority(item); @@ -4383,7 +4451,7 @@ enum GuestThreadState { ), Running, Suspended(StoreFiber<'static>), - Pending, + Ready(StoreFiber<'static>), Completed, } pub struct GuestThread { @@ -4817,13 +4885,16 @@ impl Waitable { let item = match mode { WaitMode::Fiber(fiber) => WorkItem::ResumeFiber(fiber), - WaitMode::Callback(instance) => WorkItem::GuestCall(GuestCall { - thread, - kind: GuestCallKind::DeliverEvent { - instance, - set: Some(set), + WaitMode::Callback(instance) => WorkItem::GuestCall( + state.get_mut(thread.task)?.instance.index, + GuestCall { + thread, + kind: GuestCallKind::DeliverEvent { + instance, + set: Some(set), + }, }, - }), + ), }; state.push_high_priority(item); } @@ -5115,6 +5186,48 @@ impl ConcurrentState { } } + fn promote_instance_local_thread_work_item( + &mut self, + current_instance: RuntimeComponentInstanceIndex, + ) -> bool { + self.promote_work_items_matching(|item: &WorkItem| match item { + WorkItem::ResumeThread(instance, _) | WorkItem::GuestCall(instance, _) => { + *instance == current_instance + } + _ => false, + }) + } + + fn promote_thread_work_item(&mut self, thread: QualifiedThreadId) -> bool { + self.promote_work_items_matching(|item: &WorkItem| match item { + WorkItem::ResumeThread(_, t) | WorkItem::GuestCall(_, GuestCall { thread: t, .. }) => { + *t == thread + } + _ => false, + }) + } + + fn promote_work_items_matching(&mut self, mut predicate: F) -> bool + where + F: FnMut(&WorkItem) -> bool, + { + // If there's a high-priority work item to resume the current guest thread, + // we don't need to promote anything, but we return true to indicate that + // work is pending for the current instance. + if self.high_priority.iter().any(&mut predicate) { + true + } + // Otherwise, look for a low-priority work item that matches the current + // instance and promote it to high-priority. + else if let Some(idx) = self.low_priority.iter().position(&mut predicate) { + let item = self.low_priority.remove(idx).unwrap(); + self.push_high_priority(item); + true + } else { + false + } + } + /// Implements the `context.get` intrinsic. pub(crate) fn context_get(&mut self, slot: u32) -> Result { let thread = self.guest_thread.unwrap(); diff --git a/crates/wasmtime/src/runtime/vm/component/libcalls.rs b/crates/wasmtime/src/runtime/vm/component/libcalls.rs index e8ee548e192a..7c61af164609 100644 --- a/crates/wasmtime/src/runtime/vm/component/libcalls.rs +++ b/crates/wasmtime/src/runtime/vm/component/libcalls.rs @@ -7,7 +7,7 @@ use crate::prelude::*; #[cfg(feature = "component-model-async")] use crate::runtime::component::RuntimeInstance; #[cfg(feature = "component-model-async")] -use crate::runtime::component::concurrent::ResourcePair; +use crate::runtime::component::concurrent::{ResourcePair, SuspensionTarget}; use crate::runtime::vm::component::{ComponentInstance, VMComponentContext}; use crate::runtime::vm::{HostResultHasUnwindSentinel, VMStore, VmSafe}; use core::cell::Cell; @@ -839,7 +839,7 @@ fn thread_yield( RuntimeComponentInstanceIndex::from_u32(caller_instance), cancellable != 0, true, - None, + SuspensionTarget::None, ) .map(|r| r == WaitResult::Cancelled) } @@ -1422,7 +1422,7 @@ fn thread_new_indirect( } #[cfg(feature = "component-model-async")] -fn thread_switch_to( +fn thread_suspend_to_suspended( store: &mut dyn VMStore, instance: Instance, caller: u32, @@ -1435,7 +1435,26 @@ fn thread_switch_to( RuntimeComponentInstanceIndex::from_u32(caller), cancellable != 0, false, - Some(thread_idx), + SuspensionTarget::SomeSuspended(thread_idx), + ) + .map(|r| r == WaitResult::Cancelled) +} + +#[cfg(feature = "component-model-async")] +fn thread_suspend_to( + store: &mut dyn VMStore, + instance: Instance, + caller: u32, + cancellable: u8, + thread_idx: u32, +) -> Result { + instance + .suspension_intrinsic( + store, + RuntimeComponentInstanceIndex::from_u32(caller), + cancellable != 0, + false, + SuspensionTarget::Some(thread_idx), ) .map(|r| r == WaitResult::Cancelled) } @@ -1453,28 +1472,29 @@ fn thread_suspend( RuntimeComponentInstanceIndex::from_u32(caller), cancellable != 0, false, - None, + SuspensionTarget::None, ) .map(|r| r == WaitResult::Cancelled) } #[cfg(feature = "component-model-async")] -fn thread_resume_later( +fn thread_unsuspend( store: &mut dyn VMStore, instance: Instance, caller_instance: u32, thread_idx: u32, ) -> Result<()> { - instance.resume_suspended_thread( + instance.resume_thread( store, RuntimeComponentInstanceIndex::from_u32(caller_instance), thread_idx, false, + false, ) } #[cfg(feature = "component-model-async")] -fn thread_yield_to( +fn thread_yield_to_suspended( store: &mut dyn VMStore, instance: Instance, caller_instance: u32, @@ -1487,7 +1507,7 @@ fn thread_yield_to( RuntimeComponentInstanceIndex::from_u32(caller_instance), cancellable != 0, true, - Some(thread_idx), + SuspensionTarget::SomeSuspended(thread_idx), ) .map(|r| r == WaitResult::Cancelled) } diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 88a614eff236..d9d3417f364a 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -12,6 +12,7 @@ use heck::*; use indexmap::{IndexMap, IndexSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Write as _; +use std::hash::RandomState; use std::io::{Read, Write}; use std::mem; use std::process::{Command, Stdio}; @@ -75,7 +76,7 @@ struct Wasmtime { sizes: SizeAlign, interface_names: HashMap, interface_last_seen_as_import: HashMap, - trappable_errors: IndexMap, + trappable_errors: IndexMap, // Track the with options that were used. Remapped interfaces provided via `with` // are required to be used. used_with_opts: HashSet, @@ -637,7 +638,7 @@ pub fn new<_T>( uwriteln!(generator.src, "}}"); // end `impl {struct_name}Indices` uwriteln!(generator.src, "impl {struct_name} {{"); - let mut resource_methods = IndexMap::new(); + let mut resource_methods = IndexMap::with_hasher(RandomState::new()); for (_, func) in iface.functions.iter() { match func.kind.resource() { @@ -1628,7 +1629,7 @@ impl<'a> InterfaceGenerator<'a> { TypeDefKind::Handle(handle) => self.type_handle(id, name, handle, &ty.docs), TypeDefKind::Resource => self.type_resource(id, name, ty, &ty.docs), TypeDefKind::Unknown => unreachable!(), - TypeDefKind::FixedSizeList(..) => todo!(), + TypeDefKind::FixedLengthList(..) => todo!(), TypeDefKind::Map(..) => todo!(), } } @@ -2259,10 +2260,10 @@ impl<'a> InterfaceGenerator<'a> { let owner = TypeOwner::Interface(id); let wt = self.generator.wasmtime_path(); - let mut required_conversion_traits = IndexSet::new(); + let mut required_conversion_traits = IndexSet::with_hasher(RandomState::new()); let extra_functions = { let mut functions = Vec::new(); - let mut errors_converted = IndexMap::new(); + let mut errors_converted = IndexMap::with_hasher(RandomState::new()); let mut my_error_types = iface .types .iter() @@ -3449,7 +3450,7 @@ fn type_contains_lists(ty: Type, resolve: &Resolve) -> bool { .any(|case| option_type_contains_lists(case.ty, resolve)), TypeDefKind::Type(ty) => type_contains_lists(*ty, resolve), TypeDefKind::List(_) => true, - TypeDefKind::FixedSizeList(..) => todo!(), + TypeDefKind::FixedLengthList(..) => todo!(), TypeDefKind::Map(..) => todo!(), }, diff --git a/crates/wit-bindgen/src/rust.rs b/crates/wit-bindgen/src/rust.rs index bc9e39fc6770..7b0c8af468ea 100644 --- a/crates/wit-bindgen/src/rust.rs +++ b/crates/wit-bindgen/src/rust.rs @@ -132,7 +132,7 @@ pub trait RustGenerator<'a> { TypeDefKind::Type(Type::String) => true, TypeDefKind::Type(_) => false, TypeDefKind::Unknown => unreachable!(), - TypeDefKind::FixedSizeList(..) => todo!(), + TypeDefKind::FixedLengthList(..) => todo!(), TypeDefKind::Map(..) => todo!(), } } @@ -189,7 +189,7 @@ pub trait RustGenerator<'a> { TypeDefKind::Type(t) => self.ty(t, mode), TypeDefKind::Unknown => unreachable!(), - TypeDefKind::FixedSizeList(..) => todo!(), + TypeDefKind::FixedLengthList(..) => todo!(), TypeDefKind::Map(..) => todo!(), } } diff --git a/crates/wit-bindgen/src/types.rs b/crates/wit-bindgen/src/types.rs index 484c525a7592..bb3395fa02a6 100644 --- a/crates/wit-bindgen/src/types.rs +++ b/crates/wit-bindgen/src/types.rs @@ -157,7 +157,7 @@ impl Types { TypeDefKind::Handle(_) => info.has_handle = true, TypeDefKind::Resource => {} TypeDefKind::Unknown => unreachable!(), - TypeDefKind::FixedSizeList(..) => todo!(), + TypeDefKind::FixedLengthList(..) => todo!(), TypeDefKind::Map(..) => todo!(), } self.type_info.insert(ty, info);