mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-27 23:51:33 +00:00
Improved tests
This commit is contained in:
@ -56,8 +56,7 @@ fn execute_wasm(wasm_path: PathBuf) -> Result<(), String>{
|
|||||||
// if !webassembly::validate(&wasm_binary) {
|
// if !webassembly::validate(&wasm_binary) {
|
||||||
// return Err("Invalid WASM module".to_string())
|
// return Err("Invalid WASM module".to_string())
|
||||||
// };
|
// };
|
||||||
webassembly::compile(wasm_binary);
|
webassembly::instantiate(wasm_binary, None).map_err(|err| String::from(err.description()))?;
|
||||||
// println!("Data, {:?}", wasm_binary);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Shamelessly copied from greenwasm-spectest:
|
// Code adapted from greenwasm-spectest
|
||||||
// https://github.com/Kimundi/greenwasm/blob/master/greenwasm-spectest/src/lib.rs
|
// https://github.com/Kimundi/greenwasm/blob/master/greenwasm-spectest/src/lib.rs
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use wabt::script::{Value, Action};
|
use wabt::script::{Value, Action};
|
||||||
use super::{InvokationResult, ScriptHandler, run_single_file};
|
use super::{InvokationResult, ScriptHandler, run_single_file};
|
||||||
use crate::webassembly::{compile, Error, ErrorKind};
|
use crate::webassembly::{compile, instantiate, Error, ErrorKind, Module, Instance};
|
||||||
|
|
||||||
struct StoreCtrl {
|
struct StoreCtrl {
|
||||||
|
last_module: Option<Rc<Instance>>,
|
||||||
|
modules: HashMap<String, Rc<Instance>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StoreCtrl {
|
impl StoreCtrl {
|
||||||
@ -19,30 +23,35 @@ impl StoreCtrl {
|
|||||||
StoreCtrl {
|
StoreCtrl {
|
||||||
// tx,
|
// tx,
|
||||||
// _handle,
|
// _handle,
|
||||||
// modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
// last_module: None,
|
last_module: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn add_module(&mut self, name: Option<String>, module: DummyEnvironment) {
|
fn add_module(&mut self, name: Option<String>, module: Rc<Instance>) {
|
||||||
// // if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
// // println!("ADD MODULE {:?}", name);
|
// self.modules[&name] = module;
|
||||||
// // self.modules
|
self.modules.insert(name, Rc::clone(&module));
|
||||||
// // .insert(name.unwrap_or("__last_module".to_string()), module);
|
}
|
||||||
// // }
|
self.last_module = Some(Rc::clone(&module));
|
||||||
// // self.modules.insert("__last_module".to_string(), module);
|
// println!("ADD MODULE {:?}", name);
|
||||||
// // self.last_module = Some(module);
|
// self.modules
|
||||||
// }
|
// .insert(name.unwrap_or("__last_module".to_string()), module);
|
||||||
|
// }
|
||||||
|
// self.modules.insert("__last_module".to_string(), module);
|
||||||
|
// self.last_module = Some(module);
|
||||||
|
}
|
||||||
|
|
||||||
// fn get_module(&self, name: String) -> Option<&DummyEnvironment> {
|
fn get_module(self, name: Option<String>) -> Rc<Instance> {
|
||||||
// // return self
|
self.last_module.unwrap()
|
||||||
// // .modules
|
// return self
|
||||||
// // .get(&name)
|
// .modules
|
||||||
// // .or(self.modules.get("__last_module"));
|
// .get(&name)
|
||||||
// return None;
|
// .or(self.modules.get("__last_module"));
|
||||||
// // return self.modules[&name];
|
// return None;
|
||||||
// // name.map(|name| self.modules[&name]).or(self.last_module).unwrap()
|
// return self.modules[&name];
|
||||||
// }
|
// name.map(|name| self.modules[&name]).or(self.last_module).unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScriptHandler for StoreCtrl {
|
impl ScriptHandler for StoreCtrl {
|
||||||
@ -53,14 +62,33 @@ impl ScriptHandler for StoreCtrl {
|
|||||||
field: String,
|
field: String,
|
||||||
args: Vec<Value>,
|
args: Vec<Value>,
|
||||||
) -> InvokationResult {
|
) -> InvokationResult {
|
||||||
|
if let Some(module) = &self.last_module {
|
||||||
|
// let function = module.exports.get(field).expect("field not found");
|
||||||
|
println!("HEEY {:?}", module);
|
||||||
|
}
|
||||||
|
// match module {
|
||||||
|
// Some(m) => {
|
||||||
|
// println!("HEEY {:?}", m);
|
||||||
|
// },
|
||||||
|
// _ => unimplemented!()
|
||||||
|
// }
|
||||||
|
// println!("action invoke {}", module.unwrap_or("as".to_string()));
|
||||||
|
// let modul = &self.last_module;
|
||||||
|
// modul.expect("a");
|
||||||
|
//
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn action_get(&mut self, module: Option<String>, field: String) -> Value {
|
fn action_get(&mut self, module: Option<String>, field: String) -> Value {
|
||||||
|
// println!("action get");
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
fn module(&mut self, bytes: Vec<u8>, name: Option<String>) {
|
||||||
let module_wrapped = compile(bytes);
|
let module_wrapped = instantiate(bytes, None);
|
||||||
module_wrapped.expect("Module is invalid");
|
let result = module_wrapped.expect("Module is invalid");
|
||||||
|
// let module: &'module Module = result.module;
|
||||||
|
// self.last_module = Some(result.module);
|
||||||
|
self.add_module(name, Rc::new(result.instance));
|
||||||
|
// println!("ADD MODULE {}", name.unwrap_or("no name".to_string()))
|
||||||
}
|
}
|
||||||
fn assert_malformed(&mut self, bytes: Vec<u8>) {
|
fn assert_malformed(&mut self, bytes: Vec<u8>) {
|
||||||
let module_wrapped = compile(bytes);
|
let module_wrapped = compile(bytes);
|
||||||
@ -111,4 +139,5 @@ macro_rules! wasm_tests {
|
|||||||
|
|
||||||
wasm_tests!{
|
wasm_tests!{
|
||||||
_type,
|
_type,
|
||||||
|
br_if,
|
||||||
}
|
}
|
||||||
|
542
src/spec/tests/br_if.wast
Normal file
542
src/spec/tests/br_if.wast
Normal file
@ -0,0 +1,542 @@
|
|||||||
|
;; Test `br_if` operator
|
||||||
|
|
||||||
|
(module
|
||||||
|
(func $dummy)
|
||||||
|
|
||||||
|
(func (export "type-i32")
|
||||||
|
(block (drop (i32.ctz (br_if 0 (i32.const 0) (i32.const 1)))))
|
||||||
|
)
|
||||||
|
(func (export "type-i64")
|
||||||
|
(block (drop (i64.ctz (br_if 0 (i64.const 0) (i32.const 1)))))
|
||||||
|
)
|
||||||
|
(func (export "type-f32")
|
||||||
|
(block (drop (f32.neg (br_if 0 (f32.const 0) (i32.const 1)))))
|
||||||
|
)
|
||||||
|
(func (export "type-f64")
|
||||||
|
(block (drop (f64.neg (br_if 0 (f64.const 0) (i32.const 1)))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "type-i32-value") (result i32)
|
||||||
|
(block (result i32) (i32.ctz (br_if 0 (i32.const 1) (i32.const 1))))
|
||||||
|
)
|
||||||
|
(func (export "type-i64-value") (result i64)
|
||||||
|
(block (result i64) (i64.ctz (br_if 0 (i64.const 2) (i32.const 1))))
|
||||||
|
)
|
||||||
|
(func (export "type-f32-value") (result f32)
|
||||||
|
(block (result f32) (f32.neg (br_if 0 (f32.const 3) (i32.const 1))))
|
||||||
|
)
|
||||||
|
(func (export "type-f64-value") (result f64)
|
||||||
|
(block (result f64) (f64.neg (br_if 0 (f64.const 4) (i32.const 1))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-block-first") (param i32) (result i32)
|
||||||
|
(block (br_if 0 (get_local 0)) (return (i32.const 2))) (i32.const 3)
|
||||||
|
)
|
||||||
|
(func (export "as-block-mid") (param i32) (result i32)
|
||||||
|
(block (call $dummy) (br_if 0 (get_local 0)) (return (i32.const 2)))
|
||||||
|
(i32.const 3)
|
||||||
|
)
|
||||||
|
(func (export "as-block-last") (param i32)
|
||||||
|
(block (call $dummy) (call $dummy) (br_if 0 (get_local 0)))
|
||||||
|
)
|
||||||
|
(func (export "as-block-first-value") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 0 (i32.const 10) (get_local 0))) (return (i32.const 11))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-block-mid-value") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call $dummy)
|
||||||
|
(drop (br_if 0 (i32.const 20) (get_local 0)))
|
||||||
|
(return (i32.const 21))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-block-last-value") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call $dummy) (call $dummy) (br_if 0 (i32.const 11) (get_local 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-loop-first") (param i32) (result i32)
|
||||||
|
(block (loop (br_if 1 (get_local 0)) (return (i32.const 2)))) (i32.const 3)
|
||||||
|
)
|
||||||
|
(func (export "as-loop-mid") (param i32) (result i32)
|
||||||
|
(block (loop (call $dummy) (br_if 1 (get_local 0)) (return (i32.const 2))))
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
(func (export "as-loop-last") (param i32)
|
||||||
|
(loop (call $dummy) (br_if 1 (get_local 0)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-br-value") (result i32)
|
||||||
|
(block (result i32) (br 0 (br_if 0 (i32.const 1) (i32.const 2))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-br_if-cond")
|
||||||
|
(block (br_if 0 (br_if 0 (i32.const 1) (i32.const 1))))
|
||||||
|
)
|
||||||
|
(func (export "as-br_if-value") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 0 (br_if 0 (i32.const 1) (i32.const 2)) (i32.const 3)))
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-br_if-value-cond") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 0 (i32.const 2) (br_if 0 (i32.const 1) (get_local 0))))
|
||||||
|
(i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-br_table-index")
|
||||||
|
(block (br_table 0 0 0 (br_if 0 (i32.const 1) (i32.const 2))))
|
||||||
|
)
|
||||||
|
(func (export "as-br_table-value") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(br_table 0 0 0 (br_if 0 (i32.const 1) (i32.const 2)) (i32.const 3)) (i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-br_table-value-index") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(br_table 0 0 (i32.const 2) (br_if 0 (i32.const 1) (i32.const 3))) (i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-return-value") (result i64)
|
||||||
|
(block (result i64) (return (br_if 0 (i64.const 1) (i32.const 2))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-if-cond") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(if (result i32)
|
||||||
|
(br_if 0 (i32.const 1) (get_local 0))
|
||||||
|
(then (i32.const 2))
|
||||||
|
(else (i32.const 3))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-if-then") (param i32 i32)
|
||||||
|
(block
|
||||||
|
(if (get_local 0) (then (br_if 1 (get_local 1))) (else (call $dummy)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-if-else") (param i32 i32)
|
||||||
|
(block
|
||||||
|
(if (get_local 0) (then (call $dummy)) (else (br_if 1 (get_local 1))))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-select-first") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(select (br_if 0 (i32.const 3) (i32.const 10)) (i32.const 2) (get_local 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-select-second") (param i32) (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(select (i32.const 1) (br_if 0 (i32.const 3) (i32.const 10)) (get_local 0))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-select-cond") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(select (i32.const 1) (i32.const 2) (br_if 0 (i32.const 3) (i32.const 10)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $f (param i32 i32 i32) (result i32) (i32.const -1))
|
||||||
|
(func (export "as-call-first") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call $f
|
||||||
|
(br_if 0 (i32.const 12) (i32.const 1)) (i32.const 2) (i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-call-mid") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call $f
|
||||||
|
(i32.const 1) (br_if 0 (i32.const 13) (i32.const 1)) (i32.const 3)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-call-last") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call $f
|
||||||
|
(i32.const 1) (i32.const 2) (br_if 0 (i32.const 14) (i32.const 1))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func $func (param i32 i32 i32) (result i32) (get_local 0))
|
||||||
|
(type $check (func (param i32 i32 i32) (result i32)))
|
||||||
|
(table anyfunc (elem $func))
|
||||||
|
(func (export "as-call_indirect-func") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call_indirect (type $check)
|
||||||
|
(br_if 0 (i32.const 4) (i32.const 10))
|
||||||
|
(i32.const 1) (i32.const 2) (i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-call_indirect-first") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call_indirect (type $check)
|
||||||
|
(i32.const 1) (br_if 0 (i32.const 4) (i32.const 10)) (i32.const 2) (i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-call_indirect-mid") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call_indirect (type $check)
|
||||||
|
(i32.const 1) (i32.const 2) (br_if 0 (i32.const 4) (i32.const 10)) (i32.const 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "as-call_indirect-last") (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(call_indirect (type $check)
|
||||||
|
(i32.const 1) (i32.const 2) (i32.const 3) (br_if 0 (i32.const 4) (i32.const 10))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-set_local-value") (param i32) (result i32)
|
||||||
|
(local i32)
|
||||||
|
(block (result i32)
|
||||||
|
(set_local 0 (br_if 0 (i32.const 17) (get_local 0)))
|
||||||
|
(i32.const -1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "as-unary-operand") (result f64)
|
||||||
|
(block (result f64) (f64.neg (br_if 0 (f64.const 1.0) (i32.const 1))))
|
||||||
|
)
|
||||||
|
(func (export "as-binary-left") (result i32)
|
||||||
|
(block (result i32) (i32.add (br_if 0 (i32.const 1) (i32.const 1)) (i32.const 10)))
|
||||||
|
)
|
||||||
|
(func (export "as-binary-right") (result i32)
|
||||||
|
(block (result i32) (i32.sub (i32.const 10) (br_if 0 (i32.const 1) (i32.const 1))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(memory 0)
|
||||||
|
(func (export "as-memory.grow-size") (result i32)
|
||||||
|
(block (result i32) (memory.grow (br_if 0 (i32.const 1) (i32.const 1))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-block-value") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(i32.add
|
||||||
|
(i32.const 4)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0)))
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-br-value") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(br 0
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0))) (i32.const 4)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-br_if-value") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(drop (br_if 0
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0))) (i32.const 4)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
))
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-br_if-value-cond") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(drop (br_if 0
|
||||||
|
(i32.const 4)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0))) (i32.const 1)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-br_table-value") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(br_table 0
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0))) (i32.const 4)
|
||||||
|
)
|
||||||
|
(i32.const 1)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "nested-br_table-value-index") (param i32) (result i32)
|
||||||
|
(i32.add
|
||||||
|
(i32.const 1)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (i32.const 2))
|
||||||
|
(br_table 0
|
||||||
|
(i32.const 4)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 1 (i32.const 8) (get_local 0))) (i32.const 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(i32.const 16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_return (invoke "type-i32"))
|
||||||
|
(assert_return (invoke "type-i64"))
|
||||||
|
(assert_return (invoke "type-f32"))
|
||||||
|
(assert_return (invoke "type-f64"))
|
||||||
|
|
||||||
|
(assert_return (invoke "type-i32-value") (i32.const 1))
|
||||||
|
(assert_return (invoke "type-i64-value") (i64.const 2))
|
||||||
|
(assert_return (invoke "type-f32-value") (f32.const 3))
|
||||||
|
(assert_return (invoke "type-f64-value") (f64.const 4))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-block-first" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-block-first" (i32.const 1)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-block-mid" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-block-mid" (i32.const 1)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-block-last" (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-block-last" (i32.const 1)))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-block-first-value" (i32.const 0)) (i32.const 11))
|
||||||
|
(assert_return (invoke "as-block-first-value" (i32.const 1)) (i32.const 10))
|
||||||
|
(assert_return (invoke "as-block-mid-value" (i32.const 0)) (i32.const 21))
|
||||||
|
(assert_return (invoke "as-block-mid-value" (i32.const 1)) (i32.const 20))
|
||||||
|
(assert_return (invoke "as-block-last-value" (i32.const 0)) (i32.const 11))
|
||||||
|
(assert_return (invoke "as-block-last-value" (i32.const 1)) (i32.const 11))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-loop-first" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-loop-first" (i32.const 1)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-loop-mid" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-loop-mid" (i32.const 1)) (i32.const 4))
|
||||||
|
(assert_return (invoke "as-loop-last" (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-loop-last" (i32.const 1)))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-br-value") (i32.const 1))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-br_if-cond"))
|
||||||
|
(assert_return (invoke "as-br_if-value") (i32.const 1))
|
||||||
|
(assert_return (invoke "as-br_if-value-cond" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-br_if-value-cond" (i32.const 1)) (i32.const 1))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-br_table-index"))
|
||||||
|
(assert_return (invoke "as-br_table-value") (i32.const 1))
|
||||||
|
(assert_return (invoke "as-br_table-value-index") (i32.const 1))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-return-value") (i64.const 1))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-if-cond" (i32.const 0)) (i32.const 2))
|
||||||
|
(assert_return (invoke "as-if-cond" (i32.const 1)) (i32.const 1))
|
||||||
|
(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-if-then" (i32.const 0) (i32.const 1)))
|
||||||
|
(assert_return (invoke "as-if-then" (i32.const 4) (i32.const 1)))
|
||||||
|
(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 0)))
|
||||||
|
(assert_return (invoke "as-if-else" (i32.const 0) (i32.const 1)))
|
||||||
|
(assert_return (invoke "as-if-else" (i32.const 3) (i32.const 1)))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-select-first" (i32.const 0)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-select-first" (i32.const 1)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-select-second" (i32.const 0)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-select-second" (i32.const 1)) (i32.const 3))
|
||||||
|
(assert_return (invoke "as-select-cond") (i32.const 3))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-call-first") (i32.const 12))
|
||||||
|
(assert_return (invoke "as-call-mid") (i32.const 13))
|
||||||
|
(assert_return (invoke "as-call-last") (i32.const 14))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-call_indirect-func") (i32.const 4))
|
||||||
|
(assert_return (invoke "as-call_indirect-first") (i32.const 4))
|
||||||
|
(assert_return (invoke "as-call_indirect-mid") (i32.const 4))
|
||||||
|
(assert_return (invoke "as-call_indirect-last") (i32.const 4))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-set_local-value" (i32.const 0)) (i32.const -1))
|
||||||
|
(assert_return (invoke "as-set_local-value" (i32.const 1)) (i32.const 17))
|
||||||
|
|
||||||
|
(assert_return (invoke "as-unary-operand") (f64.const 1.0))
|
||||||
|
(assert_return (invoke "as-binary-left") (i32.const 1))
|
||||||
|
(assert_return (invoke "as-binary-right") (i32.const 1))
|
||||||
|
(assert_return (invoke "as-memory.grow-size") (i32.const 1))
|
||||||
|
|
||||||
|
(assert_return (invoke "nested-block-value" (i32.const 0)) (i32.const 21))
|
||||||
|
(assert_return (invoke "nested-block-value" (i32.const 1)) (i32.const 9))
|
||||||
|
(assert_return (invoke "nested-br-value" (i32.const 0)) (i32.const 5))
|
||||||
|
(assert_return (invoke "nested-br-value" (i32.const 1)) (i32.const 9))
|
||||||
|
(assert_return (invoke "nested-br_if-value" (i32.const 0)) (i32.const 5))
|
||||||
|
(assert_return (invoke "nested-br_if-value" (i32.const 1)) (i32.const 9))
|
||||||
|
(assert_return (invoke "nested-br_if-value-cond" (i32.const 0)) (i32.const 5))
|
||||||
|
(assert_return (invoke "nested-br_if-value-cond" (i32.const 1)) (i32.const 9))
|
||||||
|
(assert_return (invoke "nested-br_table-value" (i32.const 0)) (i32.const 5))
|
||||||
|
(assert_return (invoke "nested-br_table-value" (i32.const 1)) (i32.const 9))
|
||||||
|
(assert_return (invoke "nested-br_table-value-index" (i32.const 0)) (i32.const 5))
|
||||||
|
(assert_return (invoke "nested-br_table-value-index" (i32.const 1)) (i32.const 9))
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-i32 (block (i32.ctz (br_if 0 (i32.const 0))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-i64 (block (i64.ctz (br_if 0 (i32.const 0))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-f32 (block (f32.neg (br_if 0 (i32.const 0))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-f64 (block (f64.neg (br_if 0 (i32.const 0))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-i32 (block (i32.ctz (br_if 0 (i32.const 1))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-i64 (block (i64.ctz (br_if 0 (i64.const 1))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-f32 (block (f32.neg (br_if 0 (f32.const 1))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-f64 (block (f64.neg (br_if 0 (i64.const 1))))))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-arg-void-vs-num (result i32)
|
||||||
|
(block (result i32) (br_if 0 (i32.const 0)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-arg-void-vs-num (result i32)
|
||||||
|
(block (result i32) (br_if 0 (i32.const 1)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-arg-num-vs-void
|
||||||
|
(block (br_if 0 (i32.const 0) (i32.const 0)))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-arg-num-vs-void
|
||||||
|
(block (br_if 0 (i32.const 0) (i32.const 1)))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-arg-void-vs-num (result i32)
|
||||||
|
(block (result i32) (br_if 0 (nop) (i32.const 0)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-arg-void-vs-num (result i32)
|
||||||
|
(block (result i32) (br_if 0 (nop) (i32.const 1)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-false-arg-num-vs-num (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-true-arg-num-vs-num (result i32)
|
||||||
|
(block (result i32)
|
||||||
|
(drop (br_if 0 (i64.const 1) (i32.const 0))) (i32.const 1)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-cond-void-vs-i32
|
||||||
|
(block (br_if 0 (nop)))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-cond-num-vs-i32
|
||||||
|
(block (br_if 0 (i64.const 0)))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-arg-cond-void-vs-i32 (result i32)
|
||||||
|
(block (result i32) (br_if 0 (i32.const 0) (nop)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-arg-void-vs-num-nested (result i32)
|
||||||
|
(block (result i32) (i32.const 0) (block (br_if 1 (i32.const 1))))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $type-arg-cond-num-vs-i32 (result i32)
|
||||||
|
(block (result i32) (br_if 0 (i32.const 0) (i64.const 0)) (i32.const 1))
|
||||||
|
))
|
||||||
|
"type mismatch"
|
||||||
|
)
|
||||||
|
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $unbound-label (br_if 1 (i32.const 1))))
|
||||||
|
"unknown label"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $unbound-nested-label (block (block (br_if 5 (i32.const 1))))))
|
||||||
|
"unknown label"
|
||||||
|
)
|
||||||
|
(assert_invalid
|
||||||
|
(module (func $large-label (br_if 0x10000001 (i32.const 1))))
|
||||||
|
"unknown label"
|
||||||
|
)
|
224
src/webassembly/execute.rs
Normal file
224
src/webassembly/execute.rs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
use cranelift_codegen::binemit::Reloc;
|
||||||
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
|
use cranelift_entity::PrimaryMap;
|
||||||
|
use cranelift_wasm::{DefinedFuncIndex, MemoryIndex};
|
||||||
|
use region::protect;
|
||||||
|
use region::Protection;
|
||||||
|
use std::mem::transmute;
|
||||||
|
use std::ptr::{self, write_unaligned};
|
||||||
|
|
||||||
|
use super::compilation::{
|
||||||
|
compile_module, Compilation, Relocation, RelocationTarget,
|
||||||
|
};
|
||||||
|
use super::memory::LinearMemory;
|
||||||
|
use super::module::{Module, Export};
|
||||||
|
use super::instance::Instance;
|
||||||
|
use super::environ::ModuleTranslation;
|
||||||
|
|
||||||
|
/// Executes a module that has been translated with the `wasmtime-environ` environment
|
||||||
|
/// implementation.
|
||||||
|
pub fn compile_and_link_module<'data, 'module>(
|
||||||
|
isa: &TargetIsa,
|
||||||
|
translation: &ModuleTranslation<'data, 'module>,
|
||||||
|
) -> Result<Compilation, String> {
|
||||||
|
let (mut compilation, relocations) = compile_module(&translation, isa)?;
|
||||||
|
|
||||||
|
// Apply relocations, now that we have virtual addresses for everything.
|
||||||
|
relocate(&mut compilation, &relocations, &translation.module);
|
||||||
|
|
||||||
|
Ok(compilation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Performs the relocations inside the function bytecode, provided the necessary metadata
|
||||||
|
fn relocate(
|
||||||
|
compilation: &mut Compilation,
|
||||||
|
relocations: &PrimaryMap<DefinedFuncIndex, Vec<Relocation>>,
|
||||||
|
module: &Module,
|
||||||
|
) {
|
||||||
|
// The relocations are relative to the relocation's address plus four bytes
|
||||||
|
// TODO: Support architectures other than x64, and other reloc kinds.
|
||||||
|
for (i, function_relocs) in relocations.iter() {
|
||||||
|
for r in function_relocs {
|
||||||
|
let target_func_address: isize = match r.reloc_target {
|
||||||
|
RelocationTarget::UserFunc(index) => {
|
||||||
|
compilation.functions[module.defined_func_index(index).expect(
|
||||||
|
"relocation to imported function not supported yet",
|
||||||
|
)].as_ptr() as isize
|
||||||
|
}
|
||||||
|
RelocationTarget::GrowMemory => grow_memory as isize,
|
||||||
|
RelocationTarget::CurrentMemory => current_memory as isize,
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = &mut compilation.functions[i];
|
||||||
|
match r.reloc {
|
||||||
|
Reloc::Abs8 => unsafe {
|
||||||
|
let reloc_address = body.as_mut_ptr().offset(r.offset as isize) as i64;
|
||||||
|
let reloc_addend = r.addend;
|
||||||
|
let reloc_abs = target_func_address as i64 + reloc_addend;
|
||||||
|
write_unaligned(reloc_address as *mut i64, reloc_abs);
|
||||||
|
},
|
||||||
|
Reloc::X86PCRel4 => unsafe {
|
||||||
|
let reloc_address = body.as_mut_ptr().offset(r.offset as isize) as isize;
|
||||||
|
let reloc_addend = r.addend as isize;
|
||||||
|
// TODO: Handle overflow.
|
||||||
|
let reloc_delta_i32 =
|
||||||
|
(target_func_address - reloc_address + reloc_addend) as i32;
|
||||||
|
write_unaligned(reloc_address as *mut i32, reloc_delta_i32);
|
||||||
|
},
|
||||||
|
_ => panic!("unsupported reloc kind"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn grow_memory(size: u32, memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
||||||
|
unsafe {
|
||||||
|
let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
|
(*instance)
|
||||||
|
.memory_mut(memory_index as MemoryIndex)
|
||||||
|
.grow(size)
|
||||||
|
.unwrap_or(u32::max_value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn current_memory(memory_index: u32, vmctx: *mut *mut u8) -> u32 {
|
||||||
|
unsafe {
|
||||||
|
let instance = (*vmctx.offset(4)) as *mut Instance;
|
||||||
|
(*instance)
|
||||||
|
.memory_mut(memory_index as MemoryIndex)
|
||||||
|
.current_size()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the VmCtx data structure for the JIT'd code to use. This must
|
||||||
|
/// match the VmCtx layout in the environment.
|
||||||
|
fn make_vmctx(instance: &mut Instance, mem_base_addrs: &mut [*mut u8]) -> Vec<*mut u8> {
|
||||||
|
debug_assert!(
|
||||||
|
instance.tables.len() <= 1,
|
||||||
|
"non-default tables is not supported"
|
||||||
|
);
|
||||||
|
|
||||||
|
let (default_table_ptr, default_table_len) = instance
|
||||||
|
.tables
|
||||||
|
.get_mut(0)
|
||||||
|
.map(|table| (table.as_mut_ptr() as *mut u8, table.len()))
|
||||||
|
.unwrap_or((ptr::null_mut(), 0));
|
||||||
|
|
||||||
|
let mut vmctx = Vec::new();
|
||||||
|
vmctx.push(instance.globals.as_mut_ptr());
|
||||||
|
vmctx.push(mem_base_addrs.as_mut_ptr() as *mut u8);
|
||||||
|
vmctx.push(default_table_ptr);
|
||||||
|
vmctx.push(default_table_len as *mut u8);
|
||||||
|
vmctx.push(instance as *mut Instance as *mut u8);
|
||||||
|
|
||||||
|
vmctx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Jumps to the code region of memory and execute the start function of the module.
|
||||||
|
pub fn execute(
|
||||||
|
module: &Module,
|
||||||
|
compilation: &Compilation,
|
||||||
|
instance: &mut Instance,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
println!("execute");
|
||||||
|
|
||||||
|
let start_index = module.start_func.or_else(|| {
|
||||||
|
match module.exports.get("main") {
|
||||||
|
Some(&Export::Function(index)) => Some(index),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}) ;
|
||||||
|
// else {
|
||||||
|
// // TODO: We really need to handle this error nicely
|
||||||
|
// return Err("need to have a start function".to_string());
|
||||||
|
// }
|
||||||
|
// let start_index = module
|
||||||
|
// .start_func
|
||||||
|
// .ok_or_else(|| String::from("No start function defined, aborting execution"))?;
|
||||||
|
|
||||||
|
// We have to relocate here
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Put all the function bodies into a page-aligned memory region, and
|
||||||
|
// then make them ReadExecute rather than ReadWriteExecute.
|
||||||
|
for code_buf in compilation.functions.values() {
|
||||||
|
match unsafe {
|
||||||
|
protect(
|
||||||
|
code_buf.as_ptr(),
|
||||||
|
code_buf.len(),
|
||||||
|
Protection::ReadWriteExecute,
|
||||||
|
)
|
||||||
|
} {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(err) => {
|
||||||
|
return Err(format!(
|
||||||
|
"failed to give executable permission to code: {}",
|
||||||
|
err
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let code_buf = start_index.map(|i| {
|
||||||
|
&compilation.functions[module
|
||||||
|
.defined_func_index(i)
|
||||||
|
.expect("imported start functions not supported yet")]
|
||||||
|
});
|
||||||
|
|
||||||
|
// Collect all memory base addresses and Vec.
|
||||||
|
let mut mem_base_addrs = instance
|
||||||
|
.memories
|
||||||
|
.iter_mut()
|
||||||
|
.map(LinearMemory::base_addr)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let vmctx = make_vmctx(instance, &mut mem_base_addrs);
|
||||||
|
|
||||||
|
code_buf.map(|code_buf_pt|{
|
||||||
|
// Rather than writing inline assembly to jump to the code region, we use the fact that
|
||||||
|
// the Rust ABI for calling a function with no arguments and no return matches the one of
|
||||||
|
// the generated code. Thanks to this, we can transmute the code region into a first-class
|
||||||
|
// Rust function and call it.
|
||||||
|
unsafe {
|
||||||
|
let start_func = transmute::<_, fn(*const *mut u8)>(code_buf_pt.as_ptr());
|
||||||
|
start_func(vmctx.as_ptr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
println!("{:?}", module.exports);
|
||||||
|
println!("execute end");
|
||||||
|
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// pub fn execute_fn(
|
||||||
|
// instance: &mut Instance,
|
||||||
|
// func_name: String
|
||||||
|
// ) -> Result<(), String> {
|
||||||
|
// println!("execute");
|
||||||
|
|
||||||
|
// let start_index = match instance.module.exports.get(&func_name) {
|
||||||
|
// Some(&Export::Function(index)) => index,
|
||||||
|
// _ => panic!("No func name")
|
||||||
|
// };
|
||||||
|
|
||||||
|
// let code_buf = &instance.compilation.functions[instance.module
|
||||||
|
// .defined_func_index(start_index)
|
||||||
|
// .expect("imported start functions not supported yet")];
|
||||||
|
|
||||||
|
|
||||||
|
// let mut mem_base_addrs = instance
|
||||||
|
// .memories
|
||||||
|
// .iter_mut()
|
||||||
|
// .map(LinearMemory::base_addr)
|
||||||
|
// .collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// let vmctx = make_vmctx(instance, &mut mem_base_addrs);
|
||||||
|
|
||||||
|
// unsafe {
|
||||||
|
// let start_func = transmute::<_, fn(*const *mut u8)>(code_buf.as_ptr());
|
||||||
|
// start_func(vmctx.as_ptr())
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Ok(())
|
||||||
|
// }
|
@ -10,6 +10,10 @@ use super::compilation::Compilation;
|
|||||||
/// An Instance of a WebAssemby module.
|
/// An Instance of a WebAssemby module.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
|
// pub module: Box<Module>,
|
||||||
|
|
||||||
|
// pub compilation: Box<Compilation>,
|
||||||
|
|
||||||
/// WebAssembly table data.
|
/// WebAssembly table data.
|
||||||
pub tables: Vec<Vec<usize>>,
|
pub tables: Vec<Vec<usize>>,
|
||||||
|
|
||||||
@ -28,12 +32,17 @@ impl Instance {
|
|||||||
data_initializers: &[DataInitializer],
|
data_initializers: &[DataInitializer],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut result = Self {
|
let mut result = Self {
|
||||||
|
// module: Box::new(module),
|
||||||
|
// compilation: Box::new(compilation),
|
||||||
tables: Vec::new(),
|
tables: Vec::new(),
|
||||||
memories: Vec::new(),
|
memories: Vec::new(),
|
||||||
globals: Vec::new(),
|
globals: Vec::new(),
|
||||||
};
|
};
|
||||||
|
// println!("Instance::instantiate tables");
|
||||||
result.instantiate_tables(module, compilation, &module.table_elements);
|
result.instantiate_tables(module, compilation, &module.table_elements);
|
||||||
|
// println!("Instance::instantiate memories");
|
||||||
result.instantiate_memories(module, data_initializers);
|
result.instantiate_memories(module, data_initializers);
|
||||||
|
// println!("Instance::instantiate globals");
|
||||||
result.instantiate_globals(module);
|
result.instantiate_globals(module);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -70,12 +79,23 @@ impl Instance {
|
|||||||
fn instantiate_memories(&mut self, module: &Module, data_initializers: &[DataInitializer]) {
|
fn instantiate_memories(&mut self, module: &Module, data_initializers: &[DataInitializer]) {
|
||||||
debug_assert!(self.memories.is_empty());
|
debug_assert!(self.memories.is_empty());
|
||||||
// Allocate the underlying memory and initialize it to all zeros.
|
// Allocate the underlying memory and initialize it to all zeros.
|
||||||
|
// println!("instantiate_memories::reserve exact");
|
||||||
self.memories.reserve_exact(module.memories.len());
|
self.memories.reserve_exact(module.memories.len());
|
||||||
|
// println!("instantiate_memories::loop");
|
||||||
for memory in &module.memories {
|
for memory in &module.memories {
|
||||||
let v = LinearMemory::new(memory.pages_count as u32, memory.maximum.map(|m| m as u32));
|
// println!("instantiate_memories::new linear memory: {}", memory.pages_count);
|
||||||
|
// We do this so at least there is one page
|
||||||
|
let pages_count = if (memory.pages_count as u32) > 0 {
|
||||||
|
memory.pages_count as u32
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
1
|
||||||
|
};
|
||||||
|
let v = LinearMemory::new(pages_count, memory.maximum.map(|m| m as u32));
|
||||||
self.memories.push(v);
|
self.memories.push(v);
|
||||||
}
|
}
|
||||||
for init in data_initializers {
|
for init in data_initializers {
|
||||||
|
// println!("instantiate_memories::initialize data");
|
||||||
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
debug_assert!(init.base.is_none(), "globalvar base not supported yet");
|
||||||
let mem_mut = self.memories[init.memory_index].as_mut();
|
let mem_mut = self.memories[init.memory_index].as_mut();
|
||||||
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
|
let to_init = &mut mem_mut[init.offset..init.offset + init.data.len()];
|
||||||
|
@ -4,6 +4,7 @@ pub mod memory;
|
|||||||
pub mod environ;
|
pub mod environ;
|
||||||
pub mod instance;
|
pub mod instance;
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
pub mod execute;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
use cranelift_native;
|
use cranelift_native;
|
||||||
@ -16,15 +17,16 @@ pub use self::environ::ModuleEnvironment;
|
|||||||
pub use self::module::Module;
|
pub use self::module::Module;
|
||||||
pub use self::instance::Instance;
|
pub use self::instance::Instance;
|
||||||
pub use self::errors::{Error, ErrorKind};
|
pub use self::errors::{Error, ErrorKind};
|
||||||
|
pub use self::execute::{compile_and_link_module,execute};
|
||||||
use wasmparser;
|
use wasmparser;
|
||||||
|
|
||||||
pub struct ResultObject {
|
pub struct ResultObject {
|
||||||
/// A WebAssembly.Module object representing the compiled WebAssembly module.
|
/// A WebAssembly.Module object representing the compiled WebAssembly module.
|
||||||
/// This Module can be instantiated again
|
/// This Module can be instantiated again
|
||||||
module: Module,
|
pub module: Module,
|
||||||
/// A WebAssembly.Instance object that contains all the Exported WebAssembly
|
/// A WebAssembly.Instance object that contains all the Exported WebAssembly
|
||||||
/// functions.
|
/// functions.
|
||||||
instance: Instance
|
pub instance: Instance
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ImportObject {
|
pub struct ImportObject {
|
||||||
@ -47,13 +49,31 @@ pub struct ImportObject {
|
|||||||
/// If the operation fails, the Result rejects with a
|
/// If the operation fails, the Result rejects with a
|
||||||
/// WebAssembly.CompileError, WebAssembly.LinkError, or
|
/// WebAssembly.CompileError, WebAssembly.LinkError, or
|
||||||
/// WebAssembly.RuntimeError, depending on the cause of the failure.
|
/// WebAssembly.RuntimeError, depending on the cause of the failure.
|
||||||
pub fn instantiate(buffer_source: Vec<u8>, import_object: ImportObject) -> Result<ResultObject, Error> {
|
pub fn instantiate(buffer_source: Vec<u8>, import_object: Option<ImportObject>) -> Result<ResultObject, Error> {
|
||||||
let module = compile(buffer_source)?;
|
let isa = construct_isa();
|
||||||
let instance = Instance {
|
println!("instantiate::init");
|
||||||
tables: Vec::new(),
|
let mut module = Module::new();
|
||||||
memories: Vec::new(),
|
let environ = ModuleEnvironment::new(&*isa, &mut module);
|
||||||
globals: Vec::new(),
|
let translation = environ.translate(&buffer_source).map_err(|e| ErrorKind::CompileError(e.to_string()))?;
|
||||||
};
|
println!("instantiate::compile and link");
|
||||||
|
let compilation = compile_and_link_module(&*isa, &translation)?;
|
||||||
|
// let (compilation, relocations) = compile_module(&translation, &*isa)?;
|
||||||
|
println!("instantiate::instantiate");
|
||||||
|
|
||||||
|
let mut instance = Instance::new(
|
||||||
|
translation.module,
|
||||||
|
&compilation,
|
||||||
|
&translation.lazy.data_initializers,
|
||||||
|
);
|
||||||
|
println!("instantiate::execute");
|
||||||
|
|
||||||
|
let x = execute(&module, &compilation, &mut instance)?;
|
||||||
|
|
||||||
|
// let instance = Instance {
|
||||||
|
// tables: Vec::new(),
|
||||||
|
// memories: Vec::new(),
|
||||||
|
// globals: Vec::new(),
|
||||||
|
// };
|
||||||
|
|
||||||
Ok(ResultObject {
|
Ok(ResultObject {
|
||||||
module,
|
module,
|
||||||
@ -79,7 +99,8 @@ pub fn compile(buffer_source: Vec<u8>) -> Result<Module, Error> {
|
|||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
let environ = ModuleEnvironment::new(&*isa, &mut module);
|
let environ = ModuleEnvironment::new(&*isa, &mut module);
|
||||||
let translation = environ.translate(&buffer_source).map_err(|e| ErrorKind::CompileError(e.to_string()))?;
|
let translation = environ.translate(&buffer_source).map_err(|e| ErrorKind::CompileError(e.to_string()))?;
|
||||||
compile_module(&translation, &*isa)?;
|
// compile_module(&translation, &*isa)?;
|
||||||
|
compile_and_link_module(&*isa, &translation)?;
|
||||||
|
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ pub enum Export {
|
|||||||
|
|
||||||
/// A translated WebAssembly module, excluding the function bodies and
|
/// A translated WebAssembly module, excluding the function bodies and
|
||||||
/// memory initializers.
|
/// memory initializers.
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
||||||
pub signatures: Vec<ir::Signature>,
|
pub signatures: Vec<ir::Signature>,
|
||||||
|
Reference in New Issue
Block a user