Move table_utils into wasmtime_runtime
This commit is contained in:
committed by
Dan Gohman
parent
de1c0f63eb
commit
164039f08d
@@ -1,10 +1,9 @@
|
|||||||
use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable};
|
use crate::callable::{Callable, NativeCallable, WasmtimeFn, WrappedCallable};
|
||||||
use crate::runtime::Store;
|
use crate::runtime::Store;
|
||||||
use crate::table_utils;
|
|
||||||
use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
|
use crate::trampoline::{generate_global_export, generate_memory_export, generate_table_export};
|
||||||
use crate::trap::Trap;
|
use crate::trap::Trap;
|
||||||
use crate::types::{ExternType, FuncType, GlobalType, MemoryType, TableType, ValType};
|
use crate::types::{ExternType, FuncType, GlobalType, MemoryType, TableType, ValType};
|
||||||
use crate::values::Val;
|
use crate::values::{from_checked_anyfunc, into_checked_anyfunc, AnyRef, Val};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
@@ -244,20 +243,62 @@ impl Global {
|
|||||||
pub struct Table {
|
pub struct Table {
|
||||||
store: Rc<RefCell<Store>>,
|
store: Rc<RefCell<Store>>,
|
||||||
r#type: TableType,
|
r#type: TableType,
|
||||||
#[allow(dead_code)]
|
|
||||||
wasmtime_handle: InstanceHandle,
|
wasmtime_handle: InstanceHandle,
|
||||||
wasmtime_export: wasmtime_runtime::Export,
|
wasmtime_export: wasmtime_runtime::Export,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_table_item(
|
||||||
|
handle: &InstanceHandle,
|
||||||
|
store: &Rc<RefCell<Store>>,
|
||||||
|
table_index: cranelift_wasm::DefinedTableIndex,
|
||||||
|
item_index: u32,
|
||||||
|
) -> Val {
|
||||||
|
if let Some(item) = handle.table_get(table_index, item_index) {
|
||||||
|
from_checked_anyfunc(item, store)
|
||||||
|
} else {
|
||||||
|
AnyRef::null().into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_table_item(
|
||||||
|
handle: &mut InstanceHandle,
|
||||||
|
store: &Rc<RefCell<Store>>,
|
||||||
|
table_index: cranelift_wasm::DefinedTableIndex,
|
||||||
|
item_index: u32,
|
||||||
|
val: Val,
|
||||||
|
) -> bool {
|
||||||
|
let item = into_checked_anyfunc(val, store);
|
||||||
|
if let Some(item_ref) = handle.table_get_mut(table_index, item_index) {
|
||||||
|
*item_ref = item;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Table {
|
impl Table {
|
||||||
pub fn new(store: Rc<RefCell<Store>>, r#type: TableType, _init: Val) -> Table {
|
pub fn new(store: Rc<RefCell<Store>>, r#type: TableType, init: Val) -> Table {
|
||||||
match r#type.element() {
|
match r#type.element() {
|
||||||
ValType::FuncRef => (),
|
ValType::FuncRef => (),
|
||||||
_ => panic!("table is not for funcref"),
|
_ => panic!("table is not for funcref"),
|
||||||
}
|
}
|
||||||
// TODO implement _init initialization
|
let (mut wasmtime_handle, wasmtime_export) =
|
||||||
let (wasmtime_handle, wasmtime_export) =
|
|
||||||
generate_table_export(&r#type).expect("generated table");
|
generate_table_export(&r#type).expect("generated table");
|
||||||
|
|
||||||
|
// Initialize entries with the init value.
|
||||||
|
match wasmtime_export {
|
||||||
|
wasmtime_runtime::Export::Table { definition, .. } => {
|
||||||
|
let index = wasmtime_handle.table_index(unsafe { &*definition });
|
||||||
|
let len = unsafe { (*definition).current_elements as u32 };
|
||||||
|
for i in 0..len {
|
||||||
|
let _success =
|
||||||
|
set_table_item(&mut wasmtime_handle, &store, index, i, init.clone());
|
||||||
|
assert!(_success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("global definition not found"),
|
||||||
|
}
|
||||||
|
|
||||||
Table {
|
Table {
|
||||||
store,
|
store,
|
||||||
r#type,
|
r#type,
|
||||||
@@ -270,31 +311,49 @@ impl Table {
|
|||||||
&self.r#type
|
&self.r#type
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wasmtime_table_definition(&self) -> *mut wasmtime_runtime::VMTableDefinition {
|
fn wasmtime_table_index(&self) -> cranelift_wasm::DefinedTableIndex {
|
||||||
match self.wasmtime_export {
|
match self.wasmtime_export {
|
||||||
wasmtime_runtime::Export::Table { definition, .. } => definition,
|
wasmtime_runtime::Export::Table { definition, .. } => {
|
||||||
|
self.wasmtime_handle.table_index(unsafe { &*definition })
|
||||||
|
}
|
||||||
_ => panic!("global definition not found"),
|
_ => panic!("global definition not found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, index: u32) -> Val {
|
pub fn get(&self, index: u32) -> Val {
|
||||||
let definition = self.wasmtime_table_definition();
|
let table_index = self.wasmtime_table_index();
|
||||||
unsafe { table_utils::get_item(definition, &self.store, index) }
|
get_table_item(&self.wasmtime_handle, &self.store, table_index, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&self, index: u32, val: Val) -> bool {
|
pub fn set(&self, index: u32, val: Val) -> bool {
|
||||||
let definition = self.wasmtime_table_definition();
|
let table_index = self.wasmtime_table_index();
|
||||||
unsafe { table_utils::set_item(definition, &self.store, index, val) }
|
let mut wasmtime_handle = self.wasmtime_handle.clone();
|
||||||
|
set_table_item(&mut wasmtime_handle, &self.store, table_index, index, val)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> u32 {
|
pub fn size(&self) -> u32 {
|
||||||
let definition = self.wasmtime_table_definition();
|
match self.wasmtime_export {
|
||||||
unsafe { table_utils::get_size(definition) }
|
wasmtime_runtime::Export::Table { definition, .. } => unsafe {
|
||||||
|
(*definition).current_elements as u32
|
||||||
|
},
|
||||||
|
_ => panic!("global definition not found"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn grow(&mut self, delta: u32, init: Val) -> bool {
|
pub fn grow(&mut self, delta: u32, init: Val) -> bool {
|
||||||
let definition = self.wasmtime_table_definition();
|
let index = self.wasmtime_table_index();
|
||||||
unsafe { table_utils::grow_table(definition, &self.r#type, &self.store, delta, init) }
|
if let Some(len) = self.wasmtime_handle.table_grow(index, delta) {
|
||||||
|
let mut wasmtime_handle = self.wasmtime_handle.clone();
|
||||||
|
for i in 0..delta {
|
||||||
|
let i = len as u32 - (delta - i);
|
||||||
|
let _success =
|
||||||
|
set_table_item(&mut wasmtime_handle, &self.store, index, i, init.clone());
|
||||||
|
assert!(_success);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
|
pub(crate) fn wasmtime_export(&self) -> &wasmtime_runtime::Export {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ mod externals;
|
|||||||
mod instance;
|
mod instance;
|
||||||
mod module;
|
mod module;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
mod table_utils;
|
|
||||||
mod trampoline;
|
mod trampoline;
|
||||||
mod trap;
|
mod trap;
|
||||||
mod types;
|
mod types;
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
use std::cell::RefCell;
|
|
||||||
use std::mem;
|
|
||||||
use std::ptr;
|
|
||||||
use std::rc::Rc;
|
|
||||||
use std::slice;
|
|
||||||
use wasmtime_runtime::{
|
|
||||||
InstanceHandle, VMCallerCheckedAnyfunc, VMSharedSignatureIndex, VMTableDefinition,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::callable::WasmtimeFn;
|
|
||||||
use crate::runtime::SignatureRegistry;
|
|
||||||
use crate::runtime::Store;
|
|
||||||
use crate::types::TableType;
|
|
||||||
use crate::values::{AnyRef, FuncRef, Val};
|
|
||||||
|
|
||||||
fn into_checked_anyfunc(val: Val, store: &Rc<RefCell<Store>>) -> VMCallerCheckedAnyfunc {
|
|
||||||
match val {
|
|
||||||
Val::AnyRef(AnyRef::Null) => VMCallerCheckedAnyfunc {
|
|
||||||
func_ptr: ptr::null(),
|
|
||||||
type_index: VMSharedSignatureIndex::default(),
|
|
||||||
vmctx: ptr::null_mut(),
|
|
||||||
},
|
|
||||||
Val::AnyRef(AnyRef::Func(f)) | Val::FuncRef(f) => {
|
|
||||||
let (vmctx, func_ptr, signature) = match f.0.wasmtime_export() {
|
|
||||||
wasmtime_runtime::Export::Function {
|
|
||||||
vmctx,
|
|
||||||
address,
|
|
||||||
signature,
|
|
||||||
} => (*vmctx, *address, signature),
|
|
||||||
_ => panic!("expected function export"),
|
|
||||||
};
|
|
||||||
let type_index = store.borrow_mut().register_cranelift_signature(signature);
|
|
||||||
VMCallerCheckedAnyfunc {
|
|
||||||
func_ptr,
|
|
||||||
type_index,
|
|
||||||
vmctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("val is not funcref"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn from_checked_anyfunc(item: &VMCallerCheckedAnyfunc, store: &Rc<RefCell<Store>>) -> Val {
|
|
||||||
if item.type_index == VMSharedSignatureIndex::default() {
|
|
||||||
return Val::AnyRef(AnyRef::Null);
|
|
||||||
}
|
|
||||||
let signature = store
|
|
||||||
.borrow()
|
|
||||||
.lookup_cranelift_signature(item.type_index)
|
|
||||||
.expect("signature")
|
|
||||||
.clone();
|
|
||||||
let instance_handle = InstanceHandle::from_vmctx(item.vmctx);
|
|
||||||
let export = wasmtime_runtime::Export::Function {
|
|
||||||
address: item.func_ptr,
|
|
||||||
signature,
|
|
||||||
vmctx: item.vmctx,
|
|
||||||
};
|
|
||||||
let f = WasmtimeFn::new(store.clone(), instance_handle, export);
|
|
||||||
Val::FuncRef(FuncRef(Rc::new(f)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_item(
|
|
||||||
table: *mut VMTableDefinition,
|
|
||||||
store: &Rc<RefCell<Store>>,
|
|
||||||
index: u32,
|
|
||||||
) -> Val {
|
|
||||||
let base = slice::from_raw_parts(
|
|
||||||
(*table).base as *const VMCallerCheckedAnyfunc,
|
|
||||||
(*table).current_elements,
|
|
||||||
);
|
|
||||||
|
|
||||||
from_checked_anyfunc(&base[index as usize], store)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn set_item(
|
|
||||||
table: *mut VMTableDefinition,
|
|
||||||
store: &Rc<RefCell<Store>>,
|
|
||||||
index: u32,
|
|
||||||
val: Val,
|
|
||||||
) -> bool {
|
|
||||||
let base = slice::from_raw_parts_mut(
|
|
||||||
(*table).base as *mut VMCallerCheckedAnyfunc,
|
|
||||||
(*table).current_elements,
|
|
||||||
);
|
|
||||||
if index as usize >= base.len() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
base[index as usize] = into_checked_anyfunc(val, store);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn get_size(table: *mut VMTableDefinition) -> u32 {
|
|
||||||
(*table).current_elements as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
pub unsafe fn grow_table(
|
|
||||||
table: *mut VMTableDefinition,
|
|
||||||
table_type: &TableType,
|
|
||||||
store: &Rc<RefCell<Store>>,
|
|
||||||
delta: u32,
|
|
||||||
init: Val,
|
|
||||||
) -> bool {
|
|
||||||
let new_len = (*table).current_elements + delta as usize;
|
|
||||||
if (table_type.limits().max() as usize) < new_len {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut buffer = Vec::from_raw_parts(
|
|
||||||
(*table).base as *mut VMCallerCheckedAnyfunc,
|
|
||||||
(*table).current_elements,
|
|
||||||
(*table).current_elements,
|
|
||||||
);
|
|
||||||
buffer.resize(new_len, into_checked_anyfunc(init, store));
|
|
||||||
buffer.shrink_to_fit();
|
|
||||||
assert!(buffer.capacity() == new_len);
|
|
||||||
|
|
||||||
(*table).base = buffer.as_mut_ptr() as *mut u8;
|
|
||||||
(*table).current_elements = new_len;
|
|
||||||
mem::forget(buffer);
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
use crate::callable::WrappedCallable;
|
use crate::callable::{WasmtimeFn, WrappedCallable};
|
||||||
|
use crate::runtime::{SignatureRegistry, Store};
|
||||||
use crate::types::ValType;
|
use crate::types::ValType;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@@ -199,3 +201,55 @@ impl Into<AnyRef> for Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn into_checked_anyfunc(
|
||||||
|
val: Val,
|
||||||
|
store: &Rc<RefCell<Store>>,
|
||||||
|
) -> wasmtime_runtime::VMCallerCheckedAnyfunc {
|
||||||
|
match val {
|
||||||
|
Val::AnyRef(AnyRef::Null) => wasmtime_runtime::VMCallerCheckedAnyfunc {
|
||||||
|
func_ptr: ptr::null(),
|
||||||
|
type_index: wasmtime_runtime::VMSharedSignatureIndex::default(),
|
||||||
|
vmctx: ptr::null_mut(),
|
||||||
|
},
|
||||||
|
Val::AnyRef(AnyRef::Func(f)) | Val::FuncRef(f) => {
|
||||||
|
let (vmctx, func_ptr, signature) = match f.0.wasmtime_export() {
|
||||||
|
wasmtime_runtime::Export::Function {
|
||||||
|
vmctx,
|
||||||
|
address,
|
||||||
|
signature,
|
||||||
|
} => (*vmctx, *address, signature),
|
||||||
|
_ => panic!("expected function export"),
|
||||||
|
};
|
||||||
|
let type_index = store.borrow_mut().register_cranelift_signature(signature);
|
||||||
|
wasmtime_runtime::VMCallerCheckedAnyfunc {
|
||||||
|
func_ptr,
|
||||||
|
type_index,
|
||||||
|
vmctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("val is not funcref"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_checked_anyfunc(
|
||||||
|
item: &wasmtime_runtime::VMCallerCheckedAnyfunc,
|
||||||
|
store: &Rc<RefCell<Store>>,
|
||||||
|
) -> Val {
|
||||||
|
if item.type_index == wasmtime_runtime::VMSharedSignatureIndex::default() {
|
||||||
|
return Val::AnyRef(AnyRef::Null);
|
||||||
|
}
|
||||||
|
let signature = store
|
||||||
|
.borrow()
|
||||||
|
.lookup_cranelift_signature(item.type_index)
|
||||||
|
.expect("signature")
|
||||||
|
.clone();
|
||||||
|
let instance_handle = unsafe { wasmtime_runtime::InstanceHandle::from_vmctx(item.vmctx) };
|
||||||
|
let export = wasmtime_runtime::Export::Function {
|
||||||
|
address: item.func_ptr,
|
||||||
|
signature,
|
||||||
|
vmctx: item.vmctx,
|
||||||
|
};
|
||||||
|
let f = WasmtimeFn::new(store.clone(), instance_handle, export);
|
||||||
|
Val::FuncRef(FuncRef(Rc::new(f)))
|
||||||
|
}
|
||||||
|
|||||||
@@ -622,6 +622,47 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grow table by the specified amount of elements.
|
||||||
|
///
|
||||||
|
/// Returns `None` if table can't be grown by the specified amount
|
||||||
|
/// of elements.
|
||||||
|
pub(crate) fn table_grow(&mut self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
|
||||||
|
let result = self
|
||||||
|
.tables
|
||||||
|
.get_mut(table_index)
|
||||||
|
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
|
||||||
|
.grow(delta);
|
||||||
|
|
||||||
|
// Keep current the VMContext pointers used by compiled wasm code.
|
||||||
|
*self.table_mut(table_index) = self.tables[table_index].vmtable();
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get table element by index.
|
||||||
|
pub(crate) fn table_get(
|
||||||
|
&self,
|
||||||
|
table_index: DefinedTableIndex,
|
||||||
|
index: u32,
|
||||||
|
) -> Option<&VMCallerCheckedAnyfunc> {
|
||||||
|
self.tables
|
||||||
|
.get(table_index)
|
||||||
|
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
|
||||||
|
.get(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get table mutable element by index.
|
||||||
|
pub(crate) fn table_get_mut(
|
||||||
|
&mut self,
|
||||||
|
table_index: DefinedTableIndex,
|
||||||
|
index: u32,
|
||||||
|
) -> Option<&mut VMCallerCheckedAnyfunc> {
|
||||||
|
self.tables
|
||||||
|
.get_mut(table_index)
|
||||||
|
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
|
||||||
|
.get_mut(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle holding an `Instance` of a WebAssembly module.
|
/// A handle holding an `Instance` of a WebAssembly module.
|
||||||
@@ -871,6 +912,41 @@ impl InstanceHandle {
|
|||||||
pub fn memory_grow(&mut self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
|
pub fn memory_grow(&mut self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
|
||||||
self.instance_mut().memory_grow(memory_index, delta)
|
self.instance_mut().memory_grow(memory_index, delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the table index for the given `VMTableDefinition` in this instance.
|
||||||
|
pub fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
|
||||||
|
self.instance().table_index(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Grow table in this instance by the specified amount of pages.
|
||||||
|
///
|
||||||
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
|
/// of pages.
|
||||||
|
pub fn table_grow(&mut self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
|
||||||
|
self.instance_mut().table_grow(table_index, delta)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get table element reference.
|
||||||
|
///
|
||||||
|
/// Returns `None` if index is out of bounds.
|
||||||
|
pub fn table_get(
|
||||||
|
&self,
|
||||||
|
table_index: DefinedTableIndex,
|
||||||
|
index: u32,
|
||||||
|
) -> Option<&VMCallerCheckedAnyfunc> {
|
||||||
|
self.instance().table_get(table_index, index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable table element reference.
|
||||||
|
///
|
||||||
|
/// Returns `None` if index is out of bounds.
|
||||||
|
pub fn table_get_mut(
|
||||||
|
&mut self,
|
||||||
|
table_index: DefinedTableIndex,
|
||||||
|
index: u32,
|
||||||
|
) -> Option<&mut VMCallerCheckedAnyfunc> {
|
||||||
|
self.instance_mut().table_get_mut(table_index, index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InstanceHandle {
|
impl InstanceHandle {
|
||||||
|
|||||||
@@ -32,6 +32,48 @@ impl Table {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of allocated elements.
|
||||||
|
pub fn size(&self) -> u32 {
|
||||||
|
self.vec.len() as u32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Grow table by the specified amount of elements.
|
||||||
|
///
|
||||||
|
/// Returns `None` if table can't be grown by the specified amount
|
||||||
|
/// of elements.
|
||||||
|
pub fn grow(&mut self, delta: u32) -> Option<u32> {
|
||||||
|
let new_len = match self.size().checked_add(delta) {
|
||||||
|
Some(len) => {
|
||||||
|
if let Some(max) = self.maximum {
|
||||||
|
if len > max {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
len
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.vec
|
||||||
|
.resize(new_len as usize, VMCallerCheckedAnyfunc::default());
|
||||||
|
Some(new_len)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get reference to the specified element.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the index is out of bounds.
|
||||||
|
pub fn get(&self, index: u32) -> Option<&VMCallerCheckedAnyfunc> {
|
||||||
|
self.vec.get(index as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable reference to the specified element.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the index is out of bounds.
|
||||||
|
pub fn get_mut(&mut self, index: u32) -> Option<&mut VMCallerCheckedAnyfunc> {
|
||||||
|
self.vec.get_mut(index as usize)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return a `VMTableDefinition` for exposing the table to compiled wasm code.
|
/// Return a `VMTableDefinition` for exposing the table to compiled wasm code.
|
||||||
pub fn vmtable(&mut self) -> VMTableDefinition {
|
pub fn vmtable(&mut self) -> VMTableDefinition {
|
||||||
VMTableDefinition {
|
VMTableDefinition {
|
||||||
|
|||||||
Reference in New Issue
Block a user