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