1use crate::component::Instance;
4use crate::prelude::*;
5#[cfg(feature = "component-model-async")]
6use crate::runtime::component::concurrent::ResourcePair;
7use crate::runtime::vm::component::{ComponentInstance, VMComponentContext};
8use crate::runtime::vm::{HostResultHasUnwindSentinel, VMStore, VmSafe};
9use core::cell::Cell;
10use core::ptr::NonNull;
11use core::slice;
12use wasmtime_environ::component::*;
13
14const UTF16_TAG: usize = 1 << 31;
15
16macro_rules! signature {
17 (@ty size) => (usize);
18 (@ty ptr_u8) => (*mut u8);
19 (@ty ptr_u16) => (*mut u16);
20 (@ty ptr_size) => (*mut usize);
21 (@ty u8) => (u8);
22 (@ty u32) => (u32);
23 (@ty u64) => (u64);
24 (@ty bool) => (bool);
25 (@ty vmctx) => (NonNull<VMComponentContext>);
26}
27
28macro_rules! define_builtins {
31 (
32 $(
33 $( #[$attr:meta] )*
34 $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
35 )*
36 ) => {
37 #[repr(C)]
40 pub struct VMComponentBuiltins {
41 $(
42 $name: unsafe extern "C" fn(
43 $(signature!(@ty $param),)*
44 ) $( -> signature!(@ty $result))?,
45 )*
46 }
47
48 unsafe impl VmSafe for VMComponentBuiltins {}
51
52 impl VMComponentBuiltins {
53 pub const INIT: VMComponentBuiltins = VMComponentBuiltins {
54 $($name: trampolines::$name,)*
55 };
56
57 pub fn expose_provenance(&self) -> NonNull<Self>{
67 $(
68 (self.$name as *mut u8).expose_provenance();
69 )*
70 NonNull::from(self)
71 }
72 }
73 };
74}
75
76wasmtime_environ::foreach_builtin_component_function!(define_builtins);
77
78mod trampolines {
83 use super::{ComponentInstance, VMComponentContext};
84 use core::ptr::NonNull;
85
86 macro_rules! shims {
87 (
88 $(
89 $( #[cfg($attr:meta)] )?
90 $name:ident( vmctx: vmctx $(, $pname:ident: $param:ident )* ) $( -> $result:ident )?;
91 )*
92 ) => (
93 $(
94 pub unsafe extern "C" fn $name(
95 vmctx: NonNull<VMComponentContext>
96 $(,$pname : signature!(@ty $param))*
97 ) $( -> signature!(@ty $result))? {
98 $(#[cfg($attr)])?
99 {
100 $(shims!(@validate_param $pname $param);)*
101
102 let ret = unsafe {
103 ComponentInstance::enter_host_from_wasm(vmctx, |store, instance| {
104 shims!(@invoke $name(store, instance,) $($pname)*)
105 })
106 };
107 shims!(@convert_ret ret $($pname: $param)*)
108 }
109 $(
110 #[cfg(not($attr))]
111 {
112 let _ = vmctx;
113 unreachable!();
114 }
115 )?
116 }
117 )*
118 );
119
120 (@convert_ret $ret:ident) => ($ret);
123 (@convert_ret $ret:ident $retptr:ident: ptr_size) => ({
124 let (a, b) = $ret;
125 unsafe {
126 *$retptr = b;
127 }
128 a
129 });
130 (@convert_ret $ret:ident $name:ident: $ty:ident $($rest:tt)*) => (
131 shims!(@convert_ret $ret $($rest)*)
132 );
133
134 (@validate_param $arg:ident ptr_u16) => ({
135 assert!(($arg as usize) % 2 == 0, "unaligned 16-bit pointer");
139 });
140 (@validate_param $arg:ident $ty:ident) => ();
141
142 (@invoke $m:ident ($($args:tt)*)) => (super::$m($($args)*));
145
146 (@invoke $m:ident ($($args:tt)*) ret2 $($rest:tt)*) => (
148 shims!(@invoke $m ($($args)*) $($rest)*)
149 );
150
151 (@invoke $m:ident ($($args:tt)*) $param:ident $($rest:tt)*) => (
153 shims!(@invoke $m ($($args)* $param,) $($rest)*)
154 );
155 }
156
157 wasmtime_environ::foreach_builtin_component_function!(shims);
158}
159
160fn assert_no_overlap<T, U>(a: &[T], b: &[U]) {
164 let a_start = a.as_ptr() as usize;
165 let a_end = a_start + (a.len() * core::mem::size_of::<T>());
166 let b_start = b.as_ptr() as usize;
167 let b_end = b_start + (b.len() * core::mem::size_of::<U>());
168
169 if a_start < b_start {
170 assert!(a_end < b_start);
171 } else {
172 assert!(b_end < a_start);
173 }
174}
175
176unsafe fn utf8_to_utf8(
182 _: &mut dyn VMStore,
183 _: Instance,
184 src: *mut u8,
185 len: usize,
186 dst: *mut u8,
187) -> Result<()> {
188 let src = unsafe { slice::from_raw_parts(src, len) };
189 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
190 assert_no_overlap(src, dst);
191 log::trace!("utf8-to-utf8 {len}");
192 let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?;
193 dst.copy_from_slice(src.as_bytes());
194 Ok(())
195}
196
197unsafe fn utf16_to_utf16(
203 _: &mut dyn VMStore,
204 _: Instance,
205 src: *mut u16,
206 len: usize,
207 dst: *mut u16,
208) -> Result<()> {
209 let src = unsafe { slice::from_raw_parts(src, len) };
210 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
211 assert_no_overlap(src, dst);
212 log::trace!("utf16-to-utf16 {len}");
213 run_utf16_to_utf16(src, dst)?;
214 Ok(())
215}
216
217fn run_utf16_to_utf16(src: &[u16], mut dst: &mut [u16]) -> Result<bool> {
220 let mut all_latin1 = true;
221 for ch in core::char::decode_utf16(src.iter().map(|i| u16::from_le(*i))) {
222 let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?;
223 all_latin1 = all_latin1 && u8::try_from(u32::from(ch)).is_ok();
224 let result = ch.encode_utf16(dst);
225 let size = result.len();
226 for item in result {
227 *item = item.to_le();
228 }
229 dst = &mut dst[size..];
230 }
231 Ok(all_latin1)
232}
233
234unsafe fn latin1_to_latin1(
239 _: &mut dyn VMStore,
240 _: Instance,
241 src: *mut u8,
242 len: usize,
243 dst: *mut u8,
244) -> Result<()> {
245 let src = unsafe { slice::from_raw_parts(src, len) };
246 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
247 assert_no_overlap(src, dst);
248 log::trace!("latin1-to-latin1 {len}");
249 dst.copy_from_slice(src);
250 Ok(())
251}
252
253unsafe fn latin1_to_utf16(
258 _: &mut dyn VMStore,
259 _: Instance,
260 src: *mut u8,
261 len: usize,
262 dst: *mut u16,
263) -> Result<()> {
264 let src = unsafe { slice::from_raw_parts(src, len) };
265 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
266 assert_no_overlap(src, dst);
267 for (src, dst) in src.iter().zip(dst) {
268 *dst = u16::from(*src).to_le();
269 }
270 log::trace!("latin1-to-utf16 {len}");
271 Ok(())
272}
273
274struct CopySizeReturn(usize);
275
276unsafe impl HostResultHasUnwindSentinel for CopySizeReturn {
277 type Abi = usize;
278 const SENTINEL: usize = usize::MAX;
279 fn into_abi(self) -> usize {
280 self.0
281 }
282}
283
284unsafe fn utf8_to_utf16(
289 _: &mut dyn VMStore,
290 _: Instance,
291 src: *mut u8,
292 len: usize,
293 dst: *mut u16,
294) -> Result<CopySizeReturn> {
295 let src = unsafe { slice::from_raw_parts(src, len) };
296 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
297 assert_no_overlap(src, dst);
298
299 let result = run_utf8_to_utf16(src, dst)?;
300 log::trace!("utf8-to-utf16 {len} => {result}");
301 Ok(CopySizeReturn(result))
302}
303
304fn run_utf8_to_utf16(src: &[u8], dst: &mut [u16]) -> Result<usize> {
305 let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?;
306 let mut amt = 0;
307 for (i, dst) in src.encode_utf16().zip(dst) {
308 *dst = i.to_le();
309 amt += 1;
310 }
311 Ok(amt)
312}
313
314struct SizePair {
315 src_read: usize,
316 dst_written: usize,
317}
318
319unsafe impl HostResultHasUnwindSentinel for SizePair {
320 type Abi = (usize, usize);
321 const SENTINEL: (usize, usize) = (usize::MAX, 0);
322 fn into_abi(self) -> (usize, usize) {
323 (self.src_read, self.dst_written)
324 }
325}
326
327unsafe fn utf16_to_utf8(
334 _: &mut dyn VMStore,
335 _: Instance,
336 src: *mut u16,
337 src_len: usize,
338 dst: *mut u8,
339 dst_len: usize,
340) -> Result<SizePair> {
341 let src = unsafe { slice::from_raw_parts(src, src_len) };
342 let mut dst = unsafe { slice::from_raw_parts_mut(dst, dst_len) };
343 assert_no_overlap(src, dst);
344
345 let src_iter_read = Cell::new(0);
349 let src_iter = src.iter().map(|i| {
350 src_iter_read.set(src_iter_read.get() + 1);
351 u16::from_le(*i)
352 });
353
354 let mut src_read = 0;
355 let mut dst_written = 0;
356
357 for ch in core::char::decode_utf16(src_iter) {
358 let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?;
359
360 if dst.len() < 4 && dst.len() < ch.len_utf8() {
364 break;
365 }
366
367 src_read = src_iter_read.get();
370 let len = ch.encode_utf8(dst).len();
371 dst_written += len;
372 dst = &mut dst[len..];
373 }
374
375 log::trace!("utf16-to-utf8 {src_len}/{dst_len} => {src_read}/{dst_written}");
376 Ok(SizePair {
377 src_read,
378 dst_written,
379 })
380}
381
382unsafe fn latin1_to_utf8(
389 _: &mut dyn VMStore,
390 _: Instance,
391 src: *mut u8,
392 src_len: usize,
393 dst: *mut u8,
394 dst_len: usize,
395) -> Result<SizePair> {
396 let src = unsafe { slice::from_raw_parts(src, src_len) };
397 let dst = unsafe { slice::from_raw_parts_mut(dst, dst_len) };
398 assert_no_overlap(src, dst);
399 let (read, written) = encoding_rs::mem::convert_latin1_to_utf8_partial(src, dst);
400 log::trace!("latin1-to-utf8 {src_len}/{dst_len} => ({read}, {written})");
401 Ok(SizePair {
402 src_read: read,
403 dst_written: written,
404 })
405}
406
407unsafe fn utf16_to_compact_probably_utf16(
415 _: &mut dyn VMStore,
416 _: Instance,
417 src: *mut u16,
418 len: usize,
419 dst: *mut u16,
420) -> Result<CopySizeReturn> {
421 let src = unsafe { slice::from_raw_parts(src, len) };
422 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
423 assert_no_overlap(src, dst);
424 let all_latin1 = run_utf16_to_utf16(src, dst)?;
425 if all_latin1 {
426 let (left, dst, right) = unsafe { dst.align_to_mut::<u8>() };
427 assert!(left.is_empty());
428 assert!(right.is_empty());
429 for i in 0..len {
430 dst[i] = dst[2 * i];
431 }
432 log::trace!("utf16-to-compact-probably-utf16 {len} => latin1 {len}");
433 Ok(CopySizeReturn(len))
434 } else {
435 log::trace!("utf16-to-compact-probably-utf16 {len} => utf16 {len}");
436 Ok(CopySizeReturn(len | UTF16_TAG))
437 }
438}
439
440unsafe fn utf8_to_latin1(
451 _: &mut dyn VMStore,
452 _: Instance,
453 src: *mut u8,
454 len: usize,
455 dst: *mut u8,
456) -> Result<SizePair> {
457 let src = unsafe { slice::from_raw_parts(src, len) };
458 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
459 assert_no_overlap(src, dst);
460 let read = encoding_rs::mem::utf8_latin1_up_to(src);
461 let written = encoding_rs::mem::convert_utf8_to_latin1_lossy(&src[..read], dst);
462 log::trace!("utf8-to-latin1 {len} => ({read}, {written})");
463 Ok(SizePair {
464 src_read: read,
465 dst_written: written,
466 })
467}
468
469unsafe fn utf16_to_latin1(
473 _: &mut dyn VMStore,
474 _: Instance,
475 src: *mut u16,
476 len: usize,
477 dst: *mut u8,
478) -> Result<SizePair> {
479 let src = unsafe { slice::from_raw_parts(src, len) };
480 let dst = unsafe { slice::from_raw_parts_mut(dst, len) };
481 assert_no_overlap(src, dst);
482
483 let mut size = 0;
484 for (src, dst) in src.iter().zip(dst) {
485 let src = u16::from_le(*src);
486 match u8::try_from(src) {
487 Ok(src) => *dst = src,
488 Err(_) => break,
489 }
490 size += 1;
491 }
492 log::trace!("utf16-to-latin1 {len} => {size}");
493 Ok(SizePair {
494 src_read: size,
495 dst_written: size,
496 })
497}
498
499unsafe fn utf8_to_compact_utf16(
515 _: &mut dyn VMStore,
516 _: Instance,
517 src: *mut u8,
518 src_len: usize,
519 dst: *mut u16,
520 dst_len: usize,
521 latin1_bytes_so_far: usize,
522) -> Result<CopySizeReturn> {
523 let src = unsafe { slice::from_raw_parts(src, src_len) };
524 let dst = unsafe { slice::from_raw_parts_mut(dst, dst_len) };
525 assert_no_overlap(src, dst);
526
527 let dst = inflate_latin1_bytes(dst, latin1_bytes_so_far);
528 let result = run_utf8_to_utf16(src, dst)?;
529 log::trace!("utf8-to-compact-utf16 {src_len}/{dst_len}/{latin1_bytes_so_far} => {result}");
530 Ok(CopySizeReturn(result + latin1_bytes_so_far))
531}
532
533unsafe fn utf16_to_compact_utf16(
535 _: &mut dyn VMStore,
536 _: Instance,
537 src: *mut u16,
538 src_len: usize,
539 dst: *mut u16,
540 dst_len: usize,
541 latin1_bytes_so_far: usize,
542) -> Result<CopySizeReturn> {
543 let src = unsafe { slice::from_raw_parts(src, src_len) };
544 let dst = unsafe { slice::from_raw_parts_mut(dst, dst_len) };
545 assert_no_overlap(src, dst);
546
547 let dst = inflate_latin1_bytes(dst, latin1_bytes_so_far);
548 run_utf16_to_utf16(src, dst)?;
549 let result = src.len();
550 log::trace!("utf16-to-compact-utf16 {src_len}/{dst_len}/{latin1_bytes_so_far} => {result}");
551 Ok(CopySizeReturn(result + latin1_bytes_so_far))
552}
553
554fn inflate_latin1_bytes(dst: &mut [u16], latin1_bytes_so_far: usize) -> &mut [u16] {
561 let (to_inflate, rest) = dst.split_at_mut(latin1_bytes_so_far);
566
567 let (left, mid, right) = unsafe { to_inflate.align_to_mut::<u8>() };
569 assert!(left.is_empty());
570 assert!(right.is_empty());
571 for i in (0..latin1_bytes_so_far).rev() {
572 mid[2 * i] = mid[i];
573 mid[2 * i + 1] = 0;
574 }
575
576 return rest;
577}
578
579fn resource_new32(
580 store: &mut dyn VMStore,
581 instance: Instance,
582 caller_instance: u32,
583 resource: u32,
584 rep: u32,
585) -> Result<u32> {
586 let caller_instance = RuntimeComponentInstanceIndex::from_u32(caller_instance);
587 let resource = TypeResourceTableIndex::from_u32(resource);
588 instance.resource_new32(store, caller_instance, resource, rep)
589}
590
591fn resource_rep32(
592 store: &mut dyn VMStore,
593 instance: Instance,
594 caller_instance: u32,
595 resource: u32,
596 idx: u32,
597) -> Result<u32> {
598 let caller_instance = RuntimeComponentInstanceIndex::from_u32(caller_instance);
599 let resource = TypeResourceTableIndex::from_u32(resource);
600 instance.resource_rep32(store, caller_instance, resource, idx)
601}
602
603fn resource_drop(
604 store: &mut dyn VMStore,
605 instance: Instance,
606 caller_instance: u32,
607 resource: u32,
608 idx: u32,
609) -> Result<ResourceDropRet> {
610 let caller_instance = RuntimeComponentInstanceIndex::from_u32(caller_instance);
611 let resource = TypeResourceTableIndex::from_u32(resource);
612 Ok(ResourceDropRet(instance.resource_drop(
613 store,
614 caller_instance,
615 resource,
616 idx,
617 )?))
618}
619
620struct ResourceDropRet(Option<u32>);
621
622unsafe impl HostResultHasUnwindSentinel for ResourceDropRet {
623 type Abi = u64;
624 const SENTINEL: u64 = u64::MAX;
625 fn into_abi(self) -> u64 {
626 match self.0 {
627 Some(rep) => (u64::from(rep) << 1) | 1,
628 None => 0,
629 }
630 }
631}
632
633fn resource_transfer_own(
634 store: &mut dyn VMStore,
635 instance: Instance,
636 src_idx: u32,
637 src_table: u32,
638 dst_table: u32,
639) -> Result<u32> {
640 let src_table = TypeResourceTableIndex::from_u32(src_table);
641 let dst_table = TypeResourceTableIndex::from_u32(dst_table);
642 instance.resource_transfer_own(store, src_idx, src_table, dst_table)
643}
644
645fn resource_transfer_borrow(
646 store: &mut dyn VMStore,
647 instance: Instance,
648 src_idx: u32,
649 src_table: u32,
650 dst_table: u32,
651) -> Result<u32> {
652 let src_table = TypeResourceTableIndex::from_u32(src_table);
653 let dst_table = TypeResourceTableIndex::from_u32(dst_table);
654 instance.resource_transfer_borrow(store, src_idx, src_table, dst_table)
655}
656
657fn resource_enter_call(store: &mut dyn VMStore, instance: Instance) {
658 instance.resource_enter_call(store)
659}
660
661fn resource_exit_call(store: &mut dyn VMStore, instance: Instance) -> Result<()> {
662 instance.resource_exit_call(store)
663}
664
665fn trap(_store: &mut dyn VMStore, _instance: Instance, code: u8) -> Result<()> {
666 Err(wasmtime_environ::Trap::from_u8(code).unwrap().into())
667}
668
669#[cfg(feature = "component-model-async")]
670fn backpressure_set(
671 store: &mut dyn VMStore,
672 instance: Instance,
673 caller_instance: u32,
674 enabled: u32,
675) -> Result<()> {
676 instance.concurrent_state_mut(store).backpressure_modify(
677 RuntimeComponentInstanceIndex::from_u32(caller_instance),
678 |_| Some(if enabled != 0 { 1 } else { 0 }),
679 )
680}
681
682#[cfg(feature = "component-model-async")]
683fn backpressure_modify(
684 store: &mut dyn VMStore,
685 instance: Instance,
686 caller_instance: u32,
687 increment: u8,
688) -> Result<()> {
689 instance.concurrent_state_mut(store).backpressure_modify(
690 RuntimeComponentInstanceIndex::from_u32(caller_instance),
691 |old| {
692 if increment != 0 {
693 old.checked_add(1)
694 } else {
695 old.checked_sub(1)
696 }
697 },
698 )
699}
700
701#[cfg(feature = "component-model-async")]
702unsafe fn task_return(
703 store: &mut dyn VMStore,
704 instance: Instance,
705 caller_instance: u32,
706 ty: u32,
707 options: u32,
708 storage: *mut u8,
709 storage_len: usize,
710) -> Result<()> {
711 instance.task_return(
712 store,
713 RuntimeComponentInstanceIndex::from_u32(caller_instance),
714 TypeTupleIndex::from_u32(ty),
715 OptionsIndex::from_u32(options),
716 unsafe { core::slice::from_raw_parts(storage.cast(), storage_len) },
717 )
718}
719
720#[cfg(feature = "component-model-async")]
721fn task_cancel(store: &mut dyn VMStore, instance: Instance, caller_instance: u32) -> Result<()> {
722 instance.task_cancel(
723 store,
724 RuntimeComponentInstanceIndex::from_u32(caller_instance),
725 )
726}
727
728#[cfg(feature = "component-model-async")]
729fn waitable_set_new(
730 store: &mut dyn VMStore,
731 instance: Instance,
732 caller_instance: u32,
733) -> Result<u32> {
734 instance
735 .id()
736 .get_mut(store)
737 .waitable_set_new(RuntimeComponentInstanceIndex::from_u32(caller_instance))
738}
739
740#[cfg(feature = "component-model-async")]
741fn waitable_set_wait(
742 store: &mut dyn VMStore,
743 instance: Instance,
744 caller: u32,
745 options: u32,
746 set: u32,
747 payload: u32,
748) -> Result<u32> {
749 instance.waitable_set_wait(
750 store,
751 RuntimeComponentInstanceIndex::from_u32(caller),
752 OptionsIndex::from_u32(options),
753 set,
754 payload,
755 )
756}
757
758#[cfg(feature = "component-model-async")]
759fn waitable_set_poll(
760 store: &mut dyn VMStore,
761 instance: Instance,
762 caller: u32,
763 options: u32,
764 set: u32,
765 payload: u32,
766) -> Result<u32> {
767 instance.waitable_set_poll(
768 store,
769 RuntimeComponentInstanceIndex::from_u32(caller),
770 OptionsIndex::from_u32(options),
771 set,
772 payload,
773 )
774}
775
776#[cfg(feature = "component-model-async")]
777fn waitable_set_drop(
778 store: &mut dyn VMStore,
779 instance: Instance,
780 caller_instance: u32,
781 set: u32,
782) -> Result<()> {
783 instance.id().get_mut(store).waitable_set_drop(
784 RuntimeComponentInstanceIndex::from_u32(caller_instance),
785 set,
786 )
787}
788
789#[cfg(feature = "component-model-async")]
790fn waitable_join(
791 store: &mut dyn VMStore,
792 instance: Instance,
793 caller_instance: u32,
794 waitable: u32,
795 set: u32,
796) -> Result<()> {
797 instance.id().get_mut(store).waitable_join(
798 RuntimeComponentInstanceIndex::from_u32(caller_instance),
799 waitable,
800 set,
801 )
802}
803
804#[cfg(feature = "component-model-async")]
805fn thread_yield(
806 store: &mut dyn VMStore,
807 instance: Instance,
808 caller_instance: u32,
809 cancellable: u8,
810) -> Result<bool> {
811 instance.thread_yield(
812 store,
813 RuntimeComponentInstanceIndex::from_u32(caller_instance),
814 cancellable != 0,
815 )
816}
817
818#[cfg(feature = "component-model-async")]
819fn subtask_drop(
820 store: &mut dyn VMStore,
821 instance: Instance,
822 caller_instance: u32,
823 task_id: u32,
824) -> Result<()> {
825 instance.id().get_mut(store).subtask_drop(
826 RuntimeComponentInstanceIndex::from_u32(caller_instance),
827 task_id,
828 )
829}
830
831#[cfg(feature = "component-model-async")]
832fn subtask_cancel(
833 store: &mut dyn VMStore,
834 instance: Instance,
835 caller_instance: u32,
836 async_: u8,
837 task_id: u32,
838) -> Result<u32> {
839 instance.subtask_cancel(
840 store,
841 RuntimeComponentInstanceIndex::from_u32(caller_instance),
842 async_ != 0,
843 task_id,
844 )
845}
846
847#[cfg(feature = "component-model-async")]
848unsafe fn prepare_call(
849 store: &mut dyn VMStore,
850 instance: Instance,
851 memory: *mut u8,
852 start: *mut u8,
853 return_: *mut u8,
854 caller_instance: u32,
855 callee_instance: u32,
856 task_return_type: u32,
857 string_encoding: u32,
858 result_count_or_max_if_async: u32,
859 storage: *mut u8,
860 storage_len: usize,
861) -> Result<()> {
862 unsafe {
863 store.component_async_store().prepare_call(
864 instance,
865 memory.cast::<crate::vm::VMMemoryDefinition>(),
866 start.cast::<crate::vm::VMFuncRef>(),
867 return_.cast::<crate::vm::VMFuncRef>(),
868 RuntimeComponentInstanceIndex::from_u32(caller_instance),
869 RuntimeComponentInstanceIndex::from_u32(callee_instance),
870 TypeTupleIndex::from_u32(task_return_type),
871 u8::try_from(string_encoding).unwrap(),
872 result_count_or_max_if_async,
873 storage.cast::<crate::ValRaw>(),
874 storage_len,
875 )
876 }
877}
878
879#[cfg(feature = "component-model-async")]
880unsafe fn sync_start(
881 store: &mut dyn VMStore,
882 instance: Instance,
883 callback: *mut u8,
884 storage: *mut u8,
885 storage_len: usize,
886 callee: *mut u8,
887 param_count: u32,
888) -> Result<()> {
889 unsafe {
890 store.component_async_store().sync_start(
891 instance,
892 callback.cast::<crate::vm::VMFuncRef>(),
893 callee.cast::<crate::vm::VMFuncRef>(),
894 param_count,
895 storage.cast::<std::mem::MaybeUninit<crate::ValRaw>>(),
896 storage_len,
897 )
898 }
899}
900
901#[cfg(feature = "component-model-async")]
902unsafe fn async_start(
903 store: &mut dyn VMStore,
904 instance: Instance,
905 callback: *mut u8,
906 post_return: *mut u8,
907 callee: *mut u8,
908 param_count: u32,
909 result_count: u32,
910 flags: u32,
911) -> Result<u32> {
912 unsafe {
913 store.component_async_store().async_start(
914 instance,
915 callback.cast::<crate::vm::VMFuncRef>(),
916 post_return.cast::<crate::vm::VMFuncRef>(),
917 callee.cast::<crate::vm::VMFuncRef>(),
918 param_count,
919 result_count,
920 flags,
921 )
922 }
923}
924
925#[cfg(feature = "component-model-async")]
926fn future_transfer(
927 store: &mut dyn VMStore,
928 instance: Instance,
929 src_idx: u32,
930 src_table: u32,
931 dst_table: u32,
932) -> Result<u32> {
933 instance.id().get_mut(store).future_transfer(
934 src_idx,
935 TypeFutureTableIndex::from_u32(src_table),
936 TypeFutureTableIndex::from_u32(dst_table),
937 )
938}
939
940#[cfg(feature = "component-model-async")]
941fn stream_transfer(
942 store: &mut dyn VMStore,
943 instance: Instance,
944 src_idx: u32,
945 src_table: u32,
946 dst_table: u32,
947) -> Result<u32> {
948 instance.id().get_mut(store).stream_transfer(
949 src_idx,
950 TypeStreamTableIndex::from_u32(src_table),
951 TypeStreamTableIndex::from_u32(dst_table),
952 )
953}
954
955#[cfg(feature = "component-model-async")]
956fn error_context_transfer(
957 store: &mut dyn VMStore,
958 instance: Instance,
959 src_idx: u32,
960 src_table: u32,
961 dst_table: u32,
962) -> Result<u32> {
963 let src_table = TypeComponentLocalErrorContextTableIndex::from_u32(src_table);
964 let dst_table = TypeComponentLocalErrorContextTableIndex::from_u32(dst_table);
965 instance
966 .id()
967 .get_mut(store)
968 .error_context_transfer(src_idx, src_table, dst_table)
969}
970
971#[cfg(feature = "component-model-async")]
972unsafe impl HostResultHasUnwindSentinel for ResourcePair {
973 type Abi = u64;
974 const SENTINEL: u64 = u64::MAX;
975
976 fn into_abi(self) -> Self::Abi {
977 assert!(self.write & (1 << 31) == 0);
978 (u64::from(self.write) << 32) | u64::from(self.read)
979 }
980}
981
982#[cfg(feature = "component-model-async")]
983fn future_new(
984 store: &mut dyn VMStore,
985 instance: Instance,
986 caller_instance: u32,
987 ty: u32,
988) -> Result<ResourcePair> {
989 instance.id().get_mut(store).future_new(
990 RuntimeComponentInstanceIndex::from_u32(caller_instance),
991 TypeFutureTableIndex::from_u32(ty),
992 )
993}
994
995#[cfg(feature = "component-model-async")]
996fn future_write(
997 store: &mut dyn VMStore,
998 instance: Instance,
999 caller_instance: u32,
1000 ty: u32,
1001 options: u32,
1002 future: u32,
1003 address: u32,
1004) -> Result<u32> {
1005 store.component_async_store().future_write(
1006 instance,
1007 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1008 TypeFutureTableIndex::from_u32(ty),
1009 OptionsIndex::from_u32(options),
1010 future,
1011 address,
1012 )
1013}
1014
1015#[cfg(feature = "component-model-async")]
1016fn future_read(
1017 store: &mut dyn VMStore,
1018 instance: Instance,
1019 caller_instance: u32,
1020 ty: u32,
1021 options: u32,
1022 future: u32,
1023 address: u32,
1024) -> Result<u32> {
1025 store.component_async_store().future_read(
1026 instance,
1027 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1028 TypeFutureTableIndex::from_u32(ty),
1029 OptionsIndex::from_u32(options),
1030 future,
1031 address,
1032 )
1033}
1034
1035#[cfg(feature = "component-model-async")]
1036fn future_cancel_write(
1037 store: &mut dyn VMStore,
1038 instance: Instance,
1039 caller_instance: u32,
1040 ty: u32,
1041 async_: u8,
1042 writer: u32,
1043) -> Result<u32> {
1044 instance.future_cancel_write(
1045 store,
1046 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1047 TypeFutureTableIndex::from_u32(ty),
1048 async_ != 0,
1049 writer,
1050 )
1051}
1052
1053#[cfg(feature = "component-model-async")]
1054fn future_cancel_read(
1055 store: &mut dyn VMStore,
1056 instance: Instance,
1057 caller_instance: u32,
1058 ty: u32,
1059 async_: u8,
1060 reader: u32,
1061) -> Result<u32> {
1062 instance.future_cancel_read(
1063 store,
1064 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1065 TypeFutureTableIndex::from_u32(ty),
1066 async_ != 0,
1067 reader,
1068 )
1069}
1070
1071#[cfg(feature = "component-model-async")]
1072fn future_drop_writable(
1073 store: &mut dyn VMStore,
1074 instance: Instance,
1075 caller_instance: u32,
1076 ty: u32,
1077 writer: u32,
1078) -> Result<()> {
1079 store.component_async_store().future_drop_writable(
1080 instance,
1081 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1082 TypeFutureTableIndex::from_u32(ty),
1083 writer,
1084 )
1085}
1086
1087#[cfg(feature = "component-model-async")]
1088fn future_drop_readable(
1089 store: &mut dyn VMStore,
1090 instance: Instance,
1091 caller_instance: u32,
1092 ty: u32,
1093 reader: u32,
1094) -> Result<()> {
1095 instance.future_drop_readable(
1096 store,
1097 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1098 TypeFutureTableIndex::from_u32(ty),
1099 reader,
1100 )
1101}
1102
1103#[cfg(feature = "component-model-async")]
1104fn stream_new(
1105 store: &mut dyn VMStore,
1106 instance: Instance,
1107 caller_instance: u32,
1108 ty: u32,
1109) -> Result<ResourcePair> {
1110 instance.id().get_mut(store).stream_new(
1111 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1112 TypeStreamTableIndex::from_u32(ty),
1113 )
1114}
1115
1116#[cfg(feature = "component-model-async")]
1117fn stream_write(
1118 store: &mut dyn VMStore,
1119 instance: Instance,
1120 caller_instance: u32,
1121 ty: u32,
1122 options: u32,
1123 stream: u32,
1124 address: u32,
1125 count: u32,
1126) -> Result<u32> {
1127 store.component_async_store().stream_write(
1128 instance,
1129 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1130 TypeStreamTableIndex::from_u32(ty),
1131 OptionsIndex::from_u32(options),
1132 stream,
1133 address,
1134 count,
1135 )
1136}
1137
1138#[cfg(feature = "component-model-async")]
1139fn stream_read(
1140 store: &mut dyn VMStore,
1141 instance: Instance,
1142 caller_instance: u32,
1143 ty: u32,
1144 options: u32,
1145 stream: u32,
1146 address: u32,
1147 count: u32,
1148) -> Result<u32> {
1149 store.component_async_store().stream_read(
1150 instance,
1151 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1152 TypeStreamTableIndex::from_u32(ty),
1153 OptionsIndex::from_u32(options),
1154 stream,
1155 address,
1156 count,
1157 )
1158}
1159
1160#[cfg(feature = "component-model-async")]
1161fn stream_cancel_write(
1162 store: &mut dyn VMStore,
1163 instance: Instance,
1164 caller_instance: u32,
1165 ty: u32,
1166 async_: u8,
1167 writer: u32,
1168) -> Result<u32> {
1169 instance.stream_cancel_write(
1170 store,
1171 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1172 TypeStreamTableIndex::from_u32(ty),
1173 async_ != 0,
1174 writer,
1175 )
1176}
1177
1178#[cfg(feature = "component-model-async")]
1179fn stream_cancel_read(
1180 store: &mut dyn VMStore,
1181 instance: Instance,
1182 caller_instance: u32,
1183 ty: u32,
1184 async_: u8,
1185 reader: u32,
1186) -> Result<u32> {
1187 instance.stream_cancel_read(
1188 store,
1189 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1190 TypeStreamTableIndex::from_u32(ty),
1191 async_ != 0,
1192 reader,
1193 )
1194}
1195
1196#[cfg(feature = "component-model-async")]
1197fn stream_drop_writable(
1198 store: &mut dyn VMStore,
1199 instance: Instance,
1200 caller_instance: u32,
1201 ty: u32,
1202 writer: u32,
1203) -> Result<()> {
1204 store.component_async_store().stream_drop_writable(
1205 instance,
1206 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1207 TypeStreamTableIndex::from_u32(ty),
1208 writer,
1209 )
1210}
1211
1212#[cfg(feature = "component-model-async")]
1213fn stream_drop_readable(
1214 store: &mut dyn VMStore,
1215 instance: Instance,
1216 caller_instance: u32,
1217 ty: u32,
1218 reader: u32,
1219) -> Result<()> {
1220 instance.stream_drop_readable(
1221 store,
1222 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1223 TypeStreamTableIndex::from_u32(ty),
1224 reader,
1225 )
1226}
1227
1228#[cfg(feature = "component-model-async")]
1229fn flat_stream_write(
1230 store: &mut dyn VMStore,
1231 instance: Instance,
1232 caller_instance: u32,
1233 ty: u32,
1234 options: u32,
1235 payload_size: u32,
1236 payload_align: u32,
1237 stream: u32,
1238 address: u32,
1239 count: u32,
1240) -> Result<u32> {
1241 store.component_async_store().flat_stream_write(
1242 instance,
1243 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1244 TypeStreamTableIndex::from_u32(ty),
1245 OptionsIndex::from_u32(options),
1246 payload_size,
1247 payload_align,
1248 stream,
1249 address,
1250 count,
1251 )
1252}
1253
1254#[cfg(feature = "component-model-async")]
1255fn flat_stream_read(
1256 store: &mut dyn VMStore,
1257 instance: Instance,
1258 caller_instance: u32,
1259 ty: u32,
1260 options: u32,
1261 payload_size: u32,
1262 payload_align: u32,
1263 stream: u32,
1264 address: u32,
1265 count: u32,
1266) -> Result<u32> {
1267 store.component_async_store().flat_stream_read(
1268 instance,
1269 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1270 TypeStreamTableIndex::from_u32(ty),
1271 OptionsIndex::from_u32(options),
1272 payload_size,
1273 payload_align,
1274 stream,
1275 address,
1276 count,
1277 )
1278}
1279
1280#[cfg(feature = "component-model-async")]
1281fn error_context_new(
1282 store: &mut dyn VMStore,
1283 instance: Instance,
1284 caller_instance: u32,
1285 ty: u32,
1286 options: u32,
1287 debug_msg_address: u32,
1288 debug_msg_len: u32,
1289) -> Result<u32> {
1290 instance.error_context_new(
1291 store.store_opaque_mut(),
1292 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1293 TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1294 OptionsIndex::from_u32(options),
1295 debug_msg_address,
1296 debug_msg_len,
1297 )
1298}
1299
1300#[cfg(feature = "component-model-async")]
1301fn error_context_debug_message(
1302 store: &mut dyn VMStore,
1303 instance: Instance,
1304 caller_instance: u32,
1305 ty: u32,
1306 options: u32,
1307 err_ctx_handle: u32,
1308 debug_msg_address: u32,
1309) -> Result<()> {
1310 store.component_async_store().error_context_debug_message(
1311 instance,
1312 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1313 TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1314 OptionsIndex::from_u32(options),
1315 err_ctx_handle,
1316 debug_msg_address,
1317 )
1318}
1319
1320#[cfg(feature = "component-model-async")]
1321fn error_context_drop(
1322 store: &mut dyn VMStore,
1323 instance: Instance,
1324 caller_instance: u32,
1325 ty: u32,
1326 err_ctx_handle: u32,
1327) -> Result<()> {
1328 instance.id().get_mut(store).error_context_drop(
1329 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1330 TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1331 err_ctx_handle,
1332 )
1333}
1334
1335#[cfg(feature = "component-model-async")]
1336fn context_get(
1337 store: &mut dyn VMStore,
1338 instance: Instance,
1339 caller_instance: u32,
1340 slot: u32,
1341) -> Result<u32> {
1342 instance.context_get(
1343 store,
1344 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1345 slot,
1346 )
1347}
1348
1349#[cfg(feature = "component-model-async")]
1350fn context_set(
1351 store: &mut dyn VMStore,
1352 instance: Instance,
1353 caller_instance: u32,
1354 slot: u32,
1355 val: u32,
1356) -> Result<()> {
1357 instance.context_set(
1358 store,
1359 RuntimeComponentInstanceIndex::from_u32(caller_instance),
1360 slot,
1361 val,
1362 )
1363}