1#![allow(missing_docs)] use 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#[no_mangle]
54pub extern "C" fn unc_vm_f32_ceil(x: f32) -> f32 {
55 x.ceil()
56}
57
58#[no_mangle]
60pub extern "C" fn unc_vm_f32_floor(x: f32) -> f32 {
61 x.floor()
62}
63
64#[no_mangle]
66pub extern "C" fn unc_vm_f32_trunc(x: f32) -> f32 {
67 x.trunc()
68}
69
70#[allow(clippy::float_arithmetic, clippy::float_cmp)]
72#[no_mangle]
73pub extern "C" fn unc_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#[no_mangle]
99pub extern "C" fn unc_vm_f64_ceil(x: f64) -> f64 {
100 x.ceil()
101}
102
103#[no_mangle]
105pub extern "C" fn unc_vm_f64_floor(x: f64) -> f64 {
106 x.floor()
107}
108
109#[no_mangle]
111pub extern "C" fn unc_vm_f64_trunc(x: f64) -> f64 {
112 x.trunc()
113}
114
115#[allow(clippy::float_arithmetic, clippy::float_cmp)]
117#[no_mangle]
118pub extern "C" fn unc_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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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 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#[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 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#[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 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#[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#[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#[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#[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#[no_mangle]
484pub unsafe extern "C" fn unc_vm_externref_inc(externref: VMExternRef) {
485 externref.ref_clone();
486}
487
488#[no_mangle]
497pub unsafe extern "C" fn unc_vm_externref_dec(mut externref: VMExternRef) {
498 externref.ref_drop()
499}
500
501#[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#[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#[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#[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#[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#[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#[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#[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#[no_mangle]
661pub static unc_vm_probestack: unsafe extern "C" fn() = PROBESTACK;
662
663#[derive(
667 rkyv::Serialize, rkyv::Deserialize, rkyv::Archive, Copy, Clone, Debug, PartialEq, Eq, Hash,
668)]
669pub enum LibCall {
670 CeilF32,
672
673 CeilF64,
675
676 FloorF32,
678
679 FloorF64,
681
682 NearestF32,
684
685 NearestF64,
687
688 TruncF32,
690
691 TruncF64,
693
694 Memory32Size,
696
697 ImportedMemory32Size,
699
700 TableCopy,
702
703 TableInit,
705
706 TableFill,
708
709 TableSize,
711
712 ImportedTableSize,
714
715 TableGet,
717
718 ImportedTableGet,
720
721 TableSet,
723
724 ImportedTableSet,
726
727 TableGrow,
729
730 ImportedTableGrow,
732
733 FuncRef,
735
736 ElemDrop,
738
739 Memory32Copy,
741
742 ImportedMemory32Copy,
744
745 Memory32Fill,
747
748 ImportedMemory32Fill,
750
751 Memory32Init,
753
754 DataDrop,
756
757 RaiseTrap,
759
760 Probestack,
763}
764
765impl LibCall {
766 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 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 #[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}