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