Added ImportObject structure. Added integration tests

This commit is contained in:
Syrus Akbary 2018-10-17 16:08:31 +02:00
parent ab58faa7b7
commit e97b47e147
10 changed files with 221 additions and 29 deletions

1
Cargo.lock generated
View File

@ -752,6 +752,7 @@ dependencies = [
"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)",
"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)",
"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)",

View File

@ -3,7 +3,7 @@ name = "wasmer"
version = "0.1.0"
authors = ["Syrus Akbary <me@syrusakbary.com>"]
edition = "2018"
repository = "https://github.com/wapmio/wasmer"
repository = "https://github.com/wafoundation/wasmer"
publish = false
[dependencies]
@ -28,9 +28,11 @@ memmap = "0.6.2"
spin = "0.4.9"
log = "0.4.5"
target-lexicon = { version = "0.0.3", default-features = false }
libc = "0.2"
[dev-dependencies]
libffi = "0.6.4"
# maplit = "1.0.1"
[features]
debug = []

27
src/integrations/mod.rs Normal file
View 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();
}
}

View 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)
)
)

View File

@ -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")]
#[macro_export]
macro_rules! debug {

View File

@ -1,4 +1,4 @@
#![feature(test)]
#![feature(test, libc)]
extern crate test;
#[macro_use]
@ -18,6 +18,7 @@ use std::time::{Duration, Instant};
// #[macro_use] extern crate log;
use libc;
use std::error::Error;
use std::fs::File;
use std::io;
@ -31,6 +32,7 @@ use wabt::wat2wasm;
#[macro_use]
mod macros;
pub mod common;
pub mod integrations;
pub mod spec;
pub mod webassembly;

View File

@ -12,7 +12,7 @@ use wabt::script::{Action, Value};
use super::{run_single_file, InvokationResult, ScriptHandler};
use crate::webassembly::{
compile, instantiate, Error, ErrorKind, Export, Instance, Module, ResultObject,
compile, instantiate, Error, ErrorKind, Export, ImportObject, Instance, Module, ResultObject,
};
struct StoreCtrl<'module> {
@ -127,18 +127,15 @@ impl<'module> ScriptHandler for StoreCtrl<'module> {
unimplemented!()
}
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
let mut import_object = HashMap::new();
let mut test_import = import_object
.entry("test".to_string())
.or_insert_with(|| HashMap::new());
fn identity(x: i32) -> i32 {
let mut import_object = ImportObject::new();
extern "C" fn identity(x: i32) -> i32 {
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!{
// 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 module: &'module Module = result.module;
self.last_module = Some(result);
@ -211,8 +208,7 @@ mod tests {
macro_rules! instantiate_from_wast {
($x:expr) => {{
pub const WAST_BYTES: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
let wasm_bytes = wat2wasm(WAST_BYTES.to_vec()).expect("Can't convert wat to wasm");
let wasm_bytes = include_wast2wasm_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), $x));
let result_object = instantiate(wasm_bytes, None).expect("Not compiled properly");
result_object
}};

View 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);
}
}

View File

@ -21,6 +21,7 @@ use std::{mem, slice};
use super::super::common::slice::{BoundedSlice, UncheckedSlice};
use super::errors::ErrorKind;
use super::import_object::ImportObject;
use super::memory::LinearMemory;
use super::module::Module;
use super::module::{DataInitializer, Export, Exportable};
@ -99,9 +100,6 @@ pub struct UserData {
pub instance: Instance,
}
// The import object for the instance
pub type ImportObject = HashMap<String, HashMap<String, *const u8>>;
/// An Instance of a WebAssembly module
#[derive(Debug)]
pub struct Instance {
@ -157,7 +155,7 @@ impl Instance {
/// Create a new `Instance`.
pub fn new(
module: &Module,
import_object: Option<&ImportObject>,
import_object: &ImportObject<&str, &str>,
) -> Result<Instance, ErrorKind> {
let mut tables: Vec<Vec<usize>> = 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());
for (module, field) in module.info.imported_funcs.iter() {
// let function = &import_object.map(|i| i.get(module).map(|m| m.get(field)));
let mut function = fake_fun as *const u8;
if let Some(import_object) = import_object {
if let Some(module) = import_object.get(module) {
if let Some(field_function) = module.get(field) {
function = *field_function;
}
}
}
// let mut function = fake_fun as *const u8;
let mut function = import_object
.get(&module.as_str(), &field.as_str())
.ok_or_else(|| {
ErrorKind::LinkError(format!(
"Imported function {}.{} was not provided in the import_functions",
module, field
))
})?;
// println!("GET FUNC {:?}", function);
import_functions.push(function);
relocations.push(vec![]);
@ -444,8 +443,7 @@ impl Instance {
self.memories.clone()
}
pub fn get_function_pointer(&self, func_index: FuncIndex) -> *const u8 {
let func_pointer = &self.functions[func_index.index()];
func_pointer.as_ptr()
get_function_addr(&func_index, &self.import_functions, &self.functions)
}
// pub fn is_imported_function(&self, func_index: FuncIndex) -> bool {

View File

@ -1,4 +1,5 @@
pub mod errors;
pub mod import_object;
pub mod instance;
pub mod memory;
pub mod module;
@ -14,7 +15,8 @@ use target_lexicon::{self, Triple};
use wasmparser;
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::module::{Export, Module, ModuleInfo};
@ -43,11 +45,15 @@ pub struct ResultObject {
/// webassembly::RuntimeError, depending on the cause of the failure.
pub fn instantiate(
buffer_source: Vec<u8>,
import_object: Option<&ImportObject>,
import_object: Option<ImportObject<&str, &str>>,
) -> Result<ResultObject, ErrorKind> {
let module = compile(buffer_source)?;
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");
Ok(ResultObject { module, instance })
}