mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 06:15:33 +00:00
Added working mock for memory (grow and size)
This commit is contained in:
parent
d86e372b8e
commit
96f2440960
@ -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") {
|
||||
|
@ -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)*) => {};
|
||||
// }
|
||||
|
10
src/main.rs
10
src/main.rs
@ -71,12 +71,14 @@ 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();
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
}
|
||||
|
75
src/spec/tests/memory.wast
Normal file
75
src/spec/tests/memory.wast
Normal 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)"
|
||||
;; )
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
|
Loading…
Reference in New Issue
Block a user