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