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