wasmer/src/webassembly/instance.rs

227 lines
8.1 KiB
Rust
Raw Normal View History

//! A webassembly::Instance object is a stateful, executable instance of a
//! webassembly::Module. Instance objects contain all the Exported
//! WebAssembly functions that allow calling into WebAssembly code.
//! The webassembly::Instance() constructor function can be called to
//! synchronously instantiate a given webassembly::Module object. However, the
//! primary way to get an Instance is through the asynchronous
//! webassembly::instantiateStreaming() function.
2018-10-14 13:59:11 +02:00
use std::marker::PhantomData;
use std::sync::Arc;
2018-10-14 23:48:59 +02:00
use std::{mem, slice};
2018-10-15 02:48:59 +02:00
use memmap::MmapMut;
use spin::RwLock;
use region;
use cranelift_entity::EntityRef;
use cranelift_wasm::{FuncIndex, GlobalInit};
use cranelift_codegen::{Context, isa};
2018-10-15 02:48:59 +02:00
use super::errors::ErrorKind;
use super::memory::LinearMemory;
use super::relocation::{RelocSink, TrapSink};
use super::module::Module;
use super::module::{DataInitializer, Exportable};
2018-10-14 13:59:11 +02:00
use super::super::common::slice::{BoundedSlice, UncheckedSlice};
2018-10-12 02:45:09 +02:00
2018-10-14 23:48:59 +02:00
pub fn get_function_addr(
base: *const (),
functions: &[usize],
func_index: &FuncIndex,
) -> *const () {
2018-10-14 13:59:11 +02:00
let offset = functions[func_index.index()];
(base as usize + offset) as _
}
2018-10-12 02:45:09 +02:00
2018-10-14 13:59:11 +02:00
/// Zero-sized, non-instantiable type.
pub enum VmCtx {}
2018-10-14 13:59:11 +02:00
impl VmCtx {
pub fn data(&self) -> &VmCtxData {
let heap_ptr = self as *const _ as *const VmCtxData;
2018-10-14 23:48:59 +02:00
unsafe { &*heap_ptr.sub(1) }
2018-10-14 13:59:11 +02:00
}
2018-10-14 13:59:11 +02:00
/// This is safe because the offset is 32 bits and thus
/// cannot extend out of the guarded wasm memory.
pub fn fastpath_offset_ptr<T>(&self, offset: u32) -> *const T {
let heap_ptr = self as *const _ as *const u8;
2018-10-14 23:48:59 +02:00
unsafe { heap_ptr.add(offset as usize) as *const T }
2018-10-14 13:59:11 +02:00
}
}
2018-10-14 13:59:11 +02:00
#[repr(C)]
pub struct VmCtxData<'a> {
pub user_data: UserData,
globals: UncheckedSlice<u8>,
memories: UncheckedSlice<UncheckedSlice<u8>>,
tables: UncheckedSlice<BoundedSlice<usize>>,
phantom: PhantomData<&'a ()>,
2018-10-13 15:31:56 +02:00
}
2018-10-14 13:59:11 +02:00
#[repr(C)]
pub struct UserData {
// pub process: Dispatch<Process>,
pub instance: Instance,
}
2018-10-14 13:59:11 +02:00
/// An Instance of a WebAssembly module
#[derive(Debug)]
pub struct Instance {
/// WebAssembly table data
pub tables: Arc<Vec<RwLock<Vec<usize>>>>,
2018-10-14 13:59:11 +02:00
/// WebAssembly linear memory data
pub memories: Arc<Vec<LinearMemory>>,
2018-10-14 13:59:11 +02:00
/// WebAssembly global variable data
pub globals: Vec<u8>,
}
2018-10-14 13:59:11 +02:00
impl Instance {
/// Create a new `Instance`.
2018-10-15 02:48:59 +02:00
pub fn new(module: &Module, code_base: *const ()) -> Result<Instance, ErrorKind> {
2018-10-14 13:59:11 +02:00
let mut tables: Vec<Vec<usize>> = Vec::new();
let mut memories: Vec<LinearMemory> = Vec::new();
let mut globals: Vec<u8> = Vec::new();
2018-10-15 02:48:59 +02:00
let mut functions: Vec<usize> = Vec::with_capacity(module.info.function_bodies.len());
// instantiate functions
{
let isa = isa::lookup(module.info.triple.clone())
.unwrap()
.finish(module.info.flags.clone());
let mut total_size: usize = 0;
let mut context_and_offsets = Vec::with_capacity(module.info.function_bodies.len());
// Compile the functions
for function_body in module.info.function_bodies.values() {
let mut context = Context::for_function(function_body.to_owned());
let code_size_offset = context.compile(&*isa).map_err(|e| ErrorKind::CompileError(e.to_string()))? as usize;
total_size += code_size_offset;
context_and_offsets.push((context, code_size_offset));
}
// Allocate the total memory for this functions
let map = MmapMut::map_anon(total_size).unwrap();
let region_start = map.as_ptr();
// // Emit this functions to memory
for (ref func_context, func_offset) in context_and_offsets.iter() {
let mut trap_sink = TrapSink::new(*func_offset);
let mut reloc_sink = RelocSink::new();
unsafe {
func_context.emit_to_memory(&*isa, (region_start as usize + func_offset) as *mut u8, &mut reloc_sink, &mut trap_sink);
}
}
// Set protection of this memory region to Read + Execute
// so we are able to execute them
unsafe {
region::protect(region_start, total_size, region::Protection::ReadExecute)
.expect("unable to make memory readable+executable");
}
}
2018-10-14 13:59:11 +02:00
// instantiate_tables
{
// Reserve table space
2018-10-14 13:59:11 +02:00
tables.reserve_exact(module.info.tables.len());
for table in &module.info.tables {
let len = table.entity.size;
let mut v = Vec::with_capacity(len);
v.resize(len, 0);
tables.push(v);
}
// instantiate tables
for table_element in &module.info.table_elements {
2018-10-14 23:48:59 +02:00
assert!(
table_element.base.is_none(),
"globalvalue base not supported yet."
);
2018-10-14 13:59:11 +02:00
let base = 0;
2018-10-14 13:59:11 +02:00
let table = &mut tables[table_element.table_index];
for (i, func_index) in table_element.elements.iter().enumerate() {
// since the table just contains functions in the MVP
// we get the address of the specified function indexes
// to populate the table.
2018-10-13 15:31:56 +02:00
2018-10-14 13:59:11 +02:00
// let func_index = *elem_index - module.info.imported_funcs.len() as u32;
2018-10-15 02:48:59 +02:00
let func_addr = get_function_addr(code_base, &functions, *&func_index);
2018-10-14 13:59:11 +02:00
table[base + table_element.offset + i] = func_addr as _;
}
}
2018-10-13 15:31:56 +02:00
};
2018-10-14 13:59:11 +02:00
// instantiate_memories
{
// Allocate the underlying memory and initialize it to all zeros.
memories.reserve_exact(module.info.memories.len());
for memory in &module.info.memories {
let memory = memory.entity;
2018-10-14 23:48:59 +02:00
let v =
LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32));
2018-10-14 13:59:11 +02:00
memories.push(v);
}
for init in &module.info.data_initializers {
2018-10-14 13:59:11 +02:00
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
let mem_mut = memories[init.memory_index].as_mut();
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
to_init.copy_from_slice(&init.data);
}
};
2018-10-13 15:31:56 +02:00
2018-10-14 13:59:11 +02:00
// instantiate_globals
{
let globals_count = module.info.globals.len();
// Allocate the underlying memory and initialize it to zeros
let globals_data_size = globals_count * 8;
globals.resize(globals_data_size, 0);
// cast the globals slice to a slice of i64.
2018-10-14 23:48:59 +02:00
let globals_data = unsafe {
slice::from_raw_parts_mut(globals.as_mut_ptr() as *mut i64, globals_count)
};
2018-10-14 13:59:11 +02:00
for (i, global) in module.info.globals.iter().enumerate() {
let value: i64 = match global.entity.initializer {
GlobalInit::I32Const(n) => n as _,
GlobalInit::I64Const(n) => n,
GlobalInit::F32Const(f) => unsafe { mem::transmute(f as f64) },
GlobalInit::F64Const(f) => unsafe { mem::transmute(f) },
_ => unimplemented!(),
};
2018-10-14 23:48:59 +02:00
2018-10-14 13:59:11 +02:00
globals_data[i] = value;
}
};
2018-10-13 15:31:56 +02:00
2018-10-15 02:48:59 +02:00
Ok(Instance {
2018-10-14 13:59:11 +02:00
tables: Arc::new(tables.into_iter().map(|table| RwLock::new(table)).collect()),
memories: Arc::new(memories.into_iter().collect()),
globals: globals,
2018-10-15 02:48:59 +02:00
})
2018-10-14 13:59:11 +02:00
}
2018-10-13 15:31:56 +02:00
2018-10-14 13:59:11 +02:00
pub fn memories(&self) -> Arc<Vec<LinearMemory>> {
self.memories.clone()
2018-10-13 15:31:56 +02:00
}
2018-10-14 20:37:42 +02:00
pub fn invoke(&self, func_index: FuncIndex, args: Vec<i32>) {
unimplemented!()
}
2018-10-14 20:37:42 +02:00
// pub fn start_func(&self) -> extern fn(&VmCtx) {
// self.start_func
// }
2018-10-14 13:59:11 +02:00
}
2018-10-13 15:31:56 +02:00
2018-10-14 13:59:11 +02:00
impl Clone for Instance {
fn clone(&self) -> Instance {
Instance {
tables: Arc::clone(&self.tables),
memories: Arc::clone(&self.memories),
globals: self.globals.clone(),
}
}
}