use crate::export::Export;
use crate::imports::Imports;
use crate::jit_int::GdbJitImageRegistration;
use crate::memory::LinearMemory;
use crate::signalhandlers;
use crate::table::Table;
use crate::traphandlers::{catch_traps, Trap};
use crate::vmcontext::{
VMBuiltinFunctionsArray, VMCallerCheckedAnyfunc, VMContext, VMFunctionBody, VMFunctionImport,
VMGlobalDefinition, VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex,
VMTableDefinition, VMTableImport,
};
use crate::TrapRegistration;
use memoffset::offset_of;
use more_asserts::assert_lt;
use std::alloc::{self, Layout};
use std::any::Any;
use std::cell::Cell;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::rc::Rc;
use std::sync::Arc;
use std::{mem, ptr, slice};
use thiserror::Error;
use wasmtime_environ::entity::{BoxedSlice, EntityRef, PrimaryMap};
use wasmtime_environ::wasm::{
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
};
use wasmtime_environ::{DataInitializer, Module, TableElements, VMOffsets};
cfg_if::cfg_if! {
if #[cfg(unix)] {
pub type SignalHandler = dyn Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool;
impl InstanceHandle {
pub fn set_signal_handler<H>(&mut self, handler: H)
where
H: 'static + Fn(libc::c_int, *const libc::siginfo_t, *const libc::c_void) -> bool,
{
self.instance().signal_handler.set(Some(Box::new(handler)));
}
}
} else if #[cfg(target_os = "windows")] {
pub type SignalHandler = dyn Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool;
impl InstanceHandle {
pub fn set_signal_handler<H>(&mut self, handler: H)
where
H: 'static + Fn(winapi::um::winnt::PEXCEPTION_POINTERS) -> bool,
{
self.instance().signal_handler.set(Some(Box::new(handler)));
}
}
}
}
#[repr(C)]
pub(crate) struct Instance {
refcount: Cell<usize>,
dependencies: HashSet<InstanceHandle>,
module: Arc<Module>,
offsets: VMOffsets,
memories: BoxedSlice<DefinedMemoryIndex, LinearMemory>,
tables: BoxedSlice<DefinedTableIndex, Table>,
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
host_state: Box<dyn Any>,
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
pub(crate) signal_handler: Cell<Option<Box<SignalHandler>>>,
pub(crate) trap_registration: TrapRegistration,
vmctx: VMContext,
}
#[allow(clippy::cast_ptr_alignment)]
impl Instance {
unsafe fn vmctx_plus_offset<T>(&self, offset: u32) -> *mut T {
(self.vmctx_ptr() as *mut u8)
.add(usize::try_from(offset).unwrap())
.cast()
}
fn signature_id(&self, index: SignatureIndex) -> VMSharedSignatureIndex {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { *self.signature_ids_ptr().add(index) }
}
fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_signature_ids_begin()) }
}
fn imported_function(&self, index: FuncIndex) -> &VMFunctionImport {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { &*self.imported_functions_ptr().add(index) }
}
fn imported_functions_ptr(&self) -> *mut VMFunctionImport {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) }
}
fn imported_table(&self, index: TableIndex) -> &VMTableImport {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { &*self.imported_tables_ptr().add(index) }
}
fn imported_tables_ptr(&self) -> *mut VMTableImport {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_tables_begin()) }
}
fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { &*self.imported_memories_ptr().add(index) }
}
fn imported_memories_ptr(&self) -> *mut VMMemoryImport {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_memories_begin()) }
}
fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { &*self.imported_globals_ptr().add(index) }
}
fn imported_globals_ptr(&self) -> *mut VMGlobalImport {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_globals_begin()) }
}
#[allow(dead_code)]
fn table(&self, index: DefinedTableIndex) -> VMTableDefinition {
unsafe { *self.table_ptr(index) }
}
fn set_table(&self, index: DefinedTableIndex, table: VMTableDefinition) {
unsafe {
*self.table_ptr(index) = table;
}
}
fn table_ptr(&self, index: DefinedTableIndex) -> *mut VMTableDefinition {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { self.tables_ptr().add(index) }
}
fn tables_ptr(&self) -> *mut VMTableDefinition {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_tables_begin()) }
}
fn memory(&self, index: DefinedMemoryIndex) -> VMMemoryDefinition {
unsafe { *self.memory_ptr(index) }
}
fn set_memory(&self, index: DefinedMemoryIndex, mem: VMMemoryDefinition) {
unsafe {
*self.memory_ptr(index) = mem;
}
}
fn memory_ptr(&self, index: DefinedMemoryIndex) -> *mut VMMemoryDefinition {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { self.memories_ptr().add(index) }
}
fn memories_ptr(&self) -> *mut VMMemoryDefinition {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_memories_begin()) }
}
fn global(&self, index: DefinedGlobalIndex) -> VMGlobalDefinition {
unsafe { *self.global_ptr(index) }
}
#[allow(dead_code)]
fn set_global(&self, index: DefinedGlobalIndex, global: VMGlobalDefinition) {
unsafe {
*self.global_ptr(index) = global;
}
}
fn global_ptr(&self, index: DefinedGlobalIndex) -> *mut VMGlobalDefinition {
let index = usize::try_from(index.as_u32()).unwrap();
unsafe { self.globals_ptr().add(index) }
}
fn globals_ptr(&self) -> *mut VMGlobalDefinition {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_globals_begin()) }
}
fn builtin_functions_ptr(&self) -> *mut VMBuiltinFunctionsArray {
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_builtin_functions_begin()) }
}
pub fn vmctx(&self) -> &VMContext {
&self.vmctx
}
pub fn vmctx_ptr(&self) -> *mut VMContext {
self.vmctx() as *const VMContext as *mut VMContext
}
pub fn lookup(&self, field: &str) -> Option<Export> {
let export = if let Some(export) = self.module.exports.get(field) {
export.clone()
} else {
return None;
};
Some(self.lookup_by_declaration(&export))
}
pub fn lookup_by_declaration(&self, export: &wasmtime_environ::Export) -> Export {
match export {
wasmtime_environ::Export::Function(index) => {
let signature =
self.module.local.signatures[self.module.local.functions[*index]].clone();
let (address, vmctx) =
if let Some(def_index) = self.module.local.defined_func_index(*index) {
(
self.finished_functions[def_index] as *const _,
self.vmctx_ptr(),
)
} else {
let import = self.imported_function(*index);
(import.body, import.vmctx)
};
Export::Function {
address,
signature,
vmctx,
}
}
wasmtime_environ::Export::Table(index) => {
let (definition, vmctx) =
if let Some(def_index) = self.module.local.defined_table_index(*index) {
(self.table_ptr(def_index), self.vmctx_ptr())
} else {
let import = self.imported_table(*index);
(import.from, import.vmctx)
};
Export::Table {
definition,
vmctx,
table: self.module.local.table_plans[*index].clone(),
}
}
wasmtime_environ::Export::Memory(index) => {
let (definition, vmctx) =
if let Some(def_index) = self.module.local.defined_memory_index(*index) {
(self.memory_ptr(def_index), self.vmctx_ptr())
} else {
let import = self.imported_memory(*index);
(import.from, import.vmctx)
};
Export::Memory {
definition,
vmctx,
memory: self.module.local.memory_plans[*index].clone(),
}
}
wasmtime_environ::Export::Global(index) => Export::Global {
definition: if let Some(def_index) = self.module.local.defined_global_index(*index)
{
self.global_ptr(def_index)
} else {
self.imported_global(*index).from
},
vmctx: self.vmctx_ptr(),
global: self.module.local.globals[*index],
},
}
}
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
self.module.exports.iter()
}
pub fn host_state(&self) -> &dyn Any {
&*self.host_state
}
fn invoke_start_function(&self) -> Result<(), InstantiationError> {
let start_index = match self.module.start_func {
Some(idx) => idx,
None => return Ok(()),
};
let (callee_address, callee_vmctx) = match self.module.local.defined_func_index(start_index)
{
Some(defined_index) => {
let body = *self
.finished_functions
.get(defined_index)
.expect("function index is out of bounds");
(body as *const _, self.vmctx_ptr())
}
None => {
assert_lt!(start_index.index(), self.module.imported_funcs.len());
let import = self.imported_function(start_index);
(import.body, import.vmctx)
}
};
unsafe {
catch_traps(callee_vmctx, || {
mem::transmute::<
*const VMFunctionBody,
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
>(callee_address)(callee_vmctx, self.vmctx_ptr())
})
.map_err(InstantiationError::StartTrap)
}
}
pub(crate) fn vmctx_offset() -> isize {
offset_of!(Self, vmctx) as isize
}
pub(crate) fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
let offsets = &self.offsets;
let begin = unsafe {
(&self.vmctx as *const VMContext as *const u8)
.add(usize::try_from(offsets.vmctx_tables_begin()).unwrap())
} as *const VMTableDefinition;
let end: *const VMTableDefinition = table;
let index = DefinedTableIndex::new(
(end as usize - begin as usize) / mem::size_of::<VMTableDefinition>(),
);
assert_lt!(index.index(), self.tables.len());
index
}
pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
let offsets = &self.offsets;
let begin = unsafe {
(&self.vmctx as *const VMContext as *const u8)
.add(usize::try_from(offsets.vmctx_memories_begin()).unwrap())
} as *const VMMemoryDefinition;
let end: *const VMMemoryDefinition = memory;
let index = DefinedMemoryIndex::new(
(end as usize - begin as usize) / mem::size_of::<VMMemoryDefinition>(),
);
assert_lt!(index.index(), self.memories.len());
index
}
pub(crate) fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
let result = self
.memories
.get(memory_index)
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
.grow(delta);
self.set_memory(memory_index, self.memories[memory_index].vmmemory());
result
}
pub(crate) unsafe fn imported_memory_grow(
&self,
memory_index: MemoryIndex,
delta: u32,
) -> Option<u32> {
let import = self.imported_memory(memory_index);
let foreign_instance = (&*import.vmctx).instance();
let foreign_memory = &*import.from;
let foreign_index = foreign_instance.memory_index(foreign_memory);
foreign_instance.memory_grow(foreign_index, delta)
}
pub(crate) fn memory_size(&self, memory_index: DefinedMemoryIndex) -> u32 {
self.memories
.get(memory_index)
.unwrap_or_else(|| panic!("no memory for index {}", memory_index.index()))
.size()
}
pub(crate) unsafe fn imported_memory_size(&self, memory_index: MemoryIndex) -> u32 {
let import = self.imported_memory(memory_index);
let foreign_instance = (&mut *import.vmctx).instance();
let foreign_memory = &mut *import.from;
let foreign_index = foreign_instance.memory_index(foreign_memory);
foreign_instance.memory_size(foreign_index)
}
pub(crate) fn table_grow(&self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
let result = self
.tables
.get(table_index)
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
.grow(delta);
self.set_table(table_index, self.tables[table_index].vmtable());
result
}
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)
}
fn table_set(
&self,
table_index: DefinedTableIndex,
index: u32,
val: VMCallerCheckedAnyfunc,
) -> Result<(), ()> {
self.tables
.get(table_index)
.unwrap_or_else(|| panic!("no table for index {}", table_index.index()))
.set(index, val)
}
fn alloc_layout(&self) -> Layout {
let size = mem::size_of_val(self)
.checked_add(usize::try_from(self.offsets.size_of_vmctx()).unwrap())
.unwrap();
let align = mem::align_of_val(self);
Layout::from_size_align(size, align).unwrap()
}
}
#[derive(Hash, PartialEq, Eq)]
pub struct InstanceHandle {
instance: *mut Instance,
}
impl InstanceHandle {
pub unsafe fn new(
module: Arc<Module>,
trap_registration: TrapRegistration,
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
imports: Imports,
data_initializers: &[DataInitializer<'_>],
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
host_state: Box<dyn Any>,
) -> Result<Self, InstantiationError> {
let tables = create_tables(&module);
let memories = create_memories(&module)?;
let vmctx_tables = tables
.values()
.map(Table::vmtable)
.collect::<PrimaryMap<DefinedTableIndex, _>>()
.into_boxed_slice();
let vmctx_memories = memories
.values()
.map(LinearMemory::vmmemory)
.collect::<PrimaryMap<DefinedMemoryIndex, _>>()
.into_boxed_slice();
let vmctx_globals = create_globals(&module);
let offsets = VMOffsets::new(mem::size_of::<*const u8>() as u8, &module.local);
let handle = {
let instance = Instance {
refcount: Cell::new(1),
dependencies: imports.dependencies,
module,
offsets,
memories,
tables,
finished_functions,
dbg_jit_registration,
host_state,
signal_handler: Cell::new(None),
trap_registration,
vmctx: VMContext {},
};
let layout = instance.alloc_layout();
let instance_ptr = alloc::alloc(layout) as *mut Instance;
if instance_ptr.is_null() {
alloc::handle_alloc_error(layout);
}
ptr::write(instance_ptr, instance);
InstanceHandle {
instance: instance_ptr,
}
};
let instance = handle.instance();
ptr::copy(
vmshared_signatures.values().as_slice().as_ptr(),
instance.signature_ids_ptr() as *mut VMSharedSignatureIndex,
vmshared_signatures.len(),
);
ptr::copy(
imports.functions.values().as_slice().as_ptr(),
instance.imported_functions_ptr() as *mut VMFunctionImport,
imports.functions.len(),
);
ptr::copy(
imports.tables.values().as_slice().as_ptr(),
instance.imported_tables_ptr() as *mut VMTableImport,
imports.tables.len(),
);
ptr::copy(
imports.memories.values().as_slice().as_ptr(),
instance.imported_memories_ptr() as *mut VMMemoryImport,
imports.memories.len(),
);
ptr::copy(
imports.globals.values().as_slice().as_ptr(),
instance.imported_globals_ptr() as *mut VMGlobalImport,
imports.globals.len(),
);
ptr::copy(
vmctx_tables.values().as_slice().as_ptr(),
instance.tables_ptr() as *mut VMTableDefinition,
vmctx_tables.len(),
);
ptr::copy(
vmctx_memories.values().as_slice().as_ptr(),
instance.memories_ptr() as *mut VMMemoryDefinition,
vmctx_memories.len(),
);
ptr::copy(
vmctx_globals.values().as_slice().as_ptr(),
instance.globals_ptr() as *mut VMGlobalDefinition,
vmctx_globals.len(),
);
ptr::write(
instance.builtin_functions_ptr() as *mut VMBuiltinFunctionsArray,
VMBuiltinFunctionsArray::initialized(),
);
check_table_init_bounds(instance)?;
check_memory_init_bounds(instance, data_initializers)?;
initialize_tables(instance)?;
initialize_memories(instance, data_initializers)?;
initialize_globals(instance);
signalhandlers::init();
instance.invoke_start_function()?;
Ok(handle)
}
pub unsafe fn from_vmctx(vmctx: *mut VMContext) -> Self {
let instance = (&mut *vmctx).instance();
instance.refcount.set(instance.refcount.get() + 1);
Self {
instance: instance as *const Instance as *mut Instance,
}
}
pub fn vmctx(&self) -> &VMContext {
self.instance().vmctx()
}
pub fn vmctx_ptr(&self) -> *mut VMContext {
self.instance().vmctx_ptr()
}
pub fn module(&self) -> &Arc<Module> {
&self.instance().module
}
pub fn module_ref(&self) -> &Module {
&self.instance().module
}
pub fn lookup(&self, field: &str) -> Option<Export> {
self.instance().lookup(field)
}
pub fn lookup_by_declaration(&self, export: &wasmtime_environ::Export) -> Export {
self.instance().lookup_by_declaration(export)
}
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
self.instance().exports()
}
pub fn host_state(&self) -> &dyn Any {
self.instance().host_state()
}
pub fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
self.instance().memory_index(memory)
}
pub fn memory_grow(&self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
self.instance().memory_grow(memory_index, delta)
}
pub fn table_index(&self, table: &VMTableDefinition) -> DefinedTableIndex {
self.instance().table_index(table)
}
pub fn table_grow(&self, table_index: DefinedTableIndex, delta: u32) -> Option<u32> {
self.instance().table_grow(table_index, delta)
}
pub fn table_get(
&self,
table_index: DefinedTableIndex,
index: u32,
) -> Option<VMCallerCheckedAnyfunc> {
self.instance().table_get(table_index, index)
}
pub fn table_set(
&self,
table_index: DefinedTableIndex,
index: u32,
val: VMCallerCheckedAnyfunc,
) -> Result<(), ()> {
self.instance().table_set(table_index, index, val)
}
pub(crate) fn instance(&self) -> &Instance {
unsafe { &*(self.instance as *const Instance) }
}
}
impl Clone for InstanceHandle {
fn clone(&self) -> Self {
let instance = self.instance();
instance.refcount.set(instance.refcount.get() + 1);
Self {
instance: self.instance,
}
}
}
impl Drop for InstanceHandle {
fn drop(&mut self) {
let instance = self.instance();
let count = instance.refcount.get();
instance.refcount.set(count - 1);
if count == 1 {
let layout = instance.alloc_layout();
unsafe {
ptr::drop_in_place(self.instance);
alloc::dealloc(self.instance.cast(), layout);
}
}
}
}
fn check_table_init_bounds(instance: &Instance) -> Result<(), InstantiationError> {
let module = Arc::clone(&instance.module);
for init in &module.table_elements {
let start = get_table_init_start(init, instance);
let table = get_table(init, instance);
let size = usize::try_from(table.size()).unwrap();
if size < start + init.elements.len() {
return Err(InstantiationError::Link(LinkError(
"elements segment does not fit".to_owned(),
)));
}
}
Ok(())
}
fn get_memory_init_start(init: &DataInitializer<'_>, instance: &Instance) -> usize {
let mut start = init.location.offset;
if let Some(base) = init.location.base {
let val = unsafe {
if let Some(def_index) = instance.module.local.defined_global_index(base) {
*instance.global(def_index).as_u32()
} else {
*(*instance.imported_global(base).from).as_u32()
}
};
start += usize::try_from(val).unwrap();
}
start
}
unsafe fn get_memory_slice<'instance>(
init: &DataInitializer<'_>,
instance: &'instance Instance,
) -> &'instance mut [u8] {
let memory = if let Some(defined_memory_index) = instance
.module
.local
.defined_memory_index(init.location.memory_index)
{
instance.memory(defined_memory_index)
} else {
let import = instance.imported_memory(init.location.memory_index);
let foreign_instance = (&mut *(import).vmctx).instance();
let foreign_memory = &mut *(import).from;
let foreign_index = foreign_instance.memory_index(foreign_memory);
foreign_instance.memory(foreign_index)
};
slice::from_raw_parts_mut(memory.base, memory.current_length)
}
fn check_memory_init_bounds(
instance: &Instance,
data_initializers: &[DataInitializer<'_>],
) -> Result<(), InstantiationError> {
for init in data_initializers {
let start = get_memory_init_start(init, instance);
unsafe {
let mem_slice = get_memory_slice(init, instance);
if mem_slice.get_mut(start..start + init.data.len()).is_none() {
return Err(InstantiationError::Link(LinkError(
"data segment does not fit".to_owned(),
)));
}
}
}
Ok(())
}
fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
let num_imports = module.imported_tables.len();
let mut tables: PrimaryMap<DefinedTableIndex, _> =
PrimaryMap::with_capacity(module.local.table_plans.len() - num_imports);
for table in &module.local.table_plans.values().as_slice()[num_imports..] {
tables.push(Table::new(table));
}
tables.into_boxed_slice()
}
fn get_table_init_start(init: &TableElements, instance: &Instance) -> usize {
let mut start = init.offset;
if let Some(base) = init.base {
let val = unsafe {
if let Some(def_index) = instance.module.local.defined_global_index(base) {
*instance.global(def_index).as_u32()
} else {
*(*instance.imported_global(base).from).as_u32()
}
};
start += usize::try_from(val).unwrap();
}
start
}
fn get_table<'instance>(init: &TableElements, instance: &'instance Instance) -> &'instance Table {
if let Some(defined_table_index) = instance.module.local.defined_table_index(init.table_index) {
&instance.tables[defined_table_index]
} else {
let import = instance.imported_table(init.table_index);
let foreign_instance = unsafe { (&mut *(import).vmctx).instance() };
let foreign_table = unsafe { &mut *(import).from };
let foreign_index = foreign_instance.table_index(foreign_table);
&foreign_instance.tables[foreign_index]
}
}
fn initialize_tables(instance: &Instance) -> Result<(), InstantiationError> {
let vmctx = instance.vmctx_ptr();
let module = Arc::clone(&instance.module);
for init in &module.table_elements {
let start = get_table_init_start(init, instance);
let table = get_table(init, instance);
for (i, func_idx) in init.elements.iter().enumerate() {
let callee_sig = instance.module.local.functions[*func_idx];
let (callee_ptr, callee_vmctx) =
if let Some(index) = instance.module.local.defined_func_index(*func_idx) {
(instance.finished_functions[index] as *const _, vmctx)
} else {
let imported_func = instance.imported_function(*func_idx);
(imported_func.body, imported_func.vmctx)
};
let type_index = instance.signature_id(callee_sig);
table
.set(
u32::try_from(start + i).unwrap(),
VMCallerCheckedAnyfunc {
func_ptr: callee_ptr,
type_index,
vmctx: callee_vmctx,
},
)
.unwrap();
}
}
Ok(())
}
fn create_memories(
module: &Module,
) -> Result<BoxedSlice<DefinedMemoryIndex, LinearMemory>, InstantiationError> {
let num_imports = module.imported_memories.len();
let mut memories: PrimaryMap<DefinedMemoryIndex, _> =
PrimaryMap::with_capacity(module.local.memory_plans.len() - num_imports);
for plan in &module.local.memory_plans.values().as_slice()[num_imports..] {
memories.push(LinearMemory::new(plan).map_err(InstantiationError::Resource)?);
}
Ok(memories.into_boxed_slice())
}
fn initialize_memories(
instance: &Instance,
data_initializers: &[DataInitializer<'_>],
) -> Result<(), InstantiationError> {
for init in data_initializers {
let start = get_memory_init_start(init, instance);
unsafe {
let mem_slice = get_memory_slice(init, instance);
let to_init = &mut mem_slice[start..start + init.data.len()];
to_init.copy_from_slice(init.data);
}
}
Ok(())
}
fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDefinition> {
let num_imports = module.imported_globals.len();
let mut vmctx_globals = PrimaryMap::with_capacity(module.local.globals.len() - num_imports);
for _ in &module.local.globals.values().as_slice()[num_imports..] {
vmctx_globals.push(VMGlobalDefinition::new());
}
vmctx_globals.into_boxed_slice()
}
fn initialize_globals(instance: &Instance) {
let module = Arc::clone(&instance.module);
let num_imports = module.imported_globals.len();
for (index, global) in module.local.globals.iter().skip(num_imports) {
let def_index = module.local.defined_global_index(index).unwrap();
unsafe {
let to = instance.global_ptr(def_index);
match global.initializer {
GlobalInit::I32Const(x) => *(*to).as_i32_mut() = x,
GlobalInit::I64Const(x) => *(*to).as_i64_mut() = x,
GlobalInit::F32Const(x) => *(*to).as_f32_bits_mut() = x,
GlobalInit::F64Const(x) => *(*to).as_f64_bits_mut() = x,
GlobalInit::V128Const(x) => *(*to).as_u128_bits_mut() = x.0,
GlobalInit::GetGlobal(x) => {
let from = if let Some(def_x) = module.local.defined_global_index(x) {
instance.global(def_x)
} else {
*instance.imported_global(x).from
};
*to = from;
}
GlobalInit::Import => panic!("locally-defined global initialized as import"),
GlobalInit::RefNullConst | GlobalInit::RefFunc(_) => unimplemented!(),
}
}
}
}
#[derive(Error, Debug)]
#[error("Link error: {0}")]
pub struct LinkError(pub String);
#[derive(Error, Debug)]
pub enum InstantiationError {
#[error("Insufficient resources: {0}")]
Resource(String),
#[error("Failed to link module")]
Link(#[from] LinkError),
#[error("Trap occurred while invoking start function")]
StartTrap(#[source] Trap),
}