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 f32.sqrt
104#[unsafe(no_mangle)]
105pub extern "C" fn wasmer_vm_f32_sqrt(x: f32) -> f32 {
106    x.sqrt()
107}
108
109/// Implementation of f64.sqrt
110#[unsafe(no_mangle)]
111pub extern "C" fn wasmer_vm_f64_sqrt(x: f64) -> f64 {
112    x.sqrt()
113}
114
115/// Implementation of f64.ceil
116#[unsafe(no_mangle)]
117pub extern "C" fn wasmer_vm_f64_ceil(x: f64) -> f64 {
118    x.ceil()
119}
120
121/// Implementation of f64.floor
122#[unsafe(no_mangle)]
123pub extern "C" fn wasmer_vm_f64_floor(x: f64) -> f64 {
124    x.floor()
125}
126
127/// Implementation of f64.trunc
128#[unsafe(no_mangle)]
129pub extern "C" fn wasmer_vm_f64_trunc(x: f64) -> f64 {
130    x.trunc()
131}
132
133/// Implementation of f64.nearest
134#[allow(clippy::float_arithmetic, clippy::float_cmp)]
135#[unsafe(no_mangle)]
136pub extern "C" fn wasmer_vm_f64_nearest(x: f64) -> f64 {
137    // Rust doesn't have a nearest function, so do it manually.
138    if x == 0.0 {
139        // Preserve the sign of zero.
140        x
141    } else {
142        // Nearest is either ceil or floor depending on which is nearest or even.
143        let u = x.ceil();
144        let d = x.floor();
145        let um = (x - u).abs();
146        let dm = (x - d).abs();
147        if um < dm
148            || (um == dm && {
149                let h = u / 2.;
150                h.floor() == h
151            })
152        {
153            u
154        } else {
155            d
156        }
157    }
158}
159
160/// Implementation of memory.grow for locally-defined 32-bit memories.
161///
162/// # Safety
163///
164/// `vmctx` must be dereferenceable.
165#[unsafe(no_mangle)]
166pub unsafe extern "C" fn wasmer_vm_memory32_grow(
167    vmctx: *mut VMContext,
168    delta_in_pages: u32,
169    memory_index: u32,
170) -> u32 {
171    unsafe {
172        on_host_stack(|| {
173            let instance = (*vmctx).instance_mut();
174            let memory_index = LocalMemoryIndex::from_u32(memory_index);
175
176            instance
177                .memory_grow(memory_index, delta_in_pages)
178                .map_or(u32::MAX, |pages| pages.0)
179        })
180    }
181}
182
183/// Implementation of memory.grow for imported 32-bit memories.
184///
185/// # Safety
186///
187/// `vmctx` must be dereferenceable.
188#[unsafe(no_mangle)]
189pub unsafe extern "C" fn wasmer_vm_imported_memory32_grow(
190    vmctx: *mut VMContext,
191    delta_in_pages: u32,
192    memory_index: u32,
193) -> u32 {
194    unsafe {
195        on_host_stack(|| {
196            let instance = (*vmctx).instance_mut();
197            let memory_index = MemoryIndex::from_u32(memory_index);
198
199            instance
200                .imported_memory_grow(memory_index, delta_in_pages)
201                .map_or(u32::MAX, |pages| pages.0)
202        })
203    }
204}
205
206/// Implementation of memory.size for locally-defined 32-bit memories.
207///
208/// # Safety
209///
210/// `vmctx` must be dereferenceable.
211#[unsafe(no_mangle)]
212pub unsafe extern "C" fn wasmer_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
213    unsafe {
214        let instance = (*vmctx).instance();
215        let memory_index = LocalMemoryIndex::from_u32(memory_index);
216
217        instance.memory_size(memory_index).0
218    }
219}
220
221/// Implementation of memory.size for imported 32-bit memories.
222///
223/// # Safety
224///
225/// `vmctx` must be dereferenceable.
226#[unsafe(no_mangle)]
227pub unsafe extern "C" fn wasmer_vm_imported_memory32_size(
228    vmctx: *mut VMContext,
229    memory_index: u32,
230) -> u32 {
231    unsafe {
232        let instance = (*vmctx).instance();
233        let memory_index = MemoryIndex::from_u32(memory_index);
234
235        instance.imported_memory_size(memory_index).0
236    }
237}
238
239/// Implementation of `table.copy`.
240///
241/// # Safety
242///
243/// `vmctx` must be dereferenceable.
244#[unsafe(no_mangle)]
245pub unsafe extern "C" fn wasmer_vm_table_copy(
246    vmctx: *mut VMContext,
247    dst_table_index: u32,
248    src_table_index: u32,
249    dst: u32,
250    src: u32,
251    len: u32,
252) {
253    unsafe {
254        let result = {
255            let dst_table_index = TableIndex::from_u32(dst_table_index);
256            let src_table_index = TableIndex::from_u32(src_table_index);
257            (*vmctx)
258                .instance_mut()
259                .table_copy(dst_table_index, src_table_index, dst, src, len)
260        };
261        if let Err(trap) = result {
262            raise_lib_trap(trap);
263        }
264    }
265}
266
267/// Implementation of `table.init`.
268///
269/// # Safety
270///
271/// `vmctx` must be dereferenceable.
272#[unsafe(no_mangle)]
273pub unsafe extern "C" fn wasmer_vm_table_init(
274    vmctx: *mut VMContext,
275    table_index: u32,
276    elem_index: u32,
277    dst: u32,
278    src: u32,
279    len: u32,
280) {
281    unsafe {
282        let result = {
283            let table_index = TableIndex::from_u32(table_index);
284            let elem_index = ElemIndex::from_u32(elem_index);
285            let instance = (*vmctx).instance_mut();
286            instance.table_init(table_index, elem_index, dst, src, len)
287        };
288        if let Err(trap) = result {
289            raise_lib_trap(trap);
290        }
291    }
292}
293
294/// Implementation of `table.fill`.
295///
296/// # Safety
297///
298/// `vmctx` must be dereferenceable.
299#[unsafe(no_mangle)]
300pub unsafe extern "C" fn wasmer_vm_table_fill(
301    vmctx: *mut VMContext,
302    table_index: u32,
303    start_idx: u32,
304    item: RawTableElement,
305    len: u32,
306) {
307    unsafe {
308        let result = {
309            let table_index = TableIndex::from_u32(table_index);
310            let instance = (*vmctx).instance_mut();
311            let elem = match instance.get_table(table_index).ty().ty {
312                Type::ExternRef => TableElement::ExternRef(item.extern_ref),
313                Type::FuncRef => TableElement::FuncRef(item.func_ref),
314                _ => panic!("Unrecognized table type: does not contain references"),
315            };
316
317            instance.table_fill(table_index, start_idx, elem, len)
318        };
319        if let Err(trap) = result {
320            raise_lib_trap(trap);
321        }
322    }
323}
324
325/// Implementation of `table.size`.
326///
327/// # Safety
328///
329/// `vmctx` must be dereferenceable.
330#[unsafe(no_mangle)]
331pub unsafe extern "C" fn wasmer_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
332    unsafe {
333        let instance = (*vmctx).instance();
334        let table_index = LocalTableIndex::from_u32(table_index);
335
336        instance.table_size(table_index)
337    }
338}
339
340/// Implementation of `table.size` for imported tables.
341///
342/// # Safety
343///
344/// `vmctx` must be dereferenceable.
345#[unsafe(no_mangle)]
346pub unsafe extern "C" fn wasmer_vm_imported_table_size(
347    vmctx: *mut VMContext,
348    table_index: u32,
349) -> u32 {
350    unsafe {
351        let instance = (*vmctx).instance();
352        let table_index = TableIndex::from_u32(table_index);
353
354        instance.imported_table_size(table_index)
355    }
356}
357
358/// Implementation of `table.get`.
359///
360/// # Safety
361///
362/// `vmctx` must be dereferenceable.
363#[unsafe(no_mangle)]
364pub unsafe extern "C" fn wasmer_vm_table_get(
365    vmctx: *mut VMContext,
366    table_index: u32,
367    elem_index: u32,
368) -> RawTableElement {
369    unsafe {
370        let instance = (*vmctx).instance();
371        let table_index = LocalTableIndex::from_u32(table_index);
372
373        // TODO: type checking, maybe have specialized accessors
374        match instance.table_get(table_index, elem_index) {
375            Some(table_ref) => table_ref.into(),
376            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
377        }
378    }
379}
380
381/// Implementation of `table.get` for imported tables.
382///
383/// # Safety
384///
385/// `vmctx` must be dereferenceable.
386#[unsafe(no_mangle)]
387pub unsafe extern "C" fn wasmer_vm_imported_table_get(
388    vmctx: *mut VMContext,
389    table_index: u32,
390    elem_index: u32,
391) -> RawTableElement {
392    unsafe {
393        let instance = (*vmctx).instance_mut();
394        let table_index = TableIndex::from_u32(table_index);
395
396        // TODO: type checking, maybe have specialized accessors
397        match instance.imported_table_get(table_index, elem_index) {
398            Some(table_ref) => table_ref.into(),
399            None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
400        }
401    }
402}
403
404/// Implementation of `table.set`.
405///
406/// # Safety
407///
408/// `vmctx` must be dereferenceable.
409///
410/// It is the caller's responsibility to increment the ref count of any ref counted
411/// type before passing it to this function.
412#[unsafe(no_mangle)]
413pub unsafe extern "C" fn wasmer_vm_table_set(
414    vmctx: *mut VMContext,
415    table_index: u32,
416    elem_index: u32,
417    value: RawTableElement,
418) {
419    unsafe {
420        let instance = (*vmctx).instance_mut();
421        let table_index = TableIndex::from_u32(table_index);
422        let table_index = instance
423            .module_ref()
424            .local_table_index(table_index)
425            .unwrap();
426
427        let elem = match instance.get_local_table(table_index).ty().ty {
428            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
429            Type::FuncRef => TableElement::FuncRef(value.func_ref),
430            _ => panic!("Unrecognized table type: does not contain references"),
431        };
432
433        // TODO: type checking, maybe have specialized accessors
434        let result = instance.table_set(table_index, elem_index, elem);
435
436        if let Err(trap) = result {
437            raise_lib_trap(trap);
438        }
439    }
440}
441
442/// Implementation of `table.set` for imported tables.
443///
444/// # Safety
445///
446/// `vmctx` must be dereferenceable.
447#[unsafe(no_mangle)]
448pub unsafe extern "C" fn wasmer_vm_imported_table_set(
449    vmctx: *mut VMContext,
450    table_index: u32,
451    elem_index: u32,
452    value: RawTableElement,
453) {
454    unsafe {
455        let instance = (*vmctx).instance_mut();
456        let table_index = TableIndex::from_u32(table_index);
457        let elem = match instance.get_table(table_index).ty().ty {
458            Type::ExternRef => TableElement::ExternRef(value.extern_ref),
459            Type::FuncRef => TableElement::FuncRef(value.func_ref),
460            _ => panic!("Unrecognized table type: does not contain references"),
461        };
462
463        let result = instance.imported_table_set(table_index, elem_index, elem);
464
465        if let Err(trap) = result {
466            raise_lib_trap(trap);
467        }
468    }
469}
470
471/// Implementation of `table.grow` for locally-defined tables.
472///
473/// # Safety
474///
475/// `vmctx` must be dereferenceable.
476#[unsafe(no_mangle)]
477pub unsafe extern "C" fn wasmer_vm_table_grow(
478    vmctx: *mut VMContext,
479    init_value: RawTableElement,
480    delta: u32,
481    table_index: u32,
482) -> u32 {
483    unsafe {
484        on_host_stack(|| {
485            let instance = (*vmctx).instance_mut();
486            let table_index = LocalTableIndex::from_u32(table_index);
487
488            let init_value = match instance.get_local_table(table_index).ty().ty {
489                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
490                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
491                _ => panic!("Unrecognized table type: does not contain references"),
492            };
493
494            instance
495                .table_grow(table_index, delta, init_value)
496                .unwrap_or(u32::MAX)
497        })
498    }
499}
500
501/// Implementation of `table.grow` for imported tables.
502///
503/// # Safety
504///
505/// `vmctx` must be dereferenceable.
506#[unsafe(no_mangle)]
507pub unsafe extern "C" fn wasmer_vm_imported_table_grow(
508    vmctx: *mut VMContext,
509    init_value: RawTableElement,
510    delta: u32,
511    table_index: u32,
512) -> u32 {
513    unsafe {
514        on_host_stack(|| {
515            let instance = (*vmctx).instance_mut();
516            let table_index = TableIndex::from_u32(table_index);
517            let init_value = match instance.get_table(table_index).ty().ty {
518                Type::ExternRef => TableElement::ExternRef(init_value.extern_ref),
519                Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
520                _ => panic!("Unrecognized table type: does not contain references"),
521            };
522
523            instance
524                .imported_table_grow(table_index, delta, init_value)
525                .unwrap_or(u32::MAX)
526        })
527    }
528}
529
530/// Implementation of `func.ref`.
531///
532/// # Safety
533///
534/// `vmctx` must be dereferenceable.
535#[unsafe(no_mangle)]
536pub unsafe extern "C" fn wasmer_vm_func_ref(
537    vmctx: *mut VMContext,
538    function_index: u32,
539) -> VMFuncRef {
540    unsafe {
541        let instance = (*vmctx).instance();
542        let function_index = FunctionIndex::from_u32(function_index);
543
544        instance.func_ref(function_index).unwrap()
545    }
546}
547
548/// Implementation of `elem.drop`.
549///
550/// # Safety
551///
552/// `vmctx` must be dereferenceable.
553#[unsafe(no_mangle)]
554pub unsafe extern "C" fn wasmer_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
555    unsafe {
556        on_host_stack(|| {
557            let elem_index = ElemIndex::from_u32(elem_index);
558            let instance = (*vmctx).instance();
559            instance.elem_drop(elem_index);
560        })
561    }
562}
563
564/// Implementation of `memory.copy` for locally defined memories.
565///
566/// # Safety
567///
568/// `vmctx` must be dereferenceable.
569#[unsafe(no_mangle)]
570pub unsafe extern "C" fn wasmer_vm_memory32_copy(
571    vmctx: *mut VMContext,
572    memory_index: u32,
573    dst: u32,
574    src: u32,
575    len: u32,
576) {
577    unsafe {
578        let result = {
579            let memory_index = LocalMemoryIndex::from_u32(memory_index);
580            let instance = (*vmctx).instance();
581            instance.local_memory_copy(memory_index, dst, src, len)
582        };
583        if let Err(trap) = result {
584            raise_lib_trap(trap);
585        }
586    }
587}
588
589/// Implementation of `memory.copy` for imported memories.
590///
591/// # Safety
592///
593/// `vmctx` must be dereferenceable.
594#[unsafe(no_mangle)]
595pub unsafe extern "C" fn wasmer_vm_imported_memory32_copy(
596    vmctx: *mut VMContext,
597    memory_index: u32,
598    dst: u32,
599    src: u32,
600    len: u32,
601) {
602    unsafe {
603        let result = {
604            let memory_index = MemoryIndex::from_u32(memory_index);
605            let instance = (*vmctx).instance();
606            instance.imported_memory_copy(memory_index, dst, src, len)
607        };
608        if let Err(trap) = result {
609            raise_lib_trap(trap);
610        }
611    }
612}
613
614/// Implementation of `memory.fill` for locally defined memories.
615///
616/// # Safety
617///
618/// `vmctx` must be dereferenceable.
619#[unsafe(no_mangle)]
620pub unsafe extern "C" fn wasmer_vm_memory32_fill(
621    vmctx: *mut VMContext,
622    memory_index: u32,
623    dst: u32,
624    val: u32,
625    len: u32,
626) {
627    unsafe {
628        let result = {
629            let memory_index = LocalMemoryIndex::from_u32(memory_index);
630            let instance = (*vmctx).instance();
631            instance.local_memory_fill(memory_index, dst, val, len)
632        };
633        if let Err(trap) = result {
634            raise_lib_trap(trap);
635        }
636    }
637}
638
639/// Implementation of `memory.fill` for imported memories.
640///
641/// # Safety
642///
643/// `vmctx` must be dereferenceable.
644#[unsafe(no_mangle)]
645pub unsafe extern "C" fn wasmer_vm_imported_memory32_fill(
646    vmctx: *mut VMContext,
647    memory_index: u32,
648    dst: u32,
649    val: u32,
650    len: u32,
651) {
652    unsafe {
653        let result = {
654            let memory_index = MemoryIndex::from_u32(memory_index);
655            let instance = (*vmctx).instance();
656            instance.imported_memory_fill(memory_index, dst, val, len)
657        };
658        if let Err(trap) = result {
659            raise_lib_trap(trap);
660        }
661    }
662}
663
664/// Implementation of `memory.init`.
665///
666/// # Safety
667///
668/// `vmctx` must be dereferenceable.
669#[unsafe(no_mangle)]
670pub unsafe extern "C" fn wasmer_vm_memory32_init(
671    vmctx: *mut VMContext,
672    memory_index: u32,
673    data_index: u32,
674    dst: u32,
675    src: u32,
676    len: u32,
677) {
678    unsafe {
679        let result = {
680            let memory_index = MemoryIndex::from_u32(memory_index);
681            let data_index = DataIndex::from_u32(data_index);
682            let instance = (*vmctx).instance();
683            instance.memory_init(memory_index, data_index, dst, src, len)
684        };
685        if let Err(trap) = result {
686            raise_lib_trap(trap);
687        }
688    }
689}
690
691/// Implementation of `data.drop`.
692///
693/// # Safety
694///
695/// `vmctx` must be dereferenceable.
696#[unsafe(no_mangle)]
697pub unsafe extern "C" fn wasmer_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
698    unsafe {
699        on_host_stack(|| {
700            let data_index = DataIndex::from_u32(data_index);
701            let instance = (*vmctx).instance();
702            instance.data_drop(data_index)
703        })
704    }
705}
706
707/// Implementation for raising a trap
708///
709/// # Safety
710///
711/// Only safe to call when wasm code is on the stack, aka `wasmer_call` or
712/// `wasmer_call_trampoline` must have been previously called.
713#[unsafe(no_mangle)]
714pub unsafe extern "C" fn wasmer_vm_raise_trap(trap_code: TrapCode) -> ! {
715    unsafe {
716        let trap = Trap::lib(trap_code);
717        raise_lib_trap(trap)
718    }
719}
720
721/// (debug) Print an usize.
722#[unsafe(no_mangle)]
723pub extern "C-unwind" fn wasmer_vm_dbg_usize(value: usize) {
724    #[allow(clippy::print_stdout)]
725    {
726        println!("wasmer_vm_dbg_usize: {value}");
727    }
728}
729
730/// (debug) Print a string.
731#[unsafe(no_mangle)]
732pub extern "C-unwind" fn wasmer_vm_dbg_str(ptr: usize, len: u32) {
733    #[allow(clippy::print_stdout)]
734    unsafe {
735        let str = std::str::from_utf8(std::slice::from_raw_parts(ptr as _, len as _))
736            .unwrap_or("wasmer_vm_dbg_str failed");
737        eprintln!("{str}");
738    }
739}
740
741/// Implementation for throwing an exception.
742///
743/// # Safety
744///
745/// Calls libunwind to perform unwinding magic.
746#[unsafe(no_mangle)]
747pub unsafe extern "C-unwind" fn wasmer_vm_throw(vmctx: *mut VMContext, exnref: u32) -> ! {
748    let instance = unsafe { (*vmctx).instance() };
749    unsafe { eh::throw(instance.context(), exnref) }
750}
751
752/// Implementation for allocating an exception. Returns the exnref, i.e. a handle to the
753/// exception within the store.
754///
755/// # Safety
756///
757/// The vmctx pointer must be dereferenceable.
758#[unsafe(no_mangle)]
759pub unsafe extern "C-unwind" fn wasmer_vm_alloc_exception(vmctx: *mut VMContext, tag: u32) -> u32 {
760    let instance = unsafe { (*vmctx).instance_mut() };
761    let unique_tag = instance.shared_tag_ptr(TagIndex::from_u32(tag)).index();
762    let exn = VMExceptionObj::new_zeroed(
763        instance.context(),
764        InternalStoreHandle::from_index(unique_tag as usize).unwrap(),
765    );
766    let exnref = InternalStoreHandle::new(instance.context_mut(), exn);
767    exnref.index() as u32
768}
769
770/// Given a VMContext and an exnref (handle to an exception within the store),
771/// returns a pointer to the payload buffer of the underlying VMExceptionObj.
772#[unsafe(no_mangle)]
773pub extern "C-unwind" fn wasmer_vm_read_exnref(
774    vmctx: *mut VMContext,
775    exnref: u32,
776) -> *mut RawValue {
777    let exn = eh::exn_obj_from_exnref(vmctx, exnref);
778    unsafe { (*exn).payload().as_ptr() as *mut RawValue }
779}
780
781/// Given a pointer to a caught exception, return the exnref contained within.
782///
783/// # Safety
784///
785/// `exception` must be a pointer the platform-specific exception type; this is
786/// `UwExceptionWrapper` for gcc.
787#[unsafe(no_mangle)]
788pub unsafe extern "C-unwind" fn wasmer_vm_exception_into_exnref(exception: *mut c_void) -> u32 {
789    unsafe {
790        let exnref = eh::read_exnref(exception);
791        eh::delete_exception(exception);
792        exnref
793    }
794}
795
796/// Probestack check
797///
798/// # Safety
799///
800/// This function does not follow the standard function ABI, and is called as
801/// part of the function prologue.
802#[unsafe(no_mangle)]
803pub static WASMER_VM_PROBESTACK: unsafe extern "C" fn() = PROBESTACK;
804
805/// Implementation of memory.wait32 for locally-defined 32-bit memories.
806///
807/// # Safety
808///
809/// `vmctx` must be dereferenceable.
810#[unsafe(no_mangle)]
811pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait32(
812    vmctx: *mut VMContext,
813    memory_index: u32,
814    dst: u32,
815    val: u32,
816    timeout: i64,
817) -> u32 {
818    unsafe {
819        let result = {
820            let instance = (*vmctx).instance_mut();
821            let memory_index = LocalMemoryIndex::from_u32(memory_index);
822
823            instance.local_memory_wait32(memory_index, dst, val, timeout)
824        };
825        if let Err(trap) = result {
826            raise_lib_trap(trap);
827        }
828        result.unwrap()
829    }
830}
831
832/// Implementation of memory.wait32 for imported 32-bit memories.
833///
834/// # Safety
835///
836/// `vmctx` must be dereferenceable.
837#[unsafe(no_mangle)]
838pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait32(
839    vmctx: *mut VMContext,
840    memory_index: u32,
841    dst: u32,
842    val: u32,
843    timeout: i64,
844) -> u32 {
845    unsafe {
846        let result = {
847            let instance = (*vmctx).instance_mut();
848            let memory_index = MemoryIndex::from_u32(memory_index);
849
850            instance.imported_memory_wait32(memory_index, dst, val, timeout)
851        };
852        if let Err(trap) = result {
853            raise_lib_trap(trap);
854        }
855        result.unwrap()
856    }
857}
858
859/// Implementation of memory.wait64 for locally-defined 32-bit memories.
860///
861/// # Safety
862///
863/// `vmctx` must be dereferenceable.
864#[unsafe(no_mangle)]
865pub unsafe extern "C" fn wasmer_vm_memory32_atomic_wait64(
866    vmctx: *mut VMContext,
867    memory_index: u32,
868    dst: u32,
869    val: u64,
870    timeout: i64,
871) -> u32 {
872    unsafe {
873        let result = {
874            let instance = (*vmctx).instance_mut();
875            let memory_index = LocalMemoryIndex::from_u32(memory_index);
876
877            instance.local_memory_wait64(memory_index, dst, val, timeout)
878        };
879        if let Err(trap) = result {
880            raise_lib_trap(trap);
881        }
882        result.unwrap()
883    }
884}
885
886/// Implementation of memory.wait64 for imported 32-bit memories.
887///
888/// # Safety
889///
890/// `vmctx` must be dereferenceable.
891#[unsafe(no_mangle)]
892pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_wait64(
893    vmctx: *mut VMContext,
894    memory_index: u32,
895    dst: u32,
896    val: u64,
897    timeout: i64,
898) -> u32 {
899    unsafe {
900        let result = {
901            let instance = (*vmctx).instance_mut();
902            let memory_index = MemoryIndex::from_u32(memory_index);
903
904            instance.imported_memory_wait64(memory_index, dst, val, timeout)
905        };
906        if let Err(trap) = result {
907            raise_lib_trap(trap);
908        }
909        result.unwrap()
910    }
911}
912
913/// Implementation of memory.notify for locally-defined 32-bit memories.
914///
915/// # Safety
916///
917/// `vmctx` must be dereferenceable.
918#[unsafe(no_mangle)]
919pub unsafe extern "C" fn wasmer_vm_memory32_atomic_notify(
920    vmctx: *mut VMContext,
921    memory_index: u32,
922    dst: u32,
923    cnt: u32,
924) -> u32 {
925    unsafe {
926        let result = {
927            let instance = (*vmctx).instance_mut();
928            let memory_index = LocalMemoryIndex::from_u32(memory_index);
929
930            instance.local_memory_notify(memory_index, dst, cnt)
931        };
932        if let Err(trap) = result {
933            raise_lib_trap(trap);
934        }
935        result.unwrap()
936    }
937}
938
939/// Implementation of memory.notify for imported 32-bit memories.
940///
941/// # Safety
942///
943/// `vmctx` must be dereferenceable.
944#[unsafe(no_mangle)]
945pub unsafe extern "C" fn wasmer_vm_imported_memory32_atomic_notify(
946    vmctx: *mut VMContext,
947    memory_index: u32,
948    dst: u32,
949    cnt: u32,
950) -> u32 {
951    unsafe {
952        let result = {
953            let instance = (*vmctx).instance_mut();
954            let memory_index = MemoryIndex::from_u32(memory_index);
955
956            instance.imported_memory_notify(memory_index, dst, cnt)
957        };
958        if let Err(trap) = result {
959            raise_lib_trap(trap);
960        }
961        result.unwrap()
962    }
963}
964
965/// The function pointer to a libcall
966pub fn function_pointer(libcall: LibCall) -> usize {
967    match libcall {
968        LibCall::CeilF32 => wasmer_vm_f32_ceil as *const () as usize,
969        LibCall::CeilF64 => wasmer_vm_f64_ceil as *const () as usize,
970        LibCall::FloorF32 => wasmer_vm_f32_floor as *const () as usize,
971        LibCall::FloorF64 => wasmer_vm_f64_floor as *const () as usize,
972        LibCall::NearestF32 => wasmer_vm_f32_nearest as *const () as usize,
973        LibCall::NearestF64 => wasmer_vm_f64_nearest as *const () as usize,
974        LibCall::SqrtF32 => wasmer_vm_f32_sqrt as *const () as usize,
975        LibCall::SqrtF64 => wasmer_vm_f64_sqrt as *const () as usize,
976        LibCall::TruncF32 => wasmer_vm_f32_trunc as *const () as usize,
977        LibCall::TruncF64 => wasmer_vm_f64_trunc as *const () as usize,
978        LibCall::Memory32Size => wasmer_vm_memory32_size as *const () as usize,
979        LibCall::ImportedMemory32Size => wasmer_vm_imported_memory32_size as *const () as usize,
980        LibCall::TableCopy => wasmer_vm_table_copy as *const () as usize,
981        LibCall::TableInit => wasmer_vm_table_init as *const () as usize,
982        LibCall::TableFill => wasmer_vm_table_fill as *const () as usize,
983        LibCall::TableSize => wasmer_vm_table_size as *const () as usize,
984        LibCall::ImportedTableSize => wasmer_vm_imported_table_size as *const () as usize,
985        LibCall::TableGet => wasmer_vm_table_get as *const () as usize,
986        LibCall::ImportedTableGet => wasmer_vm_imported_table_get as *const () as usize,
987        LibCall::TableSet => wasmer_vm_table_set as *const () as usize,
988        LibCall::ImportedTableSet => wasmer_vm_imported_table_set as *const () as usize,
989        LibCall::TableGrow => wasmer_vm_table_grow as *const () as usize,
990        LibCall::ImportedTableGrow => wasmer_vm_imported_table_grow as *const () as usize,
991        LibCall::FuncRef => wasmer_vm_func_ref as *const () as usize,
992        LibCall::ElemDrop => wasmer_vm_elem_drop as *const () as usize,
993        LibCall::Memory32Copy => wasmer_vm_memory32_copy as *const () as usize,
994        LibCall::ImportedMemory32Copy => wasmer_vm_imported_memory32_copy as *const () as usize,
995        LibCall::Memory32Fill => wasmer_vm_memory32_fill as *const () as usize,
996        LibCall::ImportedMemory32Fill => wasmer_vm_imported_memory32_fill as *const () as usize,
997        LibCall::Memory32Init => wasmer_vm_memory32_init as *const () as usize,
998        LibCall::DataDrop => wasmer_vm_data_drop as *const () as usize,
999        LibCall::Probestack => WASMER_VM_PROBESTACK as *const () as usize,
1000        LibCall::RaiseTrap => wasmer_vm_raise_trap as *const () as usize,
1001        LibCall::Memory32AtomicWait32 => wasmer_vm_memory32_atomic_wait32 as *const () as usize,
1002        LibCall::ImportedMemory32AtomicWait32 => {
1003            wasmer_vm_imported_memory32_atomic_wait32 as *const () as usize
1004        }
1005        LibCall::Memory32AtomicWait64 => wasmer_vm_memory32_atomic_wait64 as *const () as usize,
1006        LibCall::ImportedMemory32AtomicWait64 => {
1007            wasmer_vm_imported_memory32_atomic_wait64 as *const () as usize
1008        }
1009        LibCall::Memory32AtomicNotify => wasmer_vm_memory32_atomic_notify as *const () as usize,
1010        LibCall::ImportedMemory32AtomicNotify => {
1011            wasmer_vm_imported_memory32_atomic_notify as *const () as usize
1012        }
1013        LibCall::Throw => wasmer_vm_throw as *const () as usize,
1014        LibCall::EHPersonality => eh::wasmer_eh_personality as *const () as usize,
1015        LibCall::EHPersonality2 => eh::wasmer_eh_personality2 as *const () as usize,
1016        LibCall::AllocException => wasmer_vm_alloc_exception as *const () as usize,
1017        LibCall::ReadExnRef => wasmer_vm_read_exnref as *const () as usize,
1018        LibCall::LibunwindExceptionIntoExnRef => {
1019            wasmer_vm_exception_into_exnref as *const () as usize
1020        }
1021        LibCall::DebugUsize => wasmer_vm_dbg_usize as *const () as usize,
1022        LibCall::DebugStr => wasmer_vm_dbg_str as *const () as usize,
1023        // --- Soft-float libcalls ---
1024        // compiler-rt / libgcc provides these on every std Rust target.
1025        // On wasm32 the JIT engine is never active, so these variants are unreachable.
1026        _lc @ (LibCall::Addsf3
1027        | LibCall::Adddf3
1028        | LibCall::Subsf3
1029        | LibCall::Subdf3
1030        | LibCall::Mulsf3
1031        | LibCall::Muldf3
1032        | LibCall::Divsf3
1033        | LibCall::Divdf3
1034        | LibCall::Negsf2
1035        | LibCall::Negdf2
1036        | LibCall::Extendsfdf2
1037        | LibCall::Truncdfsf2
1038        | LibCall::Fixsfsi
1039        | LibCall::Fixdfsi
1040        | LibCall::Fixsfdi
1041        | LibCall::Fixdfdi
1042        | LibCall::Fixunssfsi
1043        | LibCall::Fixunsdfsi
1044        | LibCall::Fixunssfdi
1045        | LibCall::Fixunsdfdi
1046        | LibCall::Floatsisf
1047        | LibCall::Floatsidf
1048        | LibCall::Floatdisf
1049        | LibCall::Floatdidf
1050        | LibCall::Floatunsisf
1051        | LibCall::Floatunsidf
1052        | LibCall::Floatundisf
1053        | LibCall::Floatundidf
1054        | LibCall::Unordsf2
1055        | LibCall::Unorddf2
1056        | LibCall::Eqsf2
1057        | LibCall::Eqdf2
1058        | LibCall::Nesf2
1059        | LibCall::Nedf2
1060        | LibCall::Gesf2
1061        | LibCall::Gedf2
1062        | LibCall::Ltsf2
1063        | LibCall::Ltdf2
1064        | LibCall::Lesf2
1065        | LibCall::Ledf2
1066        | LibCall::Gtsf2
1067        | LibCall::Gtdf2) => {
1068            #[cfg(target_arch = "wasm32")]
1069            unreachable!("soft-float libcalls are not reachable on wasm32");
1070            #[cfg(not(target_arch = "wasm32"))]
1071            match _lc {
1072                LibCall::Addsf3 => __addsf3 as *const () as usize,
1073                LibCall::Adddf3 => __adddf3 as *const () as usize,
1074                LibCall::Subsf3 => __subsf3 as *const () as usize,
1075                LibCall::Subdf3 => __subdf3 as *const () as usize,
1076                LibCall::Mulsf3 => __mulsf3 as *const () as usize,
1077                LibCall::Muldf3 => __muldf3 as *const () as usize,
1078                LibCall::Divsf3 => __divsf3 as *const () as usize,
1079                LibCall::Divdf3 => __divdf3 as *const () as usize,
1080                LibCall::Negsf2 => __negsf2 as *const () as usize,
1081                LibCall::Negdf2 => __negdf2 as *const () as usize,
1082                LibCall::Extendsfdf2 => __extendsfdf2 as *const () as usize,
1083                LibCall::Truncdfsf2 => __truncdfsf2 as *const () as usize,
1084                LibCall::Fixsfsi => __fixsfsi as *const () as usize,
1085                LibCall::Fixdfsi => __fixdfsi as *const () as usize,
1086                LibCall::Fixsfdi => __fixsfdi as *const () as usize,
1087                LibCall::Fixdfdi => __fixdfdi as *const () as usize,
1088                LibCall::Fixunssfsi => __fixunssfsi as *const () as usize,
1089                LibCall::Fixunsdfsi => __fixunsdfsi as *const () as usize,
1090                LibCall::Fixunssfdi => __fixunssfdi as *const () as usize,
1091                LibCall::Fixunsdfdi => __fixunsdfdi as *const () as usize,
1092                LibCall::Floatsisf => __floatsisf as *const () as usize,
1093                LibCall::Floatsidf => __floatsidf as *const () as usize,
1094                LibCall::Floatdisf => __floatdisf as *const () as usize,
1095                LibCall::Floatdidf => __floatdidf as *const () as usize,
1096                LibCall::Floatunsisf => __floatunsisf as *const () as usize,
1097                LibCall::Floatunsidf => __floatunsidf as *const () as usize,
1098                LibCall::Floatundisf => __floatundisf as *const () as usize,
1099                LibCall::Floatundidf => __floatundidf as *const () as usize,
1100                LibCall::Unordsf2 => __unordsf2 as *const () as usize,
1101                LibCall::Unorddf2 => __unorddf2 as *const () as usize,
1102                LibCall::Eqsf2 => __eqsf2 as *const () as usize,
1103                LibCall::Eqdf2 => __eqdf2 as *const () as usize,
1104                LibCall::Nesf2 => __nesf2 as *const () as usize,
1105                LibCall::Nedf2 => __nedf2 as *const () as usize,
1106                LibCall::Gesf2 => __gesf2 as *const () as usize,
1107                LibCall::Gedf2 => __gedf2 as *const () as usize,
1108                LibCall::Ltsf2 => __ltsf2 as *const () as usize,
1109                LibCall::Ltdf2 => __ltdf2 as *const () as usize,
1110                LibCall::Lesf2 => __lesf2 as *const () as usize,
1111                LibCall::Ledf2 => __ledf2 as *const () as usize,
1112                LibCall::Gtsf2 => __gtsf2 as *const () as usize,
1113                LibCall::Gtdf2 => __gtdf2 as *const () as usize,
1114                _ => unreachable!(),
1115            }
1116        }
1117    }
1118}
1119
1120// Soft-float arithmetic routines. Provided by compiler-rt / libgcc on all non-wasm targets.
1121#[cfg(not(target_arch = "wasm32"))]
1122unsafe extern "C" {
1123    // --- f32/f64 arithmetic ---
1124    fn __addsf3(a: f32, b: f32) -> f32;
1125    fn __adddf3(a: f64, b: f64) -> f64;
1126    fn __subsf3(a: f32, b: f32) -> f32;
1127    fn __subdf3(a: f64, b: f64) -> f64;
1128    fn __mulsf3(a: f32, b: f32) -> f32;
1129    fn __muldf3(a: f64, b: f64) -> f64;
1130    fn __divsf3(a: f32, b: f32) -> f32;
1131    fn __divdf3(a: f64, b: f64) -> f64;
1132    fn __negsf2(a: f32) -> f32;
1133    fn __negdf2(a: f64) -> f64;
1134    // --- f32/f64 conversions ---
1135    fn __extendsfdf2(a: f32) -> f64;
1136    fn __truncdfsf2(a: f64) -> f32;
1137    fn __fixsfsi(a: f32) -> i32;
1138    fn __fixdfsi(a: f64) -> i32;
1139    fn __fixsfdi(a: f32) -> i64;
1140    fn __fixdfdi(a: f64) -> i64;
1141    fn __fixunssfsi(a: f32) -> u32;
1142    fn __fixunsdfsi(a: f64) -> u32;
1143    fn __fixunssfdi(a: f32) -> u64;
1144    fn __fixunsdfdi(a: f64) -> u64;
1145    fn __floatsisf(i: i32) -> f32;
1146    fn __floatsidf(i: i32) -> f64;
1147    fn __floatdisf(i: i64) -> f32;
1148    fn __floatdidf(i: i64) -> f64;
1149    fn __floatunsisf(i: u32) -> f32;
1150    fn __floatunsidf(i: u32) -> f64;
1151    fn __floatundisf(i: u64) -> f32;
1152    fn __floatundidf(i: u64) -> f64;
1153    // --- f32/f64 comparisons (return 0 / nonzero / negative per GCC ABI) ---
1154    fn __unordsf2(a: f32, b: f32) -> i32;
1155    fn __unorddf2(a: f64, b: f64) -> i32;
1156    fn __eqsf2(a: f32, b: f32) -> i32;
1157    fn __eqdf2(a: f64, b: f64) -> i32;
1158    fn __nesf2(a: f32, b: f32) -> i32;
1159    fn __nedf2(a: f64, b: f64) -> i32;
1160    fn __gesf2(a: f32, b: f32) -> i32;
1161    fn __gedf2(a: f64, b: f64) -> i32;
1162    fn __ltsf2(a: f32, b: f32) -> i32;
1163    fn __ltdf2(a: f64, b: f64) -> i32;
1164    fn __lesf2(a: f32, b: f32) -> i32;
1165    fn __ledf2(a: f64, b: f64) -> i32;
1166    fn __gtsf2(a: f32, b: f32) -> i32;
1167    fn __gtdf2(a: f64, b: f64) -> i32;
1168}