mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-25 18:32:15 +00:00
Added ImportObject structure. Added integration tests
This commit is contained in:
parent
ab58faa7b7
commit
e97b47e147
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -752,6 +752,7 @@ dependencies = [
|
|||||||
"cranelift-wasm 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cranelift-wasm 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"docopt 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libffi 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -3,7 +3,7 @@ name = "wasmer"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Syrus Akbary <me@syrusakbary.com>"]
|
authors = ["Syrus Akbary <me@syrusakbary.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/wapmio/wasmer"
|
repository = "https://github.com/wafoundation/wasmer"
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@ -28,9 +28,11 @@ memmap = "0.6.2"
|
|||||||
spin = "0.4.9"
|
spin = "0.4.9"
|
||||||
log = "0.4.5"
|
log = "0.4.5"
|
||||||
target-lexicon = { version = "0.0.3", default-features = false }
|
target-lexicon = { version = "0.0.3", default-features = false }
|
||||||
|
libc = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
libffi = "0.6.4"
|
libffi = "0.6.4"
|
||||||
|
# maplit = "1.0.1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
|
27
src/integrations/mod.rs
Normal file
27
src/integrations/mod.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use libc::putchar;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::webassembly::{
|
||||||
|
instantiate, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
|
||||||
|
};
|
||||||
|
use libc::putchar;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_putchar() {
|
||||||
|
let wasm_bytes = include_wast2wasm_bytes!("tests/putchar.wast");
|
||||||
|
let mut import_object = ImportObject::new();
|
||||||
|
import_object.set("env", "putchar", putchar as *const u8);
|
||||||
|
|
||||||
|
let result_object =
|
||||||
|
instantiate(wasm_bytes, Some(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") {
|
||||||
|
Some(&Export::Function(index)) => index,
|
||||||
|
_ => panic!("Function not found"),
|
||||||
|
};
|
||||||
|
let main: fn() = get_instance_function!(instance, func_index);
|
||||||
|
main();
|
||||||
|
}
|
||||||
|
}
|
16
src/integrations/tests/putchar.wast
Normal file
16
src/integrations/tests/putchar.wast
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
(module
|
||||||
|
(type $FUNCSIG$ii (func (param i32) (result i32)))
|
||||||
|
(import "env" "putchar" (func $putchar (param i32) (result i32)))
|
||||||
|
(table 0 anyfunc)
|
||||||
|
(memory $0 1)
|
||||||
|
(export "memory" (memory $0))
|
||||||
|
(export "main" (func $main))
|
||||||
|
(func $main (; 1 ;) (result i32)
|
||||||
|
(drop
|
||||||
|
(call $putchar
|
||||||
|
(i32.const 97)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
@ -9,6 +9,14 @@ macro_rules! get_instance_function {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! include_wast2wasm_bytes {
|
||||||
|
($x:expr) => {{
|
||||||
|
use wabt::wat2wasm;
|
||||||
|
const wast_bytes: &[u8] = include_bytes!($x);
|
||||||
|
wat2wasm(wast_bytes.to_vec()).expect(&format!("Can't convert {} file to wasm", $x))
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "debug")]
|
// #[cfg(feature = "debug")]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! debug {
|
macro_rules! debug {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![feature(test)]
|
#![feature(test, libc)]
|
||||||
|
|
||||||
extern crate test;
|
extern crate test;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
@ -18,6 +18,7 @@ use std::time::{Duration, Instant};
|
|||||||
|
|
||||||
// #[macro_use] extern crate log;
|
// #[macro_use] extern crate log;
|
||||||
|
|
||||||
|
use libc;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@ -31,6 +32,7 @@ use wabt::wat2wasm;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
pub mod integrations;
|
||||||
pub mod spec;
|
pub mod spec;
|
||||||
pub mod webassembly;
|
pub mod webassembly;
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ use wabt::script::{Action, Value};
|
|||||||
|
|
||||||
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, Instance, Module, ResultObject,
|
compile, instantiate, Error, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StoreCtrl<'module> {
|
struct StoreCtrl<'module> {
|
||||||
@ -127,18 +127,15 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
||||||
let mut import_object = HashMap::new();
|
let mut import_object = ImportObject::new();
|
||||||
let mut test_import = import_object
|
extern "C" fn identity(x: i32) -> i32 {
|
||||||
.entry("test".to_string())
|
|
||||||
.or_insert_with(|| HashMap::new());
|
|
||||||
fn identity(x: i32) -> i32 {
|
|
||||||
x
|
x
|
||||||
};
|
};
|
||||||
test_import.insert("identity".to_string(), identity as *const u8);
|
import_object.set("test", "identity", identity as *const u8);
|
||||||
// let import_object = import_object!{
|
// let import_object = import_object!{
|
||||||
// test.identity => fn(x: i32) {x},
|
// test.identity => fn(x: i32) {x},
|
||||||
// }
|
// }
|
||||||
let module_wrapped = instantiate(bytes, Some(&import_object));
|
let module_wrapped = instantiate(bytes, Some(import_object));
|
||||||
let mut result = module_wrapped.expect("Module is invalid");
|
let mut result = module_wrapped.expect("Module is invalid");
|
||||||
// let module: &'module Module = result.module;
|
// let module: &'module Module = result.module;
|
||||||
self.last_module = Some(result);
|
self.last_module = Some(result);
|
||||||
@ -211,8 +208,7 @@ mod tests {
|
|||||||
|
|
||||||
macro_rules! instantiate_from_wast {
|
macro_rules! instantiate_from_wast {
|
||||||
($x:expr) => {{
|
($x:expr) => {{
|
||||||
pub const WAST_BYTES: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
|
let wasm_bytes = include_wast2wasm_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
|
||||||
let wasm_bytes = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert wat to wasm");
|
|
||||||
let result_object = instantiate(wasm_bytes, None).expect("Not compiled properly");
|
let result_object = instantiate(wasm_bytes, None).expect("Not compiled properly");
|
||||||
result_object
|
result_object
|
||||||
}};
|
}};
|
||||||
|
136
src/webassembly/import_object.rs
Normal file
136
src/webassembly/import_object.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
|
|
||||||
|
// See explanation (1).
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
struct Pair<A, B>(A, B);
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash)]
|
||||||
|
struct BorrowedPair<'a, 'b, A: 'a, B: 'b>(&'a A, &'b B);
|
||||||
|
|
||||||
|
// See explanation (2).
|
||||||
|
trait KeyPair<A, B> {
|
||||||
|
/// Obtains the first element of the pair.
|
||||||
|
fn a(&self) -> &A;
|
||||||
|
/// Obtains the second element of the pair.
|
||||||
|
fn b(&self) -> &B;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See explanation (3).
|
||||||
|
impl<'a, A, B> Borrow<KeyPair<A, B> + 'a> for Pair<A, B>
|
||||||
|
where
|
||||||
|
A: Eq + Hash + 'a,
|
||||||
|
B: Eq + Hash + 'a,
|
||||||
|
{
|
||||||
|
fn borrow(&self) -> &(KeyPair<A, B> + 'a) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See explanation (4).
|
||||||
|
impl<'a, A: Hash, B: Hash> Hash for (KeyPair<A, B> + 'a) {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.a().hash(state);
|
||||||
|
self.b().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: Eq, B: Eq> PartialEq for (KeyPair<A, B> + 'a) {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.a() == other.a() && self.b() == other.b()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, A: Eq, B: Eq> Eq for (KeyPair<A, B> + 'a) {}
|
||||||
|
|
||||||
|
// OP's ImportObject struct
|
||||||
|
pub struct ImportObject<A: Eq + Hash, B: Eq + Hash> {
|
||||||
|
map: HashMap<Pair<A, B>, *const u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Eq + Hash, B: Eq + Hash> ImportObject<A, B> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ImportObject {
|
||||||
|
map: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, a: &A, b: &B) -> Option<*const u8> {
|
||||||
|
self.map
|
||||||
|
.get(&BorrowedPair(a, b) as &KeyPair<A, B>)
|
||||||
|
.map(|p| *p)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(&mut self, a: A, b: B, v: *const u8) {
|
||||||
|
self.map.insert(Pair(a, b), v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub struct ImportObject<A: Eq + Hash, B: Eq + Hash> {
|
||||||
|
// map: HashMap<Pair<A, B>, *const u8>,
|
||||||
|
// }
|
||||||
|
|
||||||
|
// impl<A: Eq + Hash, B: Eq + Hash> ImportObject<A, B> {
|
||||||
|
// pub fn new() -> Self {
|
||||||
|
// ImportObject { map: HashMap::new() }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn get(&self, a: &A, b: &B) -> *const u8 {
|
||||||
|
// *self.map.get(&BorrowedPair(a, b) as &KeyPair<A, B>).unwrap()
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn set(&mut self, a: A, b: B, v: *const u8) {
|
||||||
|
// self.map.insert(Pair(a, b), v);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// Boring stuff below.
|
||||||
|
|
||||||
|
impl<A, B> KeyPair<A, B> for Pair<A, B>
|
||||||
|
where
|
||||||
|
A: Eq + Hash,
|
||||||
|
B: Eq + Hash,
|
||||||
|
{
|
||||||
|
fn a(&self) -> &A {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
fn b(&self) -> &B {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a, 'b, A, B> KeyPair<A, B> for BorrowedPair<'a, 'b, A, B>
|
||||||
|
where
|
||||||
|
A: Eq + Hash + 'a,
|
||||||
|
B: Eq + Hash + 'b,
|
||||||
|
{
|
||||||
|
fn a(&self) -> &A {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
fn b(&self) -> &B {
|
||||||
|
self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
// #[derive(Eq, PartialEq, Hash)]
|
||||||
|
// struct A(&'static str);
|
||||||
|
|
||||||
|
// #[derive(Eq, PartialEq, Hash)]
|
||||||
|
// struct B(&'static str);
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::ImportObject;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_import_object() {
|
||||||
|
fn x() {}
|
||||||
|
let mut import_object = ImportObject::new();
|
||||||
|
import_object.set("abc", "def", x as *const u8);
|
||||||
|
// import_object.set("123"), A("456"), 45.0);
|
||||||
|
assert_eq!(import_object.get(&"abc", &"def").unwrap(), x as *const u8);
|
||||||
|
// assert_eq!(import_object.get(&"abc", &"dxf"), 4.0);
|
||||||
|
// assert_eq!(import_object.get(&A("123"), &A("456")), 45.0);
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ use std::{mem, slice};
|
|||||||
|
|
||||||
use super::super::common::slice::{BoundedSlice, UncheckedSlice};
|
use super::super::common::slice::{BoundedSlice, UncheckedSlice};
|
||||||
use super::errors::ErrorKind;
|
use super::errors::ErrorKind;
|
||||||
|
use super::import_object::ImportObject;
|
||||||
use super::memory::LinearMemory;
|
use super::memory::LinearMemory;
|
||||||
use super::module::Module;
|
use super::module::Module;
|
||||||
use super::module::{DataInitializer, Export, Exportable};
|
use super::module::{DataInitializer, Export, Exportable};
|
||||||
@ -99,9 +100,6 @@ pub struct UserData {
|
|||||||
pub instance: Instance,
|
pub instance: Instance,
|
||||||
}
|
}
|
||||||
|
|
||||||
// The import object for the instance
|
|
||||||
pub type ImportObject = HashMap<String, HashMap<String, *const u8>>;
|
|
||||||
|
|
||||||
/// An Instance of a WebAssembly module
|
/// An Instance of a WebAssembly module
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
@ -157,7 +155,7 @@ impl Instance {
|
|||||||
/// Create a new `Instance`.
|
/// Create a new `Instance`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
module: &Module,
|
module: &Module,
|
||||||
import_object: Option<&ImportObject>,
|
import_object: &ImportObject<&str, &str>,
|
||||||
) -> Result<Instance, ErrorKind> {
|
) -> Result<Instance, ErrorKind> {
|
||||||
let mut tables: Vec<Vec<usize>> = Vec::new();
|
let mut tables: Vec<Vec<usize>> = Vec::new();
|
||||||
let mut memories: Vec<LinearMemory> = Vec::new();
|
let mut memories: Vec<LinearMemory> = Vec::new();
|
||||||
@ -178,14 +176,15 @@ impl Instance {
|
|||||||
// let mut context_and_offsets = Vec::with_capacity(module.info.function_bodies.len());
|
// let mut context_and_offsets = Vec::with_capacity(module.info.function_bodies.len());
|
||||||
for (module, field) in module.info.imported_funcs.iter() {
|
for (module, field) in module.info.imported_funcs.iter() {
|
||||||
// let function = &import_object.map(|i| i.get(module).map(|m| m.get(field)));
|
// let function = &import_object.map(|i| i.get(module).map(|m| m.get(field)));
|
||||||
let mut function = fake_fun as *const u8;
|
// let mut function = fake_fun as *const u8;
|
||||||
if let Some(import_object) = import_object {
|
let mut function = import_object
|
||||||
if let Some(module) = import_object.get(module) {
|
.get(&module.as_str(), &field.as_str())
|
||||||
if let Some(field_function) = module.get(field) {
|
.ok_or_else(|| {
|
||||||
function = *field_function;
|
ErrorKind::LinkError(format!(
|
||||||
}
|
"Imported function {}.{} was not provided in the import_functions",
|
||||||
}
|
module, field
|
||||||
}
|
))
|
||||||
|
})?;
|
||||||
// println!("GET FUNC {:?}", function);
|
// println!("GET FUNC {:?}", function);
|
||||||
import_functions.push(function);
|
import_functions.push(function);
|
||||||
relocations.push(vec![]);
|
relocations.push(vec![]);
|
||||||
@ -444,8 +443,7 @@ impl Instance {
|
|||||||
self.memories.clone()
|
self.memories.clone()
|
||||||
}
|
}
|
||||||
pub fn get_function_pointer(&self, func_index: FuncIndex) -> *const u8 {
|
pub fn get_function_pointer(&self, func_index: FuncIndex) -> *const u8 {
|
||||||
let func_pointer = &self.functions[func_index.index()];
|
get_function_addr(&func_index, &self.import_functions, &self.functions)
|
||||||
func_pointer.as_ptr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn is_imported_function(&self, func_index: FuncIndex) -> bool {
|
// pub fn is_imported_function(&self, func_index: FuncIndex) -> bool {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod import_object;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
@ -14,7 +15,8 @@ use target_lexicon::{self, Triple};
|
|||||||
use wasmparser;
|
use wasmparser;
|
||||||
|
|
||||||
pub use self::errors::{Error, ErrorKind};
|
pub use self::errors::{Error, ErrorKind};
|
||||||
pub use self::instance::{ImportObject, Instance};
|
pub use self::import_object::ImportObject;
|
||||||
|
pub use self::instance::Instance;
|
||||||
pub use self::memory::LinearMemory;
|
pub use self::memory::LinearMemory;
|
||||||
pub use self::module::{Export, Module, ModuleInfo};
|
pub use self::module::{Export, Module, ModuleInfo};
|
||||||
|
|
||||||
@ -43,11 +45,15 @@ pub struct ResultObject {
|
|||||||
/// webassembly::RuntimeError, depending on the cause of the failure.
|
/// webassembly::RuntimeError, depending on the cause of the failure.
|
||||||
pub fn instantiate(
|
pub fn instantiate(
|
||||||
buffer_source: Vec<u8>,
|
buffer_source: Vec<u8>,
|
||||||
import_object: Option<&ImportObject>,
|
import_object: Option<ImportObject<&str, &str>>,
|
||||||
) -> Result<ResultObject, ErrorKind> {
|
) -> Result<ResultObject, ErrorKind> {
|
||||||
let module = compile(buffer_source)?;
|
let module = compile(buffer_source)?;
|
||||||
debug!("webassembly - creating instance");
|
debug!("webassembly - creating instance");
|
||||||
let instance = Instance::new(&module, import_object)?;
|
let import_object: ImportObject<&str, &str> = match import_object {
|
||||||
|
Some(import_object) => import_object,
|
||||||
|
None => ImportObject::new(),
|
||||||
|
};
|
||||||
|
let instance = Instance::new(&module, &import_object)?;
|
||||||
debug!("webassembly - instance created");
|
debug!("webassembly - instance created");
|
||||||
Ok(ResultObject { module, instance })
|
Ok(ResultObject { module, instance })
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user