#[cfg(feature = "component-model-async")]
use crate::runtime::vm::VMStore;
use crate::runtime::vm::component::{ComponentInstance, OwnedComponentInstance};
use crate::store::{StoreData, StoreId, StoreOpaque};
use crate::{AsContext, AsContextMut, Store, StoreContextMut};
#[cfg(feature = "component-model-async")]
use alloc::vec::Vec;
use core::pin::Pin;
use wasmtime_environ::PrimaryMap;
use wasmtime_environ::component::RuntimeComponentInstanceIndex;
const DEFAULT_HOSTCALL_FUEL: usize = 128 << 20;
pub struct ComponentStoreData {
instances: PrimaryMap<ComponentInstanceId, Option<OwnedComponentInstance>>,
trapped: bool,
hostcall_fuel: usize,
}
impl Default for ComponentStoreData {
fn default() -> Self {
Self {
instances: PrimaryMap::default(),
trapped: false,
hostcall_fuel: DEFAULT_HOSTCALL_FUEL,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ComponentInstanceId(u32);
wasmtime_environ::entity_impl!(ComponentInstanceId);
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct RuntimeInstance {
pub instance: ComponentInstanceId,
pub index: RuntimeComponentInstanceIndex,
}
impl StoreOpaque {
pub(crate) fn trapped(&self) -> bool {
self.store_data().components.trapped
}
pub(crate) fn set_trapped(&mut self) {
self.store_data_mut().components.trapped = true;
}
}
impl StoreData {
pub(crate) fn push_component_instance(
&mut self,
data: OwnedComponentInstance,
) -> ComponentInstanceId {
let expected = data.get().id();
let ret = self.components.instances.push(Some(data));
assert_eq!(expected, ret);
ret
}
}
impl ComponentStoreData {
pub fn next_component_instance_id(&self) -> ComponentInstanceId {
self.instances.next_key()
}
#[cfg(feature = "component-model-async")]
pub(crate) fn drop_fibers_and_futures(store: &mut dyn VMStore) {
let mut fibers = Vec::new();
let mut futures = Vec::new();
store
.concurrent_state_mut()
.take_fibers_and_futures(&mut fibers, &mut futures);
for mut fiber in fibers {
fiber.dispose(store);
}
crate::component::concurrent::tls::set(store, move || drop(futures));
}
#[cfg(feature = "component-model-async")]
pub(crate) fn assert_instance_states_empty(&mut self) {
for (_, instance) in self.instances.iter_mut() {
let Some(instance) = instance.as_mut() else {
continue;
};
assert!(
instance
.get_mut()
.instance_states()
.0
.iter_mut()
.all(|(_, state)| state.handle_table().is_empty()
&& state.concurrent_state().pending_is_empty())
);
}
}
}
impl StoreData {
pub(crate) fn component_instance(&self, id: ComponentInstanceId) -> &ComponentInstance {
self.components.instances[id].as_ref().unwrap().get()
}
pub(crate) fn component_instance_mut(
&mut self,
id: ComponentInstanceId,
) -> Pin<&mut ComponentInstance> {
self.components.instances[id].as_mut().unwrap().get_mut()
}
}
impl StoreOpaque {
pub(crate) fn component_instance(&self, id: ComponentInstanceId) -> &ComponentInstance {
self.store_data().component_instance(id)
}
#[cfg(feature = "component-model-async")]
pub(crate) fn component_instance_mut(
&mut self,
id: ComponentInstanceId,
) -> Pin<&mut ComponentInstance> {
self.store_data_mut().component_instance_mut(id)
}
pub(crate) fn hostcall_fuel(&self) -> usize {
self.store_data().components.hostcall_fuel
}
pub(crate) fn set_hostcall_fuel(&mut self, fuel: usize) {
self.store_data_mut().components.hostcall_fuel = fuel;
}
}
#[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct StoreComponentInstanceId {
store_id: StoreId,
instance: ComponentInstanceId,
}
impl StoreComponentInstanceId {
pub(crate) fn new(
store_id: StoreId,
instance: ComponentInstanceId,
) -> StoreComponentInstanceId {
StoreComponentInstanceId { store_id, instance }
}
#[inline]
pub fn assert_belongs_to(&self, store: StoreId) {
self.store_id.assert_belongs_to(store)
}
#[inline]
pub(crate) fn store_id(&self) -> StoreId {
self.store_id
}
#[inline]
pub(crate) fn instance(&self) -> ComponentInstanceId {
self.instance
}
pub(crate) fn get<'a>(&self, store: &'a StoreOpaque) -> &'a ComponentInstance {
self.assert_belongs_to(store.id());
store.component_instance(self.instance)
}
pub(crate) fn get_mut<'a>(&self, store: &'a mut StoreOpaque) -> Pin<&'a mut ComponentInstance> {
self.from_data_get_mut(store.store_data_mut())
}
#[cfg(feature = "component-model-async")]
pub(crate) fn get_mut_and_registry<'a>(
&self,
store: &'a mut StoreOpaque,
) -> (
Pin<&'a mut ComponentInstance>,
&'a crate::module::ModuleRegistry,
) {
let (store_data, registry) = store.store_data_mut_and_registry();
let instance = self.from_data_get_mut(store_data);
(instance, registry)
}
pub(crate) fn from_data_get_mut<'a>(
&self,
store: &'a mut StoreData,
) -> Pin<&'a mut ComponentInstance> {
self.assert_belongs_to(store.id());
store.component_instance_mut(self.instance)
}
}
impl<T> Store<T> {
pub fn hostcall_fuel(&self) -> usize {
self.as_context().0.hostcall_fuel()
}
pub fn set_hostcall_fuel(&mut self, fuel: usize) {
self.as_context_mut().set_hostcall_fuel(fuel)
}
}
impl<T> StoreContextMut<'_, T> {
pub fn hostcall_fuel(&self) -> usize {
self.0.hostcall_fuel()
}
pub fn set_hostcall_fuel(&mut self, fuel: usize) {
self.0.set_hostcall_fuel(fuel)
}
}