sophon_wasm/interpreter/
native.rs

1
2use std::sync::Arc;
3use std::collections::HashMap;
4use std::borrow::Cow;
5use parking_lot::RwLock;
6use elements::{Internal, ValueType};
7use interpreter::Error;
8use interpreter::module::{ModuleInstanceInterface, ExecutionParams, ItemIndex,
9	CallerContext, ExportEntryType, InternalFunctionReference, InternalFunction, FunctionSignature};
10use interpreter::memory::MemoryInstance;
11use interpreter::table::TableInstance;
12use interpreter::value::RuntimeValue;
13use interpreter::variable::{VariableInstance, VariableType};
14
15/// Min index of native function.
16pub const NATIVE_INDEX_FUNC_MIN: u32 = 10001;
17/// Min index of native global.
18pub const NATIVE_INDEX_GLOBAL_MIN: u32 = 20001;
19
20/// User functions executor.
21pub trait UserFunctionExecutor {
22	/// Execute function with given name.
23	fn execute(&mut self, name: &str, context: CallerContext) -> Result<Option<RuntimeValue>, Error>;
24}
25
26/// User function descriptor
27#[derive(Debug, Clone)]
28pub enum UserFunctionDescriptor {
29	/// Static function definition
30	Static(&'static str, &'static [ValueType], Option<ValueType>),
31	/// Dynamic heap function definition
32	Heap(String, Vec<ValueType>, Option<ValueType>),
33}
34
35impl UserFunctionDescriptor {
36	/// New function with statically known params
37	pub fn statik(name: &'static str, params: &'static [ValueType], result: Option<ValueType>) -> Self {
38		UserFunctionDescriptor::Static(name, params, result)
39	}
40
41	/// New function with statically unknown params
42	pub fn heap(name: String, params: Vec<ValueType>, result: Option<ValueType>) -> Self {
43		UserFunctionDescriptor::Heap(name, params, result)
44	}
45
46	/// Name of the function
47	pub fn name(&self) -> &str {
48		match self {
49			&UserFunctionDescriptor::Static(name, _, _) => name,
50			&UserFunctionDescriptor::Heap(ref name, _, _) => name,
51		}
52	}
53
54	/// Arguments of the function
55	pub fn params(&self) -> &[ValueType] {
56		match self {
57			&UserFunctionDescriptor::Static(_, params, _) => params,
58			&UserFunctionDescriptor::Heap(_, ref params, _) => params,
59		}
60	}
61
62	/// Return type of the function
63	pub fn return_type(&self) -> Option<ValueType> {
64		match self {
65			&UserFunctionDescriptor::Static(_, _, result) => result,
66			&UserFunctionDescriptor::Heap(_, _, result) => result,
67		}
68	}
69}
70
71/// Set of user-defined module elements.
72pub struct UserDefinedElements<E: UserFunctionExecutor> {
73	/// User globals list.
74	pub globals: HashMap<String, Arc<VariableInstance>>,
75	/// User functions list.
76	pub functions: Cow<'static, [UserFunctionDescriptor]>,
77	/// Functions executor.
78	pub executor: Option<E>,
79}
80
81/// Native module instance.
82pub struct NativeModuleInstance<E: UserFunctionExecutor> {
83	/// Underlying module reference.
84	base: Arc<ModuleInstanceInterface>,
85	/// User function executor.
86	executor: RwLock<Option<E>>,
87	/// By-name functions index.
88	functions_by_name: HashMap<String, u32>,
89	/// User functions list.
90	functions: Cow<'static, [UserFunctionDescriptor]>,
91	/// By-name functions index.
92	globals_by_name: HashMap<String, u32>,
93	/// User globals list.
94	globals: Vec<Arc<VariableInstance>>,
95}
96
97impl<E: UserFunctionExecutor> NativeModuleInstance<E> {
98	/// Create new native module
99	pub fn new(base: Arc<ModuleInstanceInterface>, elements: UserDefinedElements<E>) -> Result<Self, Error> {
100		if !elements.functions.is_empty() && elements.executor.is_none() {
101			return Err(Error::Function("trying to construct native module with functions, but without executor".into()));
102		}
103
104		Ok(NativeModuleInstance {
105			base: base,
106			executor: RwLock::new(elements.executor),
107			functions_by_name: elements.functions.iter().enumerate().map(|(i, f)| (f.name().to_owned(), i as u32)).collect(),
108			functions: elements.functions,
109			globals_by_name: elements.globals.iter().enumerate().map(|(i, (g_name, _))| (g_name.to_owned(), i as u32)).collect(),
110			globals: elements.globals.into_iter().map(|(_, g)| g).collect(),
111		})
112	}
113}
114
115impl<E: UserFunctionExecutor> ModuleInstanceInterface for NativeModuleInstance<E> {
116	fn execute_index(&self, index: u32, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
117		self.base.execute_index(index, params)
118	}
119
120	fn execute_export(&self, name: &str, params: ExecutionParams) -> Result<Option<RuntimeValue>, Error> {
121		self.base.execute_export(name, params)
122	}
123
124	fn export_entry<'b>(&self, name: &str, required_type: &ExportEntryType) -> Result<Internal, Error> {
125		if let Some(index) = self.functions_by_name.get(name) {
126			let composite_index = NATIVE_INDEX_FUNC_MIN + *index;
127			match required_type {
128				&ExportEntryType::Any => return Ok(Internal::Function(composite_index)),
129				&ExportEntryType::Function(ref required_type) => {
130					let actual_type = self.function_type(ItemIndex::Internal(composite_index))
131						.expect(
132							"by_name contains index; function_type succeeds for all functions from by_name; qed",
133						);
134					return if actual_type == *required_type {
135						Ok(Internal::Function(composite_index))
136					} else {
137						Err(Error::Validation(format!(
138							"Export function type {} mismatch. Expected function with signature ({:?}) -> {:?} when got with ({:?}) -> {:?}",
139							index,
140							required_type.params(),
141							required_type.return_type(),
142							actual_type.params(),
143							actual_type.return_type()
144						)))
145					};
146				}
147				_ => (),
148			}
149		}
150		if let Some(index) = self.globals_by_name.get(name) {
151			let composite_index = NATIVE_INDEX_GLOBAL_MIN + *index;
152			match required_type {
153				&ExportEntryType::Any => {
154					return Ok(Internal::Global(composite_index))
155				}
156				&ExportEntryType::Global(ref required_type) => {
157					let actual_type = self.globals
158						.get(*index as usize)
159						.expect(
160							"globals_by_name maps to indexes of globals; index read from globals_by_name; qed",
161						)
162						.variable_type();
163					return if actual_type == *required_type {
164						Ok(Internal::Global(composite_index))
165					} else {
166						Err(Error::Validation(format!(
167							"Export global type {} mismatch. Expected type {:?} when got {:?}",
168							index,
169							required_type,
170							actual_type
171						)))
172					};
173				}
174				_ => (),
175			}
176		}
177
178		self.base.export_entry(name, required_type)
179	}
180
181	fn table(&self, index: ItemIndex) -> Result<Arc<TableInstance>, Error> {
182		self.base.table(index)
183	}
184
185	fn memory(&self, index: ItemIndex) -> Result<Arc<MemoryInstance>, Error> {
186		self.base.memory(index)
187	}
188
189	fn global<'b>(&self, global_index: ItemIndex, variable_type: Option<VariableType>, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<Arc<VariableInstance>, Error> {
190		let index = match global_index {
191			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
192			ItemIndex::External(_) => unreachable!("trying to get global, exported by native module"),
193		};
194
195		if index < NATIVE_INDEX_GLOBAL_MIN {
196			return self.base.global(global_index, variable_type, externals);
197		}
198
199		self.globals
200			.get((index - NATIVE_INDEX_GLOBAL_MIN) as usize)
201			.cloned()
202			.ok_or(Error::Native(format!("trying to get native global with index {}", index)))
203	}
204
205	fn function_type(&self, function_index: ItemIndex) -> Result<FunctionSignature, Error> {
206		let index = match function_index {
207			ItemIndex::IndexSpace(index) | ItemIndex::Internal(index) => index,
208			ItemIndex::External(_) => unreachable!("trying to call function, exported by native module"),
209		};
210
211		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
212			return self.base.function_type(function_index);
213		}
214
215		Ok(FunctionSignature::User(self.functions
216			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
217			.ok_or(Error::Native(format!("missing native function with index {}", index)))?))
218	}
219
220	fn function_type_by_index(&self, type_index: u32) -> Result<FunctionSignature, Error> {
221		self.function_type(ItemIndex::Internal(type_index))
222	}
223
224	fn function_reference<'b>(&self, index: ItemIndex, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
225		self.base.function_reference(index, externals)
226	}
227
228	fn function_reference_indirect<'b>(&self, table_idx: u32, type_idx: u32, func_idx: u32, externals: Option<&'b HashMap<String, Arc<ModuleInstanceInterface + 'b>>>) -> Result<InternalFunctionReference<'b>, Error> {
229		self.base.function_reference_indirect(table_idx, type_idx, func_idx, externals)
230	}
231
232	fn function_body<'b>(&'b self, _internal_index: u32) -> Result<Option<InternalFunction<'b>>, Error> {
233		Ok(None)
234	}
235
236	fn call_internal_function(&self, outer: CallerContext, index: u32) -> Result<Option<RuntimeValue>, Error> {
237		if index < NATIVE_INDEX_FUNC_MIN || index >= NATIVE_INDEX_GLOBAL_MIN {
238			return self.base.call_internal_function(outer, index);
239		}
240
241		self.functions
242			.get((index - NATIVE_INDEX_FUNC_MIN) as usize)
243			.ok_or(Error::Native(format!("trying to call native function with index {}", index)).into())
244			.and_then(|f| self.executor.write()
245				.as_mut()
246				.expect("function exists; if function exists, executor must also exists [checked in constructor]; qed")
247				.execute(&f.name(), outer))
248	}
249}
250
251/// Create wrapper for a module with given native user functions.
252///
253/// # Examples
254///
255/// ```rust
256/// use sophon_wasm::interpreter::{CallerContext, Error, ExecutionParams, ExportEntryType,
257///                                FunctionSignature, ItemIndex, ModuleInstance,
258///                                ModuleInstanceInterface, ProgramInstance, RuntimeValue,
259///                                UserDefinedElements, UserError, UserFunctionDescriptor,
260///                                UserFunctionExecutor};
261///
262/// struct MyExecutor;
263///
264/// impl UserFunctionExecutor for MyExecutor {
265///     fn execute(
266///         &mut self,
267///         name: &str,
268///         context: CallerContext,
269///     ) -> Result<Option<RuntimeValue>, Error> {
270///         match name {
271///             "add" => {
272///                 // fn add(a: u32, b: u32) -> u32
273///                 let b = context.value_stack.pop_as::<u32>()? as u32;
274///                 let a = context.value_stack.pop_as::<u32>()? as u32;
275///                 let sum = a + b;
276///                 Ok(Some(RuntimeValue::I32(sum as i32)))
277///             }
278///             _ => Err(Error::Trap("not implemented".into()).into()),
279///         }
280///     }
281/// }
282/// ```
283pub fn native_module<'a, E: UserFunctionExecutor + 'a>(base: Arc<ModuleInstanceInterface>, user_elements: UserDefinedElements<E>) -> Result<Arc<ModuleInstanceInterface + 'a>, Error> {
284	Ok(Arc::new(NativeModuleInstance::new(base, user_elements)?))
285}
286
287impl<'a> PartialEq for UserFunctionDescriptor {
288	fn eq(&self, other: &Self) -> bool {
289		self.params() == other.params()
290			&& self.return_type() == other.return_type()
291	}
292}