mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Added first tests for the vmctx (memory usage)
This commit is contained in:
parent
80f3bf161e
commit
6fce21e4d5
@ -5,16 +5,38 @@ use std::rc::Rc;
|
|||||||
use cranelift_codegen::ir::types;
|
use cranelift_codegen::ir::types;
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
use libffi::high::call::*;
|
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::iter::Iterator;
|
||||||
|
use std::marker::{Copy, PhantomData};
|
||||||
use wabt::script::{Action, Value};
|
use wabt::script::{Action, Value};
|
||||||
// use crate::webassembly::instance::InvokeResult;
|
// use crate::webassembly::instance::InvokeResult;
|
||||||
|
|
||||||
use super::{run_single_file, InvokationResult, ScriptHandler};
|
use super::{run_single_file, InvokationResult, ScriptHandler};
|
||||||
use crate::webassembly::{
|
use crate::webassembly::{
|
||||||
compile, instantiate, Error, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
|
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<Self> {
|
||||||
|
// // Type::make(middle::Type::i64())
|
||||||
|
// Type {
|
||||||
|
// untyped: middle::Type::i64(),
|
||||||
|
// _marker: PhantomData,
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
struct StoreCtrl<'module> {
|
struct StoreCtrl<'module> {
|
||||||
last_module: Option<ResultObject>,
|
last_module: Option<ResultObject>,
|
||||||
modules: HashMap<String, Rc<&'module ResultObject>>,
|
modules: HashMap<String, Rc<&'module ResultObject>>,
|
||||||
@ -73,7 +95,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
|
|||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> InvokationResult {
|
) -> InvokationResult {
|
||||||
if let Some(result) = &mut self.last_module {
|
if let Some(result) = &mut self.last_module {
|
||||||
let instance = &result.instance;
|
let instance = &mut result.instance;
|
||||||
let module = &result.module;
|
let module = &result.module;
|
||||||
let func_index = match module.info.exports.get(&field) {
|
let func_index = match module.info.exports.get(&field) {
|
||||||
Some(&Export::Function(index)) => index,
|
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
|
// We map the arguments provided into the raw Arguments provided
|
||||||
// to libffi
|
// to libffi
|
||||||
let call_args: Vec<Arg> = args
|
let mut call_args: Vec<Arg> = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| match a {
|
.map(|a| match a {
|
||||||
Value::I32(v) => arg(v),
|
Value::I32(v) => arg(v),
|
||||||
@ -90,6 +112,10 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
|
|||||||
Value::F64(v) => arg(v),
|
Value::F64(v) => arg(v),
|
||||||
})
|
})
|
||||||
.collect();
|
.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
|
// We use libffi to call a function with a vector of arguments
|
||||||
let call_func: fn() = instance.get_function(func_index);
|
let call_func: fn() = instance.get_function(func_index);
|
||||||
let result: i64 = unsafe { call(CodePtr(call_func as *mut _), &call_args) };
|
let result: i64 = unsafe { call(CodePtr(call_func as *mut _), &call_args) };
|
||||||
@ -178,7 +204,7 @@ mod tests {
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
use crate::webassembly::{
|
use crate::webassembly::{
|
||||||
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject,
|
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject,
|
||||||
ImportObject,
|
ImportObject, VmCtx,
|
||||||
};
|
};
|
||||||
use wabt::wat2wasm;
|
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!{
|
wasm_tests!{
|
||||||
_type,
|
_type,
|
||||||
br_if,
|
br_if,
|
||||||
call,
|
call,
|
||||||
import,
|
import,
|
||||||
memory,
|
// memory,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
6
src/spec/tests/memory2.wast
Normal file
6
src/spec/tests/memory2.wast
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(module
|
||||||
|
(memory (data "a"))
|
||||||
|
(func (export "memsize") (result i32)
|
||||||
|
(memory.size)
|
||||||
|
)
|
||||||
|
)
|
@ -69,6 +69,7 @@ fn get_function_addr(
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/// Zero-sized, non-instantiable type.
|
/// Zero-sized, non-instantiable type.
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum VmCtx {}
|
pub enum VmCtx {}
|
||||||
|
|
||||||
impl VmCtx {
|
impl VmCtx {
|
||||||
@ -85,15 +86,20 @@ impl VmCtx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct VmCtxData<'phantom> {
|
pub struct VmCtxData<'phantom> {
|
||||||
pub user_data: UserData,
|
pub user_data: UserData,
|
||||||
globals: UncheckedSlice<u8>,
|
// globals: UncheckedSlice<u8>,
|
||||||
memories: UncheckedSlice<UncheckedSlice<u8>>,
|
// memories: UncheckedSlice<UncheckedSlice<u8>>,
|
||||||
tables: UncheckedSlice<BoundedSlice<usize>>,
|
// tables: UncheckedSlice<BoundedSlice<usize>>,
|
||||||
|
globals: Vec<u8>,
|
||||||
|
memories: Vec<Vec<u8>>,
|
||||||
|
tables: Vec<Vec<usize>>,
|
||||||
phantom: PhantomData<&'phantom ()>,
|
phantom: PhantomData<&'phantom ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct UserData {
|
pub struct UserData {
|
||||||
// pub process: Dispatch<Process>,
|
// pub process: Dispatch<Process>,
|
||||||
@ -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<Vec<LinearMemory>> {
|
pub fn memories(&self) -> Arc<Vec<LinearMemory>> {
|
||||||
self.memories.clone()
|
self.memories.clone()
|
||||||
}
|
}
|
||||||
@ -491,46 +503,56 @@ impl Instance {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(&self) {
|
pub fn start(&mut self, vmctx: &VmCtx) {
|
||||||
if let Some(func_index) = self.start_func {
|
if let Some(func_index) = self.start_func {
|
||||||
// let vmctx: &VmCtx = ptr::null();
|
let func: fn(&VmCtx) = get_instance_function!(self, func_index);
|
||||||
let func: fn() = self.get_function(func_index);
|
func(vmctx)
|
||||||
func()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn generate_context(&mut self) -> &VmCtx {
|
pub fn generate_context(&mut self) -> &VmCtx {
|
||||||
// let memories: Vec<UncheckedSlice<u8>> = self.memories.iter()
|
let mut memories: Vec<Vec<u8>> = self.memories.iter().map(|mem| mem[..].into()).collect();
|
||||||
// .map(|mem| mem.into())
|
|
||||||
// .collect();
|
|
||||||
|
|
||||||
// let tables: Vec<BoundedSlice<usize>> = self.tables.iter()
|
let tables: Vec<Vec<usize>> = self.tables.iter().map(|table| table[..].into()).collect();
|
||||||
// .map(|table| table.write()[..].into())
|
|
||||||
// .collect();
|
|
||||||
|
|
||||||
// let globals: UncheckedSlice<u8> = self.globals[..].into();
|
let globals: Vec<u8> = self.globals[..].into();
|
||||||
|
|
||||||
// assert!(memories.len() >= 1, "modules must have at least one memory");
|
assert!(memories.len() >= 1, "modules must have at least one memory");
|
||||||
// // the first memory has a space of `mem::size_of::<VmCtxData>()` rounded
|
// the first memory has a space of `mem::size_of::<VmCtxData>()` rounded
|
||||||
// // up to the 4KiB before it. We write the VmCtxData into that.
|
// up to the 4KiB before it. We write the VmCtxData into that.
|
||||||
// let data = VmCtxData {
|
let instance = self.clone();
|
||||||
// globals: globals,
|
let data = VmCtxData {
|
||||||
// memories: memories[1..].into(),
|
globals: globals,
|
||||||
// tables: tables[..].into(),
|
memories: memories[1..].into(),
|
||||||
// user_data: UserData {
|
tables: tables[..].into(),
|
||||||
// // process,
|
user_data: UserData {
|
||||||
// instance,
|
// process,
|
||||||
// },
|
instance,
|
||||||
// phantom: PhantomData,
|
},
|
||||||
// };
|
phantom: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
// let main_heap_ptr = memories[0].as_mut_ptr() as *mut VmCtxData;
|
let main_heap_ptr = memories[0].as_mut_ptr() as *mut VmCtxData;
|
||||||
// unsafe {
|
unsafe {
|
||||||
// main_heap_ptr
|
main_heap_ptr.sub(1).write(data);
|
||||||
// .sub(1)
|
&*(main_heap_ptr as *const VmCtx)
|
||||||
// .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) {
|
// 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 {
|
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: &VmCtx) -> i32 {
|
||||||
return 0;
|
// return 0;
|
||||||
// unimplemented!();
|
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 {
|
// unsafe {
|
||||||
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
// (*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 {
|
extern "C" fn current_memory(memory_index: u32, vmctx: &VmCtx) -> u32 {
|
||||||
return 0;
|
// 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!();
|
// unimplemented!();
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use memmap::MmapMut;
|
use memmap::MmapMut;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
const PAGE_SIZE: u32 = 65536;
|
const PAGE_SIZE: u32 = 65536;
|
||||||
const MAX_PAGES: u32 = 65536;
|
const MAX_PAGES: u32 = 65536;
|
||||||
@ -34,16 +35,9 @@ impl LinearMemory {
|
|||||||
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
|
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
|
||||||
initial, maximum
|
initial, maximum
|
||||||
);
|
);
|
||||||
let initial = if initial > 0 { initial } else { 1 };
|
|
||||||
|
|
||||||
let len: u64 = PAGE_SIZE as u64 * match maximum {
|
let len: u64 = PAGE_SIZE as u64 * match maximum {
|
||||||
Some(val) => {
|
Some(val) => val as u64,
|
||||||
if val > initial {
|
|
||||||
val as u64
|
|
||||||
} else {
|
|
||||||
initial as u64
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => initial as u64,
|
None => initial as u64,
|
||||||
};
|
};
|
||||||
let len = if len == 0 { 1 } else { len };
|
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
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
/// of pages.
|
/// of pages.
|
||||||
pub fn grow(&mut self, add_pages: u32) -> Option<u32> {
|
pub fn grow(&mut self, add_pages: u32) -> Option<i32> {
|
||||||
let new_pages = match self.current.checked_add(add_pages) {
|
let new_pages = match self.current.checked_add(add_pages) {
|
||||||
Some(new_pages) => new_pages,
|
Some(new_pages) => new_pages,
|
||||||
None => return None,
|
None => return None,
|
||||||
@ -110,7 +104,7 @@ impl LinearMemory {
|
|||||||
assert!(self.mmap[i] == 0);
|
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
|
&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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ use wasmparser;
|
|||||||
|
|
||||||
pub use self::errors::{Error, ErrorKind};
|
pub use self::errors::{Error, ErrorKind};
|
||||||
pub use self::import_object::ImportObject;
|
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::memory::LinearMemory;
|
||||||
pub use self::module::{Export, Module, ModuleInfo};
|
pub use self::module::{Export, Module, ModuleInfo};
|
||||||
|
|
||||||
|
@ -577,7 +577,8 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
|||||||
// argument_bytes: None,
|
// argument_bytes: None,
|
||||||
params: vec![
|
params: vec![
|
||||||
AbiParam::new(I32),
|
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)],
|
returns: vec![AbiParam::new(I32)],
|
||||||
});
|
});
|
||||||
@ -608,7 +609,13 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
|||||||
let sig_ref = pos.func.import_signature(Signature {
|
let sig_ref = pos.func.import_signature(Signature {
|
||||||
call_conv: CallConv::SystemV,
|
call_conv: CallConv::SystemV,
|
||||||
// argument_bytes: None,
|
// 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)],
|
returns: vec![AbiParam::new(I32)],
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -621,9 +628,10 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
|||||||
|
|
||||||
// self.mod_info.current_memory_extfunc = cur_mem_func;
|
// 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 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.func.dfg.inst_results(call_inst).first().unwrap())
|
||||||
// Ok(pos.ins().iconst(I32, -1))
|
// Ok(pos.ins().iconst(I32, -1))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user