diff --git a/src/interpreter/env_native.rs b/src/interpreter/env_native.rs index 19216af..ec86577 100644 --- a/src/interpreter/env_native.rs +++ b/src/interpreter/env_native.rs @@ -1,5 +1,6 @@ use std::sync::Arc; use std::collections::HashMap; +use std::borrow::Cow; use parking_lot::RwLock; use elements::{FunctionType, Internal, ValueType}; use interpreter::Error; @@ -22,20 +23,62 @@ pub trait UserFunctionExecutor { fn execute(&mut self, name: &str, context: CallerContext) -> Result, Error>; } +#[derive(Clone)] +pub enum UserFunctionDescriptor { + Static(&'static str, &'static [ValueType]), + Heap(String, Vec), +} + /// User function type. +#[derive(Clone)] pub struct UserFunction { - /// User function name. - pub name: String, - /// User function parameters (for signature matching). - pub params: Vec, - /// User function return type (for signature matching). + pub desc: UserFunctionDescriptor, pub result: Option, } +impl UserFunction { + /// New function with statically known params + pub fn statik(name: &'static str, params: &'static [ValueType], result: Option) -> Self { + UserFunction { + desc: UserFunctionDescriptor::Static(name, params), + result: result, + } + } + + /// New function with statically unknown params + pub fn heap(name: String, params: Vec, result: Option) -> Self { + UserFunction { + desc: UserFunctionDescriptor::Heap(name, params), + result: result, + } + } + + /// Name of the function + pub fn name(&self) -> &str { + match self.desc { + UserFunctionDescriptor::Static(name, _) => name, + UserFunctionDescriptor::Heap(ref name, _) => name, + } + } + + /// Arguments of the function + pub fn params(&self) -> &[ValueType] { + match self.desc { + UserFunctionDescriptor::Static(_, params) => params, + UserFunctionDescriptor::Heap(_, ref params) => params, + } + } + + /// Return type of the function + pub fn result(&self) -> Option { + self.result + } +} + /// Set of user-defined functions pub struct UserFunctions<'a> { /// Functions list. - pub functions: Vec, + pub functions: Cow<'static, [UserFunction]>, /// Functions executor. pub executor: &'a mut UserFunctionExecutor, } @@ -49,7 +92,7 @@ pub struct NativeModuleInstance<'a> { /// By-name functions index. by_name: HashMap, /// User functions list. - functions: Vec, + functions: Cow<'static, [UserFunction]>, } impl<'a> NativeModuleInstance<'a> { @@ -58,7 +101,7 @@ impl<'a> NativeModuleInstance<'a> { Ok(NativeModuleInstance { env: env, executor: RwLock::new(functions.executor), - by_name: functions.functions.iter().enumerate().map(|(i, f)| (f.name.clone(), i as u32)).collect(), + by_name: functions.functions.iter().enumerate().map(|(i, f)| (f.name().to_owned(), i as u32)).collect(), functions: functions.functions, }) } @@ -98,7 +141,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("missing native env function with index {}", index))) - .map(|f| FunctionType::new(f.params.clone(), f.result.clone())) + .map(|f| FunctionType::new(f.params().to_vec(), f.result().clone())) } fn table(&self, index: ItemIndex) -> Result, Error> { @@ -130,7 +173,7 @@ impl<'a> ModuleInstanceInterface for NativeModuleInstance<'a> { self.functions .get((index - NATIVE_INDEX_FUNC_MIN) as usize) .ok_or(Error::Native(format!("trying to call native function with index {}", index))) - .and_then(|f| self.executor.write().execute(&f.name, outer)) + .and_then(|f| self.executor.write().execute(&f.name(), outer)) } } diff --git a/src/interpreter/tests/basics.rs b/src/interpreter/tests/basics.rs index b13cb00..2931529 100644 --- a/src/interpreter/tests/basics.rs +++ b/src/interpreter/tests/basics.rs @@ -5,7 +5,7 @@ use builder::module; use elements::{ExportEntry, Internal, ImportEntry, External, GlobalEntry, GlobalType, InitExpr, ValueType, BlockType, Opcodes, Opcode, FunctionType}; use interpreter::Error; -use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor}; +use interpreter::env_native::{env_native_module, UserFunction, UserFunctions, UserFunctionExecutor, UserFunctionDescriptor}; use interpreter::imports::ModuleImports; use interpreter::memory::MemoryInstance; use interpreter::module::{ModuleInstanceInterface, CallerContext, ItemIndex, ExecutionParams}; @@ -123,6 +123,25 @@ fn global_get_set() { assert_eq!(module.execute_index(2, vec![].into()).unwrap_err(), Error::Variable("trying to update variable of type I32 with value of type Some(I64)".into())); } +const SIGNATURE_I32: &'static [ValueType] = &[ValueType::I32]; + +const SIGNATURES: &'static [UserFunction] = &[ + UserFunction { + desc: UserFunctionDescriptor::Static( + "add", + SIGNATURE_I32, + ), + result: Some(ValueType::I32), + }, + UserFunction { + desc: UserFunctionDescriptor::Static( + "sub", + SIGNATURE_I32, + ), + result: Some(ValueType::I32), + }, +]; + #[test] fn single_program_different_modules() { // user function executor @@ -170,15 +189,7 @@ fn single_program_different_modules() { { let functions: UserFunctions = UserFunctions { executor: &mut executor, - functions: vec![UserFunction { - name: "add".into(), - params: vec![ValueType::I32], - result: Some(ValueType::I32), - }, UserFunction { - name: "sub".into(), - params: vec![ValueType::I32], - result: Some(ValueType::I32), - }], + functions: ::std::borrow::Cow::from(SIGNATURES), }; let native_env_instance = Arc::new(env_native_module(env_instance, functions).unwrap()); let params = ExecutionParams::with_external("env".into(), native_env_instance);