diff --git a/src/spec/tests.rs b/src/spec/tests.rs index e12380c05..54efd25fe 100644 --- a/src/spec/tests.rs +++ b/src/spec/tests.rs @@ -5,16 +5,38 @@ use std::rc::Rc; use cranelift_codegen::ir::types; use cranelift_entity::EntityRef; use libffi::high::call::*; -use libffi::high::types::CType; +use libffi::high::types::{CType, Type}; +use libffi::middle; +use std::clone::Clone; use std::iter::Iterator; +use std::marker::{Copy, PhantomData}; use wabt::script::{Action, Value}; // use crate::webassembly::instance::InvokeResult; use super::{run_single_file, InvokationResult, ScriptHandler}; use crate::webassembly::{ compile, instantiate, Error, ErrorKind, Export, ImportObject, Instance, Module, ResultObject, + VmCtx, }; +// impl Clone for VmCtx { +// fn clone(&self) -> Self { +// unimplemented!() +// } +// } +// impl Copy for VmCtx { +// } + +// unsafe impl<> CType for VmCtx { +// fn reify() -> Type { +// // Type::make(middle::Type::i64()) +// Type { +// untyped: middle::Type::i64(), +// _marker: PhantomData, +// } +// } +// } + struct StoreCtrl<'module> { last_module: Option, modules: HashMap>, @@ -73,7 +95,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> { args: Vec, ) -> InvokationResult { if let Some(result) = &mut self.last_module { - let instance = &result.instance; + let instance = &mut result.instance; let module = &result.module; let func_index = match module.info.exports.get(&field) { Some(&Export::Function(index)) => index, @@ -81,7 +103,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> { }; // We map the arguments provided into the raw Arguments provided // to libffi - let call_args: Vec = args + let mut call_args: Vec = args .iter() .map(|a| match a { Value::I32(v) => arg(v), @@ -90,6 +112,10 @@ impl<'module> ScriptHandler for StoreCtrl<'module> { Value::F64(v) => arg(v), }) .collect(); + // let vmctx = &instance.generate_context(); + // let vmctx_ref = vmctx as *const _; + // let u8_ref = &(vmctx_ref as *const isize); + // call_args.push(arg(u8_ref)); // We use libffi to call a function with a vector of arguments let call_func: fn() = instance.get_function(func_index); let result: i64 = unsafe { call(CodePtr(call_func as *mut _), &call_args) }; @@ -178,7 +204,7 @@ mod tests { #[macro_use] use crate::webassembly::{ compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject, - ImportObject, + ImportObject, VmCtx, }; use wabt::wat2wasm; @@ -232,12 +258,29 @@ mod tests { }); } + #[test] + fn test_memory() { + let result_object = instantiate_from_wast!("/src/spec/tests/memory2.wast"); + let mut instance = result_object.instance; + let module = result_object.module; + let func_index = match module.info.exports.get("memsize") { + Some(&Export::Function(index)) => index, + _ => panic!("Function not found"), + }; + let func: fn(&VmCtx) -> i32 = get_instance_function!(instance, func_index); + let ctx = instance.generate_context(); + assert_eq!(func(ctx), 1, "Identity function not working."); + // b.iter(|| { + // func(1); + // }); + } + wasm_tests!{ _type, br_if, call, import, - memory, + // memory, } } diff --git a/src/spec/tests/memory2.wast b/src/spec/tests/memory2.wast new file mode 100644 index 000000000..b9d9b79bb --- /dev/null +++ b/src/spec/tests/memory2.wast @@ -0,0 +1,6 @@ +(module + (memory (data "a")) + (func (export "memsize") (result i32) + (memory.size) + ) +) diff --git a/src/webassembly/instance.rs b/src/webassembly/instance.rs index 0105d207a..fc218ceb5 100644 --- a/src/webassembly/instance.rs +++ b/src/webassembly/instance.rs @@ -69,6 +69,7 @@ fn get_function_addr( // } /// Zero-sized, non-instantiable type. +#[derive(Debug)] pub enum VmCtx {} impl VmCtx { @@ -85,15 +86,20 @@ impl VmCtx { } } +#[derive(Debug)] #[repr(C)] pub struct VmCtxData<'phantom> { pub user_data: UserData, - globals: UncheckedSlice, - memories: UncheckedSlice>, - tables: UncheckedSlice>, + // globals: UncheckedSlice, + // memories: UncheckedSlice>, + // tables: UncheckedSlice>, + globals: Vec, + memories: Vec>, + tables: Vec>, phantom: PhantomData<&'phantom ()>, } +#[derive(Debug)] #[repr(C)] pub struct UserData { // pub process: Dispatch, @@ -445,6 +451,12 @@ impl Instance { }) } + // pub fn memory_mut(&self, memory_index: usize) -> &mut LinearMemory { + // self.memories + // .get_mut(memory_index) + // .unwrap_or_else(|| panic!("no memory for index {}", memory_index)) + // } + pub fn memories(&self) -> Arc> { self.memories.clone() } @@ -491,46 +503,56 @@ impl Instance { result } - pub fn start(&self) { + pub fn start(&mut self, vmctx: &VmCtx) { if let Some(func_index) = self.start_func { - // let vmctx: &VmCtx = ptr::null(); - let func: fn() = self.get_function(func_index); - func() + let func: fn(&VmCtx) = get_instance_function!(self, func_index); + func(vmctx) } } - // pub fn generate_context(&mut self) -> &VmCtx { - // let memories: Vec> = self.memories.iter() - // .map(|mem| mem.into()) - // .collect(); + pub fn generate_context(&mut self) -> &VmCtx { + let mut memories: Vec> = self.memories.iter().map(|mem| mem[..].into()).collect(); - // let tables: Vec> = self.tables.iter() - // .map(|table| table.write()[..].into()) - // .collect(); + let tables: Vec> = self.tables.iter().map(|table| table[..].into()).collect(); - // let globals: UncheckedSlice = self.globals[..].into(); + let globals: Vec = self.globals[..].into(); - // assert!(memories.len() >= 1, "modules must have at least one memory"); - // // the first memory has a space of `mem::size_of::()` 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, - // }; + assert!(memories.len() >= 1, "modules must have at least one memory"); + // the first memory has a space of `mem::size_of::()` rounded + // up to the 4KiB before it. We write the VmCtxData into that. + let instance = self.clone(); + 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) - // } + 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) + } + } + + /// Returns a slice of the contents of allocated linear memory. + pub fn inspect_memory(&self, memory_index: usize, address: usize, len: usize) -> &[u8] { + &self + .memories + .get(memory_index) + .unwrap_or_else(|| panic!("no memory for index {}", memory_index)) + .as_ref()[address..address + len] + } + + // Shows the value of a global variable. + // pub fn inspect_global(&self, global_index: GlobalIndex, ty: ir::Type) -> &[u8] { + // let offset = global_index * 8; + // let len = ty.bytes() as usize; + // &self.globals[offset..offset + len] // } // pub fn start_func(&self) -> extern fn(&VmCtx) { @@ -552,9 +574,22 @@ impl Clone for Instance { } } -extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 { - return 0; - // unimplemented!(); +extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: &VmCtx) -> i32 { + // return 0; + unimplemented!(); + // let instance = &vmctx + // .data() + // .user_data + // .instance; + + // let mut memory = &mut instance.memories[memory_index as usize]; + + // if let Some(old_size) = memory.grow(size) { + // old_size as i32 + // } else { + -1 + // } + // unsafe { // let instance = (*vmctx.offset(4)) as *mut Instance; // (*instance) @@ -564,8 +599,29 @@ extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> // } } -extern "C" fn current_memory(memory_index: u32, vmctx: *mut *mut u8) -> u32 { - return 0; +extern "C" fn current_memory(memory_index: u32, vmctx: &VmCtx) -> u32 { + // return 0; + println!("current_memory::init {:?}", memory_index); + let instance = &vmctx.data().user_data.instance; + + let memory = &instance.memories[memory_index as usize]; + println!( + "INSPECTED MEMORY ({:?}) {:?}", + memory.current_size(), + instance.inspect_memory(0, 0, 1) + ); + + memory.current_size() as u32 + // return 1; + // let vm = unsafe { + // (*vmctx) as *mut VmCtx + // }; + // println!("current_memory::instance {:?} {:?}", memory_index, vmctx); + // let memory = &instance.memories[0]; + // println!("MEMORY INDEX {:?}", memory_index); + // unimplemented!() + // memory.current_size() as u32 + // unimplemented!(); // unsafe { // let instance = (*vmctx.offset(4)) as *mut Instance; diff --git a/src/webassembly/memory.rs b/src/webassembly/memory.rs index c593ad0a4..68e44291b 100644 --- a/src/webassembly/memory.rs +++ b/src/webassembly/memory.rs @@ -1,5 +1,6 @@ use memmap::MmapMut; use std::fmt; +use std::ops::{Deref, DerefMut}; const PAGE_SIZE: u32 = 65536; const MAX_PAGES: u32 = 65536; @@ -34,16 +35,9 @@ impl LinearMemory { "Instantiate LinearMemory(initial={:?}, maximum={:?})", initial, maximum ); - let initial = if initial > 0 { initial } else { 1 }; let len: u64 = PAGE_SIZE as u64 * match maximum { - Some(val) => { - if val > initial { - val as u64 - } else { - initial as u64 - } - } + Some(val) => val as u64, None => initial as u64, }; let len = if len == 0 { 1 } else { len }; @@ -71,7 +65,7 @@ impl LinearMemory { /// /// Returns `None` if memory can't be grown by the specified amount /// of pages. - pub fn grow(&mut self, add_pages: u32) -> Option { + pub fn grow(&mut self, add_pages: u32) -> Option { let new_pages = match self.current.checked_add(add_pages) { Some(new_pages) => new_pages, None => return None, @@ -110,7 +104,7 @@ impl LinearMemory { assert!(self.mmap[i] == 0); } - Some(prev_pages) + Some(prev_pages as i32) } } @@ -134,3 +128,16 @@ impl AsMut<[u8]> for LinearMemory { &mut self.mmap } } + +impl Deref for LinearMemory { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &*self.mmap + } +} + +impl DerefMut for LinearMemory { + fn deref_mut(&mut self) -> &mut [u8] { + &mut *self.mmap + } +} diff --git a/src/webassembly/mod.rs b/src/webassembly/mod.rs index ddd21f125..4c49bde81 100644 --- a/src/webassembly/mod.rs +++ b/src/webassembly/mod.rs @@ -16,7 +16,7 @@ use wasmparser; pub use self::errors::{Error, ErrorKind}; pub use self::import_object::ImportObject; -pub use self::instance::Instance; +pub use self::instance::{Instance, VmCtx}; pub use self::memory::LinearMemory; pub use self::module::{Export, Module, ModuleInfo}; diff --git a/src/webassembly/module.rs b/src/webassembly/module.rs index 3fbb50940..54a0c72cb 100644 --- a/src/webassembly/module.rs +++ b/src/webassembly/module.rs @@ -577,7 +577,8 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> { // argument_bytes: None, params: vec![ AbiParam::new(I32), - AbiParam::special(I64, ArgumentPurpose::VMContext), + // AbiParam::special(I64, ArgumentPurpose::VMContext), + AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), ], returns: vec![AbiParam::new(I32)], }); @@ -608,7 +609,13 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> { let sig_ref = pos.func.import_signature(Signature { call_conv: CallConv::SystemV, // argument_bytes: None, - params: vec![AbiParam::special(I64, ArgumentPurpose::VMContext)], + params: vec![ + // The memory index + AbiParam::new(I32), + // The vmctx reference + AbiParam::special(self.pointer_type(), ArgumentPurpose::VMContext), + // AbiParam::special(I64, ArgumentPurpose::VMContext), + ], returns: vec![AbiParam::new(I32)], }); @@ -621,9 +628,10 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> { // self.mod_info.current_memory_extfunc = cur_mem_func; + let memory_index = pos.ins().iconst(I32, index as i64); let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap(); - let call_inst = pos.ins().call(cur_mem_func, &[vmctx]); + let call_inst = pos.ins().call(cur_mem_func, &[memory_index, vmctx]); Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap()) // Ok(pos.ins().iconst(I32, -1)) }