Added working mock for memory (grow and size)

This commit is contained in:
Syrus Akbary 2018-10-18 00:09:04 +02:00
parent d86e372b8e
commit 96f2440960
9 changed files with 192 additions and 36 deletions

View File

@ -1,5 +1,5 @@
use libc::putchar;
use crate::webassembly::ImportObject;
use libc::putchar;
pub fn generate_libc_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
let mut import_object = ImportObject::new();
@ -9,18 +9,17 @@ pub fn generate_libc_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
#[cfg(test)]
mod tests {
use super::generate_libc_env;
use crate::webassembly::{
instantiate, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
};
use super::generate_libc_env;
use libc::putchar;
#[test]
fn test_putchar() {
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
let import_object = generate_libc_env();
let result_object =
instantiate(wasm_bytes, import_object).expect("Not compiled properly");
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
let module = result_object.module;
let instance = result_object.instance;
let func_index = match module.info.exports.get("main") {

View File

@ -18,16 +18,16 @@ macro_rules! include_wast2wasm_bytes {
}};
}
#[cfg(feature= "debug")]
// #[cfg(feature= "debug")]
#[macro_export]
macro_rules! debug {
($fmt:expr) => (println!(concat!("Wasmer::", $fmt)));
($fmt:expr, $($arg:tt)*) => (println!(concat!("Wasmer::", $fmt, "\n"), $($arg)*));
}
#[cfg(not(feature= "debug"))]
#[macro_export]
macro_rules! debug {
($fmt:expr) => {};
($fmt:expr, $($arg:tt)*) => {};
}
// #[cfg(not(feature= "debug"))]
// #[macro_export]
// macro_rules! debug {
// ($fmt:expr) => {};
// ($fmt:expr, $($arg:tt)*) => {};
// }

View File

@ -71,13 +71,15 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
}
let import_object = integrations::generate_libc_env();
let webassembly::ResultObject {module, instance} = webassembly::instantiate(wasm_binary, import_object).map_err(|err| String::from(err.description()))?;
let func_index = instance.start_func.unwrap_or_else(|| {
match module.info.exports.get("main") {
let webassembly::ResultObject { module, instance } =
webassembly::instantiate(wasm_binary, import_object)
.map_err(|err| String::from(err.description()))?;
let func_index = instance
.start_func
.unwrap_or_else(|| match module.info.exports.get("main") {
Some(&webassembly::Export::Function(index)) => index,
_ => panic!("Main function not found"),
}
});
});
let main: fn() = get_instance_function!(instance, func_index);
main();
Ok(())

View File

@ -111,7 +111,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
};
println!(
"Function {:?}(index: {:?}) ({:?}) => {:?}",
"Function {:?}(index: {:?}) ({:?}) => returned {:?}",
field.to_string(),
func_index,
call_args,
@ -177,7 +177,8 @@ mod tests {
use std::path::Path;
#[macro_use]
use crate::webassembly::{
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject, ImportObject
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject,
ImportObject,
};
use wabt::wat2wasm;
@ -209,7 +210,8 @@ mod tests {
macro_rules! instantiate_from_wast {
($x:expr) => {{
let wasm_bytes = include_wast2wasm_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
let result_object = instantiate(wasm_bytes, ImportObject::new()).expect("Not compiled properly");
let result_object =
instantiate(wasm_bytes, ImportObject::new()).expect("Not compiled properly");
result_object
}};
}
@ -235,6 +237,7 @@ mod tests {
br_if,
call,
import,
memory,
}
}

View File

@ -0,0 +1,75 @@
(module (memory 0 0))
(module (memory 0 1))
(module (memory 1 256))
(module (memory 0 65536))
(assert_invalid (module (memory 0) (memory 0)) "multiple memories")
(assert_invalid (module (memory (import "spectest" "memory") 0) (memory 0)) "multiple memories")
(module (memory (data)) (func (export "memsize") (result i32) (memory.size)))
(assert_return (invoke "memsize") (i32.const 0))
;; (module (memory (data "")) (func (export "memsize") (result i32) (memory.size)))
;; (assert_return (invoke "memsize") (i32.const 0))
;; (module (memory (data "x")) (func (export "memsize") (result i32) (memory.size)))
;; (assert_return (invoke "memsize") (i32.const 1))
;; (assert_invalid (module (data (i32.const 0))) "unknown memory")
;; (assert_invalid (module (data (i32.const 0) "")) "unknown memory")
;; (assert_invalid (module (data (i32.const 0) "x")) "unknown memory")
;; (assert_invalid
;; (module (func (drop (f32.load (i32.const 0)))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (func (f32.store (f32.const 0) (i32.const 0))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (func (drop (i32.load8_s (i32.const 0)))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (func (i32.store8 (i32.const 0) (i32.const 0))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (func (drop (memory.size))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (func (drop (memory.grow (i32.const 0)))))
;; "unknown memory"
;; )
;; (assert_invalid
;; (module (memory 1 0))
;; "size minimum must not be greater than maximum"
;; )
;; (assert_invalid
;; (module (memory 65537))
;; "memory size must be at most 65536 pages (4GiB)"
;; )
;; (assert_invalid
;; (module (memory 2147483648))
;; "memory size must be at most 65536 pages (4GiB)"
;; )
;; (assert_invalid
;; (module (memory 4294967295))
;; "memory size must be at most 65536 pages (4GiB)"
;; )
;; (assert_invalid
;; (module (memory 0 65537))
;; "memory size must be at most 65536 pages (4GiB)"
;; )
;; (assert_invalid
;; (module (memory 0 2147483648))
;; "memory size must be at most 65536 pages (4GiB)"
;; )
;; (assert_invalid
;; (module (memory 0 4294967295))
;; "memory size must be at most 65536 pages (4GiB)"
;; )

View File

@ -232,6 +232,12 @@ impl Instance {
RelocationType::Normal(func_index) => {
get_function_addr(&FuncIndex::new(*func_index as usize), &import_functions, &functions) as isize
},
RelocationType::CurrentMemory => {
current_memory as isize
},
RelocationType::GrowMemory => {
grow_memory as isize
},
_ => unimplemented!()
// RelocationType::Intrinsic(name) => {
// get_abi_intrinsic(name)?
@ -547,7 +553,8 @@ impl Clone for Instance {
}
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 {
unimplemented!();
return 0;
// unimplemented!();
// unsafe {
// let instance = (*vmctx.offset(4)) as *mut Instance;
// (*instance)
@ -558,7 +565,8 @@ 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 {
unimplemented!();
return 0;
// unimplemented!();
// unsafe {
// let instance = (*vmctx.offset(4)) as *mut Instance;
// (*instance)

View File

@ -34,16 +34,20 @@ impl LinearMemory {
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
initial, maximum
);
let len = PAGE_SIZE * match maximum {
Some(val) => val,
None => {
if initial > 0 {
initial
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 {
1
initial as u64
}
}
None => initial as u64,
};
let len = if len == 0 { 1 } else { len };
let mmap = MmapMut::map_anon(len as usize).unwrap();
debug!("LinearMemory instantiated");
Self {

View File

@ -13,6 +13,7 @@ use cranelift_codegen::ir::{
FuncRef, Function, InstBuilder, Signature,
};
use cranelift_codegen::print_errors::pretty_verifier_error;
use cranelift_codegen::settings::CallConv;
use cranelift_codegen::{isa, settings, verifier};
use cranelift_entity::{EntityRef, PrimaryMap};
@ -127,6 +128,12 @@ pub struct ModuleInfo {
/// We use this in order to have a O(1) allocation of the exports
/// rather than iterating through the Exportable elements.
pub exports: HashMap<String, Export>,
/// The external function declaration for implementing wasm's `current_memory`.
pub current_memory_extfunc: Option<FuncRef>,
/// The external function declaration for implementing wasm's `grow_memory`.
pub grow_memory_extfunc: Option<FuncRef>,
}
impl ModuleInfo {
@ -150,8 +157,13 @@ impl ModuleInfo {
main_memory_base: None,
memory_base: None,
exports: HashMap::new(),
current_memory_extfunc: None,
grow_memory_extfunc: None,
}
}
pub fn set_current_memory_extfunc(&mut self, func: FuncRef) {
self.current_memory_extfunc = Some(func);
}
}
/// A data initializer for linear memory.
@ -557,20 +569,66 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
fn translate_memory_grow(
&mut self,
mut pos: FuncCursor,
_index: MemoryIndex,
_heap: ir::Heap,
_val: ir::Value,
index: MemoryIndex,
heap: ir::Heap,
val: ir::Value,
) -> WasmResult<ir::Value> {
Ok(pos.ins().iconst(I32, -1))
debug_assert_eq!(index, 0, "non-default memories not supported yet");
let grow_mem_func = self.mod_info.grow_memory_extfunc.unwrap_or_else(|| {
let sig_ref = pos.func.import_signature(Signature {
call_conv: CallConv::SystemV,
// argument_bytes: None,
params: vec![
AbiParam::new(I32),
AbiParam::special(I64, ArgumentPurpose::VMContext),
],
returns: vec![AbiParam::new(I32)],
});
pos.func.import_function(ExtFuncData {
name: ExternalName::testcase("grow_memory"),
signature: sig_ref,
colocated: false,
})
});
// self.mod_info.grow_memory_extfunc = Some(grow_mem_func);
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
let call_inst = pos.ins().call(grow_mem_func, &[val, vmctx]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
}
fn translate_memory_size(
&mut self,
mut pos: FuncCursor,
_index: MemoryIndex,
_heap: ir::Heap,
index: MemoryIndex,
heap: ir::Heap,
) -> WasmResult<ir::Value> {
Ok(pos.ins().iconst(I32, -1))
debug_assert_eq!(index, 0, "non-default memories not supported yet");
let cur_mem_func = self.mod_info.current_memory_extfunc.unwrap_or_else(|| {
let sig_ref = pos.func.import_signature(Signature {
call_conv: CallConv::SystemV,
// argument_bytes: None,
params: vec![AbiParam::special(I64, ArgumentPurpose::VMContext)],
returns: vec![AbiParam::new(I32)],
});
pos.func.import_function(ExtFuncData {
name: ExternalName::testcase("current_memory"),
signature: sig_ref,
colocated: false,
})
});
// self.mod_info.set_current_memory_extfunc(f);
let vmctx = pos.func.special_param(ArgumentPurpose::VMContext).unwrap();
let call_inst = pos.ins().call(cur_mem_func, &[vmctx]);
Ok(*pos.func.dfg.inst_results(call_inst).first().unwrap())
// Ok(pos.ins().iconst(I32, -1))
}
// fn return_mode(&self) -> ReturnMode {
@ -677,6 +735,7 @@ impl<'data> ModuleEnvironment<'data> for Module {
data: &'data [u8],
) {
debug_assert!(base.is_none(), "global-value offsets not supported yet");
// debug!("DATA INITIALIZATION {:?} {:?}", memory_index, base);
self.info.data_initializers.push(DataInitializer {
memory_index,
base,

View File

@ -19,6 +19,8 @@ pub struct Relocation {
pub enum RelocationType {
Normal(u32),
Intrinsic(String),
GrowMemory,
CurrentMemory,
}
/// Implementation of a relocation sink that just saves all the information for later
@ -62,14 +64,18 @@ impl binemit::RelocSink for RelocSink {
ExternalName::TestCase { length, ascii } => {
let (slice, _) = ascii.split_at(length as usize);
let name = String::from_utf8(slice.to_vec()).unwrap();
let relocation_type = match name.as_str() {
"current_memory" => RelocationType::CurrentMemory,
"grow_memory" => RelocationType::GrowMemory,
_ => RelocationType::Intrinsic(name),
};
self.func_relocs.push((
Relocation {
reloc,
offset,
addend,
},
RelocationType::Intrinsic(name),
relocation_type,
));
}
_ => {