mirror of
https://github.com/fluencelabs/wasmer
synced 2025-04-25 10:22:19 +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)",
|
||||
"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)",
|
||||
|
@ -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
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")]
|
||||
#[macro_export]
|
||||
macro_rules! debug {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
}};
|
||||
|
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::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 {
|
||||
|
@ -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 })
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user