near_vm_vm/
libcalls.rs

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