diff --git a/spec/src/run.rs b/spec/src/run.rs index bb6111e..117948e 100644 --- a/spec/src/run.rs +++ b/spec/src/run.rs @@ -11,9 +11,10 @@ use test; use parity_wasm::{self, elements, builder}; use parity_wasm::interpreter::{ RuntimeValue, - ProgramInstance, ModuleInstance, + ProgramInstance, ItemIndex, ExportEntryType, Error as InterpreterError, + ModuleId, }; fn spec_test_module() -> elements::Module { @@ -41,13 +42,13 @@ fn spec_test_module() -> elements::Module { .build() } -fn load_module(base_dir: &str, path: &str, name: &Option, program: &ProgramInstance) -> Arc { +fn load_module(base_dir: &str, path: &str, name: &Option, program: &mut ProgramInstance) -> ModuleId { let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path)); - program.add_module("spectest", spec_test_module(), None).expect("Failed adding 'spectest' module"); + program.add_module("spectest", spec_test_module(), &mut ()).expect("Failed adding 'spectest' module"); let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$'); - let module_instance = program.add_module(module_name, module, None).expect(&format!("Failed adding {} module", module_name)); + let module_instance = program.add_module(module_name, module, &mut ()).expect(&format!("Failed adding {} module", module_name)); module_instance } @@ -59,8 +60,8 @@ fn try_deserialize(base_dir: &str, module_path: &str) -> Result Result<(), InterpreterError> { let module = try_deserialize(base_dir, module_path).map_err(|e| parity_wasm::interpreter::Error::Program(format!("{:?}", e)))?; - let program = ProgramInstance::new(); - program.add_module("try_load", module, None).map(|_| ()) + let mut program = ProgramInstance::new(); + program.add_module("try_load", module, &mut ()).map(|_| ()) } fn runtime_value(test_val: &test::RuntimeValue) -> parity_wasm::RuntimeValue { @@ -89,7 +90,7 @@ fn runtime_values(test_vals: &[test::RuntimeValue]) -> Vec>() } -fn run_action(program: &ProgramInstance, action: &test::Action) +fn run_action(program: &mut ProgramInstance, action: &test::Action) -> Result, InterpreterError> { match *action { @@ -97,7 +98,8 @@ fn run_action(program: &ProgramInstance, action: &test::Action) let module = module.clone().unwrap_or("wasm_test".into()); let module = module.trim_left_matches('$'); let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); - module.execute_export(&jstring_to_rstring(field), runtime_values(args).into()) + let func = module.export_by_name(program.store(), &jstring_to_rstring(field)).unwrap().as_func().unwrap(); + program.invoke_func(func, runtime_values(args), &mut ()) }, test::Action::Get { ref module, ref field, .. } => { let module = module.clone().unwrap_or("wasm_test".into()); @@ -105,12 +107,12 @@ fn run_action(program: &ProgramInstance, action: &test::Action) let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module)); let field = jstring_to_rstring(&field); - module.export_entry(field.as_ref(), &ExportEntryType::Any) - .and_then(|i| match i { - elements::Internal::Global(global_index) => Ok(ItemIndex::IndexSpace(global_index)), - _ => Err(InterpreterError::Global(format!("Expected to have exported global with name {}", field))), - }) - .and_then(|g| module.global(g, None, None).map(|g| Some(g.get()))) + let global = module + .export_by_name(program.store(), &field) + .ok_or_else(|| InterpreterError::Global(format!("Expected to have export with name {}", field)))? + .as_global() + .ok_or_else(|| InterpreterError::Global(format!("Expected export {} to be a global", field)))?; + Ok(Some(program.store().read_global(global))) } } } @@ -172,16 +174,16 @@ pub fn spec(name: &str) { .expect(&format!("Failed to load json file {}", &fixture.json)); let spec: test::Spec = serde_json::from_reader(&mut f).expect("Failed to deserialize JSON file"); - let program = ProgramInstance::new(); + let mut program = ProgramInstance::new(); let mut last_module = None; for command in &spec.commands { println!("command {:?}", command); match command { &test::Command::Module { ref name, ref filename, .. } => { - last_module = Some(load_module(&outdir, &filename, &name, &program)); + last_module = Some(load_module(&outdir, &filename, &name, &mut program)); }, &test::Command::AssertReturn { line, ref action, ref expected } => { - let result = run_action(&program, action); + let result = run_action(&mut program, action); match result { Ok(result) => { let spec_expected = runtime_values(expected); @@ -209,7 +211,7 @@ pub fn spec(name: &str) { } }, &test::Command::AssertReturnCanonicalNan { line, ref action } | &test::Command::AssertReturnArithmeticNan { line, ref action } => { - let result = run_action(&program, action); + let result = run_action(&mut program, action); match result { Ok(result) => { for actual_result in result.into_iter().collect::>() { @@ -227,14 +229,14 @@ pub fn spec(name: &str) { } }, &test::Command::AssertExhaustion { line, ref action, .. } => { - let result = run_action(&program, action); + let result = run_action(&mut program, action); match result { Ok(result) => panic!("Expected exhaustion, got result: {:?}", result), Err(e) => println!("assert_exhaustion at line {} - success ({:?})", line, e), } }, &test::Command::AssertTrap { line, ref action, .. } => { - let result = run_action(&program, action); + let result = run_action(&mut program, action); match result { Ok(result) => { panic!("Expected action to result in a trap, got result: {:?}", result); @@ -267,11 +269,11 @@ pub fn spec(name: &str) { &test::Command::Register { ref name, ref as_name, .. } => { match name { &Some(ref name) => assert_eq!(name.trim_left_matches('$'), as_name), // we have already registered this module without $ prefix - &None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")).map(|_| ()).unwrap(), + &None => program.insert_loaded_module(as_name, last_module.take().expect("Last module must be set for this command")), } }, &test::Command::Action { line, ref action } => { - match run_action(&program, action) { + match run_action(&mut program, action) { Ok(_) => { }, Err(e) => { panic!("Failed to invoke action at line {}: {:?}", line, e) diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs index 62015e7..28de549 100644 --- a/src/interpreter/mod.rs +++ b/src/interpreter/mod.rs @@ -151,3 +151,6 @@ pub use self::program::ProgramInstance; pub use self::value::RuntimeValue; pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue}; pub use self::host::{HostModule, HostModuleBuilder, Func1, AnyFunc, AsReturnVal, FromArg}; + +// TODO: All exports +pub use self::store::ModuleId; diff --git a/src/interpreter/program.rs b/src/interpreter/program.rs index 8d6de15..6f90d8d 100644 --- a/src/interpreter/program.rs +++ b/src/interpreter/program.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use elements::Module; use interpreter::Error; -use interpreter::store::{ModuleId, Store, ExternVal}; +use interpreter::store::{ModuleId, FuncId, Store, ExternVal}; use interpreter::host::HostModule; use interpreter::value::RuntimeValue; @@ -59,6 +59,10 @@ impl ProgramInstance { Ok(module_id) } + pub fn insert_loaded_module(&mut self, name: &str, module: ModuleId) { + self.modules.insert(name.to_owned(), module); + } + pub fn invoke_export( &mut self, module_name: &str, @@ -100,14 +104,22 @@ impl ProgramInstance { args: Vec, state: &mut St, ) -> Result, Error> { - let module_id = self.modules.get(module_name).ok_or_else(|| { + let module_id = self.modules.get(module_name).cloned().ok_or_else(|| { Error::Program(format!("Module {} not found", module_name)) })?; let func_id = module_id.func_by_index(&self.store, func_idx).ok_or_else(|| { Error::Program(format!("Module doesn't contain function at index {}", func_idx)) })?; + self.invoke_func(func_id, args, state) + } - self.store.invoke(func_id, args, state) + pub fn invoke_func( + &mut self, + func: FuncId, + args: Vec, + state: &mut St, + ) -> Result, Error> { + self.store.invoke(func, args, state) } pub fn store(&self) -> &Store { diff --git a/src/interpreter/store.rs b/src/interpreter/store.rs index 14b07cd..b547991 100644 --- a/src/interpreter/store.rs +++ b/src/interpreter/store.rs @@ -310,14 +310,12 @@ impl Store { ) -> Result<(), Error> { let mut aux_data = validate_module(module)?; - for type_ in module + for &Type::Function(ref ty) in module .type_section() .map(|ts| ts.types()) .unwrap_or(&[]) - .into_iter() - .map(|&Type::Function(ref ty)| ty) { - let type_id = self.alloc_func_type(type_.clone()); + let type_id = self.alloc_func_type(ty.clone()); instance.types.push(type_id); }