mirror of
https://github.com/fluencelabs/parity-wasm
synced 2025-06-23 19:52:02 +00:00
Implement SpecModule in terms of import resolver
This commit is contained in:
149
spec/src/run.rs
149
spec/src/run.rs
@ -5,47 +5,136 @@ use std::path::PathBuf;
|
|||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::any::Any;
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use test;
|
use test;
|
||||||
use parity_wasm::{self, elements, builder};
|
use parity_wasm::{self, builder};
|
||||||
|
use parity_wasm::elements::{self, ValueType, GlobalType, MemoryType, TableType, FunctionType};
|
||||||
use parity_wasm::interpreter::{
|
use parity_wasm::interpreter::{
|
||||||
RuntimeValue,
|
RuntimeValue,
|
||||||
ProgramInstance,
|
ProgramInstance,
|
||||||
ItemIndex, ExportEntryType,
|
ItemIndex, ExportEntryType,
|
||||||
Error as InterpreterError,
|
Error as InterpreterError,
|
||||||
ModuleId,
|
ImportResolver,
|
||||||
|
Imports,
|
||||||
|
FuncInstance,
|
||||||
|
GlobalInstance,
|
||||||
|
MemoryInstance,
|
||||||
|
TableInstance,
|
||||||
|
ModuleInstance,
|
||||||
|
AnyFunc,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn spec_test_module() -> elements::Module {
|
struct DefaultHostCallback;
|
||||||
builder::module()
|
|
||||||
.function().signature().build().body().build().build()
|
impl AnyFunc for DefaultHostCallback {
|
||||||
.function().signature().param().i32().build().body().build().build()
|
fn call_as_any(
|
||||||
.function().signature().param().i64().build().body().build().build()
|
&self,
|
||||||
.function().signature().param().f32().build().body().build().build()
|
_: &mut Any,
|
||||||
.function().signature().param().f64().build().body().build().build()
|
args: &[RuntimeValue],
|
||||||
.function().signature().param().i32().param().f32().build().body().build().build()
|
) -> Result<Option<RuntimeValue>, InterpreterError> {
|
||||||
.function().signature().param().f64().param().f64().build().body().build().build()
|
println!("called host: {:?}", args);
|
||||||
.global().value_type().i32().init_expr(elements::Opcode::I32Const(666)).build()
|
Ok(None)
|
||||||
.with_table(elements::TableType::new(100, None))
|
}
|
||||||
.memory().with_min(1).with_max(Some(2)).build()
|
|
||||||
.export().field("print").internal().func(0).build()
|
|
||||||
.export().field("print").internal().func(1).build()
|
|
||||||
.export().field("print").internal().func(2).build()
|
|
||||||
.export().field("print").internal().func(3).build()
|
|
||||||
.export().field("print").internal().func(4).build()
|
|
||||||
.export().field("print").internal().func(5).build()
|
|
||||||
.export().field("print").internal().func(6).build()
|
|
||||||
.export().field("global").internal().global(0).build()
|
|
||||||
.export().field("table").internal().table(0).build()
|
|
||||||
.export().field("memory").internal().memory(0).build()
|
|
||||||
.build()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &mut ProgramInstance) -> ModuleId {
|
struct SpecModule {
|
||||||
|
default_host_callback: Rc<AnyFunc>,
|
||||||
|
table: Rc<TableInstance>,
|
||||||
|
memory: Rc<MemoryInstance>,
|
||||||
|
global_i32: Rc<GlobalInstance>,
|
||||||
|
global_i64: Rc<GlobalInstance>,
|
||||||
|
global_f32: Rc<GlobalInstance>,
|
||||||
|
global_f64: Rc<GlobalInstance>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpecModule {
|
||||||
|
fn new() -> SpecModule {
|
||||||
|
SpecModule {
|
||||||
|
default_host_callback: Rc::new(DefaultHostCallback) as Rc<AnyFunc>,
|
||||||
|
table: Rc::new(TableInstance::new(&TableType::new(10, Some(20))).unwrap()),
|
||||||
|
memory: Rc::new(MemoryInstance::new(&MemoryType::new(1, Some(2))).unwrap()),
|
||||||
|
global_i32: Rc::new(GlobalInstance::new(RuntimeValue::I32(666), false)),
|
||||||
|
global_i64: Rc::new(GlobalInstance::new(RuntimeValue::I64(666), false)),
|
||||||
|
global_f32: Rc::new(GlobalInstance::new(RuntimeValue::F32(666.0), false)),
|
||||||
|
global_f64: Rc::new(GlobalInstance::new(RuntimeValue::F64(666.0), false)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ImportResolver for SpecModule {
|
||||||
|
fn resolve_func(
|
||||||
|
&self,
|
||||||
|
field_name: &str,
|
||||||
|
func_type: &FunctionType,
|
||||||
|
) -> Result<Rc<FuncInstance>, InterpreterError> {
|
||||||
|
if field_name == "print" {
|
||||||
|
let func = FuncInstance::Host {
|
||||||
|
func_type: Rc::new(func_type.clone()),
|
||||||
|
host_func: Rc::clone(&self.default_host_callback),
|
||||||
|
};
|
||||||
|
return Ok(Rc::new(func));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(InterpreterError::Global(format!("Unknown host func import {}", field_name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_global(
|
||||||
|
&self,
|
||||||
|
field_name: &str,
|
||||||
|
global_type: &GlobalType,
|
||||||
|
) -> Result<Rc<GlobalInstance>, InterpreterError> {
|
||||||
|
if field_name == "global" {
|
||||||
|
return match global_type.content_type() {
|
||||||
|
ValueType::I32 => {
|
||||||
|
Ok(Rc::clone(&self.global_i32))
|
||||||
|
}
|
||||||
|
ValueType::I64 => {
|
||||||
|
Ok(Rc::clone(&self.global_i64))
|
||||||
|
}
|
||||||
|
ValueType::F32 => {
|
||||||
|
Ok(Rc::clone(&self.global_f32))
|
||||||
|
}
|
||||||
|
ValueType::F64 => {
|
||||||
|
Ok(Rc::clone(&self.global_f64))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(InterpreterError::Global(format!("Unknown host global import {}", field_name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_memory(
|
||||||
|
&self,
|
||||||
|
field_name: &str,
|
||||||
|
memory_type: &MemoryType,
|
||||||
|
) -> Result<Rc<MemoryInstance>, InterpreterError> {
|
||||||
|
if field_name == "memory" {
|
||||||
|
return Ok(Rc::clone(&self.memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(InterpreterError::Global(format!("Unknown host memory import {}", field_name)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn resolve_table(
|
||||||
|
&self,
|
||||||
|
field_name: &str,
|
||||||
|
table_type: &TableType,
|
||||||
|
) -> Result<Rc<TableInstance>, InterpreterError> {
|
||||||
|
if field_name == "table" {
|
||||||
|
return Ok(Rc::clone(&self.table));
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(InterpreterError::Global(format!("Unknown host table import {}", field_name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_module(base_dir: &str, path: &str, name: &Option<String>, program: &mut ProgramInstance) -> Rc<ModuleInstance> {
|
||||||
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));
|
let module = try_deserialize(base_dir, path).expect(&format!("Wasm file {} failed to load", path));
|
||||||
|
|
||||||
program.add_module("spectest", spec_test_module(), &mut ()).expect("Failed adding 'spectest' module");
|
program.add_import_resolver("spectest", Box::new(SpecModule::new()) as Box<ImportResolver>);
|
||||||
|
|
||||||
let module_name = name.as_ref().map(|s| s.as_ref()).unwrap_or("wasm_test").trim_left_matches('$');
|
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, &mut ()).expect(&format!("Failed adding {} module", module_name));
|
let module_instance = program.add_module(module_name, module, &mut ()).expect(&format!("Failed adding {} module", module_name));
|
||||||
@ -98,7 +187,7 @@ fn run_action(program: &mut ProgramInstance, action: &test::Action)
|
|||||||
let module = module.clone().unwrap_or("wasm_test".into());
|
let module = module.clone().unwrap_or("wasm_test".into());
|
||||||
let module = module.trim_left_matches('$');
|
let module = module.trim_left_matches('$');
|
||||||
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
let module = program.module(&module).expect(&format!("Expected program to have loaded module {}", module));
|
||||||
let func = module.export_by_name(program.store(), &jstring_to_rstring(field)).unwrap().as_func().unwrap();
|
let func = module.export_by_name(&jstring_to_rstring(field)).unwrap().as_func().unwrap();
|
||||||
program.invoke_func(func, runtime_values(args), &mut ())
|
program.invoke_func(func, runtime_values(args), &mut ())
|
||||||
},
|
},
|
||||||
test::Action::Get { ref module, ref field, .. } => {
|
test::Action::Get { ref module, ref field, .. } => {
|
||||||
@ -108,11 +197,11 @@ fn run_action(program: &mut ProgramInstance, action: &test::Action)
|
|||||||
let field = jstring_to_rstring(&field);
|
let field = jstring_to_rstring(&field);
|
||||||
|
|
||||||
let global = module
|
let global = module
|
||||||
.export_by_name(program.store(), &field)
|
.export_by_name(&field)
|
||||||
.ok_or_else(|| InterpreterError::Global(format!("Expected to have export with name {}", field)))?
|
.ok_or_else(|| InterpreterError::Global(format!("Expected to have export with name {}", field)))?
|
||||||
.as_global()
|
.as_global()
|
||||||
.ok_or_else(|| InterpreterError::Global(format!("Expected export {} to be a global", field)))?;
|
.ok_or_else(|| InterpreterError::Global(format!("Expected export {} to be a global", field)))?;
|
||||||
Ok(Some(program.store().read_global(global)))
|
Ok(Some(global.get()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,3 +152,5 @@ pub use self::program::ProgramInstance;
|
|||||||
pub use self::value::RuntimeValue;
|
pub use self::value::RuntimeValue;
|
||||||
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
|
pub use self::variable::{VariableInstance, VariableType, ExternalVariableValue};
|
||||||
pub use self::host::{HostModule, HostModuleBuilder, Func1, AnyFunc, AsReturnVal, FromArg};
|
pub use self::host::{HostModule, HostModuleBuilder, Func1, AnyFunc, AsReturnVal, FromArg};
|
||||||
|
pub use self::imports::{ImportResolver, Imports};
|
||||||
|
pub use self::store::{FuncInstance, ModuleInstance, GlobalInstance};
|
||||||
|
@ -5,11 +5,12 @@ use interpreter::Error;
|
|||||||
use interpreter::store::{FuncInstance, ModuleInstance};
|
use interpreter::store::{FuncInstance, ModuleInstance};
|
||||||
use interpreter::host::HostModule;
|
use interpreter::host::HostModule;
|
||||||
use interpreter::value::RuntimeValue;
|
use interpreter::value::RuntimeValue;
|
||||||
use interpreter::imports::Imports;
|
use interpreter::imports::{Imports, ImportResolver};
|
||||||
|
|
||||||
/// Program instance. Program is a set of instantiated modules.
|
/// Program instance. Program is a set of instantiated modules.
|
||||||
pub struct ProgramInstance {
|
pub struct ProgramInstance {
|
||||||
modules: HashMap<String, Rc<ModuleInstance>>,
|
modules: HashMap<String, Rc<ModuleInstance>>,
|
||||||
|
resolvers: HashMap<String, Box<ImportResolver>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProgramInstance {
|
impl ProgramInstance {
|
||||||
@ -17,6 +18,7 @@ impl ProgramInstance {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ProgramInstance {
|
ProgramInstance {
|
||||||
modules: HashMap::new(),
|
modules: HashMap::new(),
|
||||||
|
resolvers: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +34,9 @@ impl ProgramInstance {
|
|||||||
for (module_name, module_instance) in self.modules.iter() {
|
for (module_name, module_instance) in self.modules.iter() {
|
||||||
imports.push_resolver(&**module_name, &**module_instance);
|
imports.push_resolver(&**module_name, &**module_instance);
|
||||||
}
|
}
|
||||||
|
for (module_name, import_resolver) in self.resolvers.iter() {
|
||||||
|
imports.push_resolver(&**module_name, &**import_resolver);
|
||||||
|
}
|
||||||
ModuleInstance::instantiate(&module, &imports, state)?
|
ModuleInstance::instantiate(&module, &imports, state)?
|
||||||
};
|
};
|
||||||
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
|
self.modules.insert(name.to_owned(), Rc::clone(&module_instance));
|
||||||
@ -39,6 +44,14 @@ impl ProgramInstance {
|
|||||||
Ok(module_instance)
|
Ok(module_instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_import_resolver(
|
||||||
|
&mut self,
|
||||||
|
name: &str,
|
||||||
|
import_resolver: Box<ImportResolver>,
|
||||||
|
) {
|
||||||
|
self.resolvers.insert(name.to_owned(), import_resolver);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_host_module(
|
pub fn add_host_module(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
|
Reference in New Issue
Block a user