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, wasmer_eh_personality2};
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_or(u32::MAX, |pages| pages.0)
167        })
168    }
169}
170
171/// Implementation of memory.grow for imported 32-bit memories.
172///
173/// # Safety
174///
175/// `vmctx` must be dereferenceable.
176#[unsafe(no_mangle)]
177pub unsafe extern "C" fn wasmer_vm_imported_memory32_grow(
178    vmctx: *mut VMContext,
179    delta: u32,
180    memory_index: u32,
181) -> u32 {
182    unsafe {
183        on_host_stack(|| {
184            let instance = (*vmctx).instance_mut();
185            let memory_index = MemoryIndex::from_u32(memory_index);
186
187            instance
188                .imported_memory_grow(memory_index, delta)
189                .map_or(u32::MAX, |pages| pages.0)
190        })
191    }
192}
193
194/// Implementation of memory.size for locally-defined 32-bit memories.
195///
196/// # Safety
197///
198/// `vmctx` must be dereferenceable.
199#[unsafe(no_mangle)]
200pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
201    unsafe {
202        let instance = (*vmctx).instance();
203        let memory_index = LocalMemoryIndex::from_u32(memory_index);
204
205        instance.memory_size(memory_index).0
206    }
207}
208
209/// Implementation of memory.size for imported 32-bit memories.
210///
211/// # Safety
212///
213/// `vmctx` must be dereferenceable.
214#[unsafe(no_mangle)]
215pub unsafe extern "C" fn wasmer_vm_imported_memory32_size(
216    vmctx: *mut VMContext,
217    memory_index: u32,
218) -> u32 {
219    unsafe {
220        let instance = (*vmctx).instance();
221        let memory_index = MemoryIndex::from_u32(memory_index);
222
223        instance.imported_memory_size(memory_index).0
224    }
225}
226
227/// Implementation of `table.copy`.
228///
229/// # Safety
230///
231/// `vmctx` must be dereferenceable.
232#[unsafe(no_mangle)]
233pub unsafe extern "C" fn wasmer_vm_table_copy(
234    vmctx: *mut VMContext,
235    dst_table_index: u32,
236    src_table_index: u32,
237    dst: u32,
238    src: u32,
239    len: u32,
240) {
241    unsafe {
242        let result = {
243            let dst_table_index = TableIndex::from_u32(dst_table_index);
244            let src_table_index = TableIndex::from_u32(src_table_index);
245            (*vmctx)
246                .instance_mut()
247                .table_copy(dst_table_index, src_table_index, dst, src, len)
248        };
249        if let Err(trap) = result {
250            raise_lib_trap(trap);
251        }
252    }
253}
254
255/// Implementation of `table.init`.
256///
257/// # Safety
258///
259/// `vmctx` must be dereferenceable.
260#[unsafe(no_mangle)]
261pub unsafe extern "C" fn wasmer_vm_table_init(
262    vmctx: *mut VMContext,
263    table_index: u32,
264    elem_index: u32,
265    dst: u32,
266    src: u32,
267    len: u32,
268) {
269    unsafe {
270        let result = {
271            let table_index = TableIndex::from_u32(table_index);
272            let elem_index = ElemIndex::from_u32(elem_index);
273            let instance = (*vmctx).instance_mut();
274            instance.table_init(table_index, elem_index, dst, src, len)
275        };
276        if let Err(trap) = result {
277            raise_lib_trap(trap);
278        }
279    }
280}
281
282/// Implementation of `table.fill`.
283///
284/// # Safety
285///
286/// `vmctx` must be dereferenceable.
287#[unsafe(no_mangle)]
288pub unsafe extern "C" fn wasmer_vm_table_fill(
289    vmctx: *mut VMContext,
290    table_index: u32,
291    start_idx: u32,
292    item: RawTableElement,
293    len: u32,
294) {
295    unsafe {
296        let result = {
297            let table_index = TableIndex::from_u32(table_index);
298            let instance = (*vmctx).instance_mut();
299            let elem = match instance.get_table(table_index).ty().ty {
300                Type::ExternRef => TableElement::ExternRef(item.extern_ref),
301                Type::FuncRef => TableElement::FuncRef(item.func_ref),
302                _ => panic!("Unrecognized table type: does not contain references"),
303            };
304
305            instance.table_fill(table_index, start_idx, elem, len)
306        };
307        if let Err(trap) = result {
308            raise_lib_trap(trap);
309        }
310    }
311}
312
313/// Implementation of `table.size`.
314///
315/// # Safety
316///
317/// `vmctx` must be dereferenceable.
318#[unsafe(no_mangle)]
319pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
320    unsafe {
321        let instance = (*vmctx).instance();
322        let table_index = LocalTableIndex::from_u32(table_index);
323
324        instance.table_size(table_index)
325    }
326}
327
328/// Implementation of `table.size` for imported tables.
329///
330/// # Safety
331///
332/// `vmctx` must be dereferenceable.
333#[unsafe(no_mangle)]
334pub unsafe extern "C" fn wasmer_vm_imported_table_size(
335    vmctx: *mut VMContext,
336    table_index: u32,
337) -> u32 {
338    unsafe {
339        let instance = (*vmctx).instance();
340        let table_index = TableIndex::from_u32(table_index);
341
342        instance.imported_table_size(table_index)
343    }
344}
345
346/// Implementation of `table.get`.
347///
348/// # Safety
349///
350/// `vmctx` must be dereferenceable.
351#[unsafe(no_mangle)]
352pub unsafe extern "C" fn wasmer_vm_table_get(
353    vmctx: *mut VMContext,
354    table_index: u32,
355    elem_index: u32,
356) -> RawTableElement {
357    unsafe {
358        let instance = (*vmctx).instance();
359        let table_index = LocalTableIndex::from_u32(table_index);
360
361        // TODO: type checking, maybe have specialized accessors
362        match instance.table_get(table_index, elem_index) {
363            Some(table_ref) => table_ref.into(),
364            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
365        }
366    }
367}
368
369/// Implementation of `table.get` for imported tables.
370///
371/// # Safety
372///
373/// `vmctx` must be dereferenceable.
374#[unsafe(no_mangle)]
375pub unsafe extern "C" fn wasmer_vm_imported_table_get(
376    vmctx: *mut VMContext,
377    table_index: u32,
378    elem_index: u32,
379) -> RawTableElement {
380    unsafe {
381        let instance = (*vmctx).instance_mut();
382        let table_index = TableIndex::from_u32(table_index);
383
384        // TODO: type checking, maybe have specialized accessors
385        match instance.imported_table_get(table_index, elem_index) {
386            Some(table_ref) => table_ref.into(),
387            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
388        }
389    }
390}
391
392/// Implementation of `table.set`.
393///
394/// # Safety
395///
396/// `vmctx` must be dereferenceable.
397///
398/// It is the caller's responsibility to increment the ref count of any ref counted
399/// type before passing it to this function.
400#[unsafe(no_mangle)]
401pub unsafe extern "C" fn wasmer_vm_table_set(
402    vmctx: *mut VMContext,
403    table_index: u32,
404    elem_index: u32,
405    value: RawTableElement,
406) {
407    unsafe {
408        let instance = (*vmctx).instance_mut();
409        let table_index = TableIndex::from_u32(table_index);
410        let table_index = instance
411            .module_ref()
412            .local_table_index(table_index)
413            .unwrap();
414
415        let elem = match instance.get_local_table(table_index).ty().ty {
416            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
417            Type::FuncRef => TableElement::FuncRef(value.func_ref),
418            _ => panic!("Unrecognized table type: does not contain references"),
419        };
420
421        // TODO: type checking, maybe have specialized accessors
422        let result = instance.table_set(table_index, elem_index, elem);
423
424        if let Err(trap) = result {
425            raise_lib_trap(trap);
426        }
427    }
428}
429
430/// Implementation of `table.set` for imported tables.
431///
432/// # Safety
433///
434/// `vmctx` must be dereferenceable.
435#[unsafe(no_mangle)]
436pub unsafe extern "C" fn wasmer_vm_imported_table_set(
437    vmctx: *mut VMContext,
438    table_index: u32,
439    elem_index: u32,
440    value: RawTableElement,
441) {
442    unsafe {
443        let instance = (*vmctx).instance_mut();
444        let table_index = TableIndex::from_u32(table_index);
445        let elem = match instance.get_table(table_index).ty().ty {
446            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
447            Type::FuncRef => TableElement::FuncRef(value.func_ref),
448            _ => panic!("Unrecognized table type: does not contain references"),
449        };
450
451        let result = instance.imported_table_set(table_index, elem_index, elem);
452
453        if let Err(trap) = result {
454            raise_lib_trap(trap);
455        }
456    }
457}
458
459/// Implementation of `table.grow` for locally-defined tables.
460///
461/// # Safety
462///
463/// `vmctx` must be dereferenceable.
464#[unsafe(no_mangle)]
465pub unsafe extern "C" fn wasmer_vm_table_grow(
466    vmctx: *mut VMContext,
467    init_value: RawTableElement,
468    delta: u32,
469    table_index: u32,
470) -> u32 {
471    unsafe {
472        on_host_stack(|| {
473            let instance = (*vmctx).instance_mut();
474            let table_index = LocalTableIndex::from_u32(table_index);
475
476            let init_value = match instance.get_local_table(table_index).ty().ty {
477                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
478                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
479                _ => panic!("Unrecognized table type: does not contain references"),
480            };
481
482            instance
483                .table_grow(table_index, delta, init_value)
484                .unwrap_or(u32::MAX)
485        })
486    }
487}
488
489/// Implementation of `table.grow` for imported tables.
490///
491/// # Safety
492///
493/// `vmctx` must be dereferenceable.
494#[unsafe(no_mangle)]
495pub unsafe extern "C" fn wasmer_vm_imported_table_grow(
496    vmctx: *mut VMContext,
497    init_value: RawTableElement,
498    delta: u32,
499    table_index: u32,
500) -> u32 {
501    unsafe {
502        on_host_stack(|| {
503            let instance = (*vmctx).instance_mut();
504            let table_index = TableIndex::from_u32(table_index);
505            let init_value = match instance.get_table(table_index).ty().ty {
506                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
507                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
508                _ => panic!("Unrecognized table type: does not contain references"),
509            };
510
511            instance
512                .imported_table_grow(table_index, delta, init_value)
513                .unwrap_or(u32::MAX)
514        })
515    }
516}
517
518/// Implementation of `func.ref`.
519///
520/// # Safety
521///
522/// `vmctx` must be dereferenceable.
523#[unsafe(no_mangle)]
524pub unsafe extern "C" fn wasmer_vm_func_ref(
525    vmctx: *mut VMContext,
526    function_index: u32,
527) -> VMFuncRef {
528    unsafe {
529        let instance = (*vmctx).instance();
530        let function_index = FunctionIndex::from_u32(function_index);
531
532        instance.func_ref(function_index).unwrap()
533    }
534}
535
536/// Implementation of `elem.drop`.
537///
538/// # Safety
539///
540/// `vmctx` must be dereferenceable.
541#[unsafe(no_mangle)]
542pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
543    unsafe {
544        on_host_stack(|| {
545            let elem_index = ElemIndex::from_u32(elem_index);
546            let instance = (*vmctx).instance();
547            instance.elem_drop(elem_index);
548        })
549    }
550}
551
552/// Implementation of `memory.copy` for locally defined memories.
553///
554/// # Safety
555///
556/// `vmctx` must be dereferenceable.
557#[unsafe(no_mangle)]
558pub unsafe extern "C" fn wasmer_vm_memory32_copy(
559    vmctx: *mut VMContext,
560    memory_index: u32,
561    dst: u32,
562    src: u32,
563    len: u32,
564) {
565    unsafe {
566        let result = {
567            let memory_index = LocalMemoryIndex::from_u32(memory_index);
568            let instance = (*vmctx).instance();
569            instance.local_memory_copy(memory_index, dst, src, len)
570        };
571        if let Err(trap) = result {
572            raise_lib_trap(trap);
573        }
574    }
575}
576
577/// Implementation of `memory.copy` for imported memories.
578///
579/// # Safety
580///
581/// `vmctx` must be dereferenceable.
582#[unsafe(no_mangle)]
583pub unsafe extern "C" fn wasmer_vm_imported_memory32_copy(
584    vmctx: *mut VMContext,
585    memory_index: u32,
586    dst: u32,
587    src: u32,
588    len: u32,
589) {
590    unsafe {
591        let result = {
592            let memory_index = MemoryIndex::from_u32(memory_index);
593            let instance = (*vmctx).instance();
594            instance.imported_memory_copy(memory_index, dst, src, len)
595        };
596        if let Err(trap) = result {
597            raise_lib_trap(trap);
598        }
599    }
600}
601
602/// Implementation of `memory.fill` for locally defined memories.
603///
604/// # Safety
605///
606/// `vmctx` must be dereferenceable.
607#[unsafe(no_mangle)]
608pub unsafe extern "C" fn wasmer_vm_memory32_fill(
609    vmctx: *mut VMContext,
610    memory_index: u32,
611    dst: u32,
612    val: u32,
613    len: u32,
614) {
615    unsafe {
616        let result = {
617            let memory_index = LocalMemoryIndex::from_u32(memory_index);
618            let instance = (*vmctx).instance();
619            instance.local_memory_fill(memory_index, dst, val, len)
620        };
621        if let Err(trap) = result {
622            raise_lib_trap(trap);
623        }
624    }
625}
626
627/// Implementation of `memory.fill` for imported memories.
628///
629/// # Safety
630///
631/// `vmctx` must be dereferenceable.
632#[unsafe(no_mangle)]
633pub unsafe extern "C" fn wasmer_vm_imported_memory32_fill(
634    vmctx: *mut VMContext,
635    memory_index: u32,
636    dst: u32,
637    val: u32,
638    len: u32,
639) {
640    unsafe {
641        let result = {
642            let memory_index = MemoryIndex::from_u32(memory_index);
643            let instance = (*vmctx).instance();
644            instance.imported_memory_fill(memory_index, dst, val, len)
645        };
646        if let Err(trap) = result {
647            raise_lib_trap(trap);
648        }
649    }
650}
651
652/// Implementation of `memory.init`.
653///
654/// # Safety
655///
656/// `vmctx` must be dereferenceable.
657#[unsafe(no_mangle)]
658pub unsafe extern "C" fn wasmer_vm_memory32_init(
659    vmctx: *mut VMContext,
660    memory_index: u32,
661    data_index: u32,
662    dst: u32,
663    src: u32,
664    len: u32,
665) {
666    unsafe {
667        let result = {
668            let memory_index = MemoryIndex::from_u32(memory_index);
669            let data_index = DataIndex::from_u32(data_index);
670            let instance = (*vmctx).instance();
671            instance.memory_init(memory_index, data_index, dst, src, len)
672        };
673        if let Err(trap) = result {
674            raise_lib_trap(trap);
675        }
676    }
677}
678
679/// Implementation of `data.drop`.
680///
681/// # Safety
682///
683/// `vmctx` must be dereferenceable.
684#[unsafe(no_mangle)]
685pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
686    unsafe {
687        on_host_stack(|| {
688            let data_index = DataIndex::from_u32(data_index);
689            let instance = (*vmctx).instance();
690            instance.data_drop(data_index)
691        })
692    }
693}
694
695/// Implementation for raising a trap
696///
697/// # Safety
698///
699/// Only safe to call when wasm code is on the stack, aka `wasmer_call` or
700/// `wasmer_call_trampoline` must have been previously called.
701#[unsafe(no_mangle)]
702pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! {
703    unsafe {
704        let trap = Trap::lib(trap_code);
705        raise_lib_trap(trap)
706    }
707}
708
709/// (debug) Print an usize.
710#[unsafe(no_mangle)]
711pub extern "C-unwind" fn wasmer_vm_dbg_usize(value: usize) {
712    #[allow(clippy::print_stdout)]
713    {
714        println!("wasmer_vm_dbg_usize: {value}");
715    }
716}
717
718/// (debug) Print a string.
719#[unsafe(no_mangle)]
720pub extern "C-unwind" fn wasmer_vm_dbg_str(ptr: usize, len: u32) {
721    #[allow(clippy::print_stdout)]
722    unsafe {
723        let str = std::str::from_utf8(std::slice::from_raw_parts(ptr as _, len as _))
724            .unwrap_or("wasmer_vm_dbg_str failed");
725        eprintln!("{str}");
726    }
727}
728
729/// Implementation for throwing an exception.
730///
731/// # Safety
732///
733/// Calls libunwind to perform unwinding magic.
734#[unsafe(no_mangle)]
735pub unsafe extern "C-unwind" fn wasmer_vm_throw(vmctx: *mut VMContext, exnref: u32) -> ! {
736    let instance = unsafe { (*vmctx).instance() };
737    unsafe { eh::throw(instance.context(), exnref) }
738}
739
740/// Implementation for allocating an exception. Returns the exnref, i.e. a handle to the
741/// exception within the store.
742///
743/// # Safety
744///
745/// The vmctx pointer must be dereferenceable.
746#[unsafe(no_mangle)]
747pub unsafe extern "C-unwind" fn wasmer_vm_alloc_exception(vmctx: *mut VMContext, tag: u32) -> u32 {
748    let instance = unsafe { (*vmctx).instance_mut() };
749    let unique_tag = instance.shared_tag_ptr(TagIndex::from_u32(tag)).index();
750    let exn = VMExceptionObj::new_zeroed(
751        instance.context(),
752        InternalStoreHandle::from_index(unique_tag as usize).unwrap(),
753    );
754    let exnref = InternalStoreHandle::new(instance.context_mut(), exn);
755    exnref.index() as u32
756}
757
758/// Given a VMContext and an exnref (handle to an exception within the store),
759/// returns a pointer to the payload buffer of the underlying VMExceptionObj.
760#[unsafe(no_mangle)]
761pub extern "C-unwind" fn wasmer_vm_read_exnref(
762    vmctx: *mut VMContext,
763    exnref: u32,
764) -> *mut RawValue {
765    let exn = eh::exn_obj_from_exnref(vmctx, exnref);
766    unsafe { (*exn).payload().as_ptr() as *mut RawValue }
767}
768
769/// Given a pointer to a caught exception, return the exnref contained within.
770///
771/// # Safety
772///
773/// `exception` must be a pointer the platform-specific exception type; this is
774/// `UwExceptionWrapper` for gcc.
775#[unsafe(no_mangle)]
776pub unsafe extern "C-unwind" fn wasmer_vm_exception_into_exnref(exception: *mut c_void) -> u32 {
777    unsafe {
778        let exnref = eh::read_exnref(exception);
779        eh::delete_exception(exception);
780        exnref
781    }
782}
783
784/// Probestack check
785///
786/// # Safety
787///
788/// This function does not follow the standard function ABI, and is called as
789/// part of the function prologue.
790#[unsafe(no_mangle)]
791pub static WASMER_VM_PROBESTACK: unsafe extern "C" fn() = PROBESTACK;
792
793/// Implementation of memory.wait32 for locally-defined 32-bit memories.
794///
795/// # Safety
796///
797/// `vmctx` must be dereferenceable.
798#[unsafe(no_mangle)]
799pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait32(
800    vmctx: *mut VMContext,
801    memory_index: u32,
802    dst: u32,
803    val: u32,
804    timeout: i64,
805) -> u32 {
806    unsafe {
807        let result = {
808            let instance = (*vmctx).instance_mut();
809            let memory_index = LocalMemoryIndex::from_u32(memory_index);
810
811            instance.local_memory_wait32(memory_index, dst, val, timeout)
812        };
813        if let Err(trap) = result {
814            raise_lib_trap(trap);
815        }
816        result.unwrap()
817    }
818}
819
820/// Implementation of memory.wait32 for imported 32-bit memories.
821///
822/// # Safety
823///
824/// `vmctx` must be dereferenceable.
825#[unsafe(no_mangle)]
826pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait32(
827    vmctx: *mut VMContext,
828    memory_index: u32,
829    dst: u32,
830    val: u32,
831    timeout: i64,
832) -> u32 {
833    unsafe {
834        let result = {
835            let instance = (*vmctx).instance_mut();
836            let memory_index = MemoryIndex::from_u32(memory_index);
837
838            instance.imported_memory_wait32(memory_index, dst, val, timeout)
839        };
840        if let Err(trap) = result {
841            raise_lib_trap(trap);
842        }
843        result.unwrap()
844    }
845}
846
847/// Implementation of memory.wait64 for locally-defined 32-bit memories.
848///
849/// # Safety
850///
851/// `vmctx` must be dereferenceable.
852#[unsafe(no_mangle)]
853pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait64(
854    vmctx: *mut VMContext,
855    memory_index: u32,
856    dst: u32,
857    val: u64,
858    timeout: i64,
859) -> u32 {
860    unsafe {
861        let result = {
862            let instance = (*vmctx).instance_mut();
863            let memory_index = LocalMemoryIndex::from_u32(memory_index);
864
865            instance.local_memory_wait64(memory_index, dst, val, timeout)
866        };
867        if let Err(trap) = result {
868            raise_lib_trap(trap);
869        }
870        result.unwrap()
871    }
872}
873
874/// Implementation of memory.wait64 for imported 32-bit memories.
875///
876/// # Safety
877///
878/// `vmctx` must be dereferenceable.
879#[unsafe(no_mangle)]
880pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait64(
881    vmctx: *mut VMContext,
882    memory_index: u32,
883    dst: u32,
884    val: u64,
885    timeout: i64,
886) -> u32 {
887    unsafe {
888        let result = {
889            let instance = (*vmctx).instance_mut();
890            let memory_index = MemoryIndex::from_u32(memory_index);
891
892            instance.imported_memory_wait64(memory_index, dst, val, timeout)
893        };
894        if let Err(trap) = result {
895            raise_lib_trap(trap);
896        }
897        result.unwrap()
898    }
899}
900
901/// Implementation of memory.notify for locally-defined 32-bit memories.
902///
903/// # Safety
904///
905/// `vmctx` must be dereferenceable.
906#[unsafe(no_mangle)]
907pub unsafe extern "C" fn wasmer_vm_memory32_atomic_notify(
908    vmctx: *mut VMContext,
909    memory_index: u32,
910    dst: u32,
911    cnt: u32,
912) -> u32 {
913    unsafe {
914        let result = {
915            let instance = (*vmctx).instance_mut();
916            let memory_index = LocalMemoryIndex::from_u32(memory_index);
917
918            instance.local_memory_notify(memory_index, dst, cnt)
919        };
920        if let Err(trap) = result {
921            raise_lib_trap(trap);
922        }
923        result.unwrap()
924    }
925}
926
927/// Implementation of memory.notfy for imported 32-bit memories.
928///
929/// # Safety
930///
931/// `vmctx` must be dereferenceable.
932#[unsafe(no_mangle)]
933pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_notify(
934    vmctx: *mut VMContext,
935    memory_index: u32,
936    dst: u32,
937    cnt: u32,
938) -> u32 {
939    unsafe {
940        let result = {
941            let instance = (*vmctx).instance_mut();
942            let memory_index = MemoryIndex::from_u32(memory_index);
943
944            instance.imported_memory_notify(memory_index, dst, cnt)
945        };
946        if let Err(trap) = result {
947            raise_lib_trap(trap);
948        }
949        result.unwrap()
950    }
951}
952
953/// The function pointer to a libcall
954pub fn function_pointer(libcall: LibCall) -> usize {
955    match libcall {
956        LibCall::CeilF32 => wasmer_vm_f32_ceil as *const () as usize,
957        LibCall::CeilF64 => wasmer_vm_f64_ceil as *const () as usize,
958        LibCall::FloorF32 => wasmer_vm_f32_floor as *const () as usize,
959        LibCall::FloorF64 => wasmer_vm_f64_floor as *const () as usize,
960        LibCall::NearestF32 => wasmer_vm_f32_nearest as *const () as usize,
961        LibCall::NearestF64 => wasmer_vm_f64_nearest as *const () as usize,
962        LibCall::TruncF32 => wasmer_vm_f32_trunc as *const () as usize,
963        LibCall::TruncF64 => wasmer_vm_f64_trunc as *const () as usize,
964        LibCall::Memory32Size => wasmer_vm_memory32_size as *const () as usize,
965        LibCall::ImportedMemory32Size => wasmer_vm_imported_memory32_size as *const () as usize,
966        LibCall::TableCopy => wasmer_vm_table_copy as *const () as usize,
967        LibCall::TableInit => wasmer_vm_table_init as *const () as usize,
968        LibCall::TableFill => wasmer_vm_table_fill as *const () as usize,
969        LibCall::TableSize => wasmer_vm_table_size as *const () as usize,
970        LibCall::ImportedTableSize => wasmer_vm_imported_table_size as *const () as usize,
971        LibCall::TableGet => wasmer_vm_table_get as *const () as usize,
972        LibCall::ImportedTableGet => wasmer_vm_imported_table_get as *const () as usize,
973        LibCall::TableSet => wasmer_vm_table_set as *const () as usize,
974        LibCall::ImportedTableSet => wasmer_vm_imported_table_set as *const () as usize,
975        LibCall::TableGrow => wasmer_vm_table_grow as *const () as usize,
976        LibCall::ImportedTableGrow => wasmer_vm_imported_table_grow as *const () as usize,
977        LibCall::FuncRef => wasmer_vm_func_ref as *const () as usize,
978        LibCall::ElemDrop => wasmer_vm_elem_drop as *const () as usize,
979        LibCall::Memory32Copy => wasmer_vm_memory32_copy as *const () as usize,
980        LibCall::ImportedMemory32Copy => wasmer_vm_imported_memory32_copy as *const () as usize,
981        LibCall::Memory32Fill => wasmer_vm_memory32_fill as *const () as usize,
982        LibCall::ImportedMemory32Fill => wasmer_vm_imported_memory32_fill as *const () as usize,
983        LibCall::Memory32Init => wasmer_vm_memory32_init as *const () as usize,
984        LibCall::DataDrop => wasmer_vm_data_drop as *const () as usize,
985        LibCall::Probestack => WASMER_VM_PROBESTACK as *const () as usize,
986        LibCall::RaiseTrap => wasmer_vm_raise_trap as *const () as usize,
987        LibCall::Memory32AtomicWait32 => wasmer_vm_memory32_atomic_wait32 as *const () as usize,
988        LibCall::ImportedMemory32AtomicWait32 => {
989            wasmer_vm_imported_memory32_atomic_wait32 as *const () as usize
990        }
991        LibCall::Memory32AtomicWait64 => wasmer_vm_memory32_atomic_wait64 as *const () as usize,
992        LibCall::ImportedMemory32AtomicWait64 => {
993            wasmer_vm_imported_memory32_atomic_wait64 as *const () as usize
994        }
995        LibCall::Memory32AtomicNotify => wasmer_vm_memory32_atomic_notify as *const () as usize,
996        LibCall::ImportedMemory32AtomicNotify => {
997            wasmer_vm_imported_memory32_atomic_notify as *const () as usize
998        }
999        LibCall::Throw => wasmer_vm_throw as *const () as usize,
1000        LibCall::EHPersonality => eh::wasmer_eh_personality as *const () as usize,
1001        LibCall::EHPersonality2 => eh::wasmer_eh_personality2 as *const () as usize,
1002        LibCall::AllocException => wasmer_vm_alloc_exception as *const () as usize,
1003        LibCall::ReadExnRef => wasmer_vm_read_exnref as *const () as usize,
1004        LibCall::LibunwindExceptionIntoExnRef => {
1005            wasmer_vm_exception_into_exnref as *const () as usize
1006        }
1007        LibCall::DebugUsize => wasmer_vm_dbg_usize as *const () as usize,
1008        LibCall::DebugStr => wasmer_vm_dbg_str as *const () as usize,
1009    }
1010}