Use wabt 0.2.0

This commit is contained in:
Sergey Pepyakin 2018-02-13 13:31:44 +03:00
parent ead61924bb
commit 6568a3655e
2 changed files with 181 additions and 207 deletions

View File

@ -10,4 +10,4 @@ description = "parity-wasm testsuite"
[dependencies] [dependencies]
wasmi = { path = ".." } wasmi = { path = ".." }
wabt = "0.1.8" wabt = "0.2.0"

View File

@ -3,15 +3,13 @@
use std::collections::HashMap; use std::collections::HashMap;
use wasmi::{ use wasmi::{
Error as InterpreterError, Externals, FuncRef, Error as InterpreterError, Externals, FuncInstance, FuncRef, GlobalDescriptor,
GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, GlobalInstance, GlobalRef, ImportResolver, ImportsBuilder, MemoryDescriptor,
MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, MemoryInstance, MemoryRef, Module, ModuleImportResolver, ModuleInstance, ModuleRef,
ModuleRef, RuntimeValue, TableInstance, TableRef, ValueType, RuntimeArgs, RuntimeValue, Signature, TableDescriptor, TableInstance, TableRef, Trap,
Module, Signature, MemoryDescriptor, Trap, ValueType};
TableDescriptor, GlobalDescriptor, FuncInstance, RuntimeArgs,
};
use wasmi::memory_units::Pages; use wasmi::memory_units::Pages;
use wabt::spec::{Action, Visitor as ScriptVisitor, Value, run_spec}; use wabt::script::{self, Action, Command, CommandKind, ScriptParser, Value};
fn spec_to_runtime_value(value: Value) -> RuntimeValue { fn spec_to_runtime_value(value: Value) -> RuntimeValue {
match value { match value {
@ -26,6 +24,7 @@ fn spec_to_runtime_value(value: Value) -> RuntimeValue {
enum Error { enum Error {
Load(String), Load(String),
Start(Trap), Start(Trap),
Script(script::Error),
Interpreter(InterpreterError), Interpreter(InterpreterError),
} }
@ -35,6 +34,12 @@ impl From<InterpreterError> for Error {
} }
} }
impl From<script::Error> for Error {
fn from(e: script::Error) -> Error {
Error::Script(e)
}
}
struct SpecModule { struct SpecModule {
table: TableRef, table: TableRef,
memory: MemoryRef, memory: MemoryRef,
@ -92,9 +97,10 @@ impl ModuleImportResolver for SpecModule {
return Ok(func); return Ok(func);
} }
Err(InterpreterError::Instantiation( Err(InterpreterError::Instantiation(format!(
format!("Unknown host func import {}", field_name), "Unknown host func import {}",
)) field_name
)))
} }
fn resolve_global( fn resolve_global(
@ -111,9 +117,10 @@ impl ModuleImportResolver for SpecModule {
}; };
} }
Err(InterpreterError::Instantiation( Err(InterpreterError::Instantiation(format!(
format!("Unknown host global import {}", field_name), "Unknown host global import {}",
)) field_name
)))
} }
fn resolve_memory( fn resolve_memory(
@ -125,9 +132,10 @@ impl ModuleImportResolver for SpecModule {
return Ok(self.memory.clone()); return Ok(self.memory.clone());
} }
Err(InterpreterError::Instantiation( Err(InterpreterError::Instantiation(format!(
format!("Unknown host memory import {}", field_name), "Unknown host memory import {}",
)) field_name
)))
} }
fn resolve_table( fn resolve_table(
@ -139,9 +147,10 @@ impl ModuleImportResolver for SpecModule {
return Ok(self.table.clone()); return Ok(self.table.clone());
} }
Err(InterpreterError::Instantiation( Err(InterpreterError::Instantiation(format!(
format!("Unknown host table import {}", field_name), "Unknown host table import {}",
)) field_name
)))
} }
} }
@ -180,9 +189,9 @@ impl SpecDriver {
fn module_or_last(&self, name: Option<&str>) -> Result<ModuleRef, InterpreterError> { fn module_or_last(&self, name: Option<&str>) -> Result<ModuleRef, InterpreterError> {
match name { match name {
Some(name) => self.module(name), Some(name) => self.module(name),
None => self.last_module.clone().ok_or_else(|| { None => self.last_module
InterpreterError::Instantiation("No modules registered".into()) .clone()
}), .ok_or_else(|| InterpreterError::Instantiation("No modules registered".into())),
} }
} }
} }
@ -249,10 +258,7 @@ fn try_load_module(wasm: &[u8]) -> Result<Module, Error> {
Module::from_buffer(wasm).map_err(|e| Error::Load(e.to_string())) Module::from_buffer(wasm).map_err(|e| Error::Load(e.to_string()))
} }
fn try_load( fn try_load(wasm: &[u8], spec_driver: &mut SpecDriver) -> Result<(), Error> {
wasm: &[u8],
spec_driver: &mut SpecDriver,
) -> Result<(), Error> {
let module = try_load_module(wasm)?; let module = try_load_module(wasm)?;
let instance = ModuleInstance::new(&module, &ImportsBuilder::default())?; let instance = ModuleInstance::new(&module, &ImportsBuilder::default())?;
instance instance
@ -261,13 +267,8 @@ fn try_load(
Ok(()) Ok(())
} }
fn load_module( fn load_module(wasm: &[u8], name: &Option<String>, spec_driver: &mut SpecDriver) -> ModuleRef {
wasm: &[u8], let module = try_load_module(wasm).expect(&format!("Wasm failed to load"));
name: &Option<String>,
spec_driver: &mut SpecDriver,
) -> ModuleRef {
let module =
try_load_module(wasm).expect(&format!("Wasm failed to load"));
let instance = ModuleInstance::new(&module, spec_driver) let instance = ModuleInstance::new(&module, spec_driver)
.expect("Instantiation failed") .expect("Instantiation failed")
.run_start(spec_driver.spec_module()) .run_start(spec_driver.spec_module())
@ -289,13 +290,18 @@ fn run_action(
ref field, ref field,
ref args, ref args,
} => { } => {
let module = program.module_or_last(module.as_ref().map(|x| x.as_ref())).expect(&format!( let module = program
.module_or_last(module.as_ref().map(|x| x.as_ref()))
.expect(&format!(
"Expected program to have loaded module {:?}", "Expected program to have loaded module {:?}",
module module
)); ));
module.invoke_export( module.invoke_export(
field, field,
&args.iter().cloned().map(spec_to_runtime_value).collect::<Vec<_>>(), &args.iter()
.cloned()
.map(spec_to_runtime_value)
.collect::<Vec<_>>(),
program.spec_module(), program.spec_module(),
) )
} }
@ -304,7 +310,9 @@ fn run_action(
ref field, ref field,
.. ..
} => { } => {
let module = program.module_or_last(module.as_ref().map(|x| x.as_ref())).expect(&format!( let module = program
.module_or_last(module.as_ref().map(|x| x.as_ref()))
.expect(&format!(
"Expected program to have loaded module {:?}", "Expected program to have loaded module {:?}",
module module
)); ));
@ -323,58 +331,29 @@ fn run_action(
} }
} }
struct SpecRunner { pub fn spec(name: &str) {
spec_driver: SpecDriver, println!("running test: {}", name);
try_spec(name).expect("Failed to run spec");
} }
impl SpecRunner { fn try_spec(name: &str) -> Result<(), Error> {
fn assert_nans(&mut self, line: u64, action: &Action) -> Result<(), Error> { let mut spec_driver = SpecDriver::new();
let result = run_action(&mut self.spec_driver, action); let spec_script_path = format!("testsuite/{}.wast", name);
let mut parser = ScriptParser::from_file(spec_script_path).expect("Can't read spec script");
while let Some(Command { kind, line }) = parser.next()? {
match kind {
CommandKind::Module { name, module, .. } => {
load_module(&module.into_vec()?, &name, &mut spec_driver);
}
CommandKind::AssertReturn { action, expected } => {
let result = run_action(&mut spec_driver, &action);
match result { match result {
Ok(result) => { Ok(result) => {
for actual_result in result.into_iter().collect::<Vec<RuntimeValue>>() { let spec_expected = expected
match actual_result { .iter()
RuntimeValue::F32(val) => if !val.is_nan() { .cloned()
panic!("Expected nan value, got {:?}", val) .map(spec_to_runtime_value)
}, .collect::<Vec<_>>();
RuntimeValue::F64(val) => if !val.is_nan() {
panic!("Expected nan value, got {:?}", val)
},
val @ _ => {
panic!("Expected action to return float value, got {:?}", val)
}
}
}
println!("assert_return_nan at line {} - success", line);
}
Err(e) => {
panic!("Expected action to return value, got error: {:?}", e);
}
}
Ok(())
}
fn assert_incorrect_modules(&mut self, line: u64, wasm: &[u8]) -> Result<(), Error> {
let module_load = try_load(wasm, &mut self.spec_driver);
match module_load {
Ok(_) => panic!("Expected invalid module definition, got some module!"),
Err(e) => println!("assert_invalid at line {} - success ({:?})", line, e),
}
Ok(())
}
}
impl ScriptVisitor<Error> for SpecRunner {
fn module(&mut self, _line: u64, wasm: &[u8], name: Option<String>) -> Result<(), Error> {
load_module(wasm, &name, &mut self.spec_driver);
Ok(())
}
fn assert_return(&mut self, line: u64, action: &Action, expected: &[Value]) -> Result<(), Error> {
let result = run_action(&mut self.spec_driver, action);
match result {
Ok(result) => {
let spec_expected = expected.iter().cloned().map(spec_to_runtime_value).collect::<Vec<_>>();
let actual_result = result.into_iter().collect::<Vec<RuntimeValue>>(); let actual_result = result.into_iter().collect::<Vec<RuntimeValue>>();
for (actual_result, spec_expected) in for (actual_result, spec_expected) in
actual_result.iter().zip(spec_expected.iter()) actual_result.iter().zip(spec_expected.iter())
@ -399,28 +378,41 @@ impl ScriptVisitor<Error> for SpecRunner {
panic!("Expected action to return value, got error: {:?}", e); panic!("Expected action to return value, got error: {:?}", e);
} }
} }
Ok(())
} }
CommandKind::AssertReturnCanonicalNan { action }
fn assert_return_canonical_nan(&mut self, line: u64, action: &Action) -> Result<(), Error> { | CommandKind::AssertReturnArithmeticNan { action } => {
self.assert_nans(line, action) let result = run_action(&mut spec_driver, &action);
match result {
Ok(result) => {
for actual_result in result.into_iter().collect::<Vec<RuntimeValue>>() {
match actual_result {
RuntimeValue::F32(val) => if !val.is_nan() {
panic!("Expected nan value, got {:?}", val)
},
RuntimeValue::F64(val) => if !val.is_nan() {
panic!("Expected nan value, got {:?}", val)
},
val @ _ => {
panic!("Expected action to return float value, got {:?}", val)
} }
fn assert_return_arithmetic_nan(&mut self, line: u64, action: &Action) -> Result<(), Error> {
self.assert_nans(line, action)
} }
}
fn assert_exhaustion(&mut self, line: u64, action: &Action) -> Result<(), Error> { println!("assert_return_nan at line {} - success", line);
let result = run_action(&mut self.spec_driver, action); }
Err(e) => {
panic!("Expected action to return value, got error: {:?}", e);
}
}
}
CommandKind::AssertExhaustion { action, .. } => {
let result = run_action(&mut spec_driver, &action);
match result { match result {
Ok(result) => panic!("Expected exhaustion, got result: {:?}", result), Ok(result) => panic!("Expected exhaustion, got result: {:?}", result),
Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e), Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e),
} }
Ok(())
} }
CommandKind::AssertTrap { action, .. } => {
fn assert_trap(&mut self, line: u64, action: &Action, _text: &str) -> Result<(), Error> { let result = run_action(&mut spec_driver, &action);
let result = run_action(&mut self.spec_driver, action);
match result { match result {
Ok(result) => { Ok(result) => {
panic!( panic!(
@ -432,53 +424,35 @@ impl ScriptVisitor<Error> for SpecRunner {
println!("assert_trap at line {} - success ({:?})", line, e); println!("assert_trap at line {} - success ({:?})", line, e);
} }
} }
Ok(())
} }
CommandKind::AssertInvalid { module, .. }
fn assert_invalid(&mut self, line: u64, wasm: &[u8], _text: &str) -> Result<(), Error> { | CommandKind::AssertMalformed { module, .. }
self.assert_incorrect_modules(line, wasm) | CommandKind::AssertUnlinkable { module, .. } => {
let module_load = try_load(&module.into_vec()?, &mut spec_driver);
match module_load {
Ok(_) => panic!("Expected invalid module definition, got some module!"),
Err(e) => println!("assert_invalid at line {} - success ({:?})", line, e),
} }
fn assert_malformed(&mut self, line: u64, wasm: &[u8], _text: &str) -> Result<(), Error> {
self.assert_incorrect_modules(line, wasm)
} }
CommandKind::AssertUninstantiable { module, .. } => {
fn assert_unlinkable(&mut self, line: u64, wasm: &[u8], _text: &str) -> Result<(), Error> { match try_load(&module.into_vec()?, &mut spec_driver) {
self.assert_incorrect_modules(line, wasm)
}
fn assert_uninstantiable(&mut self, line: u64, wasm: &[u8], _text: &str) -> Result<(), Error> {
match try_load(wasm, &mut self.spec_driver) {
Ok(_) => panic!("Expected error running start function at line {}", line), Ok(_) => panic!("Expected error running start function at line {}", line),
Err(e) => println!("assert_uninstantiable - success ({:?})", e), Err(e) => println!("assert_uninstantiable - success ({:?})", e),
} }
Ok(())
} }
CommandKind::Register { name, as_name, .. } => {
fn register(&mut self, line: u64, name: Option<&str>, as_name: &str) -> Result<(), Error> { let module = match spec_driver.module_or_last(name.as_ref().map(|x| x.as_ref())) {
let module = match self.spec_driver.module_or_last(name.as_ref().map(|x| x.as_ref())) {
Ok(module) => module, Ok(module) => module,
Err(e) => panic!("No such module, at line {} - ({:?})", e, line), Err(e) => panic!("No such module, at line {} - ({:?})", e, line),
}; };
self.spec_driver.add_module(Some(as_name.to_owned()), module); spec_driver.add_module(Some(as_name.clone()), module);
Ok(())
} }
CommandKind::PerformAction(action) => match run_action(&mut spec_driver, &action) {
fn perform_action(&mut self, line: u64, action: &Action) -> Result<(), Error> {
match run_action(&mut self.spec_driver, action) {
Ok(_) => {} Ok(_) => {}
Err(e) => panic!("Failed to invoke action at line {}: {:?}", line, e), Err(e) => panic!("Failed to invoke action at line {}: {:?}", line, e),
},
} }
}
Ok(()) Ok(())
}
}
pub fn spec(name: &str) {
println!("running test: {}", name);
let mut spec_runner = SpecRunner {
spec_driver: SpecDriver::new(),
};
let spec_script_path = format!("testsuite/{}.wast", name);
run_spec(spec_script_path, &mut spec_runner).expect("success");
} }