use crate::component::matching::InstanceType;
use crate::component::ResourceType;
use crate::store::{StoreId, StoreOpaque};
use crate::StoreContextMut;
use anyhow::{bail, Result};
use std::ptr::NonNull;
use std::sync::Arc;
use wasmtime_environ::component::{ComponentTypes, StringEncoding, TypeResourceTableIndex};
use wasmtime_runtime::component::{
CallContexts, ComponentInstance, InstanceFlags, ResourceTable, ResourceTables,
};
use wasmtime_runtime::{VMFuncRef, VMMemoryDefinition};
#[derive(Copy, Clone)]
pub struct Options {
store_id: StoreId,
memory: Option<NonNull<VMMemoryDefinition>>,
realloc: Option<NonNull<VMFuncRef>>,
string_encoding: StringEncoding,
}
unsafe impl Send for Options {}
unsafe impl Sync for Options {}
impl Options {
pub unsafe fn new(
store_id: StoreId,
memory: Option<NonNull<VMMemoryDefinition>>,
realloc: Option<NonNull<VMFuncRef>>,
string_encoding: StringEncoding,
) -> Options {
Options {
store_id,
memory,
realloc,
string_encoding,
}
}
fn realloc<'a, T>(
&self,
store: &'a mut StoreContextMut<'_, T>,
old: usize,
old_size: usize,
old_align: u32,
new_size: usize,
) -> Result<(&'a mut [u8], usize)> {
self.store_id.assert_belongs_to(store.0.id());
let realloc = self.realloc.unwrap();
let result = unsafe {
crate::TypedFunc::<(u32, u32, u32, u32), u32>::call_raw(
store,
realloc,
(
u32::try_from(old)?,
u32::try_from(old_size)?,
old_align,
u32::try_from(new_size)?,
),
)?
};
if result % old_align != 0 {
bail!("realloc return: result not aligned");
}
let result = usize::try_from(result)?;
let memory = self.memory_mut(store.0);
let result_slice = match memory.get_mut(result..).and_then(|s| s.get_mut(..new_size)) {
Some(end) => end,
None => bail!("realloc return: beyond end of memory"),
};
Ok((result_slice, result))
}
pub fn memory<'a>(&self, store: &'a StoreOpaque) -> &'a [u8] {
self.store_id.assert_belongs_to(store.id());
unsafe {
let memory = self.memory.unwrap().as_ref();
std::slice::from_raw_parts(memory.base, memory.current_length())
}
}
pub fn memory_mut<'a>(&self, store: &'a mut StoreOpaque) -> &'a mut [u8] {
self.store_id.assert_belongs_to(store.id());
unsafe {
let memory = self.memory.unwrap().as_ref();
std::slice::from_raw_parts_mut(memory.base, memory.current_length())
}
}
pub fn string_encoding(&self) -> StringEncoding {
self.string_encoding
}
pub fn store_id(&self) -> StoreId {
self.store_id
}
}
#[doc(hidden)]
pub struct LowerContext<'a, T> {
pub store: StoreContextMut<'a, T>,
pub options: &'a Options,
pub types: &'a ComponentTypes,
instance: *mut ComponentInstance,
}
#[doc(hidden)]
impl<'a, T> LowerContext<'a, T> {
pub unsafe fn new(
store: StoreContextMut<'a, T>,
options: &'a Options,
types: &'a ComponentTypes,
instance: *mut ComponentInstance,
) -> LowerContext<'a, T> {
LowerContext {
store,
options,
types,
instance,
}
}
pub fn as_slice_mut(&mut self) -> &mut [u8] {
self.options.memory_mut(self.store.0)
}
pub fn realloc(
&mut self,
old: usize,
old_size: usize,
old_align: u32,
new_size: usize,
) -> Result<usize> {
self.options
.realloc(&mut self.store, old, old_size, old_align, new_size)
.map(|(_, ptr)| ptr)
}
pub fn get<const N: usize>(&mut self, offset: usize) -> &mut [u8; N] {
(&mut self.as_slice_mut()[offset..][..N])
.try_into()
.unwrap()
}
pub fn guest_resource_lower_own(&mut self, ty: TypeResourceTableIndex, rep: u32) -> u32 {
self.resource_tables().resource_lower_own(Some(ty), rep)
}
pub fn guest_resource_lower_borrow(&mut self, ty: TypeResourceTableIndex, rep: u32) -> u32 {
if unsafe { (*self.instance).resource_owned_by_own_instance(ty) } {
return rep;
}
self.resource_tables().resource_lower_borrow(Some(ty), rep)
}
pub fn host_resource_lift_own(&mut self, idx: u32) -> Result<u32> {
self.resource_tables().resource_lift_own(None, idx)
}
pub fn host_resource_lift_borrow(&mut self, idx: u32) -> Result<u32> {
self.resource_tables().resource_lift_borrow(None, idx)
}
pub fn host_resource_lower_own(&mut self, rep: u32) -> u32 {
self.resource_tables().resource_lower_own(None, rep)
}
pub fn resource_type(&self, ty: TypeResourceTableIndex) -> ResourceType {
self.instance_type().resource_type(ty)
}
pub fn instance_type(&self) -> InstanceType<'_> {
InstanceType::new(unsafe { &*self.instance })
}
fn resource_tables(&mut self) -> ResourceTables<'_> {
let (calls, host_table) = self.store.0.component_calls_and_host_table();
ResourceTables {
host_table: Some(host_table),
calls,
tables: Some(unsafe { (*self.instance).component_resource_tables() }),
}
}
pub fn enter_call(&mut self) {
self.resource_tables().enter_call()
}
pub fn exit_call(&mut self) -> Result<()> {
self.resource_tables().exit_call()
}
}
#[doc(hidden)]
pub struct LiftContext<'a> {
pub options: &'a Options,
pub types: &'a Arc<ComponentTypes>,
memory: Option<&'a [u8]>,
instance: *mut ComponentInstance,
host_table: &'a mut ResourceTable,
calls: &'a mut CallContexts,
}
#[doc(hidden)]
impl<'a> LiftContext<'a> {
pub unsafe fn new(
store: &'a mut StoreOpaque,
options: &'a Options,
types: &'a Arc<ComponentTypes>,
instance: *mut ComponentInstance,
) -> LiftContext<'a> {
let (calls, host_table) =
(&mut *(store as *mut StoreOpaque)).component_calls_and_host_table();
let memory = options.memory.map(|_| options.memory(store));
LiftContext {
memory,
options,
types,
instance,
calls,
host_table,
}
}
pub fn memory(&self) -> &'a [u8] {
self.memory.unwrap()
}
pub fn store_id(&self) -> StoreId {
self.options.store_id
}
pub fn instance_ptr(&self) -> *mut ComponentInstance {
self.instance
}
pub fn guest_resource_lift_own(
&mut self,
ty: TypeResourceTableIndex,
idx: u32,
) -> Result<(u32, Option<NonNull<VMFuncRef>>, Option<InstanceFlags>)> {
let idx = self.resource_tables().resource_lift_own(Some(ty), idx)?;
let (dtor, flags) = unsafe { (*self.instance).dtor_and_flags(ty) };
Ok((idx, dtor, flags))
}
pub fn guest_resource_lift_borrow(
&mut self,
ty: TypeResourceTableIndex,
idx: u32,
) -> Result<u32> {
self.resource_tables().resource_lift_borrow(Some(ty), idx)
}
pub fn host_resource_lower_own(&mut self, rep: u32) -> u32 {
self.resource_tables().resource_lower_own(None, rep)
}
pub fn host_resource_lower_borrow(&mut self, rep: u32) -> u32 {
self.resource_tables().resource_lower_borrow(None, rep)
}
pub fn resource_type(&self, ty: TypeResourceTableIndex) -> ResourceType {
self.instance_type().resource_type(ty)
}
pub fn instance_type(&self) -> InstanceType<'_> {
InstanceType::new(unsafe { &*self.instance })
}
fn resource_tables(&mut self) -> ResourceTables<'_> {
ResourceTables {
host_table: Some(self.host_table),
calls: self.calls,
tables: Some(unsafe { (*self.instance).component_resource_tables() }),
}
}
pub fn enter_call(&mut self) {
self.resource_tables().enter_call()
}
pub fn exit_call(&mut self) -> Result<()> {
self.resource_tables().exit_call()
}
}