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