2018-01-17 15:32:33 +00:00
|
|
|
use parity_wasm::elements::deserialize_file;
|
|
|
|
use parity_wasm::elements::{FunctionType, GlobalType, MemoryType, Module, TableType};
|
2018-01-18 12:48:43 +00:00
|
|
|
use {Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance,
|
2018-01-17 15:32:33 +00:00
|
|
|
MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue,
|
|
|
|
TableInstance, TableRef};
|
|
|
|
use validation::validate_module;
|
|
|
|
|
|
|
|
struct Env {
|
|
|
|
table_base: GlobalRef,
|
|
|
|
memory_base: GlobalRef,
|
|
|
|
memory: MemoryRef,
|
|
|
|
table: TableRef,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Env {
|
|
|
|
fn new() -> Env {
|
|
|
|
Env {
|
|
|
|
table_base: GlobalInstance::alloc(RuntimeValue::I32(0), false),
|
|
|
|
memory_base: GlobalInstance::alloc(RuntimeValue::I32(0), false),
|
|
|
|
memory: MemoryInstance::alloc(256, None).unwrap(),
|
|
|
|
table: TableInstance::alloc(64, None).unwrap(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ModuleImportResolver for Env {
|
2018-01-18 12:48:43 +00:00
|
|
|
fn resolve_func(&self, _field_name: &str, _func_type: &Signature) -> Result<FuncRef, Error> {
|
2018-01-17 15:32:33 +00:00
|
|
|
Err(Error::Instantiation(
|
|
|
|
"env module doesn't provide any functions".into(),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_global(
|
|
|
|
&self,
|
|
|
|
field_name: &str,
|
|
|
|
_global_type: &GlobalType,
|
|
|
|
) -> Result<GlobalRef, Error> {
|
|
|
|
match field_name {
|
|
|
|
"tableBase" => Ok(self.table_base.clone()),
|
|
|
|
"memoryBase" => Ok(self.memory_base.clone()),
|
|
|
|
_ => Err(Error::Instantiation(format!(
|
|
|
|
"env module doesn't provide global '{}'",
|
|
|
|
field_name
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_memory(
|
|
|
|
&self,
|
|
|
|
field_name: &str,
|
|
|
|
_memory_type: &MemoryType,
|
|
|
|
) -> Result<MemoryRef, Error> {
|
|
|
|
match field_name {
|
|
|
|
"memory" => Ok(self.memory.clone()),
|
|
|
|
_ => Err(Error::Instantiation(format!(
|
|
|
|
"env module doesn't provide memory '{}'",
|
|
|
|
field_name
|
|
|
|
))),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_table(&self, field_name: &str, _table_type: &TableType) -> Result<TableRef, Error> {
|
|
|
|
match field_name {
|
|
|
|
"table" => Ok(self.table.clone()),
|
|
|
|
_ => Err(Error::Instantiation(
|
|
|
|
format!("env module doesn't provide table '{}'", field_name),
|
|
|
|
)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn interpreter_inc_i32() {
|
|
|
|
// Name of function contained in WASM file (note the leading underline)
|
|
|
|
const FUNCTION_NAME: &'static str = "_inc_i32";
|
|
|
|
// The WASM file containing the module and function
|
|
|
|
const WASM_FILE: &str = &"res/cases/v1/inc_i32.wasm";
|
|
|
|
|
|
|
|
let module: Module =
|
|
|
|
deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer");
|
|
|
|
let validated_module = validate_module(module).expect("Failed to validate module");
|
|
|
|
|
|
|
|
let env = Env::new();
|
|
|
|
|
|
|
|
let instance = ModuleInstance::new(
|
|
|
|
&validated_module,
|
|
|
|
&ImportsBuilder::new().with_resolver("env", &env),
|
|
|
|
).expect("Failed to instantiate module")
|
|
|
|
.assert_no_start();
|
|
|
|
|
|
|
|
let i32_val = 42;
|
|
|
|
// the functions expects a single i32 parameter
|
|
|
|
let args = &[RuntimeValue::I32(i32_val)];
|
|
|
|
let exp_retval = Some(RuntimeValue::I32(i32_val + 1));
|
|
|
|
|
|
|
|
let retval = instance
|
|
|
|
.invoke_export(FUNCTION_NAME, args, &mut NopExternals)
|
|
|
|
.expect("");
|
|
|
|
assert_eq!(exp_retval, retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn interpreter_accumulate_u8() {
|
|
|
|
// Name of function contained in WASM file (note the leading underline)
|
|
|
|
const FUNCTION_NAME: &'static str = "_accumulate_u8";
|
|
|
|
// The WASM file containing the module and function
|
|
|
|
const WASM_FILE: &str = &"res/cases/v1/accumulate_u8.wasm";
|
|
|
|
// The octet sequence being accumulated
|
|
|
|
const BUF: &[u8] = &[9,8,7,6,5,4,3,2,1];
|
|
|
|
|
|
|
|
|
|
|
|
// Load the module-structure from wasm-file and add to program
|
|
|
|
let module: Module =
|
|
|
|
deserialize_file(WASM_FILE).expect("Failed to deserialize module from buffer");
|
|
|
|
let validated_module = validate_module(module).expect("Failed to validate module");
|
|
|
|
|
|
|
|
let env = Env::new();
|
|
|
|
let instance = ModuleInstance::new(
|
|
|
|
&validated_module,
|
|
|
|
&ImportsBuilder::new().with_resolver("env", &env),
|
|
|
|
).expect("Failed to instantiate module")
|
|
|
|
.assert_no_start();
|
|
|
|
|
|
|
|
let env_memory = env.memory.clone();
|
|
|
|
|
|
|
|
// Place the octet-sequence at index 0 in linear memory
|
|
|
|
let offset: u32 = 0;
|
|
|
|
let _ = env_memory.set(offset, BUF);
|
|
|
|
|
|
|
|
// Set up the function argument list and invoke the function
|
|
|
|
let args = &[RuntimeValue::I32(BUF.len() as i32), RuntimeValue::I32(offset as i32)];
|
|
|
|
let retval = instance
|
|
|
|
.invoke_export(FUNCTION_NAME, args, &mut NopExternals)
|
|
|
|
.expect("Failed to execute function");
|
|
|
|
|
|
|
|
// For verification, repeat accumulation using native code
|
|
|
|
let accu = BUF.into_iter().fold(0 as i32, |a, b| a + *b as i32);
|
|
|
|
let exp_retval: Option<RuntimeValue> = Some(RuntimeValue::I32(accu));
|
|
|
|
|
|
|
|
// Verify calculation from WebAssembly runtime is identical to expected result
|
|
|
|
assert_eq!(exp_retval, retval);
|
|
|
|
}
|