use crate::component::{Component, InstancePre, ResourceType, RuntimeImport};
use crate::prelude::*;
use crate::runtime::component::ComponentInstanceId;
use crate::runtime::vm::{
Export, ExportFunction, ExportGlobal, ExportGlobalKind, SendSyncPtr, VMArrayCallFunction,
VMContext, VMFuncRef, VMGlobalDefinition, VMMemoryDefinition, VMOpaqueContext, VMStore,
VMStoreRawPtr, VMTableDefinition, VMTableImport, VMWasmCallFunction, ValRaw, VmPtr, VmSafe,
};
use crate::store::{InstanceId, StoreOpaque};
use alloc::alloc::Layout;
use alloc::sync::Arc;
use core::marker;
use core::mem;
use core::mem::offset_of;
use core::ops::Deref;
use core::ptr::{self, NonNull};
use wasmtime_environ::component::*;
use wasmtime_environ::{
DefinedTableIndex, EntityIndex, Global, HostPtr, PrimaryMap, VMSharedTypeIndex, WasmValType,
};
#[allow(clippy::cast_possible_truncation)] const INVALID_PTR: usize = 0xdead_dead_beef_beef_u64 as usize;
mod libcalls;
mod resources;
pub use self::resources::{
CallContexts, ResourceTable, ResourceTables, TypedResource, TypedResourceIndex,
};
#[repr(C)]
pub struct ComponentInstance {
id: ComponentInstanceId,
offsets: VMComponentOffsets<HostPtr>,
vmctx_self_reference: SendSyncPtr<VMComponentContext>,
component: Component,
instance_resource_tables: PrimaryMap<RuntimeComponentInstanceIndex, ResourceTable>,
instances: PrimaryMap<RuntimeInstanceIndex, InstanceId>,
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
store: VMStoreRawPtr,
post_return_arg: Option<(ExportIndex, ValRaw)>,
vmctx: VMComponentContext,
}
pub type VMLoweringCallee = extern "C" fn(
vmctx: NonNull<VMOpaqueContext>,
data: NonNull<u8>,
ty: u32,
caller_instance: u32,
flags: NonNull<VMGlobalDefinition>,
opt_memory: *mut VMMemoryDefinition,
opt_realloc: *mut VMFuncRef,
string_encoding: u8,
async_: u8,
args_and_results: NonNull<mem::MaybeUninit<ValRaw>>,
nargs_and_results: usize,
) -> bool;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct VMLowering {
pub callee: VMLoweringCallee,
pub data: VmPtr<u8>,
}
unsafe impl VmSafe for VMLowering {}
#[repr(C)]
#[repr(align(16))]
pub struct VMComponentContext {
_marker: marker::PhantomPinned,
}
impl ComponentInstance {
pub unsafe fn from_vmctx<R>(
vmctx: NonNull<VMComponentContext>,
f: impl FnOnce(&mut ComponentInstance) -> R,
) -> R {
let mut ptr = vmctx
.byte_sub(mem::size_of::<ComponentInstance>())
.cast::<ComponentInstance>();
f(ptr.as_mut())
}
fn alloc_layout(offsets: &VMComponentOffsets<HostPtr>) -> Layout {
let size = mem::size_of::<Self>()
.checked_add(usize::try_from(offsets.size_of_vmctx()).unwrap())
.unwrap();
let align = mem::align_of::<Self>();
Layout::from_size_align(size, align).unwrap()
}
unsafe fn new_at(
ptr: NonNull<ComponentInstance>,
alloc_size: usize,
offsets: VMComponentOffsets<HostPtr>,
id: ComponentInstanceId,
component: &Component,
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
store: NonNull<dyn VMStore>,
) {
assert!(alloc_size >= Self::alloc_layout(&offsets).size());
let num_instances = component.env_component().num_runtime_component_instances;
let mut instance_resource_tables =
PrimaryMap::with_capacity(num_instances.try_into().unwrap());
for _ in 0..num_instances {
instance_resource_tables.push(ResourceTable::default());
}
ptr::write(
ptr.as_ptr(),
ComponentInstance {
id,
offsets,
vmctx_self_reference: SendSyncPtr::new(
NonNull::new(
ptr.as_ptr()
.byte_add(mem::size_of::<ComponentInstance>())
.cast(),
)
.unwrap(),
),
instance_resource_tables,
instances: PrimaryMap::with_capacity(
component
.env_component()
.num_runtime_instances
.try_into()
.unwrap(),
),
component: component.clone(),
resource_types,
imports: imports.clone(),
store: VMStoreRawPtr(store),
post_return_arg: None,
vmctx: VMComponentContext {
_marker: marker::PhantomPinned,
},
},
);
(*ptr.as_ptr()).initialize_vmctx();
}
pub fn vmctx(&self) -> NonNull<VMComponentContext> {
let addr = &raw const self.vmctx;
let ret = self.vmctx_self_reference.as_ptr().with_addr(addr.addr());
NonNull::new(ret).unwrap()
}
unsafe fn vmctx_plus_offset<T: VmSafe>(&self, offset: u32) -> *const T {
self.vmctx()
.as_ptr()
.byte_add(usize::try_from(offset).unwrap())
.cast()
}
unsafe fn vmctx_plus_offset_mut<T: VmSafe>(&mut self, offset: u32) -> *mut T {
self.vmctx()
.as_ptr()
.byte_add(usize::try_from(offset).unwrap())
.cast()
}
#[inline]
pub fn instance_flags(&self, instance: RuntimeComponentInstanceIndex) -> InstanceFlags {
unsafe {
let ptr = self
.vmctx_plus_offset::<VMGlobalDefinition>(self.offsets.instance_flags(instance))
.cast_mut();
InstanceFlags(SendSyncPtr::new(NonNull::new(ptr).unwrap()))
}
}
pub fn store(&self) -> *mut dyn VMStore {
self.store.0.as_ptr()
}
pub fn runtime_memory(&self, idx: RuntimeMemoryIndex) -> *mut VMMemoryDefinition {
unsafe {
let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_memory(idx));
debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
ret.as_ptr()
}
}
pub fn runtime_table(&self, idx: RuntimeTableIndex) -> VMTableImport {
unsafe {
let ret = *self.vmctx_plus_offset::<VMTableImport>(self.offsets.runtime_table(idx));
debug_assert!(ret.from.as_ptr() as usize != INVALID_PTR);
debug_assert!(ret.vmctx.as_ptr() as usize != INVALID_PTR);
ret
}
}
pub fn runtime_realloc(&self, idx: RuntimeReallocIndex) -> NonNull<VMFuncRef> {
unsafe {
let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_realloc(idx));
debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
ret.as_non_null()
}
}
pub fn runtime_post_return(&self, idx: RuntimePostReturnIndex) -> NonNull<VMFuncRef> {
unsafe {
let ret = *self.vmctx_plus_offset::<VmPtr<_>>(self.offsets.runtime_post_return(idx));
debug_assert!(ret.as_ptr() as usize != INVALID_PTR);
ret.as_non_null()
}
}
pub fn lowering(&self, idx: LoweredIndex) -> VMLowering {
unsafe {
let ret = *self.vmctx_plus_offset::<VMLowering>(self.offsets.lowering(idx));
debug_assert!(ret.callee as usize != INVALID_PTR);
debug_assert!(ret.data.as_ptr() as usize != INVALID_PTR);
ret
}
}
pub fn trampoline_func_ref(&self, idx: TrampolineIndex) -> NonNull<VMFuncRef> {
unsafe {
let offset = self.offsets.trampoline_func_ref(idx);
let ret = self.vmctx_plus_offset::<VMFuncRef>(offset);
debug_assert!(
mem::transmute::<Option<VmPtr<VMWasmCallFunction>>, usize>((*ret).wasm_call)
!= INVALID_PTR
);
debug_assert!((*ret).vmctx.as_ptr() as usize != INVALID_PTR);
NonNull::new(ret.cast_mut()).unwrap()
}
}
pub fn set_runtime_memory(
&mut self,
idx: RuntimeMemoryIndex,
ptr: NonNull<VMMemoryDefinition>,
) {
unsafe {
let storage = self.vmctx_plus_offset_mut::<VmPtr<VMMemoryDefinition>>(
self.offsets.runtime_memory(idx),
);
debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
*storage = ptr.into();
}
}
pub fn set_runtime_realloc(&mut self, idx: RuntimeReallocIndex, ptr: NonNull<VMFuncRef>) {
unsafe {
let storage =
self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(self.offsets.runtime_realloc(idx));
debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
*storage = ptr.into();
}
}
pub fn set_runtime_callback(&mut self, idx: RuntimeCallbackIndex, ptr: NonNull<VMFuncRef>) {
unsafe {
let storage =
self.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(self.offsets.runtime_callback(idx));
debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
*storage = ptr.into();
}
}
pub fn set_runtime_post_return(
&mut self,
idx: RuntimePostReturnIndex,
ptr: NonNull<VMFuncRef>,
) {
unsafe {
let storage = self
.vmctx_plus_offset_mut::<VmPtr<VMFuncRef>>(self.offsets.runtime_post_return(idx));
debug_assert!((*storage).as_ptr() as usize == INVALID_PTR);
*storage = ptr.into();
}
}
pub fn set_runtime_table(
&mut self,
idx: RuntimeTableIndex,
ptr: NonNull<VMTableDefinition>,
vmctx: NonNull<VMContext>,
index: DefinedTableIndex,
) {
unsafe {
let storage =
self.vmctx_plus_offset_mut::<VMTableImport>(self.offsets.runtime_table(idx));
debug_assert!((*storage).vmctx.as_ptr() as usize == INVALID_PTR);
debug_assert!((*storage).from.as_ptr() as usize == INVALID_PTR);
*storage = VMTableImport {
vmctx: vmctx.into(),
from: ptr.into(),
index,
};
}
}
pub fn set_lowering(&mut self, idx: LoweredIndex, lowering: VMLowering) {
unsafe {
debug_assert!(
*self.vmctx_plus_offset::<usize>(self.offsets.lowering_callee(idx)) == INVALID_PTR
);
debug_assert!(
*self.vmctx_plus_offset::<usize>(self.offsets.lowering_data(idx)) == INVALID_PTR
);
*self.vmctx_plus_offset_mut(self.offsets.lowering(idx)) = lowering;
}
}
pub fn set_trampoline(
&mut self,
idx: TrampolineIndex,
wasm_call: NonNull<VMWasmCallFunction>,
array_call: NonNull<VMArrayCallFunction>,
type_index: VMSharedTypeIndex,
) {
unsafe {
let offset = self.offsets.trampoline_func_ref(idx);
debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
let vmctx = VMOpaqueContext::from_vmcomponent(self.vmctx());
*self.vmctx_plus_offset_mut(offset) = VMFuncRef {
wasm_call: Some(wasm_call.into()),
array_call: array_call.into(),
type_index,
vmctx: vmctx.into(),
};
}
}
pub fn set_resource_destructor(
&mut self,
idx: ResourceIndex,
dtor: Option<NonNull<VMFuncRef>>,
) {
unsafe {
let offset = self.offsets.resource_destructor(idx);
debug_assert!(*self.vmctx_plus_offset::<usize>(offset) == INVALID_PTR);
*self.vmctx_plus_offset_mut(offset) = dtor.map(VmPtr::from);
}
}
pub fn resource_destructor(&self, idx: ResourceIndex) -> Option<NonNull<VMFuncRef>> {
unsafe {
let offset = self.offsets.resource_destructor(idx);
debug_assert!(*self.vmctx_plus_offset::<usize>(offset) != INVALID_PTR);
(*self.vmctx_plus_offset::<Option<VmPtr<VMFuncRef>>>(offset)).map(|p| p.as_non_null())
}
}
unsafe fn initialize_vmctx(&mut self) {
*self.vmctx_plus_offset_mut(self.offsets.magic()) = VMCOMPONENT_MAGIC;
*self.vmctx_plus_offset_mut(self.offsets.builtins()) =
VmPtr::from(NonNull::from(&libcalls::VMComponentBuiltins::INIT));
*self.vmctx_plus_offset_mut(self.offsets.vm_store_context()) =
VmPtr::from(self.store.0.as_ref().vm_store_context_ptr());
for i in 0..self.offsets.num_runtime_component_instances {
let i = RuntimeComponentInstanceIndex::from_u32(i);
let mut def = VMGlobalDefinition::new();
*def.as_i32_mut() = FLAG_MAY_ENTER | FLAG_MAY_LEAVE;
self.instance_flags(i).as_raw().write(def);
}
if cfg!(debug_assertions) {
for i in 0..self.offsets.num_lowerings {
let i = LoweredIndex::from_u32(i);
let offset = self.offsets.lowering_callee(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
let offset = self.offsets.lowering_data(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_trampolines {
let i = TrampolineIndex::from_u32(i);
let offset = self.offsets.trampoline_func_ref(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_runtime_memories {
let i = RuntimeMemoryIndex::from_u32(i);
let offset = self.offsets.runtime_memory(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_runtime_reallocs {
let i = RuntimeReallocIndex::from_u32(i);
let offset = self.offsets.runtime_realloc(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_runtime_callbacks {
let i = RuntimeCallbackIndex::from_u32(i);
let offset = self.offsets.runtime_callback(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_runtime_post_returns {
let i = RuntimePostReturnIndex::from_u32(i);
let offset = self.offsets.runtime_post_return(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_resources {
let i = ResourceIndex::from_u32(i);
let offset = self.offsets.resource_destructor(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
for i in 0..self.offsets.num_runtime_tables {
let i = RuntimeTableIndex::from_u32(i);
let offset = self.offsets.runtime_table(i);
*self.vmctx_plus_offset_mut(offset) = INVALID_PTR;
}
}
}
pub fn component(&self) -> &Component {
&self.component
}
pub fn resource_types(&self) -> &Arc<PrimaryMap<ResourceIndex, ResourceType>> {
&self.resource_types
}
pub fn resource_owned_by_own_instance(&self, ty: TypeResourceTableIndex) -> bool {
let resource = &self.component.types()[ty];
let component = self.component.env_component();
let idx = match component.defined_resource_index(resource.ty) {
Some(idx) => idx,
None => return false,
};
resource.instance == component.defined_resource_instances[idx]
}
pub fn resource_new32(&mut self, ty: TypeResourceTableIndex, rep: u32) -> Result<u32> {
self.resource_tables()
.resource_new(TypedResource::Component { ty, rep })
}
pub fn resource_rep32(&mut self, ty: TypeResourceTableIndex, index: u32) -> Result<u32> {
self.resource_tables()
.resource_rep(TypedResourceIndex::Component { ty, index })
}
pub fn resource_drop(&mut self, ty: TypeResourceTableIndex, index: u32) -> Result<Option<u32>> {
self.resource_tables()
.resource_drop(TypedResourceIndex::Component { ty, index })
}
fn resource_tables(&mut self) -> ResourceTables<'_> {
ResourceTables {
host_table: None,
calls: unsafe { (&mut *self.store()).component_calls() },
guest: Some((&mut self.instance_resource_tables, self.component.types())),
}
}
#[inline]
pub fn guest_tables(
&mut self,
) -> (
&mut PrimaryMap<RuntimeComponentInstanceIndex, ResourceTable>,
&ComponentTypes,
) {
(&mut self.instance_resource_tables, self.component.types())
}
pub fn dtor_and_flags(
&self,
ty: TypeResourceTableIndex,
) -> (Option<NonNull<VMFuncRef>>, Option<InstanceFlags>) {
let resource = self.component.types()[ty].ty;
let dtor = self.resource_destructor(resource);
let component = self.component.env_component();
let flags = component.defined_resource_index(resource).map(|i| {
let instance = component.defined_resource_instances[i];
self.instance_flags(instance)
});
(dtor, flags)
}
pub(crate) fn resource_transfer_own(
&mut self,
index: u32,
src: TypeResourceTableIndex,
dst: TypeResourceTableIndex,
) -> Result<u32> {
let mut tables = self.resource_tables();
let rep = tables.resource_lift_own(TypedResourceIndex::Component { ty: src, index })?;
tables.resource_lower_own(TypedResource::Component { ty: dst, rep })
}
pub(crate) fn resource_transfer_borrow(
&mut self,
index: u32,
src: TypeResourceTableIndex,
dst: TypeResourceTableIndex,
) -> Result<u32> {
let dst_owns_resource = self.resource_owned_by_own_instance(dst);
let mut tables = self.resource_tables();
let rep = tables.resource_lift_borrow(TypedResourceIndex::Component { ty: src, index })?;
if dst_owns_resource {
return Ok(rep);
}
tables.resource_lower_borrow(TypedResource::Component { ty: dst, rep })
}
pub(crate) fn resource_enter_call(&mut self) {
self.resource_tables().enter_call()
}
pub(crate) fn resource_exit_call(&mut self) -> Result<()> {
self.resource_tables().exit_call()
}
#[cfg(feature = "component-model-async")]
pub(crate) fn future_transfer(
&mut self,
src_idx: u32,
src: TypeFutureTableIndex,
dst: TypeFutureTableIndex,
) -> Result<u32> {
_ = (src_idx, src, dst);
todo!()
}
#[cfg(feature = "component-model-async")]
pub(crate) fn stream_transfer(
&mut self,
src_idx: u32,
src: TypeStreamTableIndex,
dst: TypeStreamTableIndex,
) -> Result<u32> {
_ = (src_idx, src, dst);
todo!()
}
#[cfg(feature = "component-model-async")]
pub(crate) fn error_context_transfer(
&mut self,
src_idx: u32,
src: TypeComponentLocalErrorContextTableIndex,
dst: TypeComponentLocalErrorContextTableIndex,
) -> Result<u32> {
_ = (src_idx, src, dst);
todo!()
}
pub fn id(&self) -> ComponentInstanceId {
self.id
}
pub fn push_instance_id(&mut self, id: InstanceId) -> RuntimeInstanceIndex {
self.instances.push(id)
}
pub fn lookup_def(&self, store: &StoreOpaque, def: &CoreDef) -> Export {
match def {
CoreDef::Export(e) => self.lookup_export(store, e),
CoreDef::Trampoline(idx) => Export::Function(ExportFunction {
func_ref: self.trampoline_func_ref(*idx),
}),
CoreDef::InstanceFlags(idx) => Export::Global(ExportGlobal {
definition: self.instance_flags(*idx).as_raw(),
global: Global {
wasm_ty: WasmValType::I32,
mutability: true,
},
kind: ExportGlobalKind::ComponentFlags(self.vmctx(), *idx),
}),
}
}
pub fn lookup_export<T>(&self, store: &StoreOpaque, item: &CoreExport<T>) -> Export
where
T: Copy + Into<EntityIndex>,
{
let id = self.instances[item.instance];
let instance = store.instance(id);
let idx = match &item.item {
ExportItem::Index(idx) => (*idx).into(),
ExportItem::Name(name) => instance.module().exports[name],
};
instance.instance().get_export_by_index(idx)
}
pub(crate) fn runtime_import(&self, import: RuntimeImportIndex) -> &RuntimeImport {
&self.imports[import]
}
pub unsafe fn instance_pre<T>(&self) -> InstancePre<T> {
unsafe {
InstancePre::new_unchecked(
self.component.clone(),
self.imports.clone(),
self.resource_types.clone(),
)
}
}
pub fn post_return_arg_set(&mut self, index: ExportIndex, arg: ValRaw) {
assert!(self.post_return_arg.is_none());
self.post_return_arg = Some((index, arg));
}
pub fn post_return_arg_take(&mut self, index: ExportIndex) -> Option<ValRaw> {
let (expected_index, arg) = self.post_return_arg.take()?;
if index != expected_index {
self.post_return_arg = Some((expected_index, arg));
None
} else {
Some(arg)
}
}
}
impl VMComponentContext {
pub fn instance(&self) -> *mut ComponentInstance {
unsafe {
(self as *const Self as *mut u8)
.offset(-(offset_of!(ComponentInstance, vmctx) as isize))
as *mut ComponentInstance
}
}
}
pub struct OwnedComponentInstance {
ptr: SendSyncPtr<ComponentInstance>,
}
impl OwnedComponentInstance {
pub fn new(
id: ComponentInstanceId,
component: &Component,
resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
imports: &Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
store: NonNull<dyn VMStore>,
) -> OwnedComponentInstance {
let offsets = VMComponentOffsets::new(HostPtr, component.env_component());
let layout = ComponentInstance::alloc_layout(&offsets);
unsafe {
let ptr = alloc::alloc::alloc_zeroed(layout) as *mut ComponentInstance;
let ptr = NonNull::new(ptr).unwrap();
ComponentInstance::new_at(
ptr,
layout.size(),
offsets,
id,
component,
resource_types,
imports,
store,
);
let ptr = SendSyncPtr::new(ptr);
OwnedComponentInstance { ptr }
}
}
unsafe fn instance_mut(&mut self) -> &mut ComponentInstance {
&mut *self.ptr.as_ptr()
}
pub fn instance_ptr(&self) -> NonNull<ComponentInstance> {
self.ptr.as_non_null()
}
pub fn set_runtime_memory(
&mut self,
idx: RuntimeMemoryIndex,
ptr: NonNull<VMMemoryDefinition>,
) {
unsafe { self.instance_mut().set_runtime_memory(idx, ptr) }
}
pub fn set_runtime_realloc(&mut self, idx: RuntimeReallocIndex, ptr: NonNull<VMFuncRef>) {
unsafe { self.instance_mut().set_runtime_realloc(idx, ptr) }
}
pub fn set_runtime_callback(&mut self, idx: RuntimeCallbackIndex, ptr: NonNull<VMFuncRef>) {
unsafe { self.instance_mut().set_runtime_callback(idx, ptr) }
}
pub fn set_runtime_post_return(
&mut self,
idx: RuntimePostReturnIndex,
ptr: NonNull<VMFuncRef>,
) {
unsafe { self.instance_mut().set_runtime_post_return(idx, ptr) }
}
pub fn set_runtime_table(
&mut self,
idx: RuntimeTableIndex,
ptr: NonNull<VMTableDefinition>,
vmctx: NonNull<VMContext>,
index: DefinedTableIndex,
) {
unsafe {
self.instance_mut()
.set_runtime_table(idx, ptr, vmctx, index)
}
}
pub fn set_lowering(&mut self, idx: LoweredIndex, lowering: VMLowering) {
unsafe { self.instance_mut().set_lowering(idx, lowering) }
}
pub fn set_trampoline(
&mut self,
idx: TrampolineIndex,
wasm_call: NonNull<VMWasmCallFunction>,
array_call: NonNull<VMArrayCallFunction>,
type_index: VMSharedTypeIndex,
) {
unsafe {
self.instance_mut()
.set_trampoline(idx, wasm_call, array_call, type_index)
}
}
pub fn set_resource_destructor(
&mut self,
idx: ResourceIndex,
dtor: Option<NonNull<VMFuncRef>>,
) {
unsafe { self.instance_mut().set_resource_destructor(idx, dtor) }
}
pub fn resource_types_mut(&mut self) -> &mut Arc<PrimaryMap<ResourceIndex, ResourceType>> {
unsafe { &mut (*self.ptr.as_ptr()).resource_types }
}
pub fn push_instance_id(&mut self, id: InstanceId) -> RuntimeInstanceIndex {
unsafe { self.instance_mut().push_instance_id(id) }
}
}
impl Deref for OwnedComponentInstance {
type Target = ComponentInstance;
fn deref(&self) -> &ComponentInstance {
unsafe { &*self.ptr.as_ptr() }
}
}
impl Drop for OwnedComponentInstance {
fn drop(&mut self) {
let layout = ComponentInstance::alloc_layout(&self.offsets);
unsafe {
ptr::drop_in_place(self.ptr.as_ptr());
alloc::alloc::dealloc(self.ptr.as_ptr().cast(), layout);
}
}
}
impl VMComponentContext {
#[inline]
pub unsafe fn from_opaque(opaque: NonNull<VMOpaqueContext>) -> NonNull<VMComponentContext> {
debug_assert_eq!(opaque.as_ref().magic, VMCOMPONENT_MAGIC);
opaque.cast()
}
}
impl VMOpaqueContext {
#[inline]
pub fn from_vmcomponent(ptr: NonNull<VMComponentContext>) -> NonNull<VMOpaqueContext> {
ptr.cast()
}
}
#[allow(missing_docs)]
#[repr(transparent)]
#[derive(Copy, Clone)]
pub struct InstanceFlags(SendSyncPtr<VMGlobalDefinition>);
#[allow(missing_docs)]
impl InstanceFlags {
pub unsafe fn from_raw(ptr: NonNull<VMGlobalDefinition>) -> InstanceFlags {
InstanceFlags(SendSyncPtr::from(ptr))
}
#[inline]
pub unsafe fn may_leave(&self) -> bool {
*self.as_raw().as_ref().as_i32() & FLAG_MAY_LEAVE != 0
}
#[inline]
pub unsafe fn set_may_leave(&mut self, val: bool) {
if val {
*self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_LEAVE;
} else {
*self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_LEAVE;
}
}
#[inline]
pub unsafe fn may_enter(&self) -> bool {
*self.as_raw().as_ref().as_i32() & FLAG_MAY_ENTER != 0
}
#[inline]
pub unsafe fn set_may_enter(&mut self, val: bool) {
if val {
*self.as_raw().as_mut().as_i32_mut() |= FLAG_MAY_ENTER;
} else {
*self.as_raw().as_mut().as_i32_mut() &= !FLAG_MAY_ENTER;
}
}
#[inline]
pub unsafe fn needs_post_return(&self) -> bool {
*self.as_raw().as_ref().as_i32() & FLAG_NEEDS_POST_RETURN != 0
}
#[inline]
pub unsafe fn set_needs_post_return(&mut self, val: bool) {
if val {
*self.as_raw().as_mut().as_i32_mut() |= FLAG_NEEDS_POST_RETURN;
} else {
*self.as_raw().as_mut().as_i32_mut() &= !FLAG_NEEDS_POST_RETURN;
}
}
#[inline]
pub fn as_raw(&self) -> NonNull<VMGlobalDefinition> {
self.0.as_non_null()
}
}