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