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