use super::PoolingInstanceAllocator;
use crate::vm::{MemoryAllocationIndex, MemoryImageSlot, Table, TableAllocationIndex};
use smallvec::SmallVec;
#[cfg(feature = "async")]
use wasmtime_fiber::FiberStack;
#[cfg(unix)]
#[allow(non_camel_case_types)]
type iovec = libc::iovec;
#[cfg(not(unix))]
#[allow(non_camel_case_types)]
struct iovec {
iov_base: *mut libc::c_void,
iov_len: libc::size_t,
}
#[repr(transparent)]
struct IoVec(iovec);
unsafe impl Send for IoVec {}
unsafe impl Sync for IoVec {}
impl std::fmt::Debug for IoVec {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("IoVec")
.field("base", &self.0.iov_base)
.field("len", &self.0.iov_len)
.finish()
}
}
#[cfg(feature = "async")]
struct SendSyncStack(FiberStack);
#[cfg(feature = "async")]
unsafe impl Send for SendSyncStack {}
#[cfg(feature = "async")]
unsafe impl Sync for SendSyncStack {}
#[derive(Default)]
pub struct DecommitQueue {
raw: SmallVec<[IoVec; 2]>,
memories: SmallVec<[(MemoryAllocationIndex, MemoryImageSlot); 1]>,
tables: SmallVec<[(TableAllocationIndex, Table); 1]>,
#[cfg(feature = "async")]
stacks: SmallVec<[SendSyncStack; 1]>,
}
impl std::fmt::Debug for DecommitQueue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DecommitQueue")
.field("raw", &self.raw)
.finish_non_exhaustive()
}
}
impl DecommitQueue {
pub fn append(
&mut self,
Self {
raw,
memories,
tables,
#[cfg(feature = "async")]
stacks,
}: &mut Self,
) {
self.raw.append(raw);
self.memories.append(memories);
self.tables.append(tables);
#[cfg(feature = "async")]
self.stacks.append(stacks);
}
pub fn raw_len(&self) -> usize {
self.raw.len()
}
pub unsafe fn push_raw(&mut self, ptr: *mut u8, len: usize) {
self.raw.push(IoVec(iovec {
iov_base: ptr.cast(),
iov_len: len,
}));
}
pub unsafe fn push_memory(
&mut self,
allocation_index: MemoryAllocationIndex,
image: MemoryImageSlot,
) {
self.memories.push((allocation_index, image));
}
pub unsafe fn push_table(&mut self, allocation_index: TableAllocationIndex, table: Table) {
self.tables.push((allocation_index, table));
}
#[cfg(feature = "async")]
pub unsafe fn push_stack(&mut self, stack: FiberStack) {
self.stacks.push(SendSyncStack(stack));
}
fn decommit_all_raw(&mut self) {
for iovec in self.raw.drain(..) {
unsafe {
crate::vm::sys::vm::decommit_pages(iovec.0.iov_base.cast(), iovec.0.iov_len)
.expect("failed to decommit pages");
}
}
}
pub fn flush(mut self, pool: &PoolingInstanceAllocator) -> bool {
self.decommit_all_raw();
let mut deallocated_any = false;
for (allocation_index, image) in self.memories {
deallocated_any = true;
unsafe {
pool.memories.deallocate(allocation_index, image);
}
}
for (allocation_index, table) in self.tables {
deallocated_any = true;
unsafe {
pool.tables.deallocate(allocation_index, table);
}
}
#[cfg(feature = "async")]
for stack in self.stacks {
deallocated_any = true;
unsafe {
pool.stacks.deallocate(stack.0);
}
}
deallocated_any
}
}