wasmtime/runtime/vm/component/
libcalls.rs

1//! Implementation of string transcoding required by the component model.
2
3use crate::prelude::*;
4use crate::runtime::vm::component::{ComponentInstance, VMComponentContext};
5use crate::runtime::vm::{HostResultHasUnwindSentinel, VmSafe};
6use core::cell::Cell;
7use core::convert::Infallible;
8use core::ptr::NonNull;
9use core::slice;
10use wasmtime_environ::component::TypeResourceTableIndex;
11
12const UTF16_TAG: usize = 1 << 31;
13
14macro_rules! signature {
15    (@ty size) => (usize);
16    (@ty ptr_u8) => (*mut u8);
17    (@ty ptr_u16) => (*mut u16);
18    (@ty ptr_size) => (*mut usize);
19    (@ty u8) => (u8);
20    (@ty u32) => (u32);
21    (@ty u64) => (u64);
22    (@ty bool) => (bool);
23    (@ty vmctx) => (NonNull<VMComponentContext>);
24}
25
26/// Defines a `VMComponentBuiltins` structure which contains any builtins such
27/// as resource-related intrinsics.
28macro_rules! define_builtins {
29    (
30        $(
31            $( #[$attr:meta] )*
32            $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
33        )*
34    ) => {
35        /// An array that stores addresses of builtin functions. We translate code
36        /// to use indirect calls. This way, we don't have to patch the code.
37        #[repr(C)]
38        pub struct VMComponentBuiltins {
39            $(
40                $name: unsafe extern "C" fn(
41                    $(signature!(@ty $param),)*
42                ) $( -> signature!(@ty $result))?,
43            )*
44        }
45
46        // SAFETY: the above structure is repr(C) and only contains `VmSafe`
47        // fields.
48        unsafe impl VmSafe for VMComponentBuiltins {}
49
50        impl VMComponentBuiltins {
51            pub const INIT: VMComponentBuiltins = VMComponentBuiltins {
52                $($name: trampolines::$name,)*
53            };
54        }
55    };
56}
57
58wasmtime_environ::foreach_builtin_component_function!(define_builtins);
59
60/// Submodule with macro-generated constants which are the actual libcall
61/// transcoders that are invoked by Cranelift. These functions have a specific
62/// ABI defined by the macro itself and will defer to the actual bodies of each
63/// implementation following this submodule.
64#[allow(improper_ctypes_definitions)]
65mod trampolines {
66    use super::VMComponentContext;
67    use core::ptr::NonNull;
68
69    macro_rules! shims {
70        (
71            $(
72                $( #[cfg($attr:meta)] )?
73                $name:ident( $( $pname:ident: $param:ident ),* ) $( -> $result:ident )?;
74            )*
75        ) => (
76            $(
77                pub unsafe extern "C" fn $name(
78                    $($pname : signature!(@ty $param),)*
79                ) $( -> signature!(@ty $result))? {
80                    $(#[cfg($attr)])?
81                    {
82                        $(shims!(@validate_param $pname $param);)*
83
84                        let ret = crate::runtime::vm::traphandlers::catch_unwind_and_record_trap(|| {
85                            shims!(@invoke $name() $($pname)*)
86                        });
87                        shims!(@convert_ret ret $($pname: $param)*)
88                    }
89                    $(
90                        #[cfg(not($attr))]
91                        unreachable!();
92                    )?
93                }
94            )*
95        );
96
97        // Helper macro to convert a 2-tuple automatically when the last
98        // parameter is a `ptr_size` argument.
99        (@convert_ret $ret:ident) => ($ret);
100        (@convert_ret $ret:ident $retptr:ident: ptr_size) => ({
101            let (a, b) = $ret;
102            *$retptr = b;
103            a
104        });
105        (@convert_ret $ret:ident $name:ident: $ty:ident $($rest:tt)*) => (
106            shims!(@convert_ret $ret $($rest)*)
107        );
108
109        (@validate_param $arg:ident ptr_u16) => ({
110            // This should already be guaranteed by the canonical ABI and our
111            // adapter modules, but double-check here to be extra-sure. If this
112            // is a perf concern it can become a `debug_assert!`.
113            assert!(($arg as usize) % 2 == 0, "unaligned 16-bit pointer");
114        });
115        (@validate_param $arg:ident $ty:ident) => ();
116
117        // Helper macro to invoke `$m` with all of the tokens passed except for
118        // any argument named `ret2`
119        (@invoke $m:ident ($($args:tt)*)) => (super::$m($($args)*));
120
121        // ignore `ret2`-named arguments
122        (@invoke $m:ident ($($args:tt)*) ret2 $($rest:tt)*) => (
123            shims!(@invoke $m ($($args)*) $($rest)*)
124        );
125
126        // move all other arguments into the `$args` list
127        (@invoke $m:ident ($($args:tt)*) $param:ident $($rest:tt)*) => (
128            shims!(@invoke $m ($($args)* $param,) $($rest)*)
129        );
130    }
131
132    wasmtime_environ::foreach_builtin_component_function!(shims);
133}
134
135/// This property should already be guaranteed by construction in the component
136/// model but assert it here to be extra sure. Nothing below is sound if regions
137/// can overlap.
138fn assert_no_overlap<T, U>(a: &[T], b: &[U]) {
139    let a_start = a.as_ptr() as usize;
140    let a_end = a_start + (a.len() * core::mem::size_of::<T>());
141    let b_start = b.as_ptr() as usize;
142    let b_end = b_start + (b.len() * core::mem::size_of::<U>());
143
144    if a_start < b_start {
145        assert!(a_end < b_start);
146    } else {
147        assert!(b_end < a_start);
148    }
149}
150
151/// Converts a utf8 string to a utf8 string.
152///
153/// The length provided is length of both the source and the destination
154/// buffers. No value is returned other than whether an invalid string was
155/// found.
156unsafe fn utf8_to_utf8(src: *mut u8, len: usize, dst: *mut u8) -> Result<()> {
157    let src = slice::from_raw_parts(src, len);
158    let dst = slice::from_raw_parts_mut(dst, len);
159    assert_no_overlap(src, dst);
160    log::trace!("utf8-to-utf8 {len}");
161    let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?;
162    dst.copy_from_slice(src.as_bytes());
163    Ok(())
164}
165
166/// Converts a utf16 string to a utf16 string.
167///
168/// The length provided is length of both the source and the destination
169/// buffers. No value is returned other than whether an invalid string was
170/// found.
171unsafe fn utf16_to_utf16(src: *mut u16, len: usize, dst: *mut u16) -> Result<()> {
172    let src = slice::from_raw_parts(src, len);
173    let dst = slice::from_raw_parts_mut(dst, len);
174    assert_no_overlap(src, dst);
175    log::trace!("utf16-to-utf16 {len}");
176    run_utf16_to_utf16(src, dst)?;
177    Ok(())
178}
179
180/// Transcodes utf16 to itself, returning whether all code points were inside of
181/// the latin1 space.
182fn run_utf16_to_utf16(src: &[u16], mut dst: &mut [u16]) -> Result<bool> {
183    let mut all_latin1 = true;
184    for ch in core::char::decode_utf16(src.iter().map(|i| u16::from_le(*i))) {
185        let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?;
186        all_latin1 = all_latin1 && u8::try_from(u32::from(ch)).is_ok();
187        let result = ch.encode_utf16(dst);
188        let size = result.len();
189        for item in result {
190            *item = item.to_le();
191        }
192        dst = &mut dst[size..];
193    }
194    Ok(all_latin1)
195}
196
197/// Converts a latin1 string to a latin1 string.
198///
199/// Given that all byte sequences are valid latin1 strings this is simply a
200/// memory copy.
201unsafe fn latin1_to_latin1(src: *mut u8, len: usize, dst: *mut u8) -> Result<()> {
202    let src = slice::from_raw_parts(src, len);
203    let dst = slice::from_raw_parts_mut(dst, len);
204    assert_no_overlap(src, dst);
205    log::trace!("latin1-to-latin1 {len}");
206    dst.copy_from_slice(src);
207    Ok(())
208}
209
210/// Converts a latin1 string to a utf16 string.
211///
212/// This simply inflates the latin1 characters to the u16 code points. The
213/// length provided is the same length of the source and destination buffers.
214unsafe fn latin1_to_utf16(src: *mut u8, len: usize, dst: *mut u16) -> Result<()> {
215    let src = slice::from_raw_parts(src, len);
216    let dst = slice::from_raw_parts_mut(dst, len);
217    assert_no_overlap(src, dst);
218    for (src, dst) in src.iter().zip(dst) {
219        *dst = u16::from(*src).to_le();
220    }
221    log::trace!("latin1-to-utf16 {len}");
222    Ok(())
223}
224
225struct CopySizeReturn(usize);
226
227unsafe impl HostResultHasUnwindSentinel for CopySizeReturn {
228    type Abi = usize;
229    const SENTINEL: usize = usize::MAX;
230    fn into_abi(self) -> usize {
231        self.0
232    }
233}
234
235/// Converts utf8 to utf16.
236///
237/// The length provided is the same unit length of both buffers, and the
238/// returned value from this function is how many u16 units were written.
239unsafe fn utf8_to_utf16(src: *mut u8, len: usize, dst: *mut u16) -> Result<CopySizeReturn> {
240    let src = slice::from_raw_parts(src, len);
241    let dst = slice::from_raw_parts_mut(dst, len);
242    assert_no_overlap(src, dst);
243
244    let result = run_utf8_to_utf16(src, dst)?;
245    log::trace!("utf8-to-utf16 {len} => {result}");
246    Ok(CopySizeReturn(result))
247}
248
249fn run_utf8_to_utf16(src: &[u8], dst: &mut [u16]) -> Result<usize> {
250    let src = core::str::from_utf8(src).map_err(|_| anyhow!("invalid utf8 encoding"))?;
251    let mut amt = 0;
252    for (i, dst) in src.encode_utf16().zip(dst) {
253        *dst = i.to_le();
254        amt += 1;
255    }
256    Ok(amt)
257}
258
259struct SizePair {
260    src_read: usize,
261    dst_written: usize,
262}
263
264unsafe impl HostResultHasUnwindSentinel for SizePair {
265    type Abi = (usize, usize);
266    const SENTINEL: (usize, usize) = (usize::MAX, 0);
267    fn into_abi(self) -> (usize, usize) {
268        (self.src_read, self.dst_written)
269    }
270}
271
272/// Converts utf16 to utf8.
273///
274/// Each buffer is specified independently here and the returned value is a pair
275/// of the number of code units read and code units written. This might perform
276/// a partial transcode if the destination buffer is not large enough to hold
277/// the entire contents.
278unsafe fn utf16_to_utf8(
279    src: *mut u16,
280    src_len: usize,
281    dst: *mut u8,
282    dst_len: usize,
283) -> Result<SizePair> {
284    let src = slice::from_raw_parts(src, src_len);
285    let mut dst = slice::from_raw_parts_mut(dst, dst_len);
286    assert_no_overlap(src, dst);
287
288    // This iterator will convert to native endianness and additionally count
289    // how many items have been read from the iterator so far. This
290    // count is used to return how many of the source code units were read.
291    let src_iter_read = Cell::new(0);
292    let src_iter = src.iter().map(|i| {
293        src_iter_read.set(src_iter_read.get() + 1);
294        u16::from_le(*i)
295    });
296
297    let mut src_read = 0;
298    let mut dst_written = 0;
299
300    for ch in core::char::decode_utf16(src_iter) {
301        let ch = ch.map_err(|_| anyhow!("invalid utf16 encoding"))?;
302
303        // If the destination doesn't have enough space for this character
304        // then the loop is ended and this function will be called later with a
305        // larger destination buffer.
306        if dst.len() < 4 && dst.len() < ch.len_utf8() {
307            break;
308        }
309
310        // Record that characters were read and then convert the `char` to
311        // utf-8, advancing the destination buffer.
312        src_read = src_iter_read.get();
313        let len = ch.encode_utf8(dst).len();
314        dst_written += len;
315        dst = &mut dst[len..];
316    }
317
318    log::trace!("utf16-to-utf8 {src_len}/{dst_len} => {src_read}/{dst_written}");
319    Ok(SizePair {
320        src_read,
321        dst_written,
322    })
323}
324
325/// Converts latin1 to utf8.
326///
327/// Receives the independent size of both buffers and returns the number of code
328/// units read and code units written (both bytes in this case).
329///
330/// This may perform a partial encoding if the destination is not large enough.
331unsafe fn latin1_to_utf8(
332    src: *mut u8,
333    src_len: usize,
334    dst: *mut u8,
335    dst_len: usize,
336) -> Result<SizePair> {
337    let src = slice::from_raw_parts(src, src_len);
338    let dst = slice::from_raw_parts_mut(dst, dst_len);
339    assert_no_overlap(src, dst);
340    let (read, written) = encoding_rs::mem::convert_latin1_to_utf8_partial(src, dst);
341    log::trace!("latin1-to-utf8 {src_len}/{dst_len} => ({read}, {written})");
342    Ok(SizePair {
343        src_read: read,
344        dst_written: written,
345    })
346}
347
348/// Converts utf16 to "latin1+utf16", probably using a utf16 encoding.
349///
350/// The length specified is the length of both the source and destination
351/// buffers. If the source string has any characters that don't fit in the
352/// latin1 code space (0xff and below) then a utf16-tagged length will be
353/// returned. Otherwise the string is "deflated" from a utf16 string to a latin1
354/// string and the latin1 length is returned.
355unsafe fn utf16_to_compact_probably_utf16(
356    src: *mut u16,
357    len: usize,
358    dst: *mut u16,
359) -> Result<CopySizeReturn> {
360    let src = slice::from_raw_parts(src, len);
361    let dst = slice::from_raw_parts_mut(dst, len);
362    assert_no_overlap(src, dst);
363    let all_latin1 = run_utf16_to_utf16(src, dst)?;
364    if all_latin1 {
365        let (left, dst, right) = dst.align_to_mut::<u8>();
366        assert!(left.is_empty());
367        assert!(right.is_empty());
368        for i in 0..len {
369            dst[i] = dst[2 * i];
370        }
371        log::trace!("utf16-to-compact-probably-utf16 {len} => latin1 {len}");
372        Ok(CopySizeReturn(len))
373    } else {
374        log::trace!("utf16-to-compact-probably-utf16 {len} => utf16 {len}");
375        Ok(CopySizeReturn(len | UTF16_TAG))
376    }
377}
378
379/// Converts a utf8 string to latin1.
380///
381/// The length specified is the same length of both the input and the output
382/// buffers.
383///
384/// Returns the number of code units read from the source and the number of code
385/// units written to the destination.
386///
387/// Note that this may not convert the entire source into the destination if the
388/// original utf8 string has usvs not representable in latin1.
389unsafe fn utf8_to_latin1(src: *mut u8, len: usize, dst: *mut u8) -> Result<SizePair> {
390    let src = slice::from_raw_parts(src, len);
391    let dst = slice::from_raw_parts_mut(dst, len);
392    assert_no_overlap(src, dst);
393    let read = encoding_rs::mem::utf8_latin1_up_to(src);
394    let written = encoding_rs::mem::convert_utf8_to_latin1_lossy(&src[..read], dst);
395    log::trace!("utf8-to-latin1 {len} => ({read}, {written})");
396    Ok(SizePair {
397        src_read: read,
398        dst_written: written,
399    })
400}
401
402/// Converts a utf16 string to latin1
403///
404/// This is the same as `utf8_to_latin1` in terms of parameters/results.
405unsafe fn utf16_to_latin1(src: *mut u16, len: usize, dst: *mut u8) -> Result<SizePair> {
406    let src = slice::from_raw_parts(src, len);
407    let dst = slice::from_raw_parts_mut(dst, len);
408    assert_no_overlap(src, dst);
409
410    let mut size = 0;
411    for (src, dst) in src.iter().zip(dst) {
412        let src = u16::from_le(*src);
413        match u8::try_from(src) {
414            Ok(src) => *dst = src,
415            Err(_) => break,
416        }
417        size += 1;
418    }
419    log::trace!("utf16-to-latin1 {len} => {size}");
420    Ok(SizePair {
421        src_read: size,
422        dst_written: size,
423    })
424}
425
426/// Converts a utf8 string to a utf16 string which has been partially converted
427/// as latin1 prior.
428///
429/// The original string has already been partially transcoded with
430/// `utf8_to_latin1` and that was determined to not be able to transcode the
431/// entire string. The substring of the source that couldn't be encoded into
432/// latin1 is passed here via `src` and `src_len`.
433///
434/// The destination buffer is specified by `dst` and `dst_len`. The first
435/// `latin1_bytes_so_far` bytes (not code units) of the `dst` buffer have
436/// already been filled in with latin1 characters and need to be inflated
437/// in-place to their utf16 equivalents.
438///
439/// After the initial latin1 code units have been inflated the entirety of `src`
440/// is then transcoded into the remaining space within `dst`.
441unsafe fn utf8_to_compact_utf16(
442    src: *mut u8,
443    src_len: usize,
444    dst: *mut u16,
445    dst_len: usize,
446    latin1_bytes_so_far: usize,
447) -> Result<CopySizeReturn> {
448    let src = slice::from_raw_parts(src, src_len);
449    let dst = slice::from_raw_parts_mut(dst, dst_len);
450    assert_no_overlap(src, dst);
451
452    let dst = inflate_latin1_bytes(dst, latin1_bytes_so_far);
453    let result = run_utf8_to_utf16(src, dst)?;
454    log::trace!("utf8-to-compact-utf16 {src_len}/{dst_len}/{latin1_bytes_so_far} => {result}");
455    Ok(CopySizeReturn(result + latin1_bytes_so_far))
456}
457
458/// Same as `utf8_to_compact_utf16` but for utf16 source strings.
459unsafe fn utf16_to_compact_utf16(
460    src: *mut u16,
461    src_len: usize,
462    dst: *mut u16,
463    dst_len: usize,
464    latin1_bytes_so_far: usize,
465) -> Result<CopySizeReturn> {
466    let src = slice::from_raw_parts(src, src_len);
467    let dst = slice::from_raw_parts_mut(dst, dst_len);
468    assert_no_overlap(src, dst);
469
470    let dst = inflate_latin1_bytes(dst, latin1_bytes_so_far);
471    run_utf16_to_utf16(src, dst)?;
472    let result = src.len();
473    log::trace!("utf16-to-compact-utf16 {src_len}/{dst_len}/{latin1_bytes_so_far} => {result}");
474    Ok(CopySizeReturn(result + latin1_bytes_so_far))
475}
476
477/// Inflates the `latin1_bytes_so_far` number of bytes written to the beginning
478/// of `dst` into u16 codepoints.
479///
480/// Returns the remaining space in the destination that can be transcoded into,
481/// slicing off the prefix of the string that was inflated from the latin1
482/// bytes.
483fn inflate_latin1_bytes(dst: &mut [u16], latin1_bytes_so_far: usize) -> &mut [u16] {
484    // Note that `latin1_bytes_so_far` is a byte measure while `dst` is a region
485    // of u16 units. This `split_at_mut` uses the byte index as an index into
486    // the u16 unit because each of the latin1 bytes will become a whole code
487    // unit in the destination which is 2 bytes large.
488    let (to_inflate, rest) = dst.split_at_mut(latin1_bytes_so_far);
489
490    // Use a byte-oriented view to inflate the original latin1 bytes.
491    let (left, mid, right) = unsafe { to_inflate.align_to_mut::<u8>() };
492    assert!(left.is_empty());
493    assert!(right.is_empty());
494    for i in (0..latin1_bytes_so_far).rev() {
495        mid[2 * i] = mid[i];
496        mid[2 * i + 1] = 0;
497    }
498
499    return rest;
500}
501
502unsafe fn resource_new32(
503    vmctx: NonNull<VMComponentContext>,
504    resource: u32,
505    rep: u32,
506) -> Result<u32> {
507    let resource = TypeResourceTableIndex::from_u32(resource);
508    ComponentInstance::from_vmctx(vmctx, |instance| instance.resource_new32(resource, rep))
509}
510
511unsafe fn resource_rep32(
512    vmctx: NonNull<VMComponentContext>,
513    resource: u32,
514    idx: u32,
515) -> Result<u32> {
516    let resource = TypeResourceTableIndex::from_u32(resource);
517    ComponentInstance::from_vmctx(vmctx, |instance| instance.resource_rep32(resource, idx))
518}
519
520unsafe fn resource_drop(
521    vmctx: NonNull<VMComponentContext>,
522    resource: u32,
523    idx: u32,
524) -> Result<ResourceDropRet> {
525    let resource = TypeResourceTableIndex::from_u32(resource);
526    ComponentInstance::from_vmctx(vmctx, |instance| {
527        Ok(ResourceDropRet(instance.resource_drop(resource, idx)?))
528    })
529}
530
531struct ResourceDropRet(Option<u32>);
532
533unsafe impl HostResultHasUnwindSentinel for ResourceDropRet {
534    type Abi = u64;
535    const SENTINEL: u64 = u64::MAX;
536    fn into_abi(self) -> u64 {
537        match self.0 {
538            Some(rep) => (u64::from(rep) << 1) | 1,
539            None => 0,
540        }
541    }
542}
543
544unsafe fn resource_transfer_own(
545    vmctx: NonNull<VMComponentContext>,
546    src_idx: u32,
547    src_table: u32,
548    dst_table: u32,
549) -> Result<u32> {
550    let src_table = TypeResourceTableIndex::from_u32(src_table);
551    let dst_table = TypeResourceTableIndex::from_u32(dst_table);
552    ComponentInstance::from_vmctx(vmctx, |instance| {
553        instance.resource_transfer_own(src_idx, src_table, dst_table)
554    })
555}
556
557unsafe fn resource_transfer_borrow(
558    vmctx: NonNull<VMComponentContext>,
559    src_idx: u32,
560    src_table: u32,
561    dst_table: u32,
562) -> Result<u32> {
563    let src_table = TypeResourceTableIndex::from_u32(src_table);
564    let dst_table = TypeResourceTableIndex::from_u32(dst_table);
565    ComponentInstance::from_vmctx(vmctx, |instance| {
566        instance.resource_transfer_borrow(src_idx, src_table, dst_table)
567    })
568}
569
570unsafe fn resource_enter_call(vmctx: NonNull<VMComponentContext>) {
571    ComponentInstance::from_vmctx(vmctx, |instance| instance.resource_enter_call())
572}
573
574unsafe fn resource_exit_call(vmctx: NonNull<VMComponentContext>) -> Result<()> {
575    ComponentInstance::from_vmctx(vmctx, |instance| instance.resource_exit_call())
576}
577
578unsafe fn trap(_vmctx: NonNull<VMComponentContext>, code: u8) -> Result<Infallible> {
579    Err(wasmtime_environ::Trap::from_u8(code).unwrap().into())
580}
581
582#[cfg(feature = "component-model-async")]
583unsafe fn backpressure_set(
584    vmctx: NonNull<VMComponentContext>,
585    caller_instance: u32,
586    enabled: u32,
587) -> Result<()> {
588    ComponentInstance::from_vmctx(vmctx, |instance| {
589        (*instance.store())
590            .component_async_store()
591            .backpressure_set(
592                wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(
593                    caller_instance,
594                ),
595                enabled,
596            )
597    })
598}
599
600#[cfg(feature = "component-model-async")]
601unsafe fn task_return(
602    vmctx: NonNull<VMComponentContext>,
603    ty: u32,
604    storage: *mut u8,
605    storage_len: usize,
606) -> Result<()> {
607    ComponentInstance::from_vmctx(vmctx, |instance| {
608        (*instance.store()).component_async_store().task_return(
609            instance,
610            wasmtime_environ::component::TypeTupleIndex::from_u32(ty),
611            storage.cast::<crate::ValRaw>(),
612            storage_len,
613        )
614    })
615}
616
617#[cfg(feature = "component-model-async")]
618unsafe fn waitable_set_new(
619    vmctx: NonNull<VMComponentContext>,
620    caller_instance: u32,
621) -> Result<u32> {
622    ComponentInstance::from_vmctx(vmctx, |instance| {
623        (*instance.store())
624            .component_async_store()
625            .waitable_set_new(
626                instance,
627                wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(
628                    caller_instance,
629                ),
630            )
631    })
632}
633
634#[cfg(feature = "component-model-async")]
635unsafe fn waitable_set_wait(
636    vmctx: NonNull<VMComponentContext>,
637    caller_instance: u32,
638    set: u32,
639    async_: u8,
640    memory: *mut u8,
641    payload: u32,
642) -> Result<u32> {
643    ComponentInstance::from_vmctx(vmctx, |instance| {
644        (*instance.store())
645            .component_async_store()
646            .waitable_set_wait(
647                instance,
648                wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(
649                    caller_instance,
650                ),
651                set,
652                async_ != 0,
653                memory.cast::<crate::vm::VMMemoryDefinition>(),
654                payload,
655            )
656    })
657}
658
659#[cfg(feature = "component-model-async")]
660unsafe fn waitable_set_poll(
661    vmctx: NonNull<VMComponentContext>,
662    caller_instance: u32,
663    set: u32,
664    async_: u8,
665    memory: *mut u8,
666    payload: u32,
667) -> Result<u32> {
668    ComponentInstance::from_vmctx(vmctx, |instance| {
669        (*instance.store())
670            .component_async_store()
671            .waitable_set_poll(
672                instance,
673                wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(
674                    caller_instance,
675                ),
676                set,
677                async_ != 0,
678                memory.cast::<crate::vm::VMMemoryDefinition>(),
679                payload,
680            )
681    })
682}
683
684#[cfg(feature = "component-model-async")]
685unsafe fn waitable_set_drop(
686    vmctx: NonNull<VMComponentContext>,
687    caller_instance: u32,
688    set: u32,
689) -> Result<()> {
690    ComponentInstance::from_vmctx(vmctx, |instance| {
691        (*instance.store())
692            .component_async_store()
693            .waitable_set_drop(
694                instance,
695                wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(
696                    caller_instance,
697                ),
698                set,
699            )
700    })
701}
702
703#[cfg(feature = "component-model-async")]
704unsafe fn waitable_join(
705    vmctx: NonNull<VMComponentContext>,
706    caller_instance: u32,
707    set: u32,
708    waitable: u32,
709) -> Result<()> {
710    ComponentInstance::from_vmctx(vmctx, |instance| {
711        (*instance.store()).component_async_store().waitable_join(
712            instance,
713            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
714            set,
715            waitable,
716        )
717    })
718}
719
720#[cfg(feature = "component-model-async")]
721unsafe fn yield_(vmctx: NonNull<VMComponentContext>, async_: u8) -> Result<()> {
722    ComponentInstance::from_vmctx(vmctx, |instance| {
723        (*instance.store())
724            .component_async_store()
725            .yield_(instance, async_ != 0)
726    })
727}
728
729#[cfg(feature = "component-model-async")]
730unsafe fn subtask_drop(
731    vmctx: NonNull<VMComponentContext>,
732    caller_instance: u32,
733    task_id: u32,
734) -> Result<()> {
735    ComponentInstance::from_vmctx(vmctx, |instance| {
736        (*instance.store()).component_async_store().subtask_drop(
737            instance,
738            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
739            task_id,
740        )
741    })
742}
743
744#[cfg(feature = "component-model-async")]
745unsafe fn sync_enter(
746    vmctx: NonNull<VMComponentContext>,
747    start: *mut u8,
748    return_: *mut u8,
749    caller_instance: u32,
750    task_return_type: u32,
751    result_count: u32,
752    storage: *mut u8,
753    storage_len: usize,
754) -> Result<()> {
755    ComponentInstance::from_vmctx(vmctx, |instance| {
756        (*instance.store()).component_async_store().sync_enter(
757            start.cast::<crate::vm::VMFuncRef>(),
758            return_.cast::<crate::vm::VMFuncRef>(),
759            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
760            wasmtime_environ::component::TypeTupleIndex::from_u32(task_return_type),
761            result_count,
762            storage.cast::<crate::ValRaw>(),
763            storage_len,
764        )
765    })
766}
767
768#[cfg(feature = "component-model-async")]
769unsafe fn sync_exit(
770    vmctx: NonNull<VMComponentContext>,
771    callback: *mut u8,
772    caller_instance: u32,
773    callee: *mut u8,
774    callee_instance: u32,
775    param_count: u32,
776    storage: *mut u8,
777    storage_len: usize,
778) -> Result<()> {
779    ComponentInstance::from_vmctx(vmctx, |instance| {
780        (*instance.store()).component_async_store().sync_exit(
781            instance,
782            callback.cast::<crate::vm::VMFuncRef>(),
783            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
784            callee.cast::<crate::vm::VMFuncRef>(),
785            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(callee_instance),
786            param_count,
787            storage.cast::<std::mem::MaybeUninit<crate::ValRaw>>(),
788            storage_len,
789        )
790    })
791}
792
793#[cfg(feature = "component-model-async")]
794unsafe fn async_enter(
795    vmctx: NonNull<VMComponentContext>,
796    start: *mut u8,
797    return_: *mut u8,
798    caller_instance: u32,
799    task_return_type: u32,
800    params: u32,
801    results: u32,
802) -> Result<()> {
803    ComponentInstance::from_vmctx(vmctx, |instance| {
804        (*instance.store()).component_async_store().async_enter(
805            start.cast::<crate::vm::VMFuncRef>(),
806            return_.cast::<crate::vm::VMFuncRef>(),
807            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
808            wasmtime_environ::component::TypeTupleIndex::from_u32(task_return_type),
809            params,
810            results,
811        )
812    })
813}
814
815#[cfg(feature = "component-model-async")]
816unsafe fn async_exit(
817    vmctx: NonNull<VMComponentContext>,
818    callback: *mut u8,
819    post_return: *mut u8,
820    caller_instance: u32,
821    callee: *mut u8,
822    callee_instance: u32,
823    param_count: u32,
824    result_count: u32,
825    flags: u32,
826) -> Result<u32> {
827    ComponentInstance::from_vmctx(vmctx, |instance| {
828        (*instance.store()).component_async_store().async_exit(
829            instance,
830            callback.cast::<crate::vm::VMFuncRef>(),
831            post_return.cast::<crate::vm::VMFuncRef>(),
832            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(caller_instance),
833            callee.cast::<crate::vm::VMFuncRef>(),
834            wasmtime_environ::component::RuntimeComponentInstanceIndex::from_u32(callee_instance),
835            param_count,
836            result_count,
837            flags,
838        )
839    })
840}
841
842#[cfg(feature = "component-model-async")]
843unsafe fn future_transfer(
844    vmctx: NonNull<VMComponentContext>,
845    src_idx: u32,
846    src_table: u32,
847    dst_table: u32,
848) -> Result<u32> {
849    let src_table = wasmtime_environ::component::TypeFutureTableIndex::from_u32(src_table);
850    let dst_table = wasmtime_environ::component::TypeFutureTableIndex::from_u32(dst_table);
851    ComponentInstance::from_vmctx(vmctx, |instance| {
852        instance.future_transfer(src_idx, src_table, dst_table)
853    })
854}
855
856#[cfg(feature = "component-model-async")]
857unsafe fn stream_transfer(
858    vmctx: NonNull<VMComponentContext>,
859    src_idx: u32,
860    src_table: u32,
861    dst_table: u32,
862) -> Result<u32> {
863    let src_table = wasmtime_environ::component::TypeStreamTableIndex::from_u32(src_table);
864    let dst_table = wasmtime_environ::component::TypeStreamTableIndex::from_u32(dst_table);
865    ComponentInstance::from_vmctx(vmctx, |instance| {
866        instance.stream_transfer(src_idx, src_table, dst_table)
867    })
868}
869
870#[cfg(feature = "component-model-async")]
871unsafe fn error_context_transfer(
872    vmctx: NonNull<VMComponentContext>,
873    src_idx: u32,
874    src_table: u32,
875    dst_table: u32,
876) -> Result<u32> {
877    let src_table =
878        wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(src_table);
879    let dst_table =
880        wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(dst_table);
881    ComponentInstance::from_vmctx(vmctx, |instance| {
882        instance.error_context_transfer(src_idx, src_table, dst_table)
883    })
884}
885
886#[cfg(feature = "component-model-async")]
887unsafe fn future_new(vmctx: NonNull<VMComponentContext>, ty: u32) -> Result<u32> {
888    ComponentInstance::from_vmctx(vmctx, |instance| {
889        (*instance.store()).component_async_store().future_new(
890            instance,
891            wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
892        )
893    })
894}
895
896#[cfg(feature = "component-model-async")]
897unsafe fn future_write(
898    vmctx: NonNull<VMComponentContext>,
899    memory: *mut u8,
900    realloc: *mut u8,
901    string_encoding: u8,
902    ty: u32,
903    future: u32,
904    address: u32,
905) -> Result<u32> {
906    ComponentInstance::from_vmctx(vmctx, |instance| {
907        (*instance.store()).component_async_store().future_write(
908            instance,
909            memory.cast::<crate::vm::VMMemoryDefinition>(),
910            realloc.cast::<crate::vm::VMFuncRef>(),
911            string_encoding,
912            wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
913            future,
914            address,
915        )
916    })
917}
918
919#[cfg(feature = "component-model-async")]
920unsafe fn future_read(
921    vmctx: NonNull<VMComponentContext>,
922    memory: *mut u8,
923    realloc: *mut u8,
924    string_encoding: u8,
925    ty: u32,
926    err_ctx_ty: u32,
927    future: u32,
928    address: u32,
929) -> Result<u32> {
930    ComponentInstance::from_vmctx(vmctx, |instance| {
931        (*instance.store()).component_async_store().future_read(
932            instance,
933            memory.cast::<crate::vm::VMMemoryDefinition>(),
934            realloc.cast::<crate::vm::VMFuncRef>(),
935            string_encoding,
936            wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
937            wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(
938                err_ctx_ty,
939            ),
940            future,
941            address,
942        )
943    })
944}
945
946#[cfg(feature = "component-model-async")]
947unsafe fn future_cancel_write(
948    vmctx: NonNull<VMComponentContext>,
949    ty: u32,
950    async_: u8,
951    writer: u32,
952) -> Result<u32> {
953    ComponentInstance::from_vmctx(vmctx, |instance| {
954        (*instance.store())
955            .component_async_store()
956            .future_cancel_write(
957                instance,
958                wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
959                async_ != 0,
960                writer,
961            )
962    })
963}
964
965#[cfg(feature = "component-model-async")]
966unsafe fn future_cancel_read(
967    vmctx: NonNull<VMComponentContext>,
968    ty: u32,
969    async_: u8,
970    reader: u32,
971) -> Result<u32> {
972    ComponentInstance::from_vmctx(vmctx, |instance| {
973        (*instance.store())
974            .component_async_store()
975            .future_cancel_read(
976                instance,
977                wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
978                async_ != 0,
979                reader,
980            )
981    })
982}
983
984#[cfg(feature = "component-model-async")]
985unsafe fn future_close_writable(
986    vmctx: NonNull<VMComponentContext>,
987    ty: u32,
988    err_ctx_ty: u32,
989    writer: u32,
990    error: u32,
991) -> Result<()> {
992    ComponentInstance::from_vmctx(vmctx, |instance| {
993        (*instance.store())
994            .component_async_store()
995            .future_close_writable(
996                instance,
997                wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
998                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(
999                    err_ctx_ty,
1000                ),
1001                writer,
1002                error,
1003            )
1004    })
1005}
1006
1007#[cfg(feature = "component-model-async")]
1008unsafe fn future_close_readable(
1009    vmctx: NonNull<VMComponentContext>,
1010    ty: u32,
1011    reader: u32,
1012    error: u32,
1013) -> Result<()> {
1014    ComponentInstance::from_vmctx(vmctx, |instance| {
1015        (*instance.store())
1016            .component_async_store()
1017            .future_close_readable(
1018                instance,
1019                wasmtime_environ::component::TypeFutureTableIndex::from_u32(ty),
1020                reader,
1021                error,
1022            )
1023    })
1024}
1025
1026#[cfg(feature = "component-model-async")]
1027unsafe fn stream_new(vmctx: NonNull<VMComponentContext>, ty: u32) -> Result<u32> {
1028    ComponentInstance::from_vmctx(vmctx, |instance| {
1029        (*instance.store()).component_async_store().stream_new(
1030            instance,
1031            wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1032        )
1033    })
1034}
1035
1036#[cfg(feature = "component-model-async")]
1037unsafe fn stream_write(
1038    vmctx: NonNull<VMComponentContext>,
1039    memory: *mut u8,
1040    realloc: *mut u8,
1041    string_encoding: u8,
1042    ty: u32,
1043    stream: u32,
1044    address: u32,
1045    count: u32,
1046) -> Result<u32> {
1047    ComponentInstance::from_vmctx(vmctx, |instance| {
1048        (*instance.store()).component_async_store().stream_write(
1049            instance,
1050            memory.cast::<crate::vm::VMMemoryDefinition>(),
1051            realloc.cast::<crate::vm::VMFuncRef>(),
1052            string_encoding,
1053            wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1054            stream,
1055            address,
1056            count,
1057        )
1058    })
1059}
1060
1061#[cfg(feature = "component-model-async")]
1062unsafe fn stream_read(
1063    vmctx: NonNull<VMComponentContext>,
1064    memory: *mut u8,
1065    realloc: *mut u8,
1066    string_encoding: u8,
1067    ty: u32,
1068    err_ctx_ty: u32,
1069    stream: u32,
1070    address: u32,
1071    count: u32,
1072) -> Result<u32> {
1073    ComponentInstance::from_vmctx(vmctx, |instance| {
1074        (*instance.store()).component_async_store().stream_read(
1075            instance,
1076            memory.cast::<crate::vm::VMMemoryDefinition>(),
1077            realloc.cast::<crate::vm::VMFuncRef>(),
1078            string_encoding,
1079            wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1080            wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(
1081                err_ctx_ty,
1082            ),
1083            stream,
1084            address,
1085            count,
1086        )
1087    })
1088}
1089
1090#[cfg(feature = "component-model-async")]
1091unsafe fn stream_cancel_write(
1092    vmctx: NonNull<VMComponentContext>,
1093    ty: u32,
1094    async_: u8,
1095    writer: u32,
1096) -> Result<u32> {
1097    ComponentInstance::from_vmctx(vmctx, |instance| {
1098        (*instance.store())
1099            .component_async_store()
1100            .stream_cancel_write(
1101                instance,
1102                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1103                async_ != 0,
1104                writer,
1105            )
1106    })
1107}
1108
1109#[cfg(feature = "component-model-async")]
1110unsafe fn stream_cancel_read(
1111    vmctx: NonNull<VMComponentContext>,
1112    ty: u32,
1113    async_: u8,
1114    reader: u32,
1115) -> Result<u32> {
1116    ComponentInstance::from_vmctx(vmctx, |instance| {
1117        (*instance.store())
1118            .component_async_store()
1119            .stream_cancel_read(
1120                instance,
1121                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1122                async_ != 0,
1123                reader,
1124            )
1125    })
1126}
1127
1128#[cfg(feature = "component-model-async")]
1129unsafe fn stream_close_writable(
1130    vmctx: NonNull<VMComponentContext>,
1131    ty: u32,
1132    err_ctx_ty: u32,
1133    writer: u32,
1134    error: u32,
1135) -> Result<()> {
1136    ComponentInstance::from_vmctx(vmctx, |instance| {
1137        (*instance.store())
1138            .component_async_store()
1139            .stream_close_writable(
1140                instance,
1141                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1142                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(
1143                    err_ctx_ty,
1144                ),
1145                writer,
1146                error,
1147            )
1148    })
1149}
1150
1151#[cfg(feature = "component-model-async")]
1152unsafe fn stream_close_readable(
1153    vmctx: NonNull<VMComponentContext>,
1154    ty: u32,
1155    reader: u32,
1156    error: u32,
1157) -> Result<()> {
1158    ComponentInstance::from_vmctx(vmctx, |instance| {
1159        (*instance.store())
1160            .component_async_store()
1161            .stream_close_readable(
1162                instance,
1163                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1164                reader,
1165                error,
1166            )
1167    })
1168}
1169
1170#[cfg(feature = "component-model-async")]
1171unsafe fn flat_stream_write(
1172    vmctx: NonNull<VMComponentContext>,
1173    memory: *mut u8,
1174    realloc: *mut u8,
1175    ty: u32,
1176    payload_size: u32,
1177    payload_align: u32,
1178    stream: u32,
1179    address: u32,
1180    count: u32,
1181) -> Result<u32> {
1182    ComponentInstance::from_vmctx(vmctx, |instance| {
1183        (*instance.store())
1184            .component_async_store()
1185            .flat_stream_write(
1186                instance,
1187                memory.cast::<crate::vm::VMMemoryDefinition>(),
1188                realloc.cast::<crate::vm::VMFuncRef>(),
1189                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1190                payload_size,
1191                payload_align,
1192                stream,
1193                address,
1194                count,
1195            )
1196    })
1197}
1198
1199#[cfg(feature = "component-model-async")]
1200unsafe fn flat_stream_read(
1201    vmctx: NonNull<VMComponentContext>,
1202    memory: *mut u8,
1203    realloc: *mut u8,
1204    ty: u32,
1205    err_ctx_ty: u32,
1206    payload_size: u32,
1207    payload_align: u32,
1208    stream: u32,
1209    address: u32,
1210    count: u32,
1211) -> Result<u32> {
1212    ComponentInstance::from_vmctx(vmctx, |instance| {
1213        (*instance.store())
1214            .component_async_store()
1215            .flat_stream_read(
1216                instance,
1217                memory.cast::<crate::vm::VMMemoryDefinition>(),
1218                realloc.cast::<crate::vm::VMFuncRef>(),
1219                wasmtime_environ::component::TypeStreamTableIndex::from_u32(ty),
1220                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(
1221                    err_ctx_ty,
1222                ),
1223                payload_size,
1224                payload_align,
1225                stream,
1226                address,
1227                count,
1228            )
1229    })
1230}
1231
1232#[cfg(feature = "component-model-async")]
1233unsafe fn error_context_new(
1234    vmctx: NonNull<VMComponentContext>,
1235    memory: *mut u8,
1236    realloc: *mut u8,
1237    string_encoding: u8,
1238    ty: u32,
1239    debug_msg_address: u32,
1240    debug_msg_len: u32,
1241) -> Result<u32> {
1242    ComponentInstance::from_vmctx(vmctx, |instance| {
1243        (*instance.store())
1244            .component_async_store()
1245            .error_context_new(
1246                instance,
1247                memory.cast::<crate::vm::VMMemoryDefinition>(),
1248                realloc.cast::<crate::vm::VMFuncRef>(),
1249                string_encoding,
1250                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1251                debug_msg_address,
1252                debug_msg_len,
1253            )
1254    })
1255}
1256
1257#[cfg(feature = "component-model-async")]
1258unsafe fn error_context_debug_message(
1259    vmctx: NonNull<VMComponentContext>,
1260    memory: *mut u8,
1261    realloc: *mut u8,
1262    string_encoding: u8,
1263    ty: u32,
1264    err_ctx_handle: u32,
1265    debug_msg_address: u32,
1266) -> Result<()> {
1267    ComponentInstance::from_vmctx(vmctx, |instance| {
1268        (*instance.store())
1269            .component_async_store()
1270            .error_context_debug_message(
1271                instance,
1272                memory.cast::<crate::vm::VMMemoryDefinition>(),
1273                realloc.cast::<crate::vm::VMFuncRef>(),
1274                string_encoding,
1275                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1276                err_ctx_handle,
1277                debug_msg_address,
1278            )
1279    })
1280}
1281
1282#[cfg(feature = "component-model-async")]
1283unsafe fn error_context_drop(
1284    vmctx: NonNull<VMComponentContext>,
1285    ty: u32,
1286    err_ctx_handle: u32,
1287) -> Result<()> {
1288    ComponentInstance::from_vmctx(vmctx, |instance| {
1289        (*instance.store())
1290            .component_async_store()
1291            .error_context_drop(
1292                instance,
1293                wasmtime_environ::component::TypeComponentLocalErrorContextTableIndex::from_u32(ty),
1294                err_ctx_handle,
1295            )
1296    })
1297}