Improved instance functions

This commit is contained in:
Syrus Akbary
2018-10-15 15:58:06 +02:00
parent 1482648219
commit dd0f1b1a2d
2 changed files with 76 additions and 10 deletions

View File

@ -13,6 +13,7 @@ use memmap::MmapMut;
use region; use region;
use spin::RwLock; use spin::RwLock;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr;
use std::sync::Arc; use std::sync::Arc;
use std::{mem, slice}; use std::{mem, slice};
@ -75,18 +76,26 @@ pub struct Instance {
/// WebAssembly global variable data /// WebAssembly global variable data
pub globals: Vec<u8>, pub globals: Vec<u8>,
/// Webassembly functions
functions: Vec<usize>,
/// Region start memory location
code_base: *const (),
} }
impl Instance { impl Instance {
/// Create a new `Instance`. /// Create a new `Instance`.
pub fn new(module: &Module, code_base: *const ()) -> Result<Instance, ErrorKind> { pub fn new(module: &Module) -> Result<Instance, ErrorKind> {
let mut tables: Vec<Vec<usize>> = Vec::new(); let mut tables: Vec<Vec<usize>> = Vec::new();
let mut memories: Vec<LinearMemory> = Vec::new(); let mut memories: Vec<LinearMemory> = Vec::new();
let mut globals: Vec<u8> = Vec::new(); let mut globals: Vec<u8> = Vec::new();
let mut functions: Vec<usize> = Vec::new();
let mut code_base: *const () = ptr::null();
let mut functions: Vec<usize> = Vec::with_capacity(module.info.function_bodies.len());
// Instantiate functions // Instantiate functions
{ {
functions.reserve_exact(module.info.function_bodies.len());
let isa = isa::lookup(module.info.triple.clone()) let isa = isa::lookup(module.info.triple.clone())
.unwrap() .unwrap()
.finish(module.info.flags.clone()); .finish(module.info.flags.clone());
@ -112,33 +121,34 @@ impl Instance {
} }
// We only want to allocate in memory if there is more than // We only want to allocate in memory if there is more than
// 0 functions. Otherwise reserving a 0-sized memory // 0 functions. Otherwise reserving a 0-sized memory region
// cause a panic error // cause a panic error
if total_size > 0 { if total_size > 0 {
// Allocate the total memory for this functions // Allocate the total memory for this functions
let map = MmapMut::map_anon(total_size).unwrap(); let map = MmapMut::map_anon(total_size).unwrap();
let region_start = map.as_ptr(); let region_start = map.as_ptr() as usize;
code_base = map.as_ptr() as *const ();
// // Emit this functions to memory // // Emit this functions to memory
for (ref func_context, func_offset) in context_and_offsets.iter() { for (ref func_context, func_offset) in context_and_offsets.iter() {
let mut trap_sink = TrapSink::new(*func_offset); let mut trap_sink = TrapSink::new(*func_offset);
let mut reloc_sink = RelocSink::new(); let mut reloc_sink = RelocSink::new();
let mut func_pointer = (region_start as usize + func_offset) as *mut u8; // let mut func_pointer = as *mut u8;
unsafe { unsafe {
func_context.emit_to_memory( func_context.emit_to_memory(
&*isa, &*isa,
*&mut func_pointer, (region_start + func_offset) as *mut u8,
&mut reloc_sink, &mut reloc_sink,
&mut trap_sink, &mut trap_sink,
); );
}; };
functions.push(func_pointer as usize); functions.push(*func_offset);
} }
// Set protection of this memory region to Read + Execute // Set protection of this memory region to Read + Execute
// so we are able to execute the functions emitted to memory // so we are able to execute the functions emitted to memory
unsafe { unsafe {
region::protect(region_start, total_size, region::Protection::ReadExecute) region::protect(region_start as *mut u8, total_size, region::Protection::ReadExecute)
.expect("unable to make memory readable+executable"); .expect("unable to make memory readable+executable");
} }
} }
@ -221,6 +231,8 @@ impl Instance {
tables: Arc::new(tables.into_iter().map(|table| RwLock::new(table)).collect()), tables: Arc::new(tables.into_iter().map(|table| RwLock::new(table)).collect()),
memories: Arc::new(memories.into_iter().collect()), memories: Arc::new(memories.into_iter().collect()),
globals: globals, globals: globals,
functions: functions,
code_base: code_base,
}) })
} }
@ -231,9 +243,61 @@ impl Instance {
/// Invoke a WebAssembly function given a FuncIndex and the /// Invoke a WebAssembly function given a FuncIndex and the
/// arguments that the function should be called with /// arguments that the function should be called with
pub fn invoke(&self, func_index: FuncIndex, args: Vec<i32>) { pub fn invoke(&self, func_index: FuncIndex, args: Vec<i32>) {
unimplemented!() // let vmctx = make_vmctx(instance, &mut mem_base_addrs);
// let vmctx = ptr::null();
// Rather than writing inline assembly to jump to the code region, we use the fact that
// the Rust ABI for calling a function with no arguments and no return matches the one of
// the generated code. Thanks to this, we can transmute the code region into a first-class
// Rust function and call it.
let func_pointer = get_function_addr(self.code_base, &self.functions, &func_index);
// let index = func_index.index();
// let func_pointer = self.functions[index];
println!("INVOKING FUNCTION {:?} {:?}", func_index, func_pointer);
unsafe {
let func = mem::transmute::<_, fn()>(func_pointer);
let result = func();
println!("FUNCTION INVOKED, result {:?}", result);
// start_func(vmctx.as_ptr());
}
unimplemented!();
} }
// pub fn generate_context(&mut self) -> &VmCtx {
// let memories: Vec<UncheckedSlice<u8>> = self.memories.iter()
// .map(|mem| mem.into())
// .collect();
// let tables: Vec<BoundedSlice<usize>> = self.tables.iter()
// .map(|table| table.write()[..].into())
// .collect();
// let globals: UncheckedSlice<u8> = self.globals[..].into();
// assert!(memories.len() >= 1, "modules must have at least one memory");
// // the first memory has a space of `mem::size_of::<VmCtxData>()` rounded
// // up to the 4KiB before it. We write the VmCtxData into that.
// let data = VmCtxData {
// globals: globals,
// memories: memories[1..].into(),
// tables: tables[..].into(),
// user_data: UserData {
// // process,
// instance,
// },
// phantom: PhantomData,
// };
// let main_heap_ptr = memories[0].as_mut_ptr() as *mut VmCtxData;
// unsafe {
// main_heap_ptr
// .sub(1)
// .write(data);
// &*(main_heap_ptr as *const VmCtx)
// }
// }
// pub fn start_func(&self) -> extern fn(&VmCtx) { // pub fn start_func(&self) -> extern fn(&VmCtx) {
// self.start_func // self.start_func
// } // }
@ -245,6 +309,8 @@ impl Clone for Instance {
tables: Arc::clone(&self.tables), tables: Arc::clone(&self.tables),
memories: Arc::clone(&self.memories), memories: Arc::clone(&self.memories),
globals: self.globals.clone(), globals: self.globals.clone(),
functions: self.functions.clone(),
code_base: self.code_base,
} }
} }
} }

View File

@ -49,7 +49,7 @@ pub fn instantiate(
) -> Result<ResultObject, ErrorKind> { ) -> Result<ResultObject, ErrorKind> {
let module = compile(buffer_source)?; let module = compile(buffer_source)?;
debug!("webassembly - creating instance"); debug!("webassembly - creating instance");
let instance = Instance::new(&module, ptr::null())?; let instance = Instance::new(&module)?;
debug!("webassembly - instance created"); debug!("webassembly - instance created");
Ok(ResultObject { module, instance }) Ok(ResultObject { module, instance })
} }