2019-05-17 01:10:21 +08:00
|
|
|
pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE};
|
2019-01-21 14:01:25 -08:00
|
|
|
use crate::{
|
2019-09-18 16:06:46 -07:00
|
|
|
error::CallResult,
|
|
|
|
instance::call_func_with_index_inner,
|
2019-05-04 10:33:12 -07:00
|
|
|
memory::{Memory, MemoryType},
|
|
|
|
module::{ModuleInfo, ModuleInner},
|
2019-09-18 16:06:46 -07:00
|
|
|
sig_registry::SigRegistry,
|
2019-01-21 14:05:32 -08:00
|
|
|
structures::TypedIndex,
|
2019-09-18 16:06:46 -07:00
|
|
|
types::{LocalOrImport, MemoryIndex, TableIndex, Value},
|
2019-05-04 10:33:12 -07:00
|
|
|
vmcalls,
|
2019-01-17 14:13:28 -08:00
|
|
|
};
|
2019-05-23 20:10:34 +08:00
|
|
|
use std::{
|
|
|
|
cell::UnsafeCell,
|
|
|
|
ffi::c_void,
|
2019-09-18 16:06:46 -07:00
|
|
|
mem,
|
|
|
|
ptr::{self, NonNull},
|
2019-05-23 20:10:34 +08:00
|
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
|
|
sync::Once,
|
|
|
|
};
|
2019-01-08 12:09:47 -05:00
|
|
|
|
2019-07-31 23:17:42 -07:00
|
|
|
use std::collections::HashMap;
|
2019-03-27 14:01:27 -07:00
|
|
|
|
2019-01-23 12:34:15 -08:00
|
|
|
/// The context of the currently running WebAssembly instance.
|
|
|
|
///
|
2019-05-13 11:18:57 -07:00
|
|
|
/// This is implicitly passed to every WebAssembly function.
|
|
|
|
/// Since this is per-instance, each field has a statically
|
2019-03-13 14:58:44 -07:00
|
|
|
/// (as in after compiling the wasm) known size, so no
|
|
|
|
/// runtime checks are necessary.
|
2019-01-23 12:34:15 -08:00
|
|
|
///
|
2019-03-13 14:58:44 -07:00
|
|
|
/// While the runtime currently just passes this around
|
|
|
|
/// as the first, implicit parameter of every function,
|
|
|
|
/// it may someday be pinned to a register (especially
|
|
|
|
/// on arm, which has a ton of registers) to reduce
|
|
|
|
/// register shuffling.
|
2019-01-08 12:09:47 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct Ctx {
|
2019-03-21 08:39:06 +08:00
|
|
|
// `internal` must be the first field of `Ctx`.
|
2019-05-04 09:56:52 -07:00
|
|
|
pub internal: InternalCtx,
|
2019-03-21 08:39:06 +08:00
|
|
|
|
|
|
|
pub(crate) local_functions: *const *const Func,
|
|
|
|
|
2019-03-13 14:58:44 -07:00
|
|
|
/// These are pointers to things that are known to be owned
|
|
|
|
/// by the owning `Instance`.
|
2019-06-26 01:38:39 +08:00
|
|
|
pub local_backing: *mut LocalBacking,
|
|
|
|
pub import_backing: *mut ImportBacking,
|
2019-04-27 16:31:47 +08:00
|
|
|
pub module: *const ModuleInner,
|
2019-03-21 08:39:06 +08:00
|
|
|
|
2019-07-18 11:24:25 -07:00
|
|
|
/// This is intended to be user-supplied, per-instance
|
2019-03-13 14:58:44 -07:00
|
|
|
/// contextual data. There are currently some issue with it,
|
|
|
|
/// notably that it cannot be set before running the `start`
|
2019-05-13 11:18:57 -07:00
|
|
|
/// function in a WebAssembly module.
|
2019-03-13 14:58:44 -07:00
|
|
|
///
|
|
|
|
/// [#219](https://github.com/wasmerio/wasmer/pull/219) fixes that
|
|
|
|
/// issue, as well as allowing the user to have *per-function*
|
|
|
|
/// context, instead of just per-instance.
|
2019-03-21 08:39:06 +08:00
|
|
|
pub data: *mut c_void,
|
2019-03-13 14:58:44 -07:00
|
|
|
|
|
|
|
/// If there's a function set in this field, it gets called
|
|
|
|
/// when the context is destructed, e.g. when an `Instance`
|
|
|
|
/// is dropped.
|
2019-03-28 11:56:31 -07:00
|
|
|
pub data_finalizer: Option<fn(data: *mut c_void)>,
|
2019-03-21 08:39:06 +08:00
|
|
|
}
|
|
|
|
|
2019-07-15 15:14:09 +03:00
|
|
|
/// When an instance context is destructed, we're calling its `data_finalizer`
|
|
|
|
/// In order avoid leaking resources.
|
|
|
|
///
|
|
|
|
/// Implementing the `data_finalizer` function is the responsibility of the `wasmer` end-user.
|
|
|
|
///
|
|
|
|
/// See test: `test_data_finalizer` as an example
|
|
|
|
impl Drop for Ctx {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
if let Some(ref finalizer) = self.data_finalizer {
|
|
|
|
finalizer(self.data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-21 08:39:06 +08:00
|
|
|
/// The internal context of the currently running WebAssembly instance.
|
|
|
|
///
|
|
|
|
///
|
2019-03-21 08:57:50 +08:00
|
|
|
#[doc(hidden)]
|
2019-03-21 08:39:06 +08:00
|
|
|
#[derive(Debug)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct InternalCtx {
|
2019-01-08 12:09:47 -05:00
|
|
|
/// A pointer to an array of locally-defined memories, indexed by `MemoryIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub memories: *mut *mut LocalMemory,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// A pointer to an array of locally-defined tables, indexed by `TableIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub tables: *mut *mut LocalTable,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// A pointer to an array of locally-defined globals, indexed by `GlobalIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub globals: *mut *mut LocalGlobal,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
2019-07-15 10:55:26 -07:00
|
|
|
/// A pointer to an array of imported memories, indexed by `MemoryIndex`,
|
2019-03-14 10:30:24 +08:00
|
|
|
pub imported_memories: *mut *mut LocalMemory,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// A pointer to an array of imported tables, indexed by `TableIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub imported_tables: *mut *mut LocalTable,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// A pointer to an array of imported globals, indexed by `GlobalIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub imported_globals: *mut *mut LocalGlobal,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// A pointer to an array of imported functions, indexed by `FuncIndex`.
|
2019-03-09 02:58:37 +08:00
|
|
|
pub imported_funcs: *mut ImportedFunc,
|
2019-01-08 12:09:47 -05:00
|
|
|
|
2019-03-03 21:26:34 -08:00
|
|
|
/// A pointer to an array of signature ids. Conceptually, this maps
|
|
|
|
/// from a static, module-local signature id to a runtime-global
|
|
|
|
/// signature id. This is used to allow call-indirect to other
|
|
|
|
/// modules safely.
|
2019-03-19 11:47:38 +08:00
|
|
|
pub dynamic_sigindices: *const SigId,
|
2019-05-04 10:33:12 -07:00
|
|
|
|
|
|
|
pub intrinsics: *const Intrinsics,
|
2019-05-06 07:15:30 -07:00
|
|
|
|
|
|
|
pub stack_lower_bound: *mut u8,
|
2019-05-13 05:11:08 -07:00
|
|
|
|
|
|
|
pub memory_base: *mut u8,
|
|
|
|
pub memory_bound: usize,
|
2019-05-17 01:10:21 +08:00
|
|
|
|
|
|
|
pub internals: *mut [u64; INTERNALS_SIZE], // TODO: Make this dynamic?
|
2019-06-27 15:49:43 +08:00
|
|
|
|
|
|
|
pub interrupt_signal_mem: *mut u8,
|
2019-05-04 10:33:12 -07:00
|
|
|
}
|
|
|
|
|
2019-05-23 20:10:17 +08:00
|
|
|
static INTERNAL_FIELDS: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
|
|
|
|
pub struct InternalField {
|
|
|
|
init: Once,
|
|
|
|
inner: UnsafeCell<usize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for InternalField {}
|
|
|
|
unsafe impl Sync for InternalField {}
|
|
|
|
|
|
|
|
impl InternalField {
|
|
|
|
pub const fn allocate() -> InternalField {
|
|
|
|
InternalField {
|
|
|
|
init: Once::new(),
|
|
|
|
inner: UnsafeCell::new(::std::usize::MAX),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn index(&self) -> usize {
|
|
|
|
let inner: *mut usize = self.inner.get();
|
|
|
|
self.init.call_once(|| {
|
|
|
|
let idx = INTERNAL_FIELDS.fetch_add(1, Ordering::SeqCst);
|
|
|
|
if idx >= INTERNALS_SIZE {
|
|
|
|
INTERNAL_FIELDS.fetch_sub(1, Ordering::SeqCst);
|
|
|
|
panic!("at most {} internal fields are supported", INTERNALS_SIZE);
|
|
|
|
} else {
|
|
|
|
unsafe {
|
|
|
|
*inner = idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
unsafe { *inner }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-04 10:33:12 -07:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Intrinsics {
|
|
|
|
pub memory_grow: *const Func,
|
|
|
|
pub memory_size: *const Func,
|
|
|
|
/*pub memory_grow: unsafe extern "C" fn(
|
|
|
|
ctx: &mut Ctx,
|
|
|
|
memory_index: usize,
|
|
|
|
delta: Pages,
|
|
|
|
) -> i32,
|
|
|
|
pub memory_size: unsafe extern "C" fn(
|
|
|
|
ctx: &Ctx,
|
|
|
|
memory_index: usize,
|
|
|
|
) -> Pages,*/
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl Send for Intrinsics {}
|
|
|
|
unsafe impl Sync for Intrinsics {}
|
|
|
|
|
|
|
|
impl Intrinsics {
|
2019-05-14 16:59:18 +08:00
|
|
|
#[allow(clippy::erasing_op)]
|
2019-05-04 10:33:12 -07:00
|
|
|
pub fn offset_memory_grow() -> u8 {
|
|
|
|
(0 * ::std::mem::size_of::<usize>()) as u8
|
|
|
|
}
|
|
|
|
pub fn offset_memory_size() -> u8 {
|
|
|
|
(1 * ::std::mem::size_of::<usize>()) as u8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub static INTRINSICS_LOCAL_STATIC_MEMORY: Intrinsics = Intrinsics {
|
|
|
|
memory_grow: vmcalls::local_static_memory_grow as _,
|
|
|
|
memory_size: vmcalls::local_static_memory_size as _,
|
|
|
|
};
|
|
|
|
pub static INTRINSICS_LOCAL_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
|
|
|
memory_grow: vmcalls::local_dynamic_memory_grow as _,
|
|
|
|
memory_size: vmcalls::local_dynamic_memory_size as _,
|
|
|
|
};
|
|
|
|
pub static INTRINSICS_IMPORTED_STATIC_MEMORY: Intrinsics = Intrinsics {
|
|
|
|
memory_grow: vmcalls::imported_static_memory_grow as _,
|
|
|
|
memory_size: vmcalls::imported_static_memory_size as _,
|
|
|
|
};
|
|
|
|
pub static INTRINSICS_IMPORTED_DYNAMIC_MEMORY: Intrinsics = Intrinsics {
|
|
|
|
memory_grow: vmcalls::imported_dynamic_memory_grow as _,
|
|
|
|
memory_size: vmcalls::imported_dynamic_memory_size as _,
|
|
|
|
};
|
|
|
|
|
|
|
|
fn get_intrinsics_for_module(m: &ModuleInfo) -> *const Intrinsics {
|
|
|
|
if m.memories.len() == 0 && m.imported_memories.len() == 0 {
|
|
|
|
::std::ptr::null()
|
|
|
|
} else {
|
|
|
|
match MemoryIndex::new(0).local_or_import(m) {
|
|
|
|
LocalOrImport::Local(local_mem_index) => {
|
|
|
|
let mem_desc = &m.memories[local_mem_index];
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => &INTRINSICS_LOCAL_DYNAMIC_MEMORY,
|
|
|
|
MemoryType::Static => &INTRINSICS_LOCAL_STATIC_MEMORY,
|
2019-08-19 17:26:35 -07:00
|
|
|
MemoryType::SharedStatic => &INTRINSICS_LOCAL_STATIC_MEMORY,
|
2019-05-04 10:33:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalOrImport::Import(import_mem_index) => {
|
|
|
|
let mem_desc = &m.imported_memories[import_mem_index].1;
|
|
|
|
match mem_desc.memory_type() {
|
|
|
|
MemoryType::Dynamic => &INTRINSICS_IMPORTED_DYNAMIC_MEMORY,
|
|
|
|
MemoryType::Static => &INTRINSICS_IMPORTED_STATIC_MEMORY,
|
2019-08-19 17:26:35 -07:00
|
|
|
MemoryType::SharedStatic => &INTRINSICS_IMPORTED_STATIC_MEMORY,
|
2019-05-04 10:33:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
2019-06-27 15:49:43 +08:00
|
|
|
#[cfg(all(unix, target_arch = "x86_64"))]
|
|
|
|
fn get_interrupt_signal_mem() -> *mut u8 {
|
2019-07-04 01:27:19 +08:00
|
|
|
unsafe { crate::fault::get_wasm_interrupt_signal_mem() }
|
2019-06-27 15:49:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(not(all(unix, target_arch = "x86_64")))]
|
|
|
|
fn get_interrupt_signal_mem() -> *mut u8 {
|
|
|
|
static mut REGION: u64 = 0;
|
|
|
|
unsafe { &mut REGION as *mut u64 as *mut u8 }
|
|
|
|
}
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
impl Ctx {
|
2019-01-23 12:34:15 -08:00
|
|
|
#[doc(hidden)]
|
2019-01-12 22:02:19 -05:00
|
|
|
pub unsafe fn new(
|
|
|
|
local_backing: &mut LocalBacking,
|
|
|
|
import_backing: &mut ImportBacking,
|
2019-01-21 09:56:49 -08:00
|
|
|
module: &ModuleInner,
|
2019-01-12 22:02:19 -05:00
|
|
|
) -> Self {
|
2019-05-13 05:11:08 -07:00
|
|
|
let (mem_base, mem_bound): (*mut u8, usize) =
|
|
|
|
if module.info.memories.len() == 0 && module.info.imported_memories.len() == 0 {
|
|
|
|
(::std::ptr::null_mut(), 0)
|
|
|
|
} else {
|
|
|
|
let mem = match MemoryIndex::new(0).local_or_import(&module.info) {
|
|
|
|
LocalOrImport::Local(index) => local_backing.vm_memories[index],
|
|
|
|
LocalOrImport::Import(index) => import_backing.vm_memories[index],
|
|
|
|
};
|
|
|
|
((*mem).base, (*mem).bound)
|
|
|
|
};
|
2019-01-08 12:09:47 -05:00
|
|
|
Self {
|
2019-03-21 08:39:06 +08:00
|
|
|
internal: InternalCtx {
|
|
|
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
|
|
|
tables: local_backing.vm_tables.as_mut_ptr(),
|
|
|
|
globals: local_backing.vm_globals.as_mut_ptr(),
|
|
|
|
|
|
|
|
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
|
|
|
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
|
|
|
imported_globals: import_backing.vm_globals.as_mut_ptr(),
|
|
|
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
|
|
|
|
|
|
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
2019-05-04 10:33:12 -07:00
|
|
|
|
|
|
|
intrinsics: get_intrinsics_for_module(&module.info),
|
2019-05-06 07:15:30 -07:00
|
|
|
|
|
|
|
stack_lower_bound: ::std::ptr::null_mut(),
|
2019-05-13 05:11:08 -07:00
|
|
|
|
|
|
|
memory_base: mem_base,
|
|
|
|
memory_bound: mem_bound,
|
2019-05-17 01:10:21 +08:00
|
|
|
|
|
|
|
internals: &mut local_backing.internals.0,
|
2019-06-27 15:49:43 +08:00
|
|
|
|
|
|
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
2019-03-21 08:39:06 +08:00
|
|
|
},
|
2019-03-08 15:15:16 -08:00
|
|
|
local_functions: local_backing.local_functions.as_ptr(),
|
2019-03-03 21:26:34 -08:00
|
|
|
|
2019-01-29 12:12:37 -08:00
|
|
|
local_backing,
|
|
|
|
import_backing,
|
2019-01-21 09:56:49 -08:00
|
|
|
module,
|
2019-01-17 14:26:52 -08:00
|
|
|
|
|
|
|
data: ptr::null_mut(),
|
|
|
|
data_finalizer: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 12:34:15 -08:00
|
|
|
#[doc(hidden)]
|
2019-01-17 14:26:52 -08:00
|
|
|
pub unsafe fn new_with_data(
|
|
|
|
local_backing: &mut LocalBacking,
|
|
|
|
import_backing: &mut ImportBacking,
|
2019-01-21 09:56:49 -08:00
|
|
|
module: &ModuleInner,
|
2019-01-17 14:26:52 -08:00
|
|
|
data: *mut c_void,
|
2019-03-28 11:56:31 -07:00
|
|
|
data_finalizer: fn(*mut c_void),
|
2019-01-17 14:26:52 -08:00
|
|
|
) -> Self {
|
2019-05-13 05:11:08 -07:00
|
|
|
let (mem_base, mem_bound): (*mut u8, usize) =
|
|
|
|
if module.info.memories.len() == 0 && module.info.imported_memories.len() == 0 {
|
|
|
|
(::std::ptr::null_mut(), 0)
|
|
|
|
} else {
|
|
|
|
let mem = match MemoryIndex::new(0).local_or_import(&module.info) {
|
|
|
|
LocalOrImport::Local(index) => local_backing.vm_memories[index],
|
|
|
|
LocalOrImport::Import(index) => import_backing.vm_memories[index],
|
|
|
|
};
|
|
|
|
((*mem).base, (*mem).bound)
|
|
|
|
};
|
2019-01-17 14:26:52 -08:00
|
|
|
Self {
|
2019-03-21 08:39:06 +08:00
|
|
|
internal: InternalCtx {
|
|
|
|
memories: local_backing.vm_memories.as_mut_ptr(),
|
|
|
|
tables: local_backing.vm_tables.as_mut_ptr(),
|
|
|
|
globals: local_backing.vm_globals.as_mut_ptr(),
|
|
|
|
|
|
|
|
imported_memories: import_backing.vm_memories.as_mut_ptr(),
|
|
|
|
imported_tables: import_backing.vm_tables.as_mut_ptr(),
|
|
|
|
imported_globals: import_backing.vm_globals.as_mut_ptr(),
|
|
|
|
imported_funcs: import_backing.vm_functions.as_mut_ptr(),
|
|
|
|
|
|
|
|
dynamic_sigindices: local_backing.dynamic_sigindices.as_ptr(),
|
2019-05-04 10:33:12 -07:00
|
|
|
|
|
|
|
intrinsics: get_intrinsics_for_module(&module.info),
|
2019-05-06 07:15:30 -07:00
|
|
|
|
|
|
|
stack_lower_bound: ::std::ptr::null_mut(),
|
2019-05-13 05:11:08 -07:00
|
|
|
|
|
|
|
memory_base: mem_base,
|
|
|
|
memory_bound: mem_bound,
|
2019-05-17 01:10:21 +08:00
|
|
|
|
|
|
|
internals: &mut local_backing.internals.0,
|
2019-06-27 15:49:43 +08:00
|
|
|
|
|
|
|
interrupt_signal_mem: get_interrupt_signal_mem(),
|
2019-03-21 08:39:06 +08:00
|
|
|
},
|
2019-03-08 15:15:16 -08:00
|
|
|
local_functions: local_backing.local_functions.as_ptr(),
|
2019-03-03 21:26:34 -08:00
|
|
|
|
2019-01-29 12:12:37 -08:00
|
|
|
local_backing,
|
|
|
|
import_backing,
|
2019-01-21 09:56:49 -08:00
|
|
|
module,
|
2019-01-17 14:26:52 -08:00
|
|
|
|
|
|
|
data,
|
|
|
|
data_finalizer: Some(data_finalizer),
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 16:06:42 -08:00
|
|
|
/// This exposes the specified memory of the WebAssembly instance
|
|
|
|
/// as a immutable slice.
|
|
|
|
///
|
|
|
|
/// WebAssembly will soon support multiple linear memories, so this
|
|
|
|
/// forces the user to specify.
|
|
|
|
///
|
|
|
|
/// # Usage:
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use wasmer_runtime_core::{
|
|
|
|
/// # vm::Ctx,
|
|
|
|
/// # };
|
|
|
|
/// fn read_memory(ctx: &Ctx) -> u8 {
|
2019-02-05 10:20:04 -08:00
|
|
|
/// let first_memory = ctx.memory(0);
|
2019-01-23 16:06:42 -08:00
|
|
|
/// // Read the first byte of that linear memory.
|
2019-02-05 10:20:04 -08:00
|
|
|
/// first_memory.view()[0].get()
|
2019-01-23 16:06:42 -08:00
|
|
|
/// }
|
|
|
|
/// ```
|
2019-02-04 23:07:58 -08:00
|
|
|
pub fn memory(&self, mem_index: u32) -> &Memory {
|
2019-01-23 16:06:42 -08:00
|
|
|
let module = unsafe { &*self.module };
|
|
|
|
let mem_index = MemoryIndex::new(mem_index as usize);
|
2019-02-18 11:56:20 -08:00
|
|
|
match mem_index.local_or_import(&module.info) {
|
2019-01-25 15:28:54 -08:00
|
|
|
LocalOrImport::Local(local_mem_index) => unsafe {
|
2019-01-29 12:12:37 -08:00
|
|
|
let local_backing = &*self.local_backing;
|
2019-02-04 23:07:58 -08:00
|
|
|
&local_backing.memories[local_mem_index]
|
2019-01-25 15:28:54 -08:00
|
|
|
},
|
|
|
|
LocalOrImport::Import(import_mem_index) => unsafe {
|
2019-01-29 12:12:37 -08:00
|
|
|
let import_backing = &*self.import_backing;
|
2019-02-04 23:07:58 -08:00
|
|
|
&import_backing.memories[import_mem_index]
|
2019-01-25 15:28:54 -08:00
|
|
|
},
|
2019-01-21 09:56:49 -08:00
|
|
|
}
|
|
|
|
}
|
2019-03-27 14:01:27 -07:00
|
|
|
|
2019-03-27 14:08:17 -07:00
|
|
|
/// Gives access to the emscripten symbol map, used for debugging
|
2019-03-27 14:01:27 -07:00
|
|
|
pub unsafe fn borrow_symbol_map(&self) -> &Option<HashMap<u32, String>> {
|
|
|
|
&(*self.module).info.em_symbol_map
|
|
|
|
}
|
2019-05-04 09:56:52 -07:00
|
|
|
|
|
|
|
/// Returns the number of dynamic sigindices.
|
|
|
|
pub fn dynamic_sigindice_count(&self) -> usize {
|
2019-05-14 16:04:08 +08:00
|
|
|
unsafe { (*self.local_backing).dynamic_sigindices.len() }
|
2019-05-04 09:56:52 -07:00
|
|
|
}
|
2019-06-06 14:10:57 +08:00
|
|
|
|
|
|
|
/// Returns the value of the specified internal field.
|
|
|
|
pub fn get_internal(&self, field: &InternalField) -> u64 {
|
|
|
|
unsafe { (*self.internal.internals)[field.index()] }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes the value to the specified internal field.
|
|
|
|
pub fn set_internal(&mut self, field: &InternalField, value: u64) {
|
|
|
|
unsafe {
|
|
|
|
(*self.internal.internals)[field.index()] = value;
|
|
|
|
}
|
|
|
|
}
|
2019-09-16 15:01:18 -07:00
|
|
|
|
2019-09-18 16:43:47 -07:00
|
|
|
/// Calls a host or Wasm function at the given table index
|
|
|
|
pub fn call_with_table_index(
|
|
|
|
&mut self,
|
|
|
|
index: TableIndex,
|
|
|
|
args: &[Value],
|
|
|
|
) -> CallResult<Vec<Value>> {
|
2019-09-18 16:06:46 -07:00
|
|
|
let anyfunc_table =
|
|
|
|
unsafe { &*((**self.internal.tables).table as *mut crate::table::AnyfuncTable) };
|
2019-09-18 16:43:47 -07:00
|
|
|
let Anyfunc { func, ctx, sig_id } = anyfunc_table.backing[index.index()];
|
2019-09-18 16:06:46 -07:00
|
|
|
|
|
|
|
let signature = SigRegistry.lookup_signature(unsafe { std::mem::transmute(sig_id.0) });
|
|
|
|
let mut rets = vec![];
|
|
|
|
|
|
|
|
let wasm = {
|
|
|
|
let module = unsafe { &*self.module };
|
|
|
|
let runnable = &module.runnable_module;
|
|
|
|
|
|
|
|
let sig_index = SigRegistry.lookup_sig_index(signature.clone());
|
|
|
|
runnable
|
|
|
|
.get_trampoline(&module.info, sig_index)
|
|
|
|
.expect("wasm trampoline")
|
|
|
|
};
|
|
|
|
|
|
|
|
call_func_with_index_inner(
|
2019-09-18 16:43:47 -07:00
|
|
|
ctx,
|
|
|
|
NonNull::new(func as *mut _).unwrap(),
|
2019-09-18 16:06:46 -07:00
|
|
|
&signature,
|
|
|
|
wasm,
|
2019-09-16 15:01:18 -07:00
|
|
|
args,
|
2019-09-18 16:06:46 -07:00
|
|
|
&mut rets,
|
2019-09-16 15:01:18 -07:00
|
|
|
)?;
|
2019-09-18 16:06:46 -07:00
|
|
|
|
|
|
|
Ok(rets)
|
2019-09-16 15:01:18 -07:00
|
|
|
}
|
2019-01-21 09:56:49 -08:00
|
|
|
}
|
|
|
|
|
2019-01-23 12:34:15 -08:00
|
|
|
#[doc(hidden)]
|
2019-01-21 09:56:49 -08:00
|
|
|
impl Ctx {
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_memories() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_tables() -> u8 {
|
|
|
|
1 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_globals() -> u8 {
|
|
|
|
2 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_imported_memories() -> u8 {
|
|
|
|
3 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_imported_tables() -> u8 {
|
|
|
|
4 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_imported_globals() -> u8 {
|
|
|
|
5 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_imported_funcs() -> u8 {
|
|
|
|
6 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn offset_signatures() -> u8 {
|
|
|
|
7 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-03-08 15:15:16 -08:00
|
|
|
|
2019-05-04 10:33:12 -07:00
|
|
|
pub fn offset_intrinsics() -> u8 {
|
2019-03-08 15:15:16 -08:00
|
|
|
8 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-05-04 10:33:12 -07:00
|
|
|
|
2019-05-06 07:15:30 -07:00
|
|
|
pub fn offset_stack_lower_bound() -> u8 {
|
2019-05-04 10:33:12 -07:00
|
|
|
9 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-05-06 07:15:30 -07:00
|
|
|
|
2019-05-13 05:11:08 -07:00
|
|
|
pub fn offset_memory_base() -> u8 {
|
2019-05-06 07:15:30 -07:00
|
|
|
10 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-05-13 05:11:08 -07:00
|
|
|
|
|
|
|
pub fn offset_memory_bound() -> u8 {
|
|
|
|
11 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
2019-05-17 01:10:21 +08:00
|
|
|
pub fn offset_internals() -> u8 {
|
2019-05-13 05:11:08 -07:00
|
|
|
12 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-05-17 01:10:21 +08:00
|
|
|
|
2019-06-27 15:49:43 +08:00
|
|
|
pub fn offset_interrupt_signal_mem() -> u8 {
|
2019-05-17 01:10:21 +08:00
|
|
|
13 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-06-27 15:49:43 +08:00
|
|
|
|
|
|
|
pub fn offset_local_functions() -> u8 {
|
|
|
|
14 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
2019-01-23 15:30:35 -08:00
|
|
|
enum InnerFunc {}
|
2019-01-08 12:09:47 -05:00
|
|
|
/// Used to provide type safety (ish) for passing around function pointers.
|
|
|
|
/// The typesystem ensures this cannot be dereferenced since an
|
|
|
|
/// empty enum cannot actually exist.
|
2019-02-14 09:58:33 -08:00
|
|
|
#[repr(C)]
|
2019-01-23 15:30:35 -08:00
|
|
|
pub struct Func(InnerFunc);
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
/// An imported function, which contains the vmctx that owns this function.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct ImportedFunc {
|
|
|
|
pub func: *const Func,
|
2019-01-10 22:59:57 -05:00
|
|
|
pub vmctx: *mut Ctx,
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
2019-09-17 18:35:12 -07:00
|
|
|
// manually implemented because ImportedFunc contains raw pointers directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: review this, shouldn't `Ctx` be Send?))
|
2019-09-17 14:58:26 -07:00
|
|
|
unsafe impl Send for ImportedFunc {}
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
impl ImportedFunc {
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_func() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-01-08 21:57:28 -05:00
|
|
|
|
2019-01-10 22:59:57 -05:00
|
|
|
pub fn offset_vmctx() -> u8 {
|
|
|
|
1 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
2019-01-08 21:57:28 -05:00
|
|
|
pub fn size() -> u8 {
|
|
|
|
mem::size_of::<Self>() as u8
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Definition of a table used by the VM. (obviously)
|
2019-02-04 15:07:32 -08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2019-01-08 12:09:47 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct LocalTable {
|
|
|
|
/// pointer to the elements in the table.
|
|
|
|
pub base: *mut u8,
|
|
|
|
/// Number of elements in the table (NOT necessarily the size of the table in bytes!).
|
2019-01-29 10:16:39 -08:00
|
|
|
pub count: usize,
|
|
|
|
/// The table that this represents. At the moment, this can only be `*mut AnyfuncTable`.
|
|
|
|
pub table: *mut (),
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
2019-09-17 18:35:12 -07:00
|
|
|
// manually implemented because LocalTable contains raw pointers directly
|
2019-09-17 11:45:13 -07:00
|
|
|
unsafe impl Send for LocalTable {}
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
impl LocalTable {
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_base() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
2019-01-29 10:16:39 -08:00
|
|
|
pub fn offset_count() -> u8 {
|
2019-01-08 12:09:47 -05:00
|
|
|
1 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-01-16 17:59:12 -08:00
|
|
|
|
|
|
|
pub fn size() -> u8 {
|
|
|
|
mem::size_of::<Self>() as u8
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Definition of a memory used by the VM.
|
2019-02-04 15:07:32 -08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2019-01-08 12:09:47 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct LocalMemory {
|
|
|
|
/// Pointer to the bottom of this linear memory.
|
|
|
|
pub base: *mut u8,
|
|
|
|
/// Current size of this linear memory in bytes.
|
2019-01-25 15:28:54 -08:00
|
|
|
pub bound: usize,
|
|
|
|
/// The actual memory that this represents.
|
|
|
|
/// This is either `*mut DynamicMemory`, `*mut StaticMemory`,
|
|
|
|
/// or `*mut SharedStaticMemory`.
|
|
|
|
pub memory: *mut (),
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
2019-09-17 18:35:12 -07:00
|
|
|
// manually implemented because LocalMemory contains raw pointers
|
|
|
|
unsafe impl Send for LocalMemory {}
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
impl LocalMemory {
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_base() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
2019-01-25 15:28:54 -08:00
|
|
|
pub fn offset_bound() -> u8 {
|
2019-01-08 12:09:47 -05:00
|
|
|
1 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-01-16 17:59:12 -08:00
|
|
|
|
|
|
|
pub fn size() -> u8 {
|
|
|
|
mem::size_of::<Self>() as u8
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Definition of a global used by the VM.
|
2019-02-04 15:07:32 -08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2019-01-08 12:09:47 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct LocalGlobal {
|
2019-07-18 13:39:41 -07:00
|
|
|
pub data: u128,
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl LocalGlobal {
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_data() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn null() -> Self {
|
|
|
|
Self { data: 0 }
|
|
|
|
}
|
2019-01-16 10:26:10 -08:00
|
|
|
|
|
|
|
pub fn size() -> u8 {
|
|
|
|
mem::size_of::<Self>() as u8
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
#[repr(transparent)]
|
|
|
|
pub struct SigId(pub u32);
|
|
|
|
|
|
|
|
/// Caller-checked anyfunc
|
2019-02-04 15:07:32 -08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2019-01-08 12:09:47 -05:00
|
|
|
#[repr(C)]
|
|
|
|
pub struct Anyfunc {
|
2019-01-29 10:16:39 -08:00
|
|
|
pub func: *const Func,
|
|
|
|
pub ctx: *mut Ctx,
|
2019-01-08 12:09:47 -05:00
|
|
|
pub sig_id: SigId,
|
|
|
|
}
|
|
|
|
|
2019-09-17 18:35:12 -07:00
|
|
|
// manually implemented because Anyfunc contains raw pointers directly
|
2019-09-17 11:45:13 -07:00
|
|
|
unsafe impl Send for Anyfunc {}
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
impl Anyfunc {
|
|
|
|
pub fn null() -> Self {
|
|
|
|
Self {
|
2019-01-29 10:16:39 -08:00
|
|
|
func: ptr::null(),
|
|
|
|
ctx: ptr::null_mut(),
|
2019-01-08 12:09:47 -05:00
|
|
|
sig_id: SigId(u32::max_value()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 00:33:46 -06:00
|
|
|
#[allow(clippy::erasing_op)] // TODO
|
2019-01-08 12:09:47 -05:00
|
|
|
pub fn offset_func() -> u8 {
|
|
|
|
0 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
|
|
|
|
2019-01-10 22:59:57 -05:00
|
|
|
pub fn offset_vmctx() -> u8 {
|
|
|
|
1 * (mem::size_of::<usize>() as u8)
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
pub fn offset_sig_id() -> u8 {
|
2019-01-10 22:59:57 -05:00
|
|
|
2 * (mem::size_of::<usize>() as u8)
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
2019-01-16 17:59:12 -08:00
|
|
|
|
|
|
|
pub fn size() -> u8 {
|
|
|
|
mem::size_of::<Self>() as u8
|
|
|
|
}
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod vm_offset_tests {
|
2019-03-21 09:24:44 +08:00
|
|
|
use super::{Anyfunc, Ctx, ImportedFunc, InternalCtx, LocalGlobal, LocalMemory, LocalTable};
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn vmctx() {
|
2019-03-21 09:24:44 +08:00
|
|
|
assert_eq!(0usize, offset_of!(Ctx => internal).get_byte_offset(),);
|
|
|
|
|
2019-01-08 12:09:47 -05:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_memories() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => memories).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_tables() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => tables).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_globals() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => globals).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_imported_memories() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => imported_memories).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_imported_tables() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => imported_tables).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_imported_globals() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => imported_globals).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_imported_funcs() as usize,
|
2019-03-21 09:24:44 +08:00
|
|
|
offset_of!(InternalCtx => imported_funcs).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
2019-03-08 15:15:16 -08:00
|
|
|
|
2019-05-04 10:33:12 -07:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_intrinsics() as usize,
|
|
|
|
offset_of!(InternalCtx => intrinsics).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-05-06 07:15:30 -07:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_stack_lower_bound() as usize,
|
|
|
|
offset_of!(InternalCtx => stack_lower_bound).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-05-13 05:11:08 -07:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_memory_base() as usize,
|
|
|
|
offset_of!(InternalCtx => memory_base).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_memory_bound() as usize,
|
|
|
|
offset_of!(InternalCtx => memory_bound).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-05-17 01:10:21 +08:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_internals() as usize,
|
|
|
|
offset_of!(InternalCtx => internals).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-06-27 15:49:43 +08:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_interrupt_signal_mem() as usize,
|
|
|
|
offset_of!(InternalCtx => interrupt_signal_mem).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-03-08 15:15:16 -08:00
|
|
|
assert_eq!(
|
|
|
|
Ctx::offset_local_functions() as usize,
|
|
|
|
offset_of!(Ctx => local_functions).get_byte_offset(),
|
|
|
|
);
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn imported_func() {
|
|
|
|
assert_eq!(
|
|
|
|
ImportedFunc::offset_func() as usize,
|
|
|
|
offset_of!(ImportedFunc => func).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
2019-01-10 22:59:57 -05:00
|
|
|
assert_eq!(
|
|
|
|
ImportedFunc::offset_vmctx() as usize,
|
|
|
|
offset_of!(ImportedFunc => vmctx).get_byte_offset(),
|
|
|
|
);
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn local_table() {
|
|
|
|
assert_eq!(
|
|
|
|
LocalTable::offset_base() as usize,
|
|
|
|
offset_of!(LocalTable => base).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-01-29 10:16:39 -08:00
|
|
|
LocalTable::offset_count() as usize,
|
|
|
|
offset_of!(LocalTable => count).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn local_memory() {
|
|
|
|
assert_eq!(
|
|
|
|
LocalMemory::offset_base() as usize,
|
|
|
|
offset_of!(LocalMemory => base).get_byte_offset(),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(
|
2019-01-25 15:28:54 -08:00
|
|
|
LocalMemory::offset_bound() as usize,
|
|
|
|
offset_of!(LocalMemory => bound).get_byte_offset(),
|
2019-01-10 22:59:57 -05:00
|
|
|
);
|
2019-01-08 12:09:47 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn local_global() {
|
|
|
|
assert_eq!(
|
|
|
|
LocalGlobal::offset_data() as usize,
|
|
|
|
offset_of!(LocalGlobal => data).get_byte_offset(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cc_anyfunc() {
|
|
|
|
assert_eq!(
|
|
|
|
Anyfunc::offset_func() as usize,
|
2019-01-29 10:16:39 -08:00
|
|
|
offset_of!(Anyfunc => func).get_byte_offset(),
|
2019-01-08 12:09:47 -05:00
|
|
|
);
|
|
|
|
|
2019-01-10 22:59:57 -05:00
|
|
|
assert_eq!(
|
|
|
|
Anyfunc::offset_vmctx() as usize,
|
2019-01-29 10:16:39 -08:00
|
|
|
offset_of!(Anyfunc => ctx).get_byte_offset(),
|
2019-01-10 22:59:57 -05:00
|
|
|
);
|
2019-01-08 12:09:47 -05:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
Anyfunc::offset_sig_id() as usize,
|
|
|
|
offset_of!(Anyfunc => sig_id).get_byte_offset(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2019-01-17 14:26:52 -08:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod vm_ctx_tests {
|
|
|
|
use super::{Ctx, ImportBacking, LocalBacking};
|
2019-02-06 16:26:45 -08:00
|
|
|
use crate::module::{ModuleInfo, ModuleInner, StringTable};
|
2019-01-17 14:26:52 -08:00
|
|
|
use crate::structures::Map;
|
|
|
|
use std::ffi::c_void;
|
|
|
|
|
|
|
|
struct TestData {
|
|
|
|
x: u32,
|
|
|
|
y: bool,
|
|
|
|
str: String,
|
2019-08-08 16:46:52 -06:00
|
|
|
finalizer: Box<dyn FnMut()>,
|
2019-07-15 15:14:09 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for TestData {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
(*self.finalizer)();
|
|
|
|
}
|
2019-01-17 14:26:52 -08:00
|
|
|
}
|
|
|
|
|
2019-03-28 13:55:38 -07:00
|
|
|
fn test_data_finalizer(data: *mut c_void) {
|
2019-01-17 14:26:52 -08:00
|
|
|
let test_data: &mut TestData = unsafe { &mut *(data as *mut TestData) };
|
2019-07-15 15:14:09 +03:00
|
|
|
|
|
|
|
assert_eq!(10, test_data.x);
|
|
|
|
assert_eq!(true, test_data.y);
|
|
|
|
assert_eq!("Test".to_string(), test_data.str,);
|
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
println!("hello from finalizer");
|
2019-07-15 15:14:09 +03:00
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
drop(test_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_callback_on_drop() {
|
|
|
|
let mut data = TestData {
|
|
|
|
x: 10,
|
|
|
|
y: true,
|
|
|
|
str: "Test".to_string(),
|
2019-07-15 15:14:09 +03:00
|
|
|
finalizer: Box::new(move || {}),
|
2019-01-17 14:26:52 -08:00
|
|
|
};
|
2019-07-15 15:14:09 +03:00
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
let mut local_backing = LocalBacking {
|
|
|
|
memories: Map::new().into_boxed_map(),
|
|
|
|
tables: Map::new().into_boxed_map(),
|
2019-01-28 11:55:44 -08:00
|
|
|
globals: Map::new().into_boxed_map(),
|
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
vm_memories: Map::new().into_boxed_map(),
|
|
|
|
vm_tables: Map::new().into_boxed_map(),
|
|
|
|
vm_globals: Map::new().into_boxed_map(),
|
2019-03-05 14:57:37 -08:00
|
|
|
|
|
|
|
dynamic_sigindices: Map::new().into_boxed_map(),
|
2019-03-08 15:15:16 -08:00
|
|
|
local_functions: Map::new().into_boxed_map(),
|
2019-05-17 01:32:41 +08:00
|
|
|
|
2019-05-17 01:33:33 +08:00
|
|
|
internals: crate::backing::Internals([0; crate::backing::INTERNALS_SIZE]),
|
2019-01-17 14:26:52 -08:00
|
|
|
};
|
2019-07-15 15:14:09 +03:00
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
let mut import_backing = ImportBacking {
|
|
|
|
memories: Map::new().into_boxed_map(),
|
2019-01-29 10:16:39 -08:00
|
|
|
tables: Map::new().into_boxed_map(),
|
2019-01-28 11:55:44 -08:00
|
|
|
globals: Map::new().into_boxed_map(),
|
2019-01-25 15:28:54 -08:00
|
|
|
|
|
|
|
vm_functions: Map::new().into_boxed_map(),
|
|
|
|
vm_memories: Map::new().into_boxed_map(),
|
|
|
|
vm_tables: Map::new().into_boxed_map(),
|
|
|
|
vm_globals: Map::new().into_boxed_map(),
|
2019-01-17 14:26:52 -08:00
|
|
|
};
|
2019-07-15 15:14:09 +03:00
|
|
|
|
2019-01-21 10:07:57 -08:00
|
|
|
let module = generate_module();
|
2019-07-15 15:14:09 +03:00
|
|
|
let data_ptr = &mut data as *mut _ as *mut c_void;
|
2019-01-17 14:26:52 -08:00
|
|
|
let ctx = unsafe {
|
|
|
|
Ctx::new_with_data(
|
|
|
|
&mut local_backing,
|
|
|
|
&mut import_backing,
|
2019-01-21 10:07:57 -08:00
|
|
|
&module,
|
2019-07-15 15:14:09 +03:00
|
|
|
data_ptr,
|
2019-01-17 14:26:52 -08:00
|
|
|
test_data_finalizer,
|
|
|
|
)
|
|
|
|
};
|
2019-07-15 15:14:09 +03:00
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
let ctx_test_data = cast_test_data(ctx.data);
|
2019-07-15 15:14:09 +03:00
|
|
|
assert_eq!(10, ctx_test_data.x);
|
|
|
|
assert_eq!(true, ctx_test_data.y);
|
|
|
|
assert_eq!("Test".to_string(), ctx_test_data.str);
|
|
|
|
|
2019-01-17 14:26:52 -08:00
|
|
|
drop(ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cast_test_data(data: *mut c_void) -> &'static mut TestData {
|
|
|
|
let test_data: &mut TestData = unsafe { &mut *(data as *mut TestData) };
|
|
|
|
test_data
|
|
|
|
}
|
2019-01-21 10:07:57 -08:00
|
|
|
|
|
|
|
fn generate_module() -> ModuleInner {
|
|
|
|
use super::Func;
|
2019-04-18 10:14:25 -07:00
|
|
|
use crate::backend::{sys::Memory, Backend, CacheGen, RunnableModule};
|
2019-03-25 19:43:52 -07:00
|
|
|
use crate::cache::Error as CacheError;
|
2019-04-09 16:15:50 -07:00
|
|
|
use crate::typed_func::Wasm;
|
2019-04-11 18:01:54 -07:00
|
|
|
use crate::types::{LocalFuncIndex, SigIndex};
|
2019-08-01 01:27:21 -07:00
|
|
|
use indexmap::IndexMap;
|
2019-04-18 10:14:25 -07:00
|
|
|
use std::any::Any;
|
2019-07-31 23:51:12 -07:00
|
|
|
use std::collections::HashMap;
|
2019-01-21 10:07:57 -08:00
|
|
|
use std::ptr::NonNull;
|
|
|
|
struct Placeholder;
|
2019-04-11 18:01:54 -07:00
|
|
|
impl RunnableModule for Placeholder {
|
|
|
|
fn get_func(
|
2019-01-21 10:07:57 -08:00
|
|
|
&self,
|
2019-04-11 18:01:54 -07:00
|
|
|
_module: &ModuleInfo,
|
2019-01-21 11:51:41 -08:00
|
|
|
_local_func_index: LocalFuncIndex,
|
2019-01-21 10:07:57 -08:00
|
|
|
) -> Option<NonNull<Func>> {
|
|
|
|
None
|
|
|
|
}
|
2019-04-11 18:01:54 -07:00
|
|
|
|
|
|
|
fn get_trampoline(&self, _module: &ModuleInfo, _sig_index: SigIndex) -> Option<Wasm> {
|
2019-04-09 16:15:50 -07:00
|
|
|
unimplemented!()
|
|
|
|
}
|
2019-04-18 10:08:17 -07:00
|
|
|
unsafe fn do_early_trap(&self, _: Box<dyn Any>) -> ! {
|
2019-02-08 13:08:03 -08:00
|
|
|
unimplemented!()
|
|
|
|
}
|
2019-01-21 14:01:25 -08:00
|
|
|
}
|
2019-02-19 09:58:01 -08:00
|
|
|
impl CacheGen for Placeholder {
|
2019-04-19 14:02:21 -07:00
|
|
|
fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> {
|
2019-02-19 09:58:01 -08:00
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
}
|
2019-01-21 10:07:57 -08:00
|
|
|
|
|
|
|
ModuleInner {
|
2019-04-11 18:01:54 -07:00
|
|
|
runnable_module: Box::new(Placeholder),
|
2019-02-19 09:58:01 -08:00
|
|
|
cache_gen: Box::new(Placeholder),
|
2019-02-06 16:26:45 -08:00
|
|
|
info: ModuleInfo {
|
|
|
|
memories: Map::new(),
|
|
|
|
globals: Map::new(),
|
|
|
|
tables: Map::new(),
|
2019-01-21 10:07:57 -08:00
|
|
|
|
2019-02-06 16:26:45 -08:00
|
|
|
// These are strictly imported and the typesystem ensures that.
|
|
|
|
imported_functions: Map::new(),
|
|
|
|
imported_memories: Map::new(),
|
|
|
|
imported_tables: Map::new(),
|
|
|
|
imported_globals: Map::new(),
|
2019-01-21 10:07:57 -08:00
|
|
|
|
2019-08-01 01:27:21 -07:00
|
|
|
exports: IndexMap::new(),
|
2019-01-21 10:07:57 -08:00
|
|
|
|
2019-02-06 16:26:45 -08:00
|
|
|
data_initializers: Vec::new(),
|
|
|
|
elem_initializers: Vec::new(),
|
2019-01-21 10:07:57 -08:00
|
|
|
|
2019-02-06 16:26:45 -08:00
|
|
|
start_func: None,
|
2019-01-21 10:07:57 -08:00
|
|
|
|
2019-02-06 16:26:45 -08:00
|
|
|
func_assoc: Map::new(),
|
|
|
|
signatures: Map::new(),
|
|
|
|
backend: Backend::Cranelift,
|
|
|
|
|
|
|
|
namespace_table: StringTable::new(),
|
|
|
|
name_table: StringTable::new(),
|
2019-03-28 09:20:54 -07:00
|
|
|
|
|
|
|
em_symbol_map: None,
|
2019-03-28 11:41:45 -07:00
|
|
|
|
2019-03-12 13:04:14 -07:00
|
|
|
custom_sections: HashMap::new(),
|
2019-02-06 16:26:45 -08:00
|
|
|
},
|
2019-01-21 10:07:57 -08:00
|
|
|
}
|
|
|
|
}
|
2019-01-17 14:26:52 -08:00
|
|
|
}
|