Implement RFC 11: Redesigning Wasmtime's APIs (#2897)
Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
This commit is contained in:
@@ -5,12 +5,9 @@
|
||||
use crate::vmcontext::{VMCallerCheckedAnyfunc, VMTableDefinition};
|
||||
use crate::{ResourceLimiter, Trap, VMExternRef};
|
||||
use anyhow::{bail, Result};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cmp::min;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Range;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use wasmtime_environ::wasm::TableElementType;
|
||||
use wasmtime_environ::{ir, TablePlan};
|
||||
|
||||
@@ -25,6 +22,11 @@ pub enum TableElement {
|
||||
ExternRef(Option<VMExternRef>),
|
||||
}
|
||||
|
||||
// The usage of `*mut VMCallerCheckedAnyfunc` is safe w.r.t. thread safety, this
|
||||
// just relies on thread-safety of `VMExternRef` itself.
|
||||
unsafe impl Send for TableElement where VMExternRef: Send {}
|
||||
unsafe impl Sync for TableElement where VMExternRef: Sync {}
|
||||
|
||||
impl TableElement {
|
||||
/// Consumes the given raw pointer into a table element.
|
||||
///
|
||||
@@ -33,13 +35,13 @@ impl TableElement {
|
||||
/// This is unsafe as it will *not* clone any externref, leaving the reference count unchanged.
|
||||
///
|
||||
/// This should only be used if the raw pointer is no longer in use.
|
||||
unsafe fn from_raw(ty: TableElementType, ptr: *mut u8) -> Self {
|
||||
unsafe fn from_raw(ty: TableElementType, ptr: usize) -> Self {
|
||||
match ty {
|
||||
TableElementType::Func => Self::FuncRef(ptr as _),
|
||||
TableElementType::Val(_) => Self::ExternRef(if ptr.is_null() {
|
||||
TableElementType::Val(_) => Self::ExternRef(if ptr == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(VMExternRef::from_raw(ptr))
|
||||
Some(VMExternRef::from_raw(ptr as *mut u8))
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -49,13 +51,13 @@ impl TableElement {
|
||||
/// # Safety
|
||||
///
|
||||
/// This is unsafe as it will clone any externref, incrementing the reference count.
|
||||
unsafe fn clone_from_raw(ty: TableElementType, ptr: *mut u8) -> Self {
|
||||
unsafe fn clone_from_raw(ty: TableElementType, ptr: usize) -> Self {
|
||||
match ty {
|
||||
TableElementType::Func => Self::FuncRef(ptr as _),
|
||||
TableElementType::Val(_) => Self::ExternRef(if ptr.is_null() {
|
||||
TableElementType::Val(_) => Self::ExternRef(if ptr == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(VMExternRef::clone_from_raw(ptr))
|
||||
Some(VMExternRef::clone_from_raw(ptr as *mut u8))
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -68,10 +70,10 @@ impl TableElement {
|
||||
/// the reference count.
|
||||
///
|
||||
/// Use `from_raw` to properly drop any table elements stored as raw pointers.
|
||||
unsafe fn into_raw(self) -> *mut u8 {
|
||||
unsafe fn into_raw(self) -> usize {
|
||||
match self {
|
||||
Self::FuncRef(e) => e as _,
|
||||
Self::ExternRef(e) => e.map_or(ptr::null_mut(), |e| e.into_raw()),
|
||||
Self::ExternRef(e) => e.map_or(0, |e| e.into_raw() as usize),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,71 +96,68 @@ impl From<VMExternRef> for TableElement {
|
||||
}
|
||||
}
|
||||
|
||||
enum TableStorage {
|
||||
/// Represents an instance's table.
|
||||
pub enum Table {
|
||||
/// A "static" table where storage space is managed externally, currently
|
||||
/// used with the pooling allocator.
|
||||
Static {
|
||||
data: *mut *mut u8,
|
||||
size: Cell<u32>,
|
||||
/// Where data for this table is stored. The length of this list is the
|
||||
/// maximum size of the table.
|
||||
data: &'static mut [usize],
|
||||
/// The current size of the table.
|
||||
size: u32,
|
||||
/// The type of this table.
|
||||
ty: TableElementType,
|
||||
maximum: u32,
|
||||
},
|
||||
/// A "dynamic" table where table storage space is dynamically allocated via
|
||||
/// `malloc` (aka Rust's `Vec`).
|
||||
Dynamic {
|
||||
elements: RefCell<Vec<*mut u8>>,
|
||||
/// Dynamically managed storage space for this table. The length of this
|
||||
/// vector is the current size of the table.
|
||||
elements: Vec<usize>,
|
||||
/// The type of this table.
|
||||
ty: TableElementType,
|
||||
/// Maximum size that `elements` can grow to.
|
||||
maximum: Option<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
/// Represents an instance's table.
|
||||
pub struct Table {
|
||||
storage: TableStorage,
|
||||
limiter: Option<Rc<dyn ResourceLimiter>>,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
/// Create a new dynamic (movable) table instance for the specified table plan.
|
||||
pub fn new_dynamic(
|
||||
plan: &TablePlan,
|
||||
limiter: Option<&Rc<dyn ResourceLimiter>>,
|
||||
limiter: Option<&mut dyn ResourceLimiter>,
|
||||
) -> Result<Self> {
|
||||
let elements = RefCell::new(vec![ptr::null_mut(); plan.table.minimum as usize]);
|
||||
Self::limit_new(plan, limiter)?;
|
||||
let elements = vec![0; plan.table.minimum as usize];
|
||||
let ty = plan.table.ty.clone();
|
||||
let maximum = plan.table.maximum;
|
||||
|
||||
let storage = TableStorage::Dynamic {
|
||||
Ok(Table::Dynamic {
|
||||
elements,
|
||||
ty,
|
||||
maximum,
|
||||
};
|
||||
|
||||
Self::new(plan, storage, limiter)
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new static (immovable) table instance for the specified table plan.
|
||||
pub fn new_static(
|
||||
plan: &TablePlan,
|
||||
data: *mut *mut u8,
|
||||
maximum: u32,
|
||||
limiter: Option<&Rc<dyn ResourceLimiter>>,
|
||||
data: &'static mut [usize],
|
||||
limiter: Option<&mut dyn ResourceLimiter>,
|
||||
) -> Result<Self> {
|
||||
let size = Cell::new(plan.table.minimum);
|
||||
Self::limit_new(plan, limiter)?;
|
||||
let size = plan.table.minimum;
|
||||
let ty = plan.table.ty.clone();
|
||||
let maximum = min(plan.table.maximum.unwrap_or(maximum), maximum);
|
||||
|
||||
let storage = TableStorage::Static {
|
||||
data,
|
||||
size,
|
||||
ty,
|
||||
maximum,
|
||||
let data = match plan.table.maximum {
|
||||
Some(max) if (max as usize) < data.len() => &mut data[..max as usize],
|
||||
_ => data,
|
||||
};
|
||||
|
||||
Self::new(plan, storage, limiter)
|
||||
Ok(Table::Static { data, size, ty })
|
||||
}
|
||||
|
||||
fn new(
|
||||
plan: &TablePlan,
|
||||
storage: TableStorage,
|
||||
limiter: Option<&Rc<dyn ResourceLimiter>>,
|
||||
) -> Result<Self> {
|
||||
fn limit_new(plan: &TablePlan, limiter: Option<&mut dyn ResourceLimiter>) -> Result<()> {
|
||||
if let Some(limiter) = limiter {
|
||||
if !limiter.table_growing(0, plan.table.minimum, plan.table.maximum) {
|
||||
bail!(
|
||||
@@ -167,24 +166,20 @@ impl Table {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
storage,
|
||||
limiter: limiter.cloned(),
|
||||
})
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the type of the elements in this table.
|
||||
pub fn element_type(&self) -> TableElementType {
|
||||
match &self.storage {
|
||||
TableStorage::Static { ty, .. } => *ty,
|
||||
TableStorage::Dynamic { ty, .. } => *ty,
|
||||
match self {
|
||||
Table::Static { ty, .. } => *ty,
|
||||
Table::Dynamic { ty, .. } => *ty,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether or not the underlying storage of the table is "static".
|
||||
pub(crate) fn is_static(&self) -> bool {
|
||||
if let TableStorage::Static { .. } = &self.storage {
|
||||
if let Table::Static { .. } = self {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -193,9 +188,9 @@ impl Table {
|
||||
|
||||
/// Returns the number of allocated elements.
|
||||
pub fn size(&self) -> u32 {
|
||||
match &self.storage {
|
||||
TableStorage::Static { size, .. } => size.get(),
|
||||
TableStorage::Dynamic { elements, .. } => elements.borrow().len().try_into().unwrap(),
|
||||
match self {
|
||||
Table::Static { size, .. } => *size,
|
||||
Table::Dynamic { elements, .. } => elements.len().try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,9 +201,9 @@ impl Table {
|
||||
/// The runtime maximum may not be equal to the maximum from the table's Wasm type
|
||||
/// when it is being constrained by an instance allocator.
|
||||
pub fn maximum(&self) -> Option<u32> {
|
||||
match &self.storage {
|
||||
TableStorage::Static { maximum, .. } => Some(*maximum),
|
||||
TableStorage::Dynamic { maximum, .. } => maximum.clone(),
|
||||
match self {
|
||||
Table::Static { data, .. } => Some(data.len() as u32),
|
||||
Table::Dynamic { maximum, .. } => maximum.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,32 +211,31 @@ impl Table {
|
||||
///
|
||||
/// Returns a trap error on out-of-bounds accesses.
|
||||
pub fn init_funcs(
|
||||
&self,
|
||||
&mut self,
|
||||
dst: u32,
|
||||
items: impl ExactSizeIterator<Item = *mut VMCallerCheckedAnyfunc>,
|
||||
) -> Result<(), Trap> {
|
||||
assert!(self.element_type() == TableElementType::Func);
|
||||
|
||||
self.with_elements_mut(|elements| {
|
||||
let elements = match elements
|
||||
.get_mut(usize::try_from(dst).unwrap()..)
|
||||
.and_then(|s| s.get_mut(..items.len()))
|
||||
{
|
||||
Some(elements) => elements,
|
||||
None => return Err(Trap::wasm(ir::TrapCode::TableOutOfBounds)),
|
||||
};
|
||||
let elements = match self
|
||||
.elements_mut()
|
||||
.get_mut(usize::try_from(dst).unwrap()..)
|
||||
.and_then(|s| s.get_mut(..items.len()))
|
||||
{
|
||||
Some(elements) => elements,
|
||||
None => return Err(Trap::wasm(ir::TrapCode::TableOutOfBounds)),
|
||||
};
|
||||
|
||||
for (item, slot) in items.zip(elements) {
|
||||
*slot = item as *mut u8;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
for (item, slot) in items.zip(elements) {
|
||||
*slot = item as usize;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Fill `table[dst..dst + len]` with `val`.
|
||||
///
|
||||
/// Returns a trap error on out-of-bounds accesses.
|
||||
pub fn fill(&self, dst: u32, val: TableElement, len: u32) -> Result<(), Trap> {
|
||||
pub fn fill(&mut self, dst: u32, val: TableElement, len: u32) -> Result<(), Trap> {
|
||||
let start = dst as usize;
|
||||
let end = start
|
||||
.checked_add(len as usize)
|
||||
@@ -253,19 +247,16 @@ impl Table {
|
||||
|
||||
debug_assert!(self.type_matches(&val));
|
||||
|
||||
self.with_elements_mut(|elements| {
|
||||
if let Some((last, elements)) = elements[start..end].split_last_mut() {
|
||||
let ty = self.element_type();
|
||||
|
||||
for e in elements {
|
||||
Self::set_raw(ty, e, val.clone());
|
||||
}
|
||||
|
||||
Self::set_raw(self.element_type(), last, val);
|
||||
let ty = self.element_type();
|
||||
if let Some((last, elements)) = self.elements_mut()[start..end].split_last_mut() {
|
||||
for e in elements {
|
||||
Self::set_raw(ty, e, val.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Self::set_raw(ty, last, val);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Grow table by the specified amount of elements.
|
||||
@@ -284,11 +275,16 @@ impl Table {
|
||||
///
|
||||
/// Generally, prefer using `InstanceHandle::table_grow`, which encapsulates
|
||||
/// this unsafety.
|
||||
pub unsafe fn grow(&self, delta: u32, init_value: TableElement) -> Option<u32> {
|
||||
pub unsafe fn grow(
|
||||
&mut self,
|
||||
delta: u32,
|
||||
init_value: TableElement,
|
||||
limiter: Option<&mut dyn ResourceLimiter>,
|
||||
) -> Option<u32> {
|
||||
let old_size = self.size();
|
||||
let new_size = old_size.checked_add(delta)?;
|
||||
|
||||
if let Some(limiter) = &self.limiter {
|
||||
if let Some(limiter) = limiter {
|
||||
if !limiter.table_growing(old_size, new_size, self.maximum()) {
|
||||
return None;
|
||||
}
|
||||
@@ -303,13 +299,15 @@ impl Table {
|
||||
debug_assert!(self.type_matches(&init_value));
|
||||
|
||||
// First resize the storage and then fill with the init value
|
||||
match &self.storage {
|
||||
TableStorage::Static { size, .. } => {
|
||||
size.set(new_size);
|
||||
match self {
|
||||
Table::Static { size, data, .. } => {
|
||||
debug_assert!(data[*size as usize..new_size as usize]
|
||||
.iter()
|
||||
.all(|x| *x == 0));
|
||||
*size = new_size;
|
||||
}
|
||||
TableStorage::Dynamic { elements, .. } => {
|
||||
let mut elements = elements.borrow_mut();
|
||||
elements.resize(new_size as usize, ptr::null_mut());
|
||||
Table::Dynamic { elements, .. } => {
|
||||
elements.resize(new_size as usize, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,11 +321,9 @@ impl Table {
|
||||
///
|
||||
/// Returns `None` if the index is out of bounds.
|
||||
pub fn get(&self, index: u32) -> Option<TableElement> {
|
||||
self.with_elements(|elements| {
|
||||
elements
|
||||
.get(index as usize)
|
||||
.map(|p| unsafe { TableElement::clone_from_raw(self.element_type(), *p) })
|
||||
})
|
||||
self.elements()
|
||||
.get(index as usize)
|
||||
.map(|p| unsafe { TableElement::clone_from_raw(self.element_type(), *p) })
|
||||
}
|
||||
|
||||
/// Set reference to the specified element.
|
||||
@@ -336,16 +332,15 @@ impl Table {
|
||||
///
|
||||
/// Returns an error if `index` is out of bounds or if this table type does
|
||||
/// not match the element type.
|
||||
pub fn set(&self, index: u32, elem: TableElement) -> Result<(), ()> {
|
||||
pub fn set(&mut self, index: u32, elem: TableElement) -> Result<(), ()> {
|
||||
if !self.type_matches(&elem) {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
self.with_elements_mut(|elements| {
|
||||
let e = elements.get_mut(index as usize).ok_or(())?;
|
||||
Self::set_raw(self.element_type(), e, elem);
|
||||
Ok(())
|
||||
})
|
||||
let ty = self.element_type();
|
||||
let e = self.elements_mut().get_mut(index as usize).ok_or(())?;
|
||||
Self::set_raw(ty, e, elem);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Copy `len` elements from `src_table[src_index..]` into `dst_table[dst_index..]`.
|
||||
@@ -354,9 +349,9 @@ impl Table {
|
||||
///
|
||||
/// Returns an error if the range is out of bounds of either the source or
|
||||
/// destination tables.
|
||||
pub fn copy(
|
||||
dst_table: &Self,
|
||||
src_table: &Self,
|
||||
pub unsafe fn copy(
|
||||
dst_table: *mut Self,
|
||||
src_table: *mut Self,
|
||||
dst_index: u32,
|
||||
src_index: u32,
|
||||
len: u32,
|
||||
@@ -365,16 +360,16 @@ impl Table {
|
||||
|
||||
if src_index
|
||||
.checked_add(len)
|
||||
.map_or(true, |n| n > src_table.size())
|
||||
.map_or(true, |n| n > (*src_table).size())
|
||||
|| dst_index
|
||||
.checked_add(len)
|
||||
.map_or(true, |m| m > dst_table.size())
|
||||
.map_or(true, |m| m > (*dst_table).size())
|
||||
{
|
||||
return Err(Trap::wasm(ir::TrapCode::TableOutOfBounds));
|
||||
}
|
||||
|
||||
debug_assert!(
|
||||
dst_table.element_type() == src_table.element_type(),
|
||||
(*dst_table).element_type() == (*src_table).element_type(),
|
||||
"table element type mismatch"
|
||||
);
|
||||
|
||||
@@ -383,9 +378,9 @@ impl Table {
|
||||
|
||||
// Check if the tables are the same as we cannot mutably borrow and also borrow the same `RefCell`
|
||||
if ptr::eq(dst_table, src_table) {
|
||||
Self::copy_elements_within(dst_table, dst_range, src_range);
|
||||
(*dst_table).copy_elements_within(dst_range, src_range);
|
||||
} else {
|
||||
Self::copy_elements(dst_table, src_table, dst_range, src_range);
|
||||
Self::copy_elements(&mut *dst_table, &*src_table, dst_range, src_range);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -393,18 +388,15 @@ impl Table {
|
||||
|
||||
/// Return a `VMTableDefinition` for exposing the table to compiled wasm code.
|
||||
pub fn vmtable(&self) -> VMTableDefinition {
|
||||
match &self.storage {
|
||||
TableStorage::Static { data, size, .. } => VMTableDefinition {
|
||||
base: *data as _,
|
||||
current_elements: size.get(),
|
||||
match self {
|
||||
Table::Static { data, size, .. } => VMTableDefinition {
|
||||
base: data.as_ptr() as *mut _,
|
||||
current_elements: *size,
|
||||
},
|
||||
Table::Dynamic { elements, .. } => VMTableDefinition {
|
||||
base: elements.as_ptr() as _,
|
||||
current_elements: elements.len().try_into().unwrap(),
|
||||
},
|
||||
TableStorage::Dynamic { elements, .. } => {
|
||||
let elements = elements.borrow();
|
||||
VMTableDefinition {
|
||||
base: elements.as_ptr() as _,
|
||||
current_elements: elements.len().try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,37 +408,21 @@ impl Table {
|
||||
}
|
||||
}
|
||||
|
||||
fn with_elements<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&[*mut u8]) -> R,
|
||||
{
|
||||
match &self.storage {
|
||||
TableStorage::Static { data, size, .. } => unsafe {
|
||||
f(std::slice::from_raw_parts(*data, size.get() as usize))
|
||||
},
|
||||
TableStorage::Dynamic { elements, .. } => {
|
||||
let elements = elements.borrow();
|
||||
f(elements.as_slice())
|
||||
}
|
||||
fn elements(&self) -> &[usize] {
|
||||
match self {
|
||||
Table::Static { data, size, .. } => &data[..*size as usize],
|
||||
Table::Dynamic { elements, .. } => &elements[..],
|
||||
}
|
||||
}
|
||||
|
||||
fn with_elements_mut<F, R>(&self, f: F) -> R
|
||||
where
|
||||
F: FnOnce(&mut [*mut u8]) -> R,
|
||||
{
|
||||
match &self.storage {
|
||||
TableStorage::Static { data, size, .. } => unsafe {
|
||||
f(std::slice::from_raw_parts_mut(*data, size.get() as usize))
|
||||
},
|
||||
TableStorage::Dynamic { elements, .. } => {
|
||||
let mut elements = elements.borrow_mut();
|
||||
f(elements.as_mut_slice())
|
||||
}
|
||||
fn elements_mut(&mut self) -> &mut [usize] {
|
||||
match self {
|
||||
Table::Static { data, size, .. } => &mut data[..*size as usize],
|
||||
Table::Dynamic { elements, .. } => &mut elements[..],
|
||||
}
|
||||
}
|
||||
|
||||
fn set_raw(ty: TableElementType, elem: &mut *mut u8, val: TableElement) {
|
||||
fn set_raw(ty: TableElementType, elem: &mut usize, val: TableElement) {
|
||||
unsafe {
|
||||
let old = *elem;
|
||||
*elem = val.into_raw();
|
||||
@@ -457,7 +433,7 @@ impl Table {
|
||||
}
|
||||
|
||||
fn copy_elements(
|
||||
dst_table: &Self,
|
||||
dst_table: &mut Self,
|
||||
src_table: &Self,
|
||||
dst_range: Range<usize>,
|
||||
src_range: Range<usize>,
|
||||
@@ -470,47 +446,43 @@ impl Table {
|
||||
match ty {
|
||||
TableElementType::Func => {
|
||||
// `funcref` are `Copy`, so just do a mempcy
|
||||
dst_table.with_elements_mut(|dst| {
|
||||
src_table.with_elements(|src| dst[dst_range].copy_from_slice(&src[src_range]))
|
||||
});
|
||||
dst_table.elements_mut()[dst_range]
|
||||
.copy_from_slice(&src_table.elements()[src_range]);
|
||||
}
|
||||
TableElementType::Val(_) => {
|
||||
// We need to clone each `externref`
|
||||
dst_table.with_elements_mut(|dst| {
|
||||
src_table.with_elements(|src| {
|
||||
for (s, d) in src_range.zip(dst_range) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, src[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
})
|
||||
});
|
||||
let dst = dst_table.elements_mut();
|
||||
let src = src_table.elements();
|
||||
for (s, d) in src_range.zip(dst_range) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, src[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_elements_within(table: &Self, dst_range: Range<usize>, src_range: Range<usize>) {
|
||||
let ty = table.element_type();
|
||||
|
||||
fn copy_elements_within(&mut self, dst_range: Range<usize>, src_range: Range<usize>) {
|
||||
let ty = self.element_type();
|
||||
let dst = self.elements_mut();
|
||||
match ty {
|
||||
TableElementType::Func => {
|
||||
// `funcref` are `Copy`, so just do a memmove
|
||||
table.with_elements_mut(|dst| dst.copy_within(src_range, dst_range.start));
|
||||
dst.copy_within(src_range, dst_range.start);
|
||||
}
|
||||
TableElementType::Val(_) => {
|
||||
// We need to clone each `externref` while handling overlapping ranges
|
||||
table.with_elements_mut(|dst| {
|
||||
if dst_range.start <= src_range.start {
|
||||
for (s, d) in src_range.zip(dst_range) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, dst[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
} else {
|
||||
for (s, d) in src_range.rev().zip(dst_range.rev()) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, dst[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
// We need to clone each `externref` while handling overlapping
|
||||
// ranges
|
||||
if dst_range.start <= src_range.start {
|
||||
for (s, d) in src_range.zip(dst_range) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, dst[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for (s, d) in src_range.rev().zip(dst_range.rev()) {
|
||||
let elem = unsafe { TableElement::clone_from_raw(ty, dst[s]) };
|
||||
Self::set_raw(ty, &mut dst[d], elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -526,25 +498,19 @@ impl Drop for Table {
|
||||
}
|
||||
|
||||
// Properly drop any table elements stored in the table
|
||||
self.with_elements(|elements| {
|
||||
for element in elements.iter() {
|
||||
let _ = unsafe { TableElement::from_raw(ty, *element) };
|
||||
}
|
||||
});
|
||||
for element in self.elements() {
|
||||
drop(unsafe { TableElement::from_raw(ty, *element) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The default table representation is an empty funcref table that cannot grow.
|
||||
impl Default for Table {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
storage: TableStorage::Static {
|
||||
data: std::ptr::null_mut(),
|
||||
size: Cell::new(0),
|
||||
ty: TableElementType::Func,
|
||||
maximum: 0,
|
||||
},
|
||||
limiter: None,
|
||||
Table::Static {
|
||||
data: &mut [],
|
||||
size: 0,
|
||||
ty: TableElementType::Func,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user