1pub(crate) mod env;
4pub(crate) mod typed;
5
6#[cfg(feature = "experimental-async")]
7use crate::{
8 AsStoreAsync, AsyncFunctionEnvMut, BackendAsyncFunctionEnvMut, StoreAsync,
9 entities::function::async_host::{AsyncFunctionEnv, AsyncHostFunction},
10 sys::{
11 async_runtime::{AsyncRuntimeError, block_on_host_future, call_function_async},
12 function::env::AsyncFunctionEnvMutStore,
13 },
14};
15use crate::{
16 BackendFunction, FunctionEnv, FunctionEnvMut, FunctionType, HostFunction, RuntimeError,
17 StoreContext, StoreInner, Value, WithEnv, WithoutEnv,
18 backend::sys::{engine::NativeEngineExt, vm::VMFunctionCallback},
19 entities::store::{AsStoreMut, AsStoreRef, StoreMut},
20 utils::{FromToNativeWasmType, IntoResult, NativeWasmTypeInto, WasmTypeList},
21 vm::{VMExtern, VMExternFunction},
22};
23use std::panic::{self, AssertUnwindSafe};
24use std::{
25 cell::UnsafeCell, cmp::max, error::Error, ffi::c_void, future::Future, marker::PhantomData,
26 pin::Pin, sync::Arc,
27};
28use wasmer_types::{NativeWasmType, RawValue, StoreId};
29use wasmer_vm::{
30 MaybeInstanceOwned, StoreHandle, Trap, TrapCode, VMCallerCheckedAnyfunc, VMContext,
31 VMDynamicFunctionContext, VMFuncRef, VMFunction, VMFunctionBody, VMFunctionContext,
32 VMFunctionKind, VMTrampoline, on_host_stack, raise_lib_trap, raise_user_trap, resume_panic,
33 wasmer_call_trampoline,
34};
35
36#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Function {
40 pub(crate) handle: StoreHandle<VMFunction>,
41}
42
43impl From<StoreHandle<VMFunction>> for Function {
44 fn from(handle: StoreHandle<VMFunction>) -> Self {
45 Self { handle }
46 }
47}
48
49impl Function {
50 pub(crate) fn new_with_env<FT, F, T: Send + 'static>(
51 store: &mut impl AsStoreMut,
52 env: &FunctionEnv<T>,
53 ty: FT,
54 func: F,
55 ) -> Self
56 where
57 FT: Into<FunctionType>,
58 F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
59 + 'static
60 + Send
61 + Sync,
62 {
63 let function_type = ty.into();
64 let func_ty = function_type.clone();
65 let func_env = env.clone().into_sys();
66 let store_id = store.objects_mut().id();
67 let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome {
68 unsafe {
69 let mut store_wrapper = unsafe { StoreContext::get_current(store_id) };
70 let mut store_mut = store_wrapper.as_mut();
71 let mut args = Vec::with_capacity(func_ty.params().len());
72
73 for (i, ty) in func_ty.params().iter().enumerate() {
74 args.push(Value::from_raw(
75 &mut store_mut,
76 *ty,
77 values_vec.add(i).read_unaligned(),
78 ));
79 }
80 let env = env::FunctionEnvMut {
81 store_mut,
82 func_env: func_env.clone(),
83 }
84 .into();
85 let sig = func_ty.clone();
86 let result = func(env, &args);
87 HostCallOutcome::Ready {
88 func_ty: sig,
89 result,
90 }
91 }
92 };
93 let mut host_data = Box::new(VMDynamicFunctionContext {
94 address: std::ptr::null(),
95 ctx: DynamicFunction {
96 func: wrapper,
97 store_id,
98 },
99 });
100 host_data.address = host_data.ctx.func_body_ptr();
101
102 let func_ptr = std::ptr::null() as VMFunctionCallback;
106 let type_index = store
107 .as_store_ref()
108 .engine()
109 .as_sys()
110 .register_signature(&function_type);
111 let vmctx = VMFunctionContext {
112 host_env: host_data.as_ref() as *const _ as *mut c_void,
113 };
114 let call_trampoline = host_data.ctx.call_trampoline_address();
115 let anyfunc = VMCallerCheckedAnyfunc {
116 func_ptr,
117 type_index,
118 vmctx,
119 call_trampoline,
120 };
121
122 let vm_function = VMFunction {
123 anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
124 kind: VMFunctionKind::Dynamic,
125 signature: function_type,
126 host_data,
127 };
128 Self {
129 handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
130 }
131 }
132
133 #[cfg(feature = "experimental-async")]
134 pub(crate) fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
135 where
136 FT: Into<FunctionType>,
137 F: Fn(&[Value]) -> Fut + 'static,
138 Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
139 {
140 let env = FunctionEnv::new(store, ());
141 let wrapped = move |_env: AsyncFunctionEnvMut<()>, values: &[Value]| func(values);
142 Self::new_with_env_async(store, &env, ty, wrapped)
143 }
144
145 #[cfg(feature = "experimental-async")]
146 pub(crate) fn new_with_env_async<FT, F, Fut, T: 'static>(
147 store: &mut impl AsStoreMut,
148 env: &FunctionEnv<T>,
149 ty: FT,
150 func: F,
151 ) -> Self
152 where
153 FT: Into<FunctionType>,
154 F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
155 Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
156 {
157 let function_type = ty.into();
158 let func_ty = function_type.clone();
159 let func_env = env.clone().into_sys();
160 let store_id = store.objects_mut().id();
161 let wrapper = move |values_vec: *mut RawValue| -> HostCallOutcome {
162 unsafe {
163 let mut context = StoreContext::try_get_current_async(store_id);
164 let mut store_mut = match &mut context {
165 crate::GetStoreAsyncGuardResult::Ok(wrapper) => StoreMut {
166 inner: wrapper.guard.as_mut().unwrap(),
167 },
168 crate::GetStoreAsyncGuardResult::NotAsync(ptr) => ptr.as_mut(),
169 crate::GetStoreAsyncGuardResult::NotInstalled => {
170 panic!("No store context installed on this thread")
171 }
172 };
173 let id = store_mut.as_store_ref().objects().id();
174 let mut args = Vec::with_capacity(func_ty.params().len());
175
176 for (i, ty) in func_ty.params().iter().enumerate() {
177 args.push(Value::from_raw(
178 &mut store_mut,
179 *ty,
180 values_vec.add(i).read_unaligned(),
181 ));
182 }
183 let store_async = match context {
184 crate::GetStoreAsyncGuardResult::Ok(wrapper) => {
185 AsyncFunctionEnvMutStore::Async(StoreAsync {
186 id,
187 inner: crate::LocalRwLockWriteGuard::lock_handle(
188 wrapper.guard.as_mut().unwrap(),
189 ),
190 })
191 }
192 crate::GetStoreAsyncGuardResult::NotAsync(ptr) => {
193 AsyncFunctionEnvMutStore::Sync(ptr)
194 }
195 crate::GetStoreAsyncGuardResult::NotInstalled => unreachable!(),
196 };
197 let env = crate::AsyncFunctionEnvMut(crate::BackendAsyncFunctionEnvMut::Sys(
198 env::AsyncFunctionEnvMut {
199 store: store_async,
200 func_env: func_env.clone(),
201 },
202 ));
203 let sig = func_ty.clone();
204 let future = func(env, &args);
205 HostCallOutcome::Future {
206 func_ty: sig,
207 future: Box::pin(future),
208 }
209 }
210 };
211 let mut host_data = Box::new(VMDynamicFunctionContext {
212 address: std::ptr::null(),
213 ctx: DynamicFunction {
214 func: wrapper,
215 store_id,
216 },
217 });
218 host_data.address = host_data.ctx.func_body_ptr();
219
220 let func_ptr = std::ptr::null() as VMFunctionCallback;
221 let type_index = store
222 .as_store_ref()
223 .engine()
224 .as_sys()
225 .register_signature(&function_type);
226 let vmctx = VMFunctionContext {
227 host_env: host_data.as_ref() as *const _ as *mut c_void,
228 };
229 let call_trampoline = host_data.ctx.call_trampoline_address();
230 let anyfunc = VMCallerCheckedAnyfunc {
231 func_ptr,
232 type_index,
233 vmctx,
234 call_trampoline,
235 };
236
237 let vm_function = VMFunction {
238 anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
239 kind: VMFunctionKind::Dynamic,
240 signature: function_type,
241 host_data,
242 };
243 Self {
244 handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
245 }
246 }
247
248 pub(crate) fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
250 where
251 F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
252 Args: WasmTypeList,
253 Rets: WasmTypeList,
254 {
255 let env = FunctionEnv::new(store, ());
256 let func_ptr = func.function_callback_sys().into_sys();
257 let host_data = Box::new(StaticFunction {
258 store_id: store.objects_mut().id(),
259 env,
260 func,
261 });
262 let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
263
264 let type_index = store
265 .as_store_ref()
266 .engine()
267 .as_sys()
268 .register_signature(&function_type);
269 let vmctx = VMFunctionContext {
270 host_env: host_data.as_ref() as *const _ as *mut c_void,
271 };
272 let call_trampoline =
273 <F as HostFunction<(), Args, Rets, WithoutEnv>>::call_trampoline_address().into_sys();
274 let anyfunc = VMCallerCheckedAnyfunc {
275 func_ptr,
276 type_index,
277 vmctx,
278 call_trampoline,
279 };
280
281 let vm_function = VMFunction {
282 anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
283 kind: VMFunctionKind::Static,
284 signature: function_type,
285 host_data,
286 };
287 Self {
288 handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
289 }
290 }
291
292 #[cfg(feature = "experimental-async")]
293 pub(crate) fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
294 where
295 Args: WasmTypeList + 'static,
296 Rets: WasmTypeList + 'static,
297 F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
298 {
299 let env = FunctionEnv::new(store, ());
300 let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
301 let args_sig = Arc::new(signature.clone());
302 let results_sig = Arc::new(signature.clone());
303 let func = Arc::new(func);
304 Self::new_with_env_async(
305 store,
306 &env,
307 signature,
308 move |mut env_mut,
309 values|
310 -> Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>> {
311 let sys_env = match env_mut.0 {
312 BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env,
313 _ => panic!("Not a sys backend"),
314 };
315 let mut store_mut_wrapper =
316 unsafe { StoreContext::get_current(sys_env.store_id()) };
317 let mut store_mut = store_mut_wrapper.as_mut();
318 let args_sig = args_sig.clone();
319 let results_sig = results_sig.clone();
320 let func = func.clone();
321 let args =
322 match typed_args_from_values::<Args>(&mut store_mut, args_sig.as_ref(), values)
323 {
324 Ok(args) => args,
325 Err(err) => return Box::pin(async { Err(err) }),
326 };
327 drop(store_mut_wrapper);
328 let future = func.as_ref().call_async(AsyncFunctionEnv::new(), args);
329 Box::pin(async move {
330 let typed_result = future.await?;
331 let mut store_mut = env_mut.write().await;
332 typed_results_to_values::<Rets>(
333 &mut store_mut.as_store_mut(),
334 results_sig.as_ref(),
335 typed_result,
336 )
337 })
338 },
339 )
340 }
341
342 #[cfg(feature = "experimental-async")]
343 pub(crate) fn new_typed_with_env_async<T, F, Args, Rets>(
344 store: &mut impl AsStoreMut,
345 env: &FunctionEnv<T>,
346 func: F,
347 ) -> Self
348 where
349 T: 'static,
350 F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
351 Args: WasmTypeList + 'static,
352 Rets: WasmTypeList + 'static,
353 {
354 let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
355 let args_sig = Arc::new(signature.clone());
356 let results_sig = Arc::new(signature.clone());
357 let func = Arc::new(func);
358 Self::new_with_env_async(
359 store,
360 env,
361 signature,
362 move |mut env_mut,
363 values|
364 -> Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>> {
365 let sys_env = match env_mut.0 {
366 BackendAsyncFunctionEnvMut::Sys(ref mut sys_env) => sys_env,
367 _ => panic!("Not a sys backend"),
368 };
369 let mut store_mut_wrapper =
370 unsafe { StoreContext::get_current(sys_env.store_id()) };
371 let mut store_mut = store_mut_wrapper.as_mut();
372 let args_sig = args_sig.clone();
373 let results_sig = results_sig.clone();
374 let func = func.clone();
375 let args =
376 match typed_args_from_values::<Args>(&mut store_mut, args_sig.as_ref(), values)
377 {
378 Ok(args) => args,
379 Err(err) => return Box::pin(async { Err(err) }),
380 };
381 drop(store_mut_wrapper);
382 let env_mut_clone = env_mut.as_mut();
383 let future = func
384 .as_ref()
385 .call_async(AsyncFunctionEnv::with_env(env_mut), args);
386 Box::pin(async move {
387 let typed_result = future.await?;
388 let mut store_mut = env_mut_clone.write().await;
389 typed_results_to_values::<Rets>(
390 &mut store_mut.as_store_mut(),
391 results_sig.as_ref(),
392 typed_result,
393 )
394 })
395 },
396 )
397 }
398
399 pub(crate) fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
400 store: &mut impl AsStoreMut,
401 env: &FunctionEnv<T>,
402 func: F,
403 ) -> Self
404 where
405 F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
406 Args: WasmTypeList,
407 Rets: WasmTypeList,
408 {
409 let func_ptr = func.function_callback_sys().into_sys();
410 let host_data = Box::new(StaticFunction {
411 store_id: store.objects_mut().id(),
412 env: env.as_sys().clone().into(),
413 func,
414 });
415 let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
416
417 let type_index = store
418 .as_store_ref()
419 .engine()
420 .as_sys()
421 .register_signature(&function_type);
422 let vmctx = VMFunctionContext {
423 host_env: host_data.as_ref() as *const _ as *mut c_void,
424 };
425 let call_trampoline =
426 <F as HostFunction<T, Args, Rets, WithEnv>>::call_trampoline_address().into_sys();
427 let anyfunc = VMCallerCheckedAnyfunc {
428 func_ptr,
429 type_index,
430 vmctx,
431 call_trampoline,
432 };
433
434 let vm_function = VMFunction {
435 anyfunc: MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(anyfunc))),
436 kind: VMFunctionKind::Static,
437 signature: function_type,
438 host_data,
439 };
440 Self {
441 handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
442 }
443 }
444
445 pub(crate) fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
446 self.handle
447 .get(store.as_store_ref().objects().as_sys())
448 .signature
449 .clone()
450 }
451
452 fn call_wasm(
453 &self,
454 store: &mut impl AsStoreMut,
455 trampoline: VMTrampoline,
456 params: &[Value],
457 results: &mut [Value],
458 ) -> Result<(), RuntimeError> {
459 let format_types_for_error_message = |items: &[Value]| {
460 items
461 .iter()
462 .map(|param| param.ty().to_string())
463 .collect::<Vec<String>>()
464 .join(", ")
465 };
466 let signature = self.ty(store);
468 if signature.params().len() != params.len() {
469 return Err(RuntimeError::new(format!(
470 "Parameters of type [{}] did not match signature {}",
471 format_types_for_error_message(params),
472 &signature
473 )));
474 }
475 if signature.results().len() != results.len() {
476 return Err(RuntimeError::new(format!(
477 "Results of type [{}] did not match signature {}",
478 format_types_for_error_message(results),
479 &signature,
480 )));
481 }
482
483 let mut values_vec = vec![RawValue { i32: 0 }; max(params.len(), results.len())];
484
485 let param_tys = signature.params().iter();
487 for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
488 if arg.ty() != *ty {
489 let param_types = format_types_for_error_message(params);
490 return Err(RuntimeError::new(format!(
491 "Parameters of type [{}] did not match signature {}",
492 param_types, &signature,
493 )));
494 }
495 if !arg.is_from_store(store) {
496 return Err(RuntimeError::new("cross-`Store` values are not supported"));
497 }
498 *slot = arg.as_raw(store);
499 }
500
501 self.call_wasm_raw(store, trampoline, values_vec, results)?;
503 Ok(())
504 }
505
506 fn call_wasm_raw(
507 &self,
508 store: &mut impl AsStoreMut,
509 trampoline: VMTrampoline,
510 mut params: Vec<RawValue>,
511 results: &mut [Value],
512 ) -> Result<(), RuntimeError> {
513 let result = {
515 let store_id = store.objects_mut().id();
516 let store_install_guard =
519 unsafe { StoreContext::ensure_installed(store.as_store_mut().inner as *mut _) };
520
521 let mut r;
522 loop {
524 let storeref = store.as_store_ref();
525 let vm_function = self.handle.get(storeref.objects().as_sys());
526 let config = storeref.engine().tunables().vmconfig();
527 let signal_handler = storeref.signal_handler();
528 r = unsafe {
529 let pause_guard = StoreContext::pause(store_id);
532 wasmer_call_trampoline(
533 signal_handler,
534 config,
535 vm_function.anyfunc.as_ptr().as_ref().vmctx,
536 trampoline,
537 vm_function.anyfunc.as_ptr().as_ref().func_ptr,
538 params.as_mut_ptr() as *mut u8,
539 )
540 };
541 let store_mut = store.as_store_mut();
542 if let Some(callback) = store_mut.inner.on_called.take() {
543 match callback(store_mut) {
544 Ok(wasmer_types::OnCalledAction::InvokeAgain) => {
545 continue;
546 }
547 Ok(wasmer_types::OnCalledAction::Finish) => {
548 break;
549 }
550 Ok(wasmer_types::OnCalledAction::Trap(trap)) => {
551 return Err(RuntimeError::user(trap));
552 }
553 Err(trap) => return Err(RuntimeError::user(trap)),
554 }
555 }
556 break;
557 }
558
559 drop(store_install_guard);
560
561 r
562 };
563
564 if let Err(error) = result {
565 return Err(error.into());
566 }
567
568 let signature = self.ty(store);
570 for (index, &value_type) in signature.results().iter().enumerate() {
571 unsafe {
572 results[index] = Value::from_raw(store, value_type, params[index]);
573 }
574 }
575
576 Ok(())
577 }
578
579 pub(crate) fn result_arity(&self, store: &impl AsStoreRef) -> usize {
580 self.ty(store).results().len()
581 }
582
583 pub(crate) fn call(
584 &self,
585 store: &mut impl AsStoreMut,
586 params: &[Value],
587 ) -> Result<Box<[Value]>, RuntimeError> {
588 let trampoline = unsafe {
589 self.handle
590 .get(store.objects_mut().as_sys())
591 .anyfunc
592 .as_ptr()
593 .as_ref()
594 .call_trampoline
595 };
596 let mut results = vec![Value::null(); self.result_arity(store)];
597 self.call_wasm(store, trampoline, params, &mut results)?;
598 Ok(results.into_boxed_slice())
599 }
600
601 #[cfg(feature = "experimental-async")]
602 #[allow(clippy::type_complexity)]
603 pub(crate) fn call_async(
604 &self,
605 store: &impl AsStoreAsync,
606 params: Vec<Value>,
607 ) -> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static>> {
608 let function = self.clone();
609 let store = store.store();
610 Box::pin(call_function_async(function, store, params))
611 }
612
613 #[doc(hidden)]
614 #[allow(missing_docs)]
615 pub(crate) fn call_raw(
616 &self,
617 store: &mut impl AsStoreMut,
618 params: Vec<RawValue>,
619 ) -> Result<Box<[Value]>, RuntimeError> {
620 let trampoline = unsafe {
621 self.handle
622 .get(store.objects_mut().as_sys())
623 .anyfunc
624 .as_ptr()
625 .as_ref()
626 .call_trampoline
627 };
628 let mut results = vec![Value::null(); self.result_arity(store)];
629 self.call_wasm_raw(store, trampoline, params, &mut results)?;
630 Ok(results.into_boxed_slice())
631 }
632
633 pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
634 let vm_function = self.handle.get(store.as_store_ref().objects().as_sys());
635 if vm_function.kind == VMFunctionKind::Dynamic {
636 panic!("dynamic functions cannot be used in tables or as funcrefs");
637 }
638 VMFuncRef(vm_function.anyfunc.as_ptr())
639 }
640
641 pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
642 let signature = {
643 let anyfunc = unsafe { funcref.0.as_ref() };
644 store
645 .as_store_mut()
646 .engine()
647 .as_sys()
648 .lookup_signature(anyfunc.type_index)
649 .expect("Signature not found in store")
650 };
651 let vm_function = VMFunction {
652 anyfunc: MaybeInstanceOwned::Instance(funcref.0),
653 signature,
654 kind: wasmer_vm::VMFunctionKind::Static,
657 host_data: Box::new(()),
658 };
659 Self {
660 handle: StoreHandle::new(store.objects_mut().as_sys_mut(), vm_function),
661 }
662 }
663
664 pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
665 Self {
666 handle: unsafe {
667 StoreHandle::from_internal(store.objects_mut().id(), vm_extern.into_sys())
668 },
669 }
670 }
671
672 pub(crate) fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
674 self.handle.store_id() == store.as_store_ref().objects().id()
675 }
676
677 pub(crate) fn to_vm_extern(&self) -> VMExtern {
678 VMExtern::Sys(wasmer_vm::VMExtern::Function(self.handle.internal_handle()))
679 }
680}
681
682enum InvocationResult<T, E> {
688 Success(T),
689 Exception(crate::Exception),
690 Trap(Box<E>),
691 YieldOutsideAsyncContext,
692}
693
694fn to_invocation_result<T, E>(result: Result<T, E>) -> InvocationResult<T, E>
695where
696 E: Error + 'static,
697{
698 match result {
699 Ok(value) => InvocationResult::Success(value),
700 Err(trap) => {
701 let dyn_err_ref = &trap as &dyn Error;
702 if let Some(runtime_error) = dyn_err_ref.downcast_ref::<RuntimeError>()
703 && let Some(exception) = runtime_error.to_exception()
704 {
705 return InvocationResult::Exception(exception);
706 }
707 InvocationResult::Trap(Box::new(trap))
708 }
709 }
710}
711
712fn write_dynamic_results(
713 store_id: StoreId,
714 func_ty: &FunctionType,
715 returns: Vec<Value>,
716 values_vec: *mut RawValue,
717) -> Result<(), RuntimeError> {
718 let mut store_wrapper = unsafe { StoreContext::get_current(store_id) };
719 let mut store = store_wrapper.as_mut();
720 let return_types = returns.iter().map(|ret| ret.ty());
721 if return_types.ne(func_ty.results().iter().copied()) {
722 return Err(RuntimeError::new(format!(
723 "Dynamic function returned wrong signature. Expected {:?} but got {:?}",
724 func_ty.results(),
725 returns.iter().map(|ret| ret.ty())
726 )));
727 }
728 for (i, ret) in returns.iter().enumerate() {
729 unsafe {
730 values_vec.add(i).write_unaligned(ret.as_raw(&store));
731 }
732 }
733 Ok(())
734}
735
736fn finalize_dynamic_call(
737 store_id: StoreId,
738 func_ty: FunctionType,
739 values_vec: *mut RawValue,
740 result: Result<Vec<Value>, RuntimeError>,
741) -> Result<(), RuntimeError> {
742 match result {
743 Ok(values) => write_dynamic_results(store_id, &func_ty, values, values_vec),
744 Err(err) => Err(err),
745 }
746}
747
748fn typed_args_from_values<Args>(
749 store: &mut StoreMut,
750 func_ty: &FunctionType,
751 values: &[Value],
752) -> Result<Args, RuntimeError>
753where
754 Args: WasmTypeList,
755{
756 if values.len() != func_ty.params().len() {
757 return Err(RuntimeError::new(
758 "typed host function received wrong number of parameters",
759 ));
760 }
761 let mut raw_array = Args::empty_array();
762 for ((slot, value), expected_ty) in raw_array
763 .as_mut()
764 .iter_mut()
765 .zip(values.iter())
766 .zip(func_ty.params().iter())
767 {
768 debug_assert_eq!(
769 value.ty(),
770 *expected_ty,
771 "wasm should only call host functions with matching signatures"
772 );
773 *slot = value.as_raw(store);
774 }
775 unsafe { Ok(Args::from_array(store, raw_array)) }
776}
777
778fn typed_results_to_values<Rets>(
779 store: &mut StoreMut,
780 func_ty: &FunctionType,
781 rets: Rets,
782) -> Result<Vec<Value>, RuntimeError>
783where
784 Rets: WasmTypeList,
785{
786 let mut raw_array = unsafe { rets.into_array(store) };
787 let mut values = Vec::with_capacity(func_ty.results().len());
788 for (raw, ty) in raw_array.as_mut().iter().zip(func_ty.results().iter()) {
789 unsafe {
790 values.push(Value::from_raw(store, *ty, *raw));
791 }
792 }
793 Ok(values)
794}
795
796pub(crate) enum HostCallOutcome {
797 Ready {
798 func_ty: FunctionType,
799 result: Result<Vec<Value>, RuntimeError>,
800 },
801 #[cfg(feature = "experimental-async")]
802 Future {
803 func_ty: FunctionType,
804 future: Pin<Box<dyn Future<Output = Result<Vec<Value>, RuntimeError>>>>,
805 },
806}
807
808pub(crate) struct DynamicFunction<F> {
810 func: F,
811 store_id: StoreId,
812}
813
814impl<F> DynamicFunction<F>
815where
816 F: Fn(*mut RawValue) -> HostCallOutcome + 'static,
817{
818 unsafe extern "C-unwind" fn func_wrapper(
821 this: &mut VMDynamicFunctionContext<Self>,
822 values_vec: *mut RawValue,
823 ) {
824 let result = on_host_stack(|| {
825 panic::catch_unwind(AssertUnwindSafe(|| match (this.ctx.func)(values_vec) {
826 HostCallOutcome::Ready { func_ty, result } => to_invocation_result(
827 finalize_dynamic_call(this.ctx.store_id, func_ty, values_vec, result),
828 ),
829 #[cfg(feature = "experimental-async")]
830 HostCallOutcome::Future { func_ty, future } => {
831 let awaited = block_on_host_future(future);
832 let result = match awaited {
833 Ok(value) => Ok(value),
834 Err(AsyncRuntimeError::RuntimeError(e)) => Err(e),
835 Err(AsyncRuntimeError::YieldOutsideAsyncContext) => {
836 return InvocationResult::YieldOutsideAsyncContext;
837 }
838 };
839 to_invocation_result(finalize_dynamic_call(
840 this.ctx.store_id,
841 func_ty,
842 values_vec,
843 result,
844 ))
845 }
846 }))
847 });
848
849 match result {
853 Ok(InvocationResult::Success(())) => {}
854 Ok(InvocationResult::Exception(exception)) => unsafe {
855 let mut store_wrapper = StoreContext::get_current_transient(this.ctx.store_id);
859 let mut store = store_wrapper.as_mut().unwrap();
860 wasmer_vm::libcalls::throw(
861 store.objects.as_sys(),
862 exception.vm_exceptionref().as_sys().to_u32_exnref(),
863 )
864 },
865 Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
866 Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
867 raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
868 },
869 Err(panic) => unsafe { resume_panic(panic) },
870 }
871 }
872
873 fn func_body_ptr(&self) -> VMFunctionCallback {
874 Self::func_wrapper as VMFunctionCallback
875 }
876
877 fn call_trampoline_address(&self) -> VMTrampoline {
878 Self::call_trampoline
879 }
880
881 unsafe extern "C" fn call_trampoline(
882 vmctx: *mut VMContext,
883 _body: VMFunctionCallback,
884 args: *mut RawValue,
885 ) {
886 unsafe {
889 let dynamic_function = &mut *(vmctx as *mut VMDynamicFunctionContext<Self>);
890 Self::func_wrapper(dynamic_function, args);
891 }
892 }
893}
894
895pub(crate) struct StaticFunction<F, T> {
899 pub(crate) store_id: StoreId,
900 pub(crate) env: FunctionEnv<T>,
901 pub(crate) func: F,
902}
903
904impl crate::Function {
905 pub fn into_sys(self) -> crate::backend::sys::function::Function {
907 match self.0 {
908 BackendFunction::Sys(s) => s,
909 _ => panic!("Not a `sys` function!"),
910 }
911 }
912
913 pub fn as_sys(&self) -> &crate::backend::sys::function::Function {
915 match self.0 {
916 BackendFunction::Sys(ref s) => s,
917 _ => panic!("Not a `sys` function!"),
918 }
919 }
920
921 pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::function::Function {
923 match self.0 {
924 BackendFunction::Sys(ref mut s) => s,
925 _ => panic!("Not a `sys` function!"),
926 }
927 }
928}
929
930macro_rules! impl_host_function {
931 ([$c_struct_representation:ident] $c_struct_name:ident, $( $x:ident ),* ) => {
932 paste::paste! {
933 #[allow(non_snake_case)]
934 pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower _no_env>]
935 <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, Func: Fn($( $x , )*) -> RetsAsResult + 'static>
936 (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
937 unsafe extern "C-unwind" fn func_wrapper<$( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, ()>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
941 where
942 $( $x: FromToNativeWasmType, )*
943 Rets: WasmTypeList,
944 RetsAsResult: IntoResult<Rets>,
945 Func: Fn($( $x , )*) -> RetsAsResult + 'static,
946 {
947 let result = on_host_stack(|| {
948 panic::catch_unwind(AssertUnwindSafe(|| {
949 let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) };
950 let mut store = store_wrapper.as_mut();
951 $(
952 let $x = unsafe {
953 FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
954 };
955 )*
956 to_invocation_result((env.func)($($x),* ).into_result())
957 }))
958 });
959
960 match result {
964 Ok(InvocationResult::Success(result)) => unsafe {
965 let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
969 let mut store = store_wrapper.as_mut().unwrap();
970 return result.into_c_struct(store);
971 },
972 Ok(InvocationResult::Exception(exception)) => unsafe {
973 let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
977 let mut store = store_wrapper.as_mut().unwrap();
978 wasmer_vm::libcalls::throw(
979 store.objects.as_sys(),
980 exception.vm_exceptionref().as_sys().to_u32_exnref()
981 )
982 }
983 Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
984 Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
985 raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
986 },
987 Err(panic) => unsafe { resume_panic(panic) },
988 }
989 }
990
991 func_wrapper::< $( $x, )* Rets, RetsAsResult, Func > as _
992
993 }
994
995 #[allow(non_snake_case)]
996 pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower _no_env>]
997 <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
998 () -> crate::backend::sys::vm::VMTrampoline {
999
1000 unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
1001 (
1002 vmctx: *mut crate::backend::sys::vm::VMContext,
1003 body: crate::backend::sys::vm::VMFunctionCallback,
1004 args: *mut RawValue,
1005 ) {
1006 let mut _n = 0;
1007
1008 unsafe {
1009 let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body);
1010 $(
1011 let $x = *args.add(_n).cast();
1012 _n += 1;
1013 )*
1014 let results = body(vmctx, $( $x ),*);
1015 Rets::write_c_struct_to_ptr(results, args);
1016 }
1017 }
1018
1019 call_trampoline::<$( $x, )* Rets> as _
1020
1021 }
1022
1023 #[allow(non_snake_case)]
1024 pub(crate) fn [<gen_fn_callback_ $c_struct_name:lower>]
1025 <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList, RetsAsResult: IntoResult<Rets>, T: Send + 'static, Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static>
1026 (this: &Func) -> crate::backend::sys::vm::VMFunctionCallback {
1027 unsafe extern "C-unwind" fn func_wrapper<T: Send + 'static, $( $x, )* Rets, RetsAsResult, Func>( env: &StaticFunction<Func, T>, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
1031 where
1032 $( $x: FromToNativeWasmType, )*
1033 Rets: WasmTypeList,
1034 RetsAsResult: IntoResult<Rets>,
1035 Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
1036 {
1037 let result = wasmer_vm::on_host_stack(|| {
1038 panic::catch_unwind(AssertUnwindSafe(|| {
1039 let mut store_wrapper = unsafe { StoreContext::get_current(env.store_id) };
1040 let mut store = store_wrapper.as_mut();
1041 $(
1042 let $x = unsafe {
1043 FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x))
1044 };
1045 )*
1046 let f_env = crate::backend::sys::function::env::FunctionEnvMut {
1047 store_mut: store,
1048 func_env: env.env.as_sys().clone(),
1049 }.into();
1050 to_invocation_result((env.func)(f_env, $($x),* ).into_result())
1051 }))
1052 });
1053
1054 match result {
1058 Ok(InvocationResult::Success(result)) => unsafe {
1059 let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
1063 let mut store = store_wrapper.as_mut().unwrap();
1064 return result.into_c_struct(store);
1065 },
1066 Ok(InvocationResult::Exception(exception)) => unsafe {
1067 let mut store_wrapper = StoreContext::get_current_transient(env.store_id);
1071 let mut store = store_wrapper.as_mut().unwrap();
1072 wasmer_vm::libcalls::throw(
1073 store.objects.as_sys(),
1074 exception.vm_exceptionref().as_sys().to_u32_exnref()
1075 )
1076 }
1077 Ok(InvocationResult::Trap(trap)) => unsafe { raise_user_trap(trap) },
1078 Ok(InvocationResult::YieldOutsideAsyncContext) => unsafe {
1079 raise_lib_trap(Trap::lib(TrapCode::YieldOutsideAsyncContext))
1080 },
1081 Err(panic) => unsafe { resume_panic(panic) },
1082 }
1083 }
1084 func_wrapper::< T, $( $x, )* Rets, RetsAsResult, Func > as _
1085 }
1086
1087 #[allow(non_snake_case)]
1088 pub(crate) fn [<gen_call_trampoline_address_ $c_struct_name:lower>]
1089 <$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>
1090 () -> crate::backend::sys::vm::VMTrampoline {
1091
1092 unsafe extern "C" fn call_trampoline<$( $x: FromToNativeWasmType, )* Rets: WasmTypeList>(
1093 vmctx: *mut crate::backend::sys::vm::VMContext,
1094 body: crate::backend::sys::vm::VMFunctionCallback,
1095 args: *mut RawValue,
1096 ) {
1097 unsafe {
1098 let body: unsafe extern "C" fn(vmctx: *mut crate::backend::sys::vm::VMContext, $( $x: <$x::Native as NativeWasmType>::Abi, )*) -> Rets::CStruct = std::mem::transmute(body);
1099 let mut _n = 0;
1100 $(
1101 let $x = *args.add(_n).cast();
1102 _n += 1;
1103 )*
1104
1105 let results = body(vmctx, $( $x ),*);
1106
1107 Rets::write_c_struct_to_ptr(results, args);
1108 }
1109 }
1110
1111 call_trampoline::<$( $x, )* Rets> as _
1112 }
1113 }};
1114}
1115
1116impl_host_function!([C] S0,);
1119impl_host_function!([transparent] S1, A1);
1120impl_host_function!([C] S2, A1, A2);
1121impl_host_function!([C] S3, A1, A2, A3);
1122impl_host_function!([C] S4, A1, A2, A3, A4);
1123impl_host_function!([C] S5, A1, A2, A3, A4, A5);
1124impl_host_function!([C] S6, A1, A2, A3, A4, A5, A6);
1125impl_host_function!([C] S7, A1, A2, A3, A4, A5, A6, A7);
1126impl_host_function!([C] S8, A1, A2, A3, A4, A5, A6, A7, A8);
1127impl_host_function!([C] S9, A1, A2, A3, A4, A5, A6, A7, A8, A9);
1128impl_host_function!([C] S10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
1129impl_host_function!([C] S11, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
1130impl_host_function!([C] S12, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
1131impl_host_function!([C] S13, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
1132impl_host_function!([C] S14, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
1133impl_host_function!([C] S15, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
1134impl_host_function!([C] S16, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
1135impl_host_function!([C] S17, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
1136impl_host_function!([C] S18, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18);
1137impl_host_function!([C] S19, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19);
1138impl_host_function!([C] S20, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20);
1139impl_host_function!([C] S21, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21);
1140impl_host_function!([C] S22, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22);
1141impl_host_function!([C] S23, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23);
1142impl_host_function!([C] S24, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24);
1143impl_host_function!([C] S25, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25);
1144impl_host_function!([C] S26, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26);