use crate::prelude::*;
use crate::runtime::component::RuntimeInstance;
use crate::runtime::vm::component::{ResourceTables, TypedResource, TypedResourceIndex};
use crate::runtime::vm::{SendSyncPtr, VMFuncRef};
use crate::store::StoreOpaque;
use core::ptr::NonNull;
use wasmtime_environ::component::TypeResourceTableIndex;
pub struct HostResourceTables<'a> {
tables: ResourceTables<'a>,
host_resource_data: &'a mut HostResourceData,
}
#[derive(Default)]
pub struct HostResourceData {
cur_generation: u32,
table_slot_metadata: Vec<TableSlot>,
}
#[derive(Copy, Clone)]
pub struct TableSlot {
generation: u32,
pub(super) instance: Option<RuntimeInstance>,
pub(super) dtor: Option<SendSyncPtr<VMFuncRef>>,
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
#[repr(transparent)]
pub struct HostResourceIndex(u64);
impl HostResourceIndex {
pub(super) fn new(idx: u32, generation: u32) -> HostResourceIndex {
HostResourceIndex(u64::from(idx) | (u64::from(generation) << 32))
}
pub(super) const fn index(&self) -> u32 {
(self.0 & 0xffffffff) as u32
}
pub(super) const fn generation(&self) -> u32 {
(self.0 >> 32) as u32
}
}
impl<'a> HostResourceTables<'a> {
pub fn new_host(store: &'a mut StoreOpaque) -> HostResourceTables<'a> {
let (calls, host_table, host_resource_data) = store.component_resource_state();
HostResourceTables::from_parts(
ResourceTables {
host_table: Some(host_table),
calls,
guest: None,
},
host_resource_data,
)
}
pub fn from_parts(
tables: ResourceTables<'a>,
host_resource_data: &'a mut HostResourceData,
) -> Self {
HostResourceTables {
tables,
host_resource_data,
}
}
pub fn host_resource_lift_own(&mut self, idx: HostResourceIndex) -> Result<u32> {
let (idx, _) = self.validate_host_index(idx, true)?;
self.tables.resource_lift_own(TypedResourceIndex::Host(idx))
}
pub fn host_resource_lift_borrow(&mut self, idx: HostResourceIndex) -> Result<u32> {
let (idx, _) = self.validate_host_index(idx, false)?;
self.tables
.resource_lift_borrow(TypedResourceIndex::Host(idx))
}
pub fn host_resource_lower_own(
&mut self,
rep: u32,
dtor: Option<NonNull<VMFuncRef>>,
instance: Option<RuntimeInstance>,
) -> Result<HostResourceIndex> {
let idx = self.tables.resource_lower_own(TypedResource::Host(rep))?;
Ok(self.new_host_index(idx, dtor, instance))
}
pub fn host_resource_lower_borrow(&mut self, rep: u32) -> Result<HostResourceIndex> {
let idx = self
.tables
.resource_lower_borrow(TypedResource::Host(rep))?;
Ok(self.new_host_index(idx, None, None))
}
fn validate_host_index(
&mut self,
idx: HostResourceIndex,
is_removal: bool,
) -> Result<(u32, Option<TableSlot>)> {
let actual = usize::try_from(idx.index())
.ok()
.and_then(|i| self.host_resource_data.table_slot_metadata.get(i).copied());
if let Some(actual) = actual {
if actual.generation != idx.generation() {
bail!("host-owned resource is being used with the wrong type");
}
}
if is_removal {
self.host_resource_data.cur_generation += 1;
}
Ok((idx.index(), actual))
}
fn new_host_index(
&mut self,
idx: u32,
dtor: Option<NonNull<VMFuncRef>>,
instance: Option<RuntimeInstance>,
) -> HostResourceIndex {
let list = &mut self.host_resource_data.table_slot_metadata;
let info = TableSlot {
generation: self.host_resource_data.cur_generation,
instance,
dtor: dtor.map(SendSyncPtr::new),
};
match list.get_mut(idx as usize) {
Some(slot) => *slot = info,
None => {
if list.is_empty() {
assert_eq!(idx, 1);
list.push(TableSlot {
generation: 0,
instance: None,
dtor: None,
});
}
assert_eq!(idx as usize, list.len());
list.push(info);
}
}
HostResourceIndex::new(idx, info.generation)
}
pub(super) fn host_resource_drop(
&mut self,
idx: HostResourceIndex,
) -> Result<Option<(u32, TableSlot)>> {
let (idx, slot) = self.validate_host_index(idx, true)?;
match self.tables.resource_drop(TypedResourceIndex::Host(idx))? {
Some(rep) => Ok(Some((rep, slot.unwrap()))),
None => Ok(None),
}
}
pub fn guest_resource_lower_own(
&mut self,
rep: u32,
ty: TypeResourceTableIndex,
) -> Result<u32> {
self.tables
.resource_lower_own(TypedResource::Component { ty, rep })
}
pub fn guest_resource_lower_borrow(
&mut self,
rep: u32,
ty: TypeResourceTableIndex,
) -> Result<u32> {
self.tables
.resource_lower_borrow(TypedResource::Component { ty, rep })
}
pub fn guest_resource_lift_own(
&mut self,
index: u32,
ty: TypeResourceTableIndex,
) -> Result<u32> {
self.tables
.resource_lift_own(TypedResourceIndex::Component { ty, index })
}
pub fn guest_resource_lift_borrow(
&mut self,
index: u32,
ty: TypeResourceTableIndex,
) -> Result<u32> {
self.tables
.resource_lift_borrow(TypedResourceIndex::Component { ty, index })
}
#[inline]
pub fn enter_call(&mut self) {
self.tables.enter_call()
}
#[inline]
pub fn exit_call(&mut self) -> Result<()> {
self.tables.exit_call()
}
}