1#![allow(missing_docs)] use 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#[unsafe(no_mangle)]
54pub extern "C" fn near_vm_f32_ceil(x: f32) -> f32 {
55 x.ceil()
56}
57
58#[unsafe(no_mangle)]
60pub extern "C" fn near_vm_f32_floor(x: f32) -> f32 {
61 x.floor()
62}
63
64#[unsafe(no_mangle)]
66pub extern "C" fn near_vm_f32_trunc(x: f32) -> f32 {
67 x.trunc()
68}
69
70#[allow(clippy::float_arithmetic, clippy::float_cmp)]
72#[unsafe(no_mangle)]
73pub extern "C" fn near_vm_f32_nearest(x: f32) -> f32 {
74 if x == 0.0 {
76 x
78 } else {
79 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#[unsafe(no_mangle)]
99pub extern "C" fn near_vm_f64_ceil(x: f64) -> f64 {
100 x.ceil()
101}
102
103#[unsafe(no_mangle)]
105pub extern "C" fn near_vm_f64_floor(x: f64) -> f64 {
106 x.floor()
107}
108
109#[unsafe(no_mangle)]
111pub extern "C" fn near_vm_f64_trunc(x: f64) -> f64 {
112 x.trunc()
113}
114
115#[allow(clippy::float_arithmetic, clippy::float_cmp)]
117#[unsafe(no_mangle)]
118pub extern "C" fn near_vm_f64_nearest(x: f64) -> f64 {
119 if x == 0.0 {
121 x
123 } else {
124 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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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 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#[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 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#[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 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#[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#[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#[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#[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#[unsafe(no_mangle)]
515pub unsafe extern "C" fn near_vm_externref_inc(externref: VMExternRef) {
516 externref.ref_clone();
517}
518
519#[unsafe(no_mangle)]
528pub unsafe extern "C" fn near_vm_externref_dec(mut externref: VMExternRef) {
529 externref.ref_drop()
530}
531
532#[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#[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#[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#[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#[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#[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#[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#[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#[unsafe(no_mangle)]
698#[allow(non_upper_case_globals)]
699pub static near_vm_probestack: unsafe extern "C" fn() = PROBESTACK;
700
701#[derive(
705 rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Copy, Clone, Debug, PartialEq, Eq, Hash,
706)]
707pub enum LibCall {
708 CeilF32,
710
711 CeilF64,
713
714 FloorF32,
716
717 FloorF64,
719
720 NearestF32,
722
723 NearestF64,
725
726 TruncF32,
728
729 TruncF64,
731
732 Memory32Size,
734
735 ImportedMemory32Size,
737
738 TableCopy,
740
741 TableInit,
743
744 TableFill,
746
747 TableSize,
749
750 ImportedTableSize,
752
753 TableGet,
755
756 ImportedTableGet,
758
759 TableSet,
761
762 ImportedTableSet,
764
765 TableGrow,
767
768 ImportedTableGrow,
770
771 FuncRef,
773
774 ElemDrop,
776
777 Memory32Copy,
779
780 ImportedMemory32Copy,
782
783 Memory32Fill,
785
786 ImportedMemory32Fill,
788
789 Memory32Init,
791
792 DataDrop,
794
795 RaiseTrap,
797
798 Probestack,
801}
802
803impl LibCall {
804 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 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 #[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}