diff --git a/src/func.rs b/src/func.rs index f7f6339..c3549ec 100644 --- a/src/func.rs +++ b/src/func.rs @@ -3,7 +3,7 @@ use std::fmt; use std::collections::HashMap; use std::borrow::Cow; use parity_wasm::elements::{FunctionType, Local, Opcodes}; -use Error; +use {Error, Signature}; use host::Externals; use runner::{prepare_function_args, FunctionContext, Interpreter}; use value::RuntimeValue; @@ -24,12 +24,12 @@ impl ::std::ops::Deref for FuncRef { #[derive(Clone)] pub enum FuncInstance { Internal { - func_type: Rc, + signature: Rc, module: ModuleRef, body: Rc, }, Host { - func_type: FunctionType, + signature: Signature, host_func_index: usize, }, } @@ -38,19 +38,19 @@ impl fmt::Debug for FuncInstance { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &FuncInstance::Internal { - ref func_type, - ref module, + ref signature, .. } => { + // We can't write description of self.module here, because it generate + // debug string for function instances and this will lead to infinite loop. write!( f, - "Internal {{ type={:?}, module={:?} }}", - func_type, - module + "Internal {{ signature={:?} }}", + signature, ) } - &FuncInstance::Host { ref func_type, .. } => { - write!(f, "Host {{ type={:?} }}", func_type) + &FuncInstance::Host { ref signature, .. } => { + write!(f, "Host {{ signature={:?} }}", signature) } } } @@ -59,29 +59,29 @@ impl fmt::Debug for FuncInstance { impl FuncInstance { pub(crate) fn alloc_internal( module: ModuleRef, - func_type: Rc, + signature: Rc, body: FuncBody, ) -> FuncRef { let func = FuncInstance::Internal { - func_type, + signature, module: module, body: Rc::new(body), }; FuncRef(Rc::new(func)) } - pub fn alloc_host(func_type: FunctionType, host_func_index: usize) -> FuncRef { + pub fn alloc_host(signature: Signature, host_func_index: usize) -> FuncRef { let func = FuncInstance::Host { - func_type, + signature, host_func_index, }; FuncRef(Rc::new(func)) } - pub fn func_type(&self) -> &FunctionType { + pub fn signature(&self) -> &Signature { match *self { - FuncInstance::Internal { ref func_type, .. } => func_type, - FuncInstance::Host { ref func_type, .. } => func_type, + FuncInstance::Internal { ref signature, .. } => signature, + FuncInstance::Host { ref signature, .. } => signature, } } @@ -103,15 +103,15 @@ impl FuncInstance { } let result = match *func { - FuncInstance::Internal { ref func_type, .. } => { + FuncInstance::Internal { ref signature, .. } => { let mut stack = StackWithLimit::with_data(args.into_iter().cloned(), DEFAULT_VALUE_STACK_LIMIT); - let args = prepare_function_args(func_type, &mut stack)?; + let args = prepare_function_args(signature, &mut stack)?; let context = FunctionContext::new( func.clone(), DEFAULT_VALUE_STACK_LIMIT, DEFAULT_FRAME_STACK_LIMIT, - func_type, + signature, args, ); InvokeKind::Internal(context) diff --git a/src/imports.rs b/src/imports.rs index f9ed745..685e278 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -5,14 +5,14 @@ use memory::MemoryRef; use func::FuncRef; use table::TableRef; use module::ModuleRef; -use Error; +use {Error, Signature}; pub trait ImportResolver { fn resolve_func( &self, module_name: &str, field_name: &str, - func_type: &FunctionType, + func_type: &Signature, ) -> Result; fn resolve_global( @@ -75,11 +75,11 @@ impl<'a> ImportResolver for ImportsBuilder<'a> { &self, module_name: &str, field_name: &str, - func_type: &FunctionType, + signature: &Signature, ) -> Result { self.resolver(module_name).ok_or_else(|| Error::Instantiation(format!("Module {} not found", module_name)) - )?.resolve_func(field_name, func_type) + )?.resolve_func(field_name, signature) } fn resolve_global( @@ -120,7 +120,7 @@ pub trait ModuleImportResolver { fn resolve_func( &self, field_name: &str, - _func_type: &FunctionType, + _signature: &Signature, ) -> Result { Err(Error::Instantiation( format!("Export {} not found", field_name), @@ -162,7 +162,7 @@ impl ModuleImportResolver for ModuleRef { fn resolve_func( &self, field_name: &str, - _func_type: &FunctionType, + _signature: &Signature, ) -> Result { Ok(self.export_by_name(field_name) .ok_or_else(|| { diff --git a/src/lib.rs b/src/lib.rs index d38ed38..9100e08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate byteorder; use std::fmt; use std::error; +use parity_wasm::elements::{FunctionType, ValueType}; /// Internal interpreter error. #[derive(Debug)] @@ -97,6 +98,33 @@ impl From<::common::stack::Error> for Error { } } +#[derive(Debug, Clone, PartialEq)] +pub struct Signature { + func_type: FunctionType, +} + +impl Signature { + pub fn new(params: &[ValueType], return_type: Option) -> Signature { + Signature { + func_type: FunctionType::new(params.to_vec(), return_type), + } + } + + pub fn params(&self) -> &[ValueType] { + self.func_type.params() + } + + pub fn return_type(&self) -> Option { + self.func_type.return_type() + } +} + +impl From for Signature { + fn from(func_type: FunctionType) -> Signature { + Signature { func_type } + } +} + mod validation; mod common; mod memory; diff --git a/src/module.rs b/src/module.rs index ec55ebe..859cbae 100644 --- a/src/module.rs +++ b/src/module.rs @@ -4,7 +4,7 @@ use std::fmt; use std::collections::HashMap; use std::borrow::Cow; use parity_wasm::elements::{External, FunctionType, InitExpr, Internal, Opcode, ResizableLimits, Type}; -use {Error, MemoryInstance, RuntimeValue, TableInstance}; +use {Error, Signature, MemoryInstance, RuntimeValue, TableInstance}; use imports::ImportResolver; use global::{GlobalInstance, GlobalRef}; use func::{FuncRef, FuncBody, FuncInstance}; @@ -89,7 +89,7 @@ impl ExternVal { #[derive(Debug)] pub struct ModuleInstance { - types: RefCell>>, + signatures: RefCell>>, tables: RefCell>, funcs: RefCell>, memories: RefCell>, @@ -101,7 +101,7 @@ impl ModuleInstance { fn default() -> Self { ModuleInstance { funcs: RefCell::new(Vec::new()), - types: RefCell::new(Vec::new()), + signatures: RefCell::new(Vec::new()), tables: RefCell::new(Vec::new()), memories: RefCell::new(Vec::new()), globals: RefCell::new(Vec::new()), @@ -129,16 +129,16 @@ impl ModuleInstance { self.exports.borrow().get(name).cloned() } - pub(crate) fn type_by_index(&self, idx: u32) -> Option> { - self.types.borrow().get(idx as usize).cloned() + pub(crate) fn signature_by_index(&self, idx: u32) -> Option> { + self.signatures.borrow().get(idx as usize).cloned() } fn push_func(&self, func: FuncRef) { self.funcs.borrow_mut().push(func); } - fn push_type(&self, func_type: Rc) { - self.types.borrow_mut().push(func_type) + fn push_signature(&self, signature: Rc) { + self.signatures.borrow_mut().push(signature) } fn push_memory(&self, memory: MemoryRef) { @@ -165,8 +165,8 @@ impl ModuleInstance { let instance = ModuleRef(Rc::new(ModuleInstance::default())); for &Type::Function(ref ty) in module.type_section().map(|ts| ts.types()).unwrap_or(&[]) { - let type_id = alloc_func_type(ty.clone()); - instance.push_type(type_id); + let signature = Rc::new(ty.clone().into()); + instance.push_signature(signature); } { @@ -184,10 +184,10 @@ impl ModuleInstance { { match (import.external(), extern_val) { (&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => { - let expected_fn_type = instance.type_by_index(fn_type_idx).expect( + let expected_fn_type = instance.signature_by_index(fn_type_idx).expect( "Due to validation function type should exists", ); - let actual_fn_type = func.func_type(); + let actual_fn_type = func.signature(); if &*expected_fn_type != actual_fn_type { return Err(Error::Instantiation(format!( "Expected function with type {:?}, but actual type is {:?} for entry {}", @@ -241,7 +241,7 @@ impl ModuleInstance { for (index, (ty, body)) in Iterator::zip(funcs.into_iter(), bodies.into_iter()).enumerate() { - let func_type = instance.type_by_index(ty.type_ref()).expect( + let signature = instance.signature_by_index(ty.type_ref()).expect( "Due to validation type should exists", ); let labels = labels.get(&index).expect( @@ -253,7 +253,7 @@ impl ModuleInstance { labels: labels, }; let func_instance = - FuncInstance::alloc_internal(instance.clone(), func_type, func_body); + FuncInstance::alloc_internal(instance.clone(), signature, func_body); instance.push_func(func_instance); } } @@ -386,7 +386,8 @@ impl ModuleInstance { let &Type::Function(ref func_type) = types .get(fn_ty_idx as usize) .expect("Due to validation functions should have valid types"); - let func = imports.resolve_func(module_name, field_name, func_type)?; + let signature = func_type.clone().into(); + let func = imports.resolve_func(module_name, field_name, &signature)?; ExternVal::Func(func) } External::Table(ref table_type) => { @@ -478,10 +479,6 @@ impl<'a> NotStartedModuleRef<'a> { } } -fn alloc_func_type(func_type: FunctionType) -> Rc { - Rc::new(func_type) -} - fn eval_init_expr(init_expr: &InitExpr, module: &ModuleInstance) -> RuntimeValue { let code = init_expr.code(); debug_assert!( diff --git a/src/runner.rs b/src/runner.rs index 972473b..f15d675 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -5,7 +5,7 @@ use std::fmt::{self, Display}; use std::iter::repeat; use std::collections::{HashMap, VecDeque}; use parity_wasm::elements::{Opcode, BlockType, Local, FunctionType}; -use Error; +use {Error, Signature}; use module::ModuleRef; use func::FuncRef; use func::FuncInstance; @@ -102,8 +102,8 @@ impl<'a, E: Externals> Interpreter<'a, E> { function_stack.push_back(function_context); function_stack.push_back(nested_context); }, - FuncInstance::Host { ref func_type, .. } => { - let args = prepare_function_args(func_type, &mut function_context.value_stack)?; + FuncInstance::Host { ref signature, .. } => { + let args = prepare_function_args(signature, &mut function_context.value_stack)?; let return_val = FuncInstance::invoke(nested_func.clone(), args.into(), self.externals)?; if let Some(return_val) = return_val { function_context.value_stack_mut().push(return_val)?; @@ -428,7 +428,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { fn run_call_indirect( &mut self, context: &mut FunctionContext, - type_idx: u32, + signature_idx: u32, ) -> Result { let table_func_idx: u32 = context.value_stack_mut().pop_as()?; let table = context @@ -438,10 +438,10 @@ impl<'a, E: Externals> Interpreter<'a, E> { let func_ref = table.get(table_func_idx)?; { - let actual_function_type = func_ref.func_type(); + let actual_function_type = func_ref.signature(); let required_function_type = context .module() - .type_by_index(type_idx) + .signature_by_index(signature_idx) .expect("Due to validation type should exists"); if &*required_function_type != actual_function_type { @@ -1001,7 +1001,7 @@ impl<'a, E: Externals> Interpreter<'a, E> { } impl FunctionContext { - pub fn new<'store>(function: FuncRef, value_stack_limit: usize, frame_stack_limit: usize, function_type: &FunctionType, args: Vec) -> Self { + pub fn new<'store>(function: FuncRef, value_stack_limit: usize, frame_stack_limit: usize, signature: &Signature, args: Vec) -> Self { let module = match *function { FuncInstance::Internal { ref module, .. } => module.clone(), FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"), @@ -1010,7 +1010,7 @@ impl FunctionContext { is_initialized: false, function: function, module: module, - return_type: function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult), + return_type: signature.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult), value_stack: StackWithLimit::with_limit(value_stack_limit), frame_stack: StackWithLimit::with_limit(frame_stack_limit), locals: args, @@ -1024,7 +1024,7 @@ impl FunctionContext { FuncInstance::Internal { ref module, .. } => module.clone(), FuncInstance::Host { .. } => panic!("Host functions can't be called as internally defined functions; Thus FunctionContext can be created only with internally defined functions; qed"), }; - let function_type = function.func_type(); + let function_type = function.signature(); let function_return_type = function_type.return_type().map(|vt| BlockType::Value(vt)).unwrap_or(BlockType::NoResult); let function_locals = prepare_function_args(&function_type, &mut self.value_stack)?; (function_locals, module, function_return_type) @@ -1151,8 +1151,8 @@ fn effective_address(address: u32, offset: u32) -> Result { } } -pub fn prepare_function_args(function_type: &FunctionType, caller_stack: &mut StackWithLimit) -> Result, Error> { - let mut args = function_type.params().iter().cloned().rev().map(|expected_type| { +pub fn prepare_function_args(signature: &Signature, caller_stack: &mut StackWithLimit) -> Result, Error> { + let mut args = signature.params().iter().cloned().rev().map(|expected_type| { let param_value = caller_stack.pop()?; let actual_type = param_value.value_type(); if actual_type != expected_type { diff --git a/src/tests/host.rs b/src/tests/host.rs index be45f42..58cbcd6 100644 --- a/src/tests/host.rs +++ b/src/tests/host.rs @@ -2,7 +2,7 @@ use parity_wasm::elements::{deserialize_buffer, FunctionType, MemoryType, TableType, ValueType}; use validation::{validate_module, ValidatedModule}; use { - Error, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, + Error, Signature, Externals, FuncInstance, FuncRef, HostError, ImportsBuilder, MemoryInstance, MemoryRef, TableInstance, TableRef, ModuleImportResolver, ModuleInstance, ModuleRef, RuntimeValue, TryInto, }; @@ -144,14 +144,14 @@ impl Externals for TestHost { } impl TestHost { - fn check_signature(&self, index: usize, func_type: &FunctionType) -> bool { + fn check_signature(&self, index: usize, signature: &Signature) -> bool { if index == RECURSE_FUNC_INDEX { // This function requires special handling because it is polymorphic. - if func_type.params().len() != 1 { + if signature.params().len() != 1 { return false; } - let param_type = func_type.params()[0]; - return func_type.return_type() == Some(param_type); + let param_type = signature.params()[0]; + return signature.return_type() == Some(param_type); } let (params, ret_ty): (&[ValueType], Option) = match index { @@ -162,12 +162,12 @@ impl TestHost { _ => return false, }; - func_type.params() == params && func_type.return_type() == ret_ty + signature.params() == params && signature.return_type() == ret_ty } } impl ModuleImportResolver for TestHost { - fn resolve_func(&self, field_name: &str, func_type: &FunctionType) -> Result { + fn resolve_func(&self, field_name: &str, signature: &Signature) -> Result { let index = match field_name { "sub" => SUB_FUNC_INDEX, "err" => ERR_FUNC_INDEX, @@ -181,15 +181,15 @@ impl ModuleImportResolver for TestHost { } }; - if !self.check_signature(index, func_type) { + if !self.check_signature(index, signature) { return Err(Error::Instantiation(format!( "Export `{}` doesnt match expected type {:?}", field_name, - func_type + signature ))); } - Ok(FuncInstance::alloc_host(func_type.clone(), index)) + Ok(FuncInstance::alloc_host(signature.clone(), index)) } fn resolve_memory( @@ -424,22 +424,22 @@ fn defer_providing_externals() { fn resolve_func( &self, field_name: &str, - func_type: &FunctionType, + signature: &Signature, ) -> Result { if field_name != "inc" { return Err(Error::Instantiation( format!("Export {} not found", field_name), )); } - if func_type.params() != &[ValueType::I32] || func_type.return_type() != None { + if signature.params() != &[ValueType::I32] || signature.return_type() != None { return Err(Error::Instantiation(format!( "Export `{}` doesnt match expected type {:?}", field_name, - func_type + signature ))); } - Ok(FuncInstance::alloc_host(func_type.clone(), INC_FUNC_INDEX)) + Ok(FuncInstance::alloc_host(signature.clone(), INC_FUNC_INDEX)) } fn resolve_memory( @@ -552,7 +552,7 @@ fn two_envs_one_externals() { fn resolve_func( &self, field_name: &str, - func_type: &FunctionType, + signature: &Signature, ) -> Result { let index = match field_name { "ordinary" => ORDINARY_FUNC_INDEX, @@ -564,7 +564,7 @@ fn two_envs_one_externals() { } }; - Ok(FuncInstance::alloc_host(func_type.clone(), index)) + Ok(FuncInstance::alloc_host(signature.clone(), index)) } } @@ -572,7 +572,7 @@ fn two_envs_one_externals() { fn resolve_func( &self, field_name: &str, - func_type: &FunctionType, + signature: &Signature, ) -> Result { let index = match field_name { "ordinary" => ORDINARY_FUNC_INDEX, @@ -588,7 +588,7 @@ fn two_envs_one_externals() { } }; - Ok(FuncInstance::alloc_host(func_type.clone(), index)) + Ok(FuncInstance::alloc_host(signature.clone(), index)) } } @@ -663,7 +663,7 @@ fn dynamically_add_host_func() { self.added_funcs += 1; let added_func = FuncInstance::alloc_host( - FunctionType::new(vec![], Some(ValueType::I32)), + Signature::new(&[], Some(ValueType::I32)), host_func_index as usize, ); self.table.set(table_index, Some(added_func))?; @@ -682,7 +682,7 @@ fn dynamically_add_host_func() { fn resolve_func( &self, field_name: &str, - func_type: &FunctionType, + signature: &Signature, ) -> Result { let index = match field_name { "add_func" => ADD_FUNC_FUNC_INDEX, @@ -692,7 +692,7 @@ fn dynamically_add_host_func() { )) } }; - Ok(FuncInstance::alloc_host(func_type.clone(), index)) + Ok(FuncInstance::alloc_host(signature.clone(), index)) } fn resolve_table( diff --git a/src/tests/wasm.rs b/src/tests/wasm.rs index 9bc1297..282bae9 100644 --- a/src/tests/wasm.rs +++ b/src/tests/wasm.rs @@ -1,6 +1,6 @@ use parity_wasm::elements::deserialize_file; use parity_wasm::elements::{FunctionType, GlobalType, MemoryType, Module, TableType}; -use {Error, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, +use {Error, Signature, FuncRef, GlobalInstance, GlobalRef, ImportsBuilder, MemoryInstance, MemoryRef, ModuleImportResolver, ModuleInstance, NopExternals, RuntimeValue, TableInstance, TableRef}; use validation::validate_module; @@ -24,7 +24,7 @@ impl Env { } impl ModuleImportResolver for Env { - fn resolve_func(&self, _field_name: &str, _func_type: &FunctionType) -> Result { + fn resolve_func(&self, _field_name: &str, _func_type: &Signature) -> Result { Err(Error::Instantiation( "env module doesn't provide any functions".into(), ))