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