Skip to main content

unc_vm_vm/
libcalls.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/master/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 `InstanceHandle`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 crate::func_data_registry::VMFuncRef;
41use crate::probestack::PROBESTACK;
42use crate::table::{RawTableElement, TableElement};
43use crate::trap::{raise_lib_trap, Trap, TrapCode};
44use crate::vmcontext::VMContext;
45use crate::VMExternRef;
46use std::fmt;
47use unc_vm_types::{
48    DataIndex, ElemIndex, FunctionIndex, LocalMemoryIndex, LocalTableIndex, MemoryIndex,
49    TableIndex, Type,
50};
51
52/// Implementation of f32.ceil
53#[no_mangle]
54pub extern "C" fn unc_vm_f32_ceil(x: f32) -> f32 {
55    x.ceil()
56}
57
58/// Implementation of f32.floor
59#[no_mangle]
60pub extern "C" fn unc_vm_f32_floor(x: f32) -> f32 {
61    x.floor()
62}
63
64/// Implementation of f32.trunc
65#[no_mangle]
66pub extern "C" fn unc_vm_f32_trunc(x: f32) -> f32 {
67    x.trunc()
68}
69
70/// Implementation of f32.nearest
71#[allow(clippy::float_arithmetic, clippy::float_cmp)]
72#[no_mangle]
73pub extern "C" fn unc_vm_f32_nearest(x: f32) -> f32 {
74    // Rust doesn't have a nearest function, so do it manually.
75    if x == 0.0 {
76        // Preserve the sign of zero.
77        x
78    } else {
79        // Nearest is either ceil or floor depending on which is nearest or even.
80        let u = x.ceil();
81        let d = x.floor();
82        let um = (x - u).abs();
83        let dm = (x - d).abs();
84        if um < dm
85            || (um == dm && {
86                let h = u / 2.;
87                h.floor() == h
88            })
89        {
90            u
91        } else {
92            d
93        }
94    }
95}
96
97/// Implementation of f64.ceil
98#[no_mangle]
99pub extern "C" fn unc_vm_f64_ceil(x: f64) -> f64 {
100    x.ceil()
101}
102
103/// Implementation of f64.floor
104#[no_mangle]
105pub extern "C" fn unc_vm_f64_floor(x: f64) -> f64 {
106    x.floor()
107}
108
109/// Implementation of f64.trunc
110#[no_mangle]
111pub extern "C" fn unc_vm_f64_trunc(x: f64) -> f64 {
112    x.trunc()
113}
114
115/// Implementation of f64.nearest
116#[allow(clippy::float_arithmetic, clippy::float_cmp)]
117#[no_mangle]
118pub extern "C" fn unc_vm_f64_nearest(x: f64) -> f64 {
119    // Rust doesn't have a nearest function, so do it manually.
120    if x == 0.0 {
121        // Preserve the sign of zero.
122        x
123    } else {
124        // Nearest is either ceil or floor depending on which is nearest or even.
125        let u = x.ceil();
126        let d = x.floor();
127        let um = (x - u).abs();
128        let dm = (x - d).abs();
129        if um < dm
130            || (um == dm && {
131                let h = u / 2.;
132                h.floor() == h
133            })
134        {
135            u
136        } else {
137            d
138        }
139    }
140}
141
142/// Implementation of memory.grow for locally-defined 32-bit memories.
143///
144/// # Safety
145///
146/// `vmctx` must be dereferenceable.
147#[no_mangle]
148pub unsafe extern "C" fn unc_vm_memory32_grow(
149    vmctx: *mut VMContext,
150    delta: u32,
151    memory_index: u32,
152) -> u32 {
153    let instance = (&*vmctx).instance();
154    let memory_index = LocalMemoryIndex::from_u32(memory_index);
155
156    instance.memory_grow(memory_index, delta).map(|pages| pages.0).unwrap_or(u32::max_value())
157}
158
159/// Implementation of memory.grow for imported 32-bit memories.
160///
161/// # Safety
162///
163/// `vmctx` must be dereferenceable.
164#[no_mangle]
165pub unsafe extern "C" fn unc_vm_imported_memory32_grow(
166    vmctx: *mut VMContext,
167    delta: u32,
168    memory_index: u32,
169) -> u32 {
170    let instance = (&*vmctx).instance();
171    let memory_index = MemoryIndex::from_u32(memory_index);
172
173    instance
174        .imported_memory_grow(memory_index, delta)
175        .map(|pages| pages.0)
176        .unwrap_or(u32::max_value())
177}
178
179/// Implementation of memory.size for locally-defined 32-bit memories.
180///
181/// # Safety
182///
183/// `vmctx` must be dereferenceable.
184#[no_mangle]
185pub unsafe extern "C" fn unc_vm_memory32_size(vmctx: *mut VMContext, memory_index: u32) -> u32 {
186    let instance = (&*vmctx).instance();
187    let memory_index = LocalMemoryIndex::from_u32(memory_index);
188
189    instance.memory_size(memory_index).0
190}
191
192/// Implementation of memory.size for imported 32-bit memories.
193///
194/// # Safety
195///
196/// `vmctx` must be dereferenceable.
197#[no_mangle]
198pub unsafe extern "C" fn unc_vm_imported_memory32_size(
199    vmctx: *mut VMContext,
200    memory_index: u32,
201) -> u32 {
202    let instance = (&*vmctx).instance();
203    let memory_index = MemoryIndex::from_u32(memory_index);
204
205    instance.imported_memory_size(memory_index).0
206}
207
208/// Implementation of `table.copy`.
209///
210/// # Safety
211///
212/// `vmctx` must be dereferenceable.
213#[no_mangle]
214pub unsafe extern "C" fn unc_vm_table_copy(
215    vmctx: *mut VMContext,
216    dst_table_index: u32,
217    src_table_index: u32,
218    dst: u32,
219    src: u32,
220    len: u32,
221) {
222    let result = {
223        let dst_table_index = TableIndex::from_u32(dst_table_index);
224        let src_table_index = TableIndex::from_u32(src_table_index);
225        let instance = (&*vmctx).instance();
226        let dst_table = instance.get_table(dst_table_index);
227        let src_table = instance.get_table(src_table_index);
228        dst_table.copy(src_table, dst, src, len)
229    };
230    if let Err(trap) = result {
231        raise_lib_trap(trap);
232    }
233}
234
235/// Implementation of `table.init`.
236///
237/// # Safety
238///
239/// `vmctx` must be dereferenceable.
240#[no_mangle]
241pub unsafe extern "C" fn unc_vm_table_init(
242    vmctx: *mut VMContext,
243    table_index: u32,
244    elem_index: u32,
245    dst: u32,
246    src: u32,
247    len: u32,
248) {
249    let result = {
250        let table_index = TableIndex::from_u32(table_index);
251        let elem_index = ElemIndex::from_u32(elem_index);
252        let instance = (&*vmctx).instance();
253        instance.table_init(table_index, elem_index, dst, src, len)
254    };
255    if let Err(trap) = result {
256        raise_lib_trap(trap);
257    }
258}
259
260/// Implementation of `table.fill`.
261///
262/// # Safety
263///
264/// `vmctx` must be dereferenceable.
265#[no_mangle]
266pub unsafe extern "C" fn unc_vm_table_fill(
267    vmctx: *mut VMContext,
268    table_index: u32,
269    start_idx: u32,
270    item: RawTableElement,
271    len: u32,
272) {
273    let result = {
274        let table_index = TableIndex::from_u32(table_index);
275        let instance = (&*vmctx).instance();
276        let elem = match instance.get_table(table_index).ty().ty {
277            Type::ExternRef => TableElement::ExternRef(item.extern_ref.into()),
278            Type::FuncRef => TableElement::FuncRef(item.func_ref),
279            _ => panic!("Unrecognized table type: does not contain references"),
280        };
281
282        instance.table_fill(table_index, start_idx, elem, len)
283    };
284    if let Err(trap) = result {
285        raise_lib_trap(trap);
286    }
287}
288
289/// Implementation of `table.size`.
290///
291/// # Safety
292///
293/// `vmctx` must be dereferenceable.
294#[no_mangle]
295pub unsafe extern "C" fn unc_vm_table_size(vmctx: *mut VMContext, table_index: u32) -> u32 {
296    let instance = (&*vmctx).instance();
297    let table_index = LocalTableIndex::from_u32(table_index);
298
299    instance.table_size(table_index)
300}
301
302/// Implementation of `table.size` for imported tables.
303///
304/// # Safety
305///
306/// `vmctx` must be dereferenceable.
307#[no_mangle]
308pub unsafe extern "C" fn unc_vm_imported_table_size(
309    vmctx: *mut VMContext,
310    table_index: u32,
311) -> u32 {
312    let instance = (&*vmctx).instance();
313    let table_index = TableIndex::from_u32(table_index);
314
315    instance.imported_table_size(table_index)
316}
317
318/// Implementation of `table.get`.
319///
320/// # Safety
321///
322/// `vmctx` must be dereferenceable.
323#[no_mangle]
324pub unsafe extern "C" fn unc_vm_table_get(
325    vmctx: *mut VMContext,
326    table_index: u32,
327    elem_index: u32,
328) -> RawTableElement {
329    let instance = (&*vmctx).instance();
330    let table_index = LocalTableIndex::from_u32(table_index);
331
332    // TODO: type checking, maybe have specialized accessors
333    match instance.table_get(table_index, elem_index) {
334        Some(table_ref) => table_ref.into(),
335        None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
336    }
337}
338
339/// Implementation of `table.get` for imported tables.
340///
341/// # Safety
342///
343/// `vmctx` must be dereferenceable.
344#[no_mangle]
345pub unsafe extern "C" fn unc_vm_imported_table_get(
346    vmctx: *mut VMContext,
347    table_index: u32,
348    elem_index: u32,
349) -> RawTableElement {
350    let instance = (&*vmctx).instance();
351    let table_index = TableIndex::from_u32(table_index);
352
353    // TODO: type checking, maybe have specialized accessors
354    match instance.imported_table_get(table_index, elem_index) {
355        Some(table_ref) => table_ref.into(),
356        None => raise_lib_trap(Trap::lib(TrapCode::TableAccessOutOfBounds)),
357    }
358}
359
360/// Implementation of `table.set`.
361///
362/// # Safety
363///
364/// `vmctx` must be dereferenceable.
365///
366/// It is the caller's responsibility to increment the ref count of any ref counted
367/// type before passing it to this function.
368#[no_mangle]
369pub unsafe extern "C" fn unc_vm_table_set(
370    vmctx: *mut VMContext,
371    table_index: u32,
372    elem_index: u32,
373    value: RawTableElement,
374) {
375    let instance = (&*vmctx).instance();
376    let table_index = TableIndex::from_u32(table_index);
377    if let Ok(local_table) = instance.artifact.import_counts().local_table_index(table_index) {
378        let elem = match instance.get_local_table(local_table).ty().ty {
379            Type::ExternRef => TableElement::ExternRef(value.extern_ref.into()),
380            Type::FuncRef => TableElement::FuncRef(value.func_ref),
381            _ => panic!("Unrecognized table type: does not contain references"),
382        };
383        // TODO: type checking, maybe have specialized accessors
384        let result = instance.table_set(local_table, elem_index, elem);
385        if let Err(trap) = result {
386            raise_lib_trap(trap);
387        }
388    } else {
389        panic!("unc_vm_imported_table_set should have been called");
390    }
391}
392
393/// Implementation of `table.set` for imported tables.
394///
395/// # Safety
396///
397/// `vmctx` must be dereferenceable.
398#[no_mangle]
399pub unsafe extern "C" fn unc_vm_imported_table_set(
400    vmctx: *mut VMContext,
401    table_index: u32,
402    elem_index: u32,
403    value: RawTableElement,
404) {
405    let instance = (&*vmctx).instance();
406    let table_index = TableIndex::from_u32(table_index);
407    let elem = match instance.get_foreign_table(table_index).ty().ty {
408        Type::ExternRef => TableElement::ExternRef(value.extern_ref.into()),
409        Type::FuncRef => TableElement::FuncRef(value.func_ref),
410        _ => panic!("Unrecognized table type: does not contain references"),
411    };
412    let result = instance.imported_table_set(table_index, elem_index, elem);
413    if let Err(trap) = result {
414        raise_lib_trap(trap);
415    }
416}
417
418/// Implementation of `table.grow` for locally-defined tables.
419///
420/// # Safety
421///
422/// `vmctx` must be dereferenceable.
423#[no_mangle]
424pub unsafe extern "C" fn unc_vm_table_grow(
425    vmctx: *mut VMContext,
426    init_value: RawTableElement,
427    delta: u32,
428    table_index: u32,
429) -> u32 {
430    let instance = (&*vmctx).instance();
431    let table_index = LocalTableIndex::from_u32(table_index);
432    let init_value = match instance.get_local_table(table_index).ty().ty {
433        Type::ExternRef => TableElement::ExternRef(init_value.extern_ref.into()),
434        Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
435        _ => panic!("Unrecognized table type: does not contain references"),
436    };
437    instance.table_grow(table_index, delta, init_value).unwrap_or(u32::max_value())
438}
439
440/// Implementation of `table.grow` for imported tables.
441///
442/// # Safety
443///
444/// `vmctx` must be dereferenceable.
445#[no_mangle]
446pub unsafe extern "C" fn unc_vm_imported_table_grow(
447    vmctx: *mut VMContext,
448    init_value: RawTableElement,
449    delta: u32,
450    table_index: u32,
451) -> u32 {
452    let instance = (&*vmctx).instance();
453    let table_index = TableIndex::from_u32(table_index);
454    let init_value = match instance.get_table(table_index).ty().ty {
455        Type::ExternRef => TableElement::ExternRef(init_value.extern_ref.into()),
456        Type::FuncRef => TableElement::FuncRef(init_value.func_ref),
457        _ => panic!("Unrecognized table type: does not contain references"),
458    };
459
460    instance.imported_table_grow(table_index, delta, init_value).unwrap_or(u32::max_value())
461}
462
463/// Implementation of `func.ref`.
464///
465/// # Safety
466///
467/// `vmctx` must be dereferenceable.
468#[no_mangle]
469pub unsafe extern "C" fn unc_vm_func_ref(vmctx: *mut VMContext, function_index: u32) -> VMFuncRef {
470    let instance = (&*vmctx).instance();
471    let function_index = FunctionIndex::from_u32(function_index);
472
473    instance.func_ref(function_index).unwrap()
474}
475
476/// Implementation of externref increment
477///
478/// # Safety
479///
480/// `vmctx` must be dereferenceable.
481///
482/// This function must only be called at precise locations to prevent memory leaks.
483#[no_mangle]
484pub unsafe extern "C" fn unc_vm_externref_inc(externref: VMExternRef) {
485    externref.ref_clone();
486}
487
488/// Implementation of externref decrement
489///
490/// # Safety
491///
492/// `vmctx` must be dereferenceable.
493///
494/// This function must only be called at precise locations, otherwise use-after-free
495/// and other serious memory bugs may occur.
496#[no_mangle]
497pub unsafe extern "C" fn unc_vm_externref_dec(mut externref: VMExternRef) {
498    externref.ref_drop()
499}
500
501/// Implementation of `elem.drop`.
502///
503/// # Safety
504///
505/// `vmctx` must be dereferenceable.
506#[no_mangle]
507pub unsafe extern "C" fn unc_vm_elem_drop(vmctx: *mut VMContext, elem_index: u32) {
508    let elem_index = ElemIndex::from_u32(elem_index);
509    let instance = (&*vmctx).instance();
510    instance.elem_drop(elem_index);
511}
512
513/// Implementation of `memory.copy` for locally defined memories.
514///
515/// # Safety
516///
517/// `vmctx` must be dereferenceable.
518#[no_mangle]
519pub unsafe extern "C" fn unc_vm_memory32_copy(
520    vmctx: *mut VMContext,
521    memory_index: u32,
522    dst: u32,
523    src: u32,
524    len: u32,
525) {
526    let result = {
527        let memory_index = LocalMemoryIndex::from_u32(memory_index);
528        let instance = (&*vmctx).instance();
529        instance.local_memory_copy(memory_index, dst, src, len)
530    };
531    if let Err(trap) = result {
532        raise_lib_trap(trap);
533    }
534}
535
536/// Implementation of `memory.copy` for imported memories.
537///
538/// # Safety
539///
540/// `vmctx` must be dereferenceable.
541#[no_mangle]
542pub unsafe extern "C" fn unc_vm_imported_memory32_copy(
543    vmctx: *mut VMContext,
544    memory_index: u32,
545    dst: u32,
546    src: u32,
547    len: u32,
548) {
549    let result = {
550        let memory_index = MemoryIndex::from_u32(memory_index);
551        let instance = (&*vmctx).instance();
552        instance.imported_memory_copy(memory_index, dst, src, len)
553    };
554    if let Err(trap) = result {
555        raise_lib_trap(trap);
556    }
557}
558
559/// Implementation of `memory.fill` for locally defined memories.
560///
561/// # Safety
562///
563/// `vmctx` must be dereferenceable.
564#[no_mangle]
565pub unsafe extern "C" fn unc_vm_memory32_fill(
566    vmctx: *mut VMContext,
567    memory_index: u32,
568    dst: u32,
569    val: u32,
570    len: u32,
571) {
572    let result = {
573        let memory_index = LocalMemoryIndex::from_u32(memory_index);
574        let instance = (&*vmctx).instance();
575        instance.local_memory_fill(memory_index, dst, val, len)
576    };
577    if let Err(trap) = result {
578        raise_lib_trap(trap);
579    }
580}
581
582/// Implementation of `memory.fill` for imported memories.
583///
584/// # Safety
585///
586/// `vmctx` must be dereferenceable.
587#[no_mangle]
588pub unsafe extern "C" fn unc_vm_imported_memory32_fill(
589    vmctx: *mut VMContext,
590    memory_index: u32,
591    dst: u32,
592    val: u32,
593    len: u32,
594) {
595    let result = {
596        let memory_index = MemoryIndex::from_u32(memory_index);
597        let instance = (&*vmctx).instance();
598        instance.imported_memory_fill(memory_index, dst, val, len)
599    };
600    if let Err(trap) = result {
601        raise_lib_trap(trap);
602    }
603}
604
605/// Implementation of `memory.init`.
606///
607/// # Safety
608///
609/// `vmctx` must be dereferenceable.
610#[no_mangle]
611pub unsafe extern "C" fn unc_vm_memory32_init(
612    vmctx: *mut VMContext,
613    memory_index: u32,
614    data_index: u32,
615    dst: u32,
616    src: u32,
617    len: u32,
618) {
619    let result = {
620        let memory_index = MemoryIndex::from_u32(memory_index);
621        let data_index = DataIndex::from_u32(data_index);
622        let instance = (&*vmctx).instance();
623        instance.memory_init(memory_index, data_index, dst, src, len)
624    };
625    if let Err(trap) = result {
626        raise_lib_trap(trap);
627    }
628}
629
630/// Implementation of `data.drop`.
631///
632/// # Safety
633///
634/// `vmctx` must be dereferenceable.
635#[no_mangle]
636pub unsafe extern "C" fn unc_vm_data_drop(vmctx: *mut VMContext, data_index: u32) {
637    let data_index = DataIndex::from_u32(data_index);
638    let instance = (&*vmctx).instance();
639    instance.data_drop(data_index)
640}
641
642/// Implementation for raising a trap
643///
644/// # Safety
645///
646/// Only safe to call when wasm code is on the stack, aka `unc_vm_call` or
647/// `unc_vm_call_trampoline` must have been previously called.
648#[no_mangle]
649pub unsafe extern "C" fn unc_vm_raise_trap(trap_code: TrapCode) -> ! {
650    let trap = Trap::lib(trap_code);
651    raise_lib_trap(trap)
652}
653
654/// Probestack check
655///
656/// # Safety
657///
658/// This function does not follow the standard function ABI, and is called as
659/// part of the function prologue.
660#[no_mangle]
661pub static unc_vm_probestack: unsafe extern "C" fn() = PROBESTACK;
662
663/// The name of a runtime library routine.
664///
665/// This list is likely to grow over time.
666#[derive(
667    rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Copy, Clone, Debug, PartialEq, Eq, Hash,
668)]
669pub enum LibCall {
670    /// ceil.f32
671    CeilF32,
672
673    /// ceil.f64
674    CeilF64,
675
676    /// floor.f32
677    FloorF32,
678
679    /// floor.f64
680    FloorF64,
681
682    /// nearest.f32
683    NearestF32,
684
685    /// nearest.f64
686    NearestF64,
687
688    /// trunc.f32
689    TruncF32,
690
691    /// trunc.f64
692    TruncF64,
693
694    /// memory.size for local functions
695    Memory32Size,
696
697    /// memory.size for imported functions
698    ImportedMemory32Size,
699
700    /// table.copy
701    TableCopy,
702
703    /// table.init
704    TableInit,
705
706    /// table.fill
707    TableFill,
708
709    /// table.size for local tables
710    TableSize,
711
712    /// table.size for imported tables
713    ImportedTableSize,
714
715    /// table.get for local tables
716    TableGet,
717
718    /// table.get for imported tables
719    ImportedTableGet,
720
721    /// table.set for local tables
722    TableSet,
723
724    /// table.set for imported tables
725    ImportedTableSet,
726
727    /// table.grow for local tables
728    TableGrow,
729
730    /// table.grow for imported tables
731    ImportedTableGrow,
732
733    /// ref.func
734    FuncRef,
735
736    /// elem.drop
737    ElemDrop,
738
739    /// memory.copy for local memories
740    Memory32Copy,
741
742    /// memory.copy for imported memories
743    ImportedMemory32Copy,
744
745    /// memory.fill for local memories
746    Memory32Fill,
747
748    /// memory.fill for imported memories
749    ImportedMemory32Fill,
750
751    /// memory.init
752    Memory32Init,
753
754    /// data.drop
755    DataDrop,
756
757    /// A custom trap
758    RaiseTrap,
759
760    /// probe for stack overflow. These are emitted for functions which need
761    /// when the `enable_probestack` setting is true.
762    Probestack,
763}
764
765impl LibCall {
766    /// The function pointer to a libcall
767    pub fn function_pointer(self) -> usize {
768        match self {
769            Self::CeilF32 => unc_vm_f32_ceil as usize,
770            Self::CeilF64 => unc_vm_f64_ceil as usize,
771            Self::FloorF32 => unc_vm_f32_floor as usize,
772            Self::FloorF64 => unc_vm_f64_floor as usize,
773            Self::NearestF32 => unc_vm_f32_nearest as usize,
774            Self::NearestF64 => unc_vm_f64_nearest as usize,
775            Self::TruncF32 => unc_vm_f32_trunc as usize,
776            Self::TruncF64 => unc_vm_f64_trunc as usize,
777            Self::Memory32Size => unc_vm_memory32_size as usize,
778            Self::ImportedMemory32Size => unc_vm_imported_memory32_size as usize,
779            Self::TableCopy => unc_vm_table_copy as usize,
780            Self::TableInit => unc_vm_table_init as usize,
781            Self::TableFill => unc_vm_table_fill as usize,
782            Self::TableSize => unc_vm_table_size as usize,
783            Self::ImportedTableSize => unc_vm_imported_table_size as usize,
784            Self::TableGet => unc_vm_table_get as usize,
785            Self::ImportedTableGet => unc_vm_imported_table_get as usize,
786            Self::TableSet => unc_vm_table_set as usize,
787            Self::ImportedTableSet => unc_vm_imported_table_set as usize,
788            Self::TableGrow => unc_vm_table_grow as usize,
789            Self::ImportedTableGrow => unc_vm_imported_table_grow as usize,
790            Self::FuncRef => unc_vm_func_ref as usize,
791            Self::ElemDrop => unc_vm_elem_drop as usize,
792            Self::Memory32Copy => unc_vm_memory32_copy as usize,
793            Self::ImportedMemory32Copy => unc_vm_imported_memory32_copy as usize,
794            Self::Memory32Fill => unc_vm_memory32_fill as usize,
795            Self::ImportedMemory32Fill => unc_vm_memory32_fill as usize,
796            Self::Memory32Init => unc_vm_memory32_init as usize,
797            Self::DataDrop => unc_vm_data_drop as usize,
798            Self::Probestack => unc_vm_probestack as usize,
799            Self::RaiseTrap => unc_vm_raise_trap as usize,
800        }
801    }
802
803    /// Return the function name associated to the libcall.
804    pub fn to_function_name(&self) -> &str {
805        match self {
806            Self::CeilF32 => "unc_vm_f32_ceil",
807            Self::CeilF64 => "unc_vm_f64_ceil",
808            Self::FloorF32 => "unc_vm_f32_floor",
809            Self::FloorF64 => "unc_vm_f64_floor",
810            Self::NearestF32 => "unc_vm_f32_nearest",
811            Self::NearestF64 => "unc_vm_f64_nearest",
812            Self::TruncF32 => "unc_vm_f32_trunc",
813            Self::TruncF64 => "unc_vm_f64_trunc",
814            Self::Memory32Size => "unc_vm_memory32_size",
815            Self::ImportedMemory32Size => "unc_vm_imported_memory32_size",
816            Self::TableCopy => "unc_vm_table_copy",
817            Self::TableInit => "unc_vm_table_init",
818            Self::TableFill => "unc_vm_table_fill",
819            Self::TableSize => "unc_vm_table_size",
820            Self::ImportedTableSize => "unc_vm_imported_table_size",
821            Self::TableGet => "unc_vm_table_get",
822            Self::ImportedTableGet => "unc_vm_imported_table_get",
823            Self::TableSet => "unc_vm_table_set",
824            Self::ImportedTableSet => "unc_vm_imported_table_set",
825            Self::TableGrow => "unc_vm_table_grow",
826            Self::ImportedTableGrow => "unc_vm_imported_table_grow",
827            Self::FuncRef => "unc_vm_func_ref",
828            Self::ElemDrop => "unc_vm_elem_drop",
829            Self::Memory32Copy => "unc_vm_memory32_copy",
830            Self::ImportedMemory32Copy => "unc_vm_imported_memory32_copy",
831            Self::Memory32Fill => "unc_vm_memory32_fill",
832            Self::ImportedMemory32Fill => "unc_vm_imported_memory32_fill",
833            Self::Memory32Init => "unc_vm_memory32_init",
834            Self::DataDrop => "unc_vm_data_drop",
835            Self::RaiseTrap => "unc_vm_raise_trap",
836            // We have to do this because macOS requires a leading `_` and it's not
837            // a normal function, it's a static variable, so we have to do it manually.
838            #[cfg(target_vendor = "apple")]
839            Self::Probestack => "_unc_vm_probestack",
840            #[cfg(not(target_vendor = "apple"))]
841            Self::Probestack => "unc_vm_probestack",
842        }
843    }
844}
845
846impl fmt::Display for LibCall {
847    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
848        fmt::Debug::fmt(self, f)
849    }
850}