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 crate::webassembly::ImportObject;
|
||||||
|
use libc::putchar;
|
||||||
|
|
||||||
pub fn generate_libc_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
pub fn generate_libc_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
||||||
let mut import_object = ImportObject::new();
|
let mut import_object = ImportObject::new();
|
||||||
@ -9,18 +9,17 @@ pub fn generate_libc_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::generate_libc_env;
|
||||||
use crate::webassembly::{
|
use crate::webassembly::{
|
||||||
instantiate, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
|
instantiate, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
|
||||||
};
|
};
|
||||||
use super::generate_libc_env;
|
|
||||||
use libc::putchar;
|
use libc::putchar;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_putchar() {
|
fn test_putchar() {
|
||||||
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
|
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
|
||||||
let import_object = generate_libc_env();
|
let import_object = generate_libc_env();
|
||||||
let result_object =
|
let result_object = instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
||||||
instantiate(wasm_bytes, import_object).expect("Not compiled properly");
|
|
||||||
let module = result_object.module;
|
let module = result_object.module;
|
||||||
let instance = result_object.instance;
|
let instance = result_object.instance;
|
||||||
let func_index = match module.info.exports.get("main") {
|
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_export]
|
||||||
macro_rules! debug {
|
macro_rules! debug {
|
||||||
($fmt:expr) => (println!(concat!("Wasmer::", $fmt)));
|
($fmt:expr) => (println!(concat!("Wasmer::", $fmt)));
|
||||||
($fmt:expr, $($arg:tt)*) => (println!(concat!("Wasmer::", $fmt, "\n"), $($arg)*));
|
($fmt:expr, $($arg:tt)*) => (println!(concat!("Wasmer::", $fmt, "\n"), $($arg)*));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature= "debug"))]
|
// #[cfg(not(feature= "debug"))]
|
||||||
#[macro_export]
|
// #[macro_export]
|
||||||
macro_rules! debug {
|
// macro_rules! debug {
|
||||||
($fmt:expr) => {};
|
// ($fmt:expr) => {};
|
||||||
($fmt:expr, $($arg:tt)*) => {};
|
// ($fmt:expr, $($arg:tt)*) => {};
|
||||||
}
|
// }
|
||||||
|
12
src/main.rs
12
src/main.rs
@ -71,13 +71,15 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let import_object = integrations::generate_libc_env();
|
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 webassembly::ResultObject { module, instance } =
|
||||||
let func_index = instance.start_func.unwrap_or_else(|| {
|
webassembly::instantiate(wasm_binary, import_object)
|
||||||
match module.info.exports.get("main") {
|
.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,
|
Some(&webassembly::Export::Function(index)) => index,
|
||||||
_ => panic!("Main function not found"),
|
_ => panic!("Main function not found"),
|
||||||
}
|
});
|
||||||
});
|
|
||||||
let main: fn() = get_instance_function!(instance, func_index);
|
let main: fn() = get_instance_function!(instance, func_index);
|
||||||
main();
|
main();
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -111,7 +111,7 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Function {:?}(index: {:?}) ({:?}) => {:?}",
|
"Function {:?}(index: {:?}) ({:?}) => returned {:?}",
|
||||||
field.to_string(),
|
field.to_string(),
|
||||||
func_index,
|
func_index,
|
||||||
call_args,
|
call_args,
|
||||||
@ -177,7 +177,8 @@ mod tests {
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
use crate::webassembly::{
|
use crate::webassembly::{
|
||||||
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject, ImportObject
|
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject,
|
||||||
|
ImportObject,
|
||||||
};
|
};
|
||||||
use wabt::wat2wasm;
|
use wabt::wat2wasm;
|
||||||
|
|
||||||
@ -209,7 +210,8 @@ mod tests {
|
|||||||
macro_rules! instantiate_from_wast {
|
macro_rules! instantiate_from_wast {
|
||||||
($x:expr) => {{
|
($x:expr) => {{
|
||||||
let wasm_bytes = include_wast2wasm_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
|
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
|
result_object
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@ -235,6 +237,7 @@ mod tests {
|
|||||||
br_if,
|
br_if,
|
||||||
call,
|
call,
|
||||||
import,
|
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) => {
|
RelocationType::Normal(func_index) => {
|
||||||
get_function_addr(&FuncIndex::new(*func_index as usize), &import_functions, &functions) as isize
|
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!()
|
_ => unimplemented!()
|
||||||
// RelocationType::Intrinsic(name) => {
|
// RelocationType::Intrinsic(name) => {
|
||||||
// get_abi_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 {
|
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
||||||
unimplemented!();
|
return 0;
|
||||||
|
// unimplemented!();
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
// (*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 {
|
extern "C" fn current_memory(memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
||||||
unimplemented!();
|
return 0;
|
||||||
|
// unimplemented!();
|
||||||
// unsafe {
|
// unsafe {
|
||||||
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
// let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
// (*instance)
|
// (*instance)
|
||||||
|
@ -34,16 +34,20 @@ impl LinearMemory {
|
|||||||
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
|
"Instantiate LinearMemory(initial={:?}, maximum={:?})",
|
||||||
initial, maximum
|
initial, maximum
|
||||||
);
|
);
|
||||||
let len = PAGE_SIZE * match maximum {
|
let initial = if initial > 0 { initial } else { 1 };
|
||||||
Some(val) => val,
|
|
||||||
None => {
|
let len: u64 = PAGE_SIZE as u64 * match maximum {
|
||||||
if initial > 0 {
|
Some(val) => {
|
||||||
initial
|
if val > initial {
|
||||||
|
val as u64
|
||||||
} else {
|
} 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();
|
let mmap = MmapMut::map_anon(len as usize).unwrap();
|
||||||
debug!("LinearMemory instantiated");
|
debug!("LinearMemory instantiated");
|
||||||
Self {
|
Self {
|
||||||
|
@ -13,6 +13,7 @@ use cranelift_codegen::ir::{
|
|||||||
FuncRef, Function, InstBuilder, Signature,
|
FuncRef, Function, InstBuilder, Signature,
|
||||||
};
|
};
|
||||||
use cranelift_codegen::print_errors::pretty_verifier_error;
|
use cranelift_codegen::print_errors::pretty_verifier_error;
|
||||||
|
use cranelift_codegen::settings::CallConv;
|
||||||
use cranelift_codegen::{isa, settings, verifier};
|
use cranelift_codegen::{isa, settings, verifier};
|
||||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
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
|
/// We use this in order to have a O(1) allocation of the exports
|
||||||
/// rather than iterating through the Exportable elements.
|
/// rather than iterating through the Exportable elements.
|
||||||
pub exports: HashMap<String, Export>,
|
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 {
|
impl ModuleInfo {
|
||||||
@ -150,8 +157,13 @@ impl ModuleInfo {
|
|||||||
main_memory_base: None,
|
main_memory_base: None,
|
||||||
memory_base: None,
|
memory_base: None,
|
||||||
exports: HashMap::new(),
|
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.
|
/// A data initializer for linear memory.
|
||||||
@ -557,20 +569,66 @@ impl<'environment> FuncEnvironmentTrait for FuncEnvironment<'environment> {
|
|||||||
fn translate_memory_grow(
|
fn translate_memory_grow(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
_index: MemoryIndex,
|
index: MemoryIndex,
|
||||||
_heap: ir::Heap,
|
heap: ir::Heap,
|
||||||
_val: ir::Value,
|
val: ir::Value,
|
||||||
) -> WasmResult<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(
|
fn translate_memory_size(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut pos: FuncCursor,
|
mut pos: FuncCursor,
|
||||||
_index: MemoryIndex,
|
index: MemoryIndex,
|
||||||
_heap: ir::Heap,
|
heap: ir::Heap,
|
||||||
) -> WasmResult<ir::Value> {
|
) -> 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 {
|
// fn return_mode(&self) -> ReturnMode {
|
||||||
@ -677,6 +735,7 @@ impl<'data> ModuleEnvironment<'data> for Module {
|
|||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
) {
|
) {
|
||||||
debug_assert!(base.is_none(), "global-value offsets not supported yet");
|
debug_assert!(base.is_none(), "global-value offsets not supported yet");
|
||||||
|
// debug!("DATA INITIALIZATION {:?} {:?}", memory_index, base);
|
||||||
self.info.data_initializers.push(DataInitializer {
|
self.info.data_initializers.push(DataInitializer {
|
||||||
memory_index,
|
memory_index,
|
||||||
base,
|
base,
|
||||||
|
@ -19,6 +19,8 @@ pub struct Relocation {
|
|||||||
pub enum RelocationType {
|
pub enum RelocationType {
|
||||||
Normal(u32),
|
Normal(u32),
|
||||||
Intrinsic(String),
|
Intrinsic(String),
|
||||||
|
GrowMemory,
|
||||||
|
CurrentMemory,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation of a relocation sink that just saves all the information for later
|
/// 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 } => {
|
ExternalName::TestCase { length, ascii } => {
|
||||||
let (slice, _) = ascii.split_at(length as usize);
|
let (slice, _) = ascii.split_at(length as usize);
|
||||||
let name = String::from_utf8(slice.to_vec()).unwrap();
|
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((
|
self.func_relocs.push((
|
||||||
Relocation {
|
Relocation {
|
||||||
reloc,
|
reloc,
|
||||||
offset,
|
offset,
|
||||||
addend,
|
addend,
|
||||||
},
|
},
|
||||||
RelocationType::Intrinsic(name),
|
relocation_type,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
Loading…
Reference in New Issue
Block a user