wasmer_vm/
libcalls.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/main/docs/ATTRIBUTIONS.md
3
4//! Runtime library calls.
5//!
6//! Note that Wasm compilers may sometimes perform these inline rather than
7//! calling them, particularly when CPUs have special instructions which compute
8//! them directly.
9//!
10//! These functions are called by compiled Wasm code, and therefore must take
11//! certain care about some things:
12//!
13//! * They must always be `pub extern "C"` and should only contain basic, raw
14//!   i32/i64/f32/f64/pointer parameters that are safe to pass across the system
15//!   ABI!
16//!
17//! * If any nested function propagates an `Err(trap)` out to the library
18//!   function frame, we need to raise it. This involves some nasty and quite
19//!   unsafe code under the covers! Notable, after raising the trap, drops
20//!   **will not** be run for local variables! This can lead to things like
21//!   leaking `VMInstance`s which leads to never deallocating JIT code,
22//!   instances, and modules! Therefore, always use nested blocks to ensure
23//!   drops run before raising a trap:
24//!
25//!   ```ignore
26//!   pub extern "C" fn my_lib_function(...) {
27//!       let result = {
28//!           // Do everything in here so drops run at the end of the block.
29//!           ...
30//!       };
31//!       if let Err(trap) = result {
32//!           // Now we can safely raise the trap without leaking!
33//!           raise_lib_trap(trap);
34//!       }
35//!   }
36//!   ```
37
38#![allow(missing_docs)] // For some reason lint fails saying that `LibCall` is not documented, when it actually is
39
40use std::{ffi::c_void, panic};
41mod eh;
42
43use crate::trap::{Trap, TrapCode, raise_lib_trap};
44use crate::vmcontext::VMContext;
45use crate::{
46    InternalStoreHandle,
47    table::{RawTableElement, TableElement},
48};
49use crate::{VMExceptionObj, probestack::PROBESTACK};
50use crate::{VMFuncRef, on_host_stack};
51pub use eh::{throw, wasmer_eh_personality};
52pub use wasmer_types::LibCall;
53use wasmer_types::{
54    DataIndex, ElemIndex, FunctionIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex, RawValue,
55    TableIndex, TagIndex, Type,
56};
57
58/// Implementation of f32.ceil
59#[unsafe(no_mangle)]
60pub extern "C" fn wasmer_vm_f32_ceil(x: f32) -> f32 {
61    x.ceil()
62}
63
64/// Implementation of f32.floor
65#[unsafe(no_mangle)]
66pub extern "C" fn wasmer_vm_f32_floor(x: f32) -> f32 {
67    x.floor()
68}
69
70/// Implementation of f32.trunc
71#[unsafe(no_mangle)]
72pub extern "C" fn wasmer_vm_f32_trunc(x: f32) -> f32 {
73    x.trunc()
74}
75
76/// Implementation of f32.nearest
77#[allow(clippy::float_arithmetic, clippy::float_cmp)]
78#[unsafe(no_mangle)]
79pub extern "C" fn wasmer_vm_f32_nearest(x: f32) -> f32 {
80    // Rust doesn't have a nearest function, so do it manually.
81    if x == 0.0 {
82        // Preserve the sign of zero.
83        x
84    } else {
85        // Nearest is either ceil or floor depending on which is nearest or even.
86        let u = x.ceil();
87        let d = x.floor();
88        let um = (x - u).abs();
89        let dm = (x - d).abs();
90        if um < dm
91            || (um == dm && {
92                let h = u / 2.;
93                h.floor() == h
94            })
95        {
96            u
97        } else {
98            d
99        }
100    }
101}
102
103/// Implementation of f64.ceil
104#[unsafe(no_mangle)]
105pub extern "C" fn wasmer_vm_f64_ceil(x: f64) -> f64 {
106    x.ceil()
107}
108
109/// Implementation of f64.floor
110#[unsafe(no_mangle)]
111pub extern "C" fn wasmer_vm_f64_floor(x: f64) -> f64 {
112    x.floor()
113}
114
115/// Implementation of f64.trunc
116#[unsafe(no_mangle)]
117pub extern "C" fn wasmer_vm_f64_trunc(x: f64) -> f64 {
118    x.trunc()
119}
120
121/// Implementation of f64.nearest
122#[allow(clippy::float_arithmetic, clippy::float_cmp)]
123#[unsafe(no_mangle)]
124pub extern "C" fn wasmer_vm_f64_nearest(x: f64) -> f64 {
125    // Rust doesn't have a nearest function, so do it manually.
126    if x == 0.0 {
127        // Preserve the sign of zero.
128        x
129    } else {
130        // Nearest is either ceil or floor depending on which is nearest or even.
131        let u = x.ceil();
132        let d = x.floor();
133        let um = (x - u).abs();
134        let dm = (x - d).abs();
135        if um < dm
136            || (um == dm && {
137                let h = u / 2.;
138                h.floor() == h
139            })
140        {
141            u
142        } else {
143            d
144        }
145    }
146}
147
148/// Implementation of memory.grow for locally-defined 32-bit memories.
149///
150/// # Safety
151///
152/// `vmctx` must be dereferenceable.
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn wasmer_vm_memory32_grow(
155    vmctx: *mut VMContext,
156    delta: u32,
157    memory_index: u32,
158) -> u32 {
159    unsafe {
160        on_host_stack(|| {
161            let instance = (*vmctx).instance_mut();
162            let memory_index = LocalMemoryIndex::from_u32(memory_index);
163
164            instance
165                .memory_grow(memory_index, delta)
166                .map(|pages| pages.0)
167                .unwrap_or(u32::MAX)
168        })
169    }
170}
171
172/// Implementation of memory.grow for imported 32-bit memories.
173///
174/// # Safety
175///
176/// `vmctx` must be dereferenceable.
177#[unsafe(no_mangle)]
178pub unsafe extern "C" fn wasmer_vm_imported_memory32_grow(
179    vmctx: *mut VMContext,
180    delta: u32,
181    memory_index: u32,
182) -> u32 {
183    unsafe {
184        on_host_stack(|| {
185            let instance = (*vmctx).instance_mut();
186            let memory_index = MemoryIndex::from_u32(memory_index);
187
188            instance
189                .imported_memory_grow(memory_index, delta)
190                .map(|pages| pages.0)
191                .unwrap_or(u32::MAX)
192        })
193    }
194}
195
196/// Implementation of memory.size for locally-defined 32-bit memories.
197///
198/// # Safety
199///
200/// `vmctx` must be dereferenceable.
201#[unsafe(no_mangle)]
202pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
203    unsafe {
204        let instance = (*vmctx).instance();
205        let memory_index = LocalMemoryIndex::from_u32(memory_index);
206
207        instance.memory_size(memory_index).0
208    }
209}
210
211/// Implementation of memory.size for imported 32-bit memories.
212///
213/// # Safety
214///
215/// `vmctx` must be dereferenceable.
216#[unsafe(no_mangle)]
217pub unsafe extern "C" fn wasmer_vm_imported_memory32_size(
218    vmctx: *mut VMContext,
219    memory_index: u32,
220) -> u32 {
221    unsafe {
222        let instance = (*vmctx).instance();
223        let memory_index = MemoryIndex::from_u32(memory_index);
224
225        instance.imported_memory_size(memory_index).0
226    }
227}
228
229/// Implementation of `table.copy`.
230///
231/// # Safety
232///
233/// `vmctx` must be dereferenceable.
234#[unsafe(no_mangle)]
235pub unsafe extern "C" fn wasmer_vm_table_copy(
236    vmctx: *mut VMContext,
237    dst_table_index: u32,
238    src_table_index: u32,
239    dst: u32,
240    src: u32,
241    len: u32,
242) {
243    unsafe {
244        let result = {
245            let dst_table_index = TableIndex::from_u32(dst_table_index);
246            let src_table_index = TableIndex::from_u32(src_table_index);
247            if dst_table_index == src_table_index {
248                let table = (*vmctx).instance_mut().get_table(dst_table_index);
249                table.copy_within(dst, src, len)
250            } else {
251                let dst_table = (*vmctx).instance_mut().get_table(dst_table_index);
252                let src_table = (*vmctx).instance_mut().get_table(src_table_index);
253                dst_table.copy(src_table, dst, src, len)
254            }
255        };
256        if let Err(trap) = result {
257            raise_lib_trap(trap);
258        }
259    }
260}
261
262/// Implementation of `table.init`.
263///
264/// # Safety
265///
266/// `vmctx` must be dereferenceable.
267#[unsafe(no_mangle)]
268pub unsafe extern "C" fn wasmer_vm_table_init(
269    vmctx: *mut VMContext,
270    table_index: u32,
271    elem_index: u32,
272    dst: u32,
273    src: u32,
274    len: u32,
275) {
276    unsafe {
277        let result = {
278            let table_index = TableIndex::from_u32(table_index);
279            let elem_index = ElemIndex::from_u32(elem_index);
280            let instance = (*vmctx).instance_mut();
281            instance.table_init(table_index, elem_index, dst, src, len)
282        };
283        if let Err(trap) = result {
284            raise_lib_trap(trap);
285        }
286    }
287}
288
289/// Implementation of `table.fill`.
290///
291/// # Safety
292///
293/// `vmctx` must be dereferenceable.
294#[unsafe(no_mangle)]
295pub unsafe extern "C" fn wasmer_vm_table_fill(
296    vmctx: *mut VMContext,
297    table_index: u32,
298    start_idx: u32,
299    item: RawTableElement,
300    len: u32,
301) {
302    unsafe {
303        let result = {
304            let table_index = TableIndex::from_u32(table_index);
305            let instance = (*vmctx).instance_mut();
306            let elem = match instance.get_table(table_index).ty().ty {
307                Type::ExternRef => TableElement::ExternRef(item.extern_ref),
308                Type::FuncRef => TableElement::FuncRef(item.func_ref),
309                _ => panic!("Unrecognized table type: does not contain references"),
310            };
311
312            instance.table_fill(table_index, start_idx, elem, len)
313        };
314        if let Err(trap) = result {
315            raise_lib_trap(trap);
316        }
317    }
318}
319
320/// Implementation of `table.size`.
321///
322/// # Safety
323///
324/// `vmctx` must be dereferenceable.
325#[unsafe(no_mangle)]
326pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
327    unsafe {
328        let instance = (*vmctx).instance();
329        let table_index = LocalTableIndex::from_u32(table_index);
330
331        instance.table_size(table_index)
332    }
333}
334
335/// Implementation of `table.size` for imported tables.
336///
337/// # Safety
338///
339/// `vmctx` must be dereferenceable.
340#[unsafe(no_mangle)]
341pub unsafe extern "C" fn wasmer_vm_imported_table_size(
342    vmctx: *mut VMContext,
343    table_index: u32,
344) -> u32 {
345    unsafe {
346        let instance = (*vmctx).instance();
347        let table_index = TableIndex::from_u32(table_index);
348
349        instance.imported_table_size(table_index)
350    }
351}
352
353/// Implementation of `table.get`.
354///
355/// # Safety
356///
357/// `vmctx` must be dereferenceable.
358#[unsafe(no_mangle)]
359pub unsafe extern "C" fn wasmer_vm_table_get(
360    vmctx: *mut VMContext,
361    table_index: u32,
362    elem_index: u32,
363) -> RawTableElement {
364    unsafe {
365        let instance = (*vmctx).instance();
366        let table_index = LocalTableIndex::from_u32(table_index);
367
368        // TODO: type checking, maybe have specialized accessors
369        match instance.table_get(table_index, elem_index) {
370            Some(table_ref) => table_ref.into(),
371            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
372        }
373    }
374}
375
376/// Implementation of `table.get` for imported tables.
377///
378/// # Safety
379///
380/// `vmctx` must be dereferenceable.
381#[unsafe(no_mangle)]
382pub unsafe extern "C" fn wasmer_vm_imported_table_get(
383    vmctx: *mut VMContext,
384    table_index: u32,
385    elem_index: u32,
386) -> RawTableElement {
387    unsafe {
388        let instance = (*vmctx).instance_mut();
389        let table_index = TableIndex::from_u32(table_index);
390
391        // TODO: type checking, maybe have specialized accessors
392        match instance.imported_table_get(table_index, elem_index) {
393            Some(table_ref) => table_ref.into(),
394            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
395        }
396    }
397}
398
399/// Implementation of `table.set`.
400///
401/// # Safety
402///
403/// `vmctx` must be dereferenceable.
404///
405/// It is the caller's responsibility to increment the ref count of any ref counted
406/// type before passing it to this function.
407#[unsafe(no_mangle)]
408pub unsafe extern "C" fn wasmer_vm_table_set(
409    vmctx: *mut VMContext,
410    table_index: u32,
411    elem_index: u32,
412    value: RawTableElement,
413) {
414    unsafe {
415        let instance = (*vmctx).instance_mut();
416        let table_index = TableIndex::from_u32(table_index);
417        let table_index = instance
418            .module_ref()
419            .local_table_index(table_index)
420            .unwrap();
421
422        let elem = match instance.get_local_table(table_index).ty().ty {
423            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
424            Type::FuncRef => TableElement::FuncRef(value.func_ref),
425            _ => panic!("Unrecognized table type: does not contain references"),
426        };
427
428        // TODO: type checking, maybe have specialized accessors
429        let result = instance.table_set(table_index, elem_index, elem);
430
431        if let Err(trap) = result {
432            raise_lib_trap(trap);
433        }
434    }
435}
436
437/// Implementation of `table.set` for imported tables.
438///
439/// # Safety
440///
441/// `vmctx` must be dereferenceable.
442#[unsafe(no_mangle)]
443pub unsafe extern "C" fn wasmer_vm_imported_table_set(
444    vmctx: *mut VMContext,
445    table_index: u32,
446    elem_index: u32,
447    value: RawTableElement,
448) {
449    unsafe {
450        let instance = (*vmctx).instance_mut();
451        let table_index = TableIndex::from_u32(table_index);
452        let elem = match instance.get_table(table_index).ty().ty {
453            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
454            Type::FuncRef => TableElement::FuncRef(value.func_ref),
455            _ => panic!("Unrecognized table type: does not contain references"),
456        };
457
458        let result = instance.imported_table_set(table_index, elem_index, elem);
459
460        if let Err(trap) = result {
461            raise_lib_trap(trap);
462        }
463    }
464}
465
466/// Implementation of `table.grow` for locally-defined tables.
467///
468/// # Safety
469///
470/// `vmctx` must be dereferenceable.
471#[unsafe(no_mangle)]
472pub unsafe extern "C" fn wasmer_vm_table_grow(
473    vmctx: *mut VMContext,
474    init_value: RawTableElement,
475    delta: u32,
476    table_index: u32,
477) -> u32 {
478    unsafe {
479        on_host_stack(|| {
480            let instance = (*vmctx).instance_mut();
481            let table_index = LocalTableIndex::from_u32(table_index);
482
483            let init_value = match instance.get_local_table(table_index).ty().ty {
484                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
485                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
486                _ => panic!("Unrecognized table type: does not contain references"),
487            };
488
489            instance
490                .table_grow(table_index, delta, init_value)
491                .unwrap_or(u32::MAX)
492        })
493    }
494}
495
496/// Implementation of `table.grow` for imported tables.
497///
498/// # Safety
499///
500/// `vmctx` must be dereferenceable.
501#[unsafe(no_mangle)]
502pub unsafe extern "C" fn wasmer_vm_imported_table_grow(
503    vmctx: *mut VMContext,
504    init_value: RawTableElement,
505    delta: u32,
506    table_index: u32,
507) -> u32 {
508    unsafe {
509        on_host_stack(|| {
510            let instance = (*vmctx).instance_mut();
511            let table_index = TableIndex::from_u32(table_index);
512            let init_value = match instance.get_table(table_index).ty().ty {
513                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
514                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
515                _ => panic!("Unrecognized table type: does not contain references"),
516            };
517
518            instance
519                .imported_table_grow(table_index, delta, init_value)
520                .unwrap_or(u32::MAX)
521        })
522    }
523}
524
525/// Implementation of `func.ref`.
526///
527/// # Safety
528///
529/// `vmctx` must be dereferenceable.
530#[unsafe(no_mangle)]
531pub unsafe extern "C" fn wasmer_vm_func_ref(
532    vmctx: *mut VMContext,
533    function_index: u32,
534) -> VMFuncRef {
535    unsafe {
536        let instance = (*vmctx).instance();
537        let function_index = FunctionIndex::from_u32(function_index);
538
539        instance.func_ref(function_index).unwrap()
540    }
541}
542
543/// Implementation of `elem.drop`.
544///
545/// # Safety
546///
547/// `vmctx` must be dereferenceable.
548#[unsafe(no_mangle)]
549pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
550    unsafe {
551        on_host_stack(|| {
552            let elem_index = ElemIndex::from_u32(elem_index);
553            let instance = (*vmctx).instance();
554            instance.elem_drop(elem_index);
555        })
556    }
557}
558
559/// Implementation of `memory.copy` for locally defined memories.
560///
561/// # Safety
562///
563/// `vmctx` must be dereferenceable.
564#[unsafe(no_mangle)]
565pub unsafe extern "C" fn wasmer_vm_memory32_copy(
566    vmctx: *mut VMContext,
567    memory_index: u32,
568    dst: u32,
569    src: u32,
570    len: u32,
571) {
572    unsafe {
573        let result = {
574            let memory_index = LocalMemoryIndex::from_u32(memory_index);
575            let instance = (*vmctx).instance();
576            instance.local_memory_copy(memory_index, dst, src, len)
577        };
578        if let Err(trap) = result {
579            raise_lib_trap(trap);
580        }
581    }
582}
583
584/// Implementation of `memory.copy` for imported memories.
585///
586/// # Safety
587///
588/// `vmctx` must be dereferenceable.
589#[unsafe(no_mangle)]
590pub unsafe extern "C" fn wasmer_vm_imported_memory32_copy(
591    vmctx: *mut VMContext,
592    memory_index: u32,
593    dst: u32,
594    src: u32,
595    len: u32,
596) {
597    unsafe {
598        let result = {
599            let memory_index = MemoryIndex::from_u32(memory_index);
600            let instance = (*vmctx).instance();
601            instance.imported_memory_copy(memory_index, dst, src, len)
602        };
603        if let Err(trap) = result {
604            raise_lib_trap(trap);
605        }
606    }
607}
608
609/// Implementation of `memory.fill` for locally defined memories.
610///
611/// # Safety
612///
613/// `vmctx` must be dereferenceable.
614#[unsafe(no_mangle)]
615pub unsafe extern "C" fn wasmer_vm_memory32_fill(
616    vmctx: *mut VMContext,
617    memory_index: u32,
618    dst: u32,
619    val: u32,
620    len: u32,
621) {
622    unsafe {
623        let result = {
624            let memory_index = LocalMemoryIndex::from_u32(memory_index);
625            let instance = (*vmctx).instance();
626            instance.local_memory_fill(memory_index, dst, val, len)
627        };
628        if let Err(trap) = result {
629            raise_lib_trap(trap);
630        }
631    }
632}
633
634/// Implementation of `memory.fill` for imported memories.
635///
636/// # Safety
637///
638/// `vmctx` must be dereferenceable.
639#[unsafe(no_mangle)]
640pub unsafe extern "C" fn wasmer_vm_imported_memory32_fill(
641    vmctx: *mut VMContext,
642    memory_index: u32,
643    dst: u32,
644    val: u32,
645    len: u32,
646) {
647    unsafe {
648        let result = {
649            let memory_index = MemoryIndex::from_u32(memory_index);
650            let instance = (*vmctx).instance();
651            instance.imported_memory_fill(memory_index, dst, val, len)
652        };
653        if let Err(trap) = result {
654            raise_lib_trap(trap);
655        }
656    }
657}
658
659/// Implementation of `memory.init`.
660///
661/// # Safety
662///
663/// `vmctx` must be dereferenceable.
664#[unsafe(no_mangle)]
665pub unsafe extern "C" fn wasmer_vm_memory32_init(
666    vmctx: *mut VMContext,
667    memory_index: u32,
668    data_index: u32,
669    dst: u32,
670    src: u32,
671    len: u32,
672) {
673    unsafe {
674        let result = {
675            let memory_index = MemoryIndex::from_u32(memory_index);
676            let data_index = DataIndex::from_u32(data_index);
677            let instance = (*vmctx).instance();
678            instance.memory_init(memory_index, data_index, dst, src, len)
679        };
680        if let Err(trap) = result {
681            raise_lib_trap(trap);
682        }
683    }
684}
685
686/// Implementation of `data.drop`.
687///
688/// # Safety
689///
690/// `vmctx` must be dereferenceable.
691#[unsafe(no_mangle)]
692pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
693    unsafe {
694        on_host_stack(|| {
695            let data_index = DataIndex::from_u32(data_index);
696            let instance = (*vmctx).instance();
697            instance.data_drop(data_index)
698        })
699    }
700}
701
702/// Implementation for raising a trap
703///
704/// # Safety
705///
706/// Only safe to call when wasm code is on the stack, aka `wasmer_call` or
707/// `wasmer_call_trampoline` must have been previously called.
708#[unsafe(no_mangle)]
709pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! {
710    unsafe {
711        let trap = Trap::lib(trap_code);
712        raise_lib_trap(trap)
713    }
714}
715
716/// (debug) Print an usize.
717#[unsafe(no_mangle)]
718pub extern "C-unwind" fn wasmer_vm_dbg_usize(value: usize) {
719    #[allow(clippy::print_stdout)]
720    {
721        println!("wasmer_vm_dbg_usize: {value}");
722    }
723}
724
725/// (debug) Print a string.
726#[unsafe(no_mangle)]
727pub extern "C-unwind" fn wasmer_vm_dbg_str(ptr: usize, len: u32) {
728    #[allow(clippy::print_stdout)]
729    unsafe {
730        let str = std::str::from_utf8(std::slice::from_raw_parts(ptr as _, len as _))
731            .unwrap_or("wasmer_vm_dbg_str failed");
732        eprintln!("{str}");
733    }
734}
735
736/// Implementation for throwing an exception.
737///
738/// # Safety
739///
740/// Calls libunwind to perform unwinding magic.
741#[unsafe(no_mangle)]
742pub unsafe extern "C-unwind" fn wasmer_vm_throw(vmctx: *mut VMContext, exnref: u32) -> ! {
743    let instance = unsafe { (*vmctx).instance() };
744    unsafe { eh::throw(instance.context(), exnref) }
745}
746
747/// Implementation for allocating an exception. Returns the exnref, i.e. a handle to the
748/// exception within the store.
749///
750/// # Safety
751///
752/// The vmctx pointer must be dereferenceable.
753#[unsafe(no_mangle)]
754pub unsafe extern "C-unwind" fn wasmer_vm_alloc_exception(vmctx: *mut VMContext, tag: u32) -> u32 {
755    let instance = unsafe { (*vmctx).instance_mut() };
756    let unique_tag = instance.shared_tag_ptr(TagIndex::from_u32(tag)).index();
757    let exn = VMExceptionObj::new_zeroed(
758        instance.context(),
759        InternalStoreHandle::from_index(unique_tag as usize).unwrap(),
760    );
761    let exnref = InternalStoreHandle::new(instance.context_mut(), exn);
762    exnref.index() as u32
763}
764
765/// Given a VMContext and an exnref (handle to an exception within the store),
766/// returns a pointer to the payload buffer of the underlying VMExceptionObj.
767#[unsafe(no_mangle)]
768pub extern "C-unwind" fn wasmer_vm_read_exnref(
769    vmctx: *mut VMContext,
770    exnref: u32,
771) -> *mut RawValue {
772    let exn = eh::exn_obj_from_exnref(vmctx, exnref);
773    unsafe { (*exn).payload().as_ptr() as *mut RawValue }
774}
775
776/// Given a pointer to a caught exception, return the exnref contained within.
777///
778/// # Safety
779///
780/// `exception` must be a pointer the platform-specific exception type; this is
781/// `UwExceptionWrapper` for gcc.
782#[unsafe(no_mangle)]
783pub unsafe extern "C-unwind" fn wasmer_vm_exception_into_exnref(exception: *mut c_void) -> u32 {
784    unsafe {
785        let exnref = eh::read_exnref(exception);
786        eh::delete_exception(exception);
787        exnref
788    }
789}
790
791/// Probestack check
792///
793/// # Safety
794///
795/// This function does not follow the standard function ABI, and is called as
796/// part of the function prologue.
797#[unsafe(no_mangle)]
798pub static WASMER_VM_PROBESTACK: unsafe extern "C" fn() = PROBESTACK;
799
800/// Implementation of memory.wait32 for locally-defined 32-bit memories.
801///
802/// # Safety
803///
804/// `vmctx` must be dereferenceable.
805#[unsafe(no_mangle)]
806pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait32(
807    vmctx: *mut VMContext,
808    memory_index: u32,
809    dst: u32,
810    val: u32,
811    timeout: i64,
812) -> u32 {
813    unsafe {
814        let result = {
815            let instance = (*vmctx).instance_mut();
816            let memory_index = LocalMemoryIndex::from_u32(memory_index);
817
818            instance.local_memory_wait32(memory_index, dst, val, timeout)
819        };
820        if let Err(trap) = result {
821            raise_lib_trap(trap);
822        }
823        result.unwrap()
824    }
825}
826
827/// Implementation of memory.wait32 for imported 32-bit memories.
828///
829/// # Safety
830///
831/// `vmctx` must be dereferenceable.
832#[unsafe(no_mangle)]
833pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait32(
834    vmctx: *mut VMContext,
835    memory_index: u32,
836    dst: u32,
837    val: u32,
838    timeout: i64,
839) -> u32 {
840    unsafe {
841        let result = {
842            let instance = (*vmctx).instance_mut();
843            let memory_index = MemoryIndex::from_u32(memory_index);
844
845            instance.imported_memory_wait32(memory_index, dst, val, timeout)
846        };
847        if let Err(trap) = result {
848            raise_lib_trap(trap);
849        }
850        result.unwrap()
851    }
852}
853
854/// Implementation of memory.wait64 for locally-defined 32-bit memories.
855///
856/// # Safety
857///
858/// `vmctx` must be dereferenceable.
859#[unsafe(no_mangle)]
860pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait64(
861    vmctx: *mut VMContext,
862    memory_index: u32,
863    dst: u32,
864    val: u64,
865    timeout: i64,
866) -> u32 {
867    unsafe {
868        let result = {
869            let instance = (*vmctx).instance_mut();
870            let memory_index = LocalMemoryIndex::from_u32(memory_index);
871
872            instance.local_memory_wait64(memory_index, dst, val, timeout)
873        };
874        if let Err(trap) = result {
875            raise_lib_trap(trap);
876        }
877        result.unwrap()
878    }
879}
880
881/// Implementation of memory.wait64 for imported 32-bit memories.
882///
883/// # Safety
884///
885/// `vmctx` must be dereferenceable.
886#[unsafe(no_mangle)]
887pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait64(
888    vmctx: *mut VMContext,
889    memory_index: u32,
890    dst: u32,
891    val: u64,
892    timeout: i64,
893) -> u32 {
894    unsafe {
895        let result = {
896            let instance = (*vmctx).instance_mut();
897            let memory_index = MemoryIndex::from_u32(memory_index);
898
899            instance.imported_memory_wait64(memory_index, dst, val, timeout)
900        };
901        if let Err(trap) = result {
902            raise_lib_trap(trap);
903        }
904        result.unwrap()
905    }
906}
907
908/// Implementation of memory.notfy for locally-defined 32-bit memories.
909///
910/// # Safety
911///
912/// `vmctx` must be dereferenceable.
913#[unsafe(no_mangle)]
914pub unsafe extern "C" fn wasmer_vm_memory32_atomic_notify(
915    vmctx: *mut VMContext,
916    memory_index: u32,
917    dst: u32,
918    cnt: u32,
919) -> u32 {
920    unsafe {
921        let result = {
922            let instance = (*vmctx).instance_mut();
923            let memory_index = LocalMemoryIndex::from_u32(memory_index);
924
925            instance.local_memory_notify(memory_index, dst, cnt)
926        };
927        if let Err(trap) = result {
928            raise_lib_trap(trap);
929        }
930        result.unwrap()
931    }
932}
933
934/// Implementation of memory.notfy for imported 32-bit memories.
935///
936/// # Safety
937///
938/// `vmctx` must be dereferenceable.
939#[unsafe(no_mangle)]
940pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_notify(
941    vmctx: *mut VMContext,
942    memory_index: u32,
943    dst: u32,
944    cnt: u32,
945) -> u32 {
946    unsafe {
947        let result = {
948            let instance = (*vmctx).instance_mut();
949            let memory_index = MemoryIndex::from_u32(memory_index);
950
951            instance.imported_memory_notify(memory_index, dst, cnt)
952        };
953        if let Err(trap) = result {
954            raise_lib_trap(trap);
955        }
956        result.unwrap()
957    }
958}
959
960/// The function pointer to a libcall
961pub fn function_pointer(libcall: LibCall) -> usize {
962    match libcall {
963        LibCall::CeilF32 => wasmer_vm_f32_ceil as usize,
964        LibCall::CeilF64 => wasmer_vm_f64_ceil as usize,
965        LibCall::FloorF32 => wasmer_vm_f32_floor as usize,
966        LibCall::FloorF64 => wasmer_vm_f64_floor as usize,
967        LibCall::NearestF32 => wasmer_vm_f32_nearest as usize,
968        LibCall::NearestF64 => wasmer_vm_f64_nearest as usize,
969        LibCall::TruncF32 => wasmer_vm_f32_trunc as usize,
970        LibCall::TruncF64 => wasmer_vm_f64_trunc as usize,
971        LibCall::Memory32Size => wasmer_vm_memory32_size as usize,
972        LibCall::ImportedMemory32Size => wasmer_vm_imported_memory32_size as usize,
973        LibCall::TableCopy => wasmer_vm_table_copy as usize,
974        LibCall::TableInit => wasmer_vm_table_init as usize,
975        LibCall::TableFill => wasmer_vm_table_fill as usize,
976        LibCall::TableSize => wasmer_vm_table_size as usize,
977        LibCall::ImportedTableSize => wasmer_vm_imported_table_size as usize,
978        LibCall::TableGet => wasmer_vm_table_get as usize,
979        LibCall::ImportedTableGet => wasmer_vm_imported_table_get as usize,
980        LibCall::TableSet => wasmer_vm_table_set as usize,
981        LibCall::ImportedTableSet => wasmer_vm_imported_table_set as usize,
982        LibCall::TableGrow => wasmer_vm_table_grow as usize,
983        LibCall::ImportedTableGrow => wasmer_vm_imported_table_grow as usize,
984        LibCall::FuncRef => wasmer_vm_func_ref as usize,
985        LibCall::ElemDrop => wasmer_vm_elem_drop as usize,
986        LibCall::Memory32Copy => wasmer_vm_memory32_copy as usize,
987        LibCall::ImportedMemory32Copy => wasmer_vm_imported_memory32_copy as usize,
988        LibCall::Memory32Fill => wasmer_vm_memory32_fill as usize,
989        LibCall::ImportedMemory32Fill => wasmer_vm_imported_memory32_fill as usize,
990        LibCall::Memory32Init => wasmer_vm_memory32_init as usize,
991        LibCall::DataDrop => wasmer_vm_data_drop as usize,
992        LibCall::Probestack => WASMER_VM_PROBESTACK as usize,
993        LibCall::RaiseTrap => wasmer_vm_raise_trap as usize,
994        LibCall::Memory32AtomicWait32 => wasmer_vm_memory32_atomic_wait32 as usize,
995        LibCall::ImportedMemory32AtomicWait32 => wasmer_vm_imported_memory32_atomic_wait32 as usize,
996        LibCall::Memory32AtomicWait64 => wasmer_vm_memory32_atomic_wait64 as usize,
997        LibCall::ImportedMemory32AtomicWait64 => wasmer_vm_imported_memory32_atomic_wait64 as usize,
998        LibCall::Memory32AtomicNotify => wasmer_vm_memory32_atomic_notify as usize,
999        LibCall::ImportedMemory32AtomicNotify => wasmer_vm_imported_memory32_atomic_notify as usize,
1000        LibCall::Throw => wasmer_vm_throw as usize,
1001        LibCall::EHPersonality => eh::wasmer_eh_personality as usize,
1002        LibCall::EHPersonality2 => eh::wasmer_eh_personality2 as usize,
1003        LibCall::AllocException => wasmer_vm_alloc_exception as usize,
1004        LibCall::ReadExnRef => wasmer_vm_read_exnref as usize,
1005        LibCall::LibunwindExceptionIntoExnRef => wasmer_vm_exception_into_exnref as usize,
1006        LibCall::DebugUsize => wasmer_vm_dbg_usize as usize,
1007        LibCall::DebugStr => wasmer_vm_dbg_str as usize,
1008    }
1009}