1 use crate::async_functions::{PollOnce, execute_across_threads}; 2 use anyhow::Result; 3 use wasmtime::{AsContextMut, Config, component::*}; 4 use wasmtime::{Engine, Store, StoreContextMut, Trap}; 5 use wasmtime_component_util::REALLOC_AND_FREE; 6 7 /// This is super::func::thunks, except with an async store. 8 #[tokio::test] 9 #[cfg_attr(miri, ignore)] 10 async fn smoke() -> Result<()> { 11 let component = r#" 12 (component 13 (core module $m 14 (func (export "thunk")) 15 (func (export "thunk-trap") unreachable) 16 ) 17 (core instance $i (instantiate $m)) 18 (func (export "thunk") 19 (canon lift (core func $i "thunk")) 20 ) 21 (func (export "thunk-trap") 22 (canon lift (core func $i "thunk-trap")) 23 ) 24 ) 25 "#; 26 27 let engine = super::async_engine(); 28 let component = Component::new(&engine, component)?; 29 let mut store = Store::new(&engine, ()); 30 let instance = Linker::new(&engine) 31 .instantiate_async(&mut store, &component) 32 .await?; 33 34 let thunk = instance.get_typed_func::<(), ()>(&mut store, "thunk")?; 35 36 thunk.call_async(&mut store, ()).await?; 37 thunk.post_return_async(&mut store).await?; 38 39 let err = instance 40 .get_typed_func::<(), ()>(&mut store, "thunk-trap")? 41 .call_async(&mut store, ()) 42 .await 43 .unwrap_err(); 44 assert_eq!(err.downcast::<Trap>()?, Trap::UnreachableCodeReached); 45 46 Ok(()) 47 } 48 49 /// Handle an import function, created using component::Linker::func_wrap_async. 50 #[tokio::test] 51 #[cfg_attr(miri, ignore)] 52 async fn smoke_func_wrap() -> Result<()> { 53 let component = r#" 54 (component 55 (type $f (func)) 56 (import "i" (func $f)) 57 58 (core module $m 59 (import "imports" "i" (func $i)) 60 (func (export "thunk") call $i) 61 ) 62 63 (core func $f (canon lower (func $f))) 64 (core instance $i (instantiate $m 65 (with "imports" (instance 66 (export "i" (func $f)) 67 )) 68 )) 69 (func (export "thunk") 70 (canon lift (core func $i "thunk")) 71 ) 72 ) 73 "#; 74 75 let engine = super::async_engine(); 76 let component = Component::new(&engine, component)?; 77 let mut store = Store::new(&engine, ()); 78 let mut linker = Linker::new(&engine); 79 let mut root = linker.root(); 80 root.func_wrap_async("i", |_: StoreContextMut<()>, _: ()| { 81 Box::new(async { Ok(()) }) 82 })?; 83 84 let instance = linker.instantiate_async(&mut store, &component).await?; 85 86 let thunk = instance.get_typed_func::<(), ()>(&mut store, "thunk")?; 87 88 thunk.call_async(&mut store, ()).await?; 89 thunk.post_return_async(&mut store).await?; 90 91 Ok(()) 92 } 93 94 // This test stresses TLS management in combination with the `realloc` option 95 // for imported functions. This will create an async computation which invokes a 96 // component that invokes an imported function. The imported function returns a 97 // list which will require invoking malloc. 98 // 99 // As an added stressor all polls are sprinkled across threads through 100 // `execute_across_threads`. Yields are injected liberally by configuring 1 101 // fuel consumption to trigger a yield. 102 // 103 // Overall a yield should happen during malloc which should be an "interesting 104 // situation" with respect to the runtime. 105 #[tokio::test] 106 #[cfg_attr(miri, ignore)] 107 async fn resume_separate_thread() -> Result<()> { 108 let mut config = wasmtime_test_util::component::config(); 109 config.async_support(true); 110 config.consume_fuel(true); 111 let engine = Engine::new(&config)?; 112 let component = format!( 113 r#" 114 (component 115 (import "yield" (func $yield (result (list u8)))) 116 (core module $libc 117 (memory (export "memory") 1) 118 {REALLOC_AND_FREE} 119 ) 120 (core instance $libc (instantiate $libc)) 121 122 (core func $yield 123 (canon lower 124 (func $yield) 125 (memory $libc "memory") 126 (realloc (func $libc "realloc")) 127 ) 128 ) 129 130 (core module $m 131 (import "" "yield" (func $yield (param i32))) 132 (import "libc" "memory" (memory 0)) 133 (func $start 134 i32.const 8 135 call $yield 136 ) 137 (start $start) 138 ) 139 (core instance (instantiate $m 140 (with "" (instance (export "yield" (func $yield)))) 141 (with "libc" (instance $libc)) 142 )) 143 ) 144 "# 145 ); 146 let component = Component::new(&engine, component)?; 147 let mut linker = Linker::new(&engine); 148 linker 149 .root() 150 .func_wrap_async("yield", |_: StoreContextMut<()>, _: ()| { 151 Box::new(async { 152 tokio::task::yield_now().await; 153 Ok((vec![1u8, 2u8],)) 154 }) 155 })?; 156 157 execute_across_threads(async move { 158 let mut store = Store::new(&engine, ()); 159 store.set_fuel(u64::MAX).unwrap(); 160 store.fuel_async_yield_interval(Some(1)).unwrap(); 161 linker.instantiate_async(&mut store, &component).await?; 162 Ok::<_, anyhow::Error>(()) 163 }) 164 .await?; 165 Ok(()) 166 } 167 168 // This test is intended to stress TLS management in the component model around 169 // the management of the `realloc` function. This creates an async computation 170 // representing the execution of a component model function where entry into the 171 // component uses `realloc` and then the component runs. This async computation 172 // is then polled iteratively with another "wasm activation" (in this case a 173 // core wasm function) on the stack. The poll-per-call should work and nothing 174 // should in theory have problems here. 175 // 176 // As an added stressor all polls are sprinkled across threads through 177 // `execute_across_threads`. Yields are injected liberally by configuring 1 178 // fuel consumption to trigger a yield. 179 // 180 // Overall a yield should happen during malloc which should be an "interesting 181 // situation" with respect to the runtime. 182 #[tokio::test] 183 #[cfg_attr(miri, ignore)] 184 async fn poll_through_wasm_activation() -> Result<()> { 185 let mut config = wasmtime_test_util::component::config(); 186 config.async_support(true); 187 config.consume_fuel(true); 188 let engine = Engine::new(&config)?; 189 let component = format!( 190 r#" 191 (component 192 (core module $m 193 {REALLOC_AND_FREE} 194 (memory (export "memory") 1) 195 (func (export "run") (param i32 i32) 196 ) 197 ) 198 (core instance $i (instantiate $m)) 199 (func (export "run") (param "x" (list u8)) 200 (canon lift (core func $i "run") 201 (memory $i "memory") 202 (realloc (func $i "realloc")))) 203 ) 204 "# 205 ); 206 let component = Component::new(&engine, component)?; 207 let linker = Linker::new(&engine); 208 209 let invoke_component = { 210 let engine = engine.clone(); 211 async move { 212 let mut store = Store::new(&engine, ()); 213 store.set_fuel(u64::MAX).unwrap(); 214 store.fuel_async_yield_interval(Some(1)).unwrap(); 215 let instance = linker.instantiate_async(&mut store, &component).await?; 216 let func = instance.get_typed_func::<(Vec<u8>,), ()>(&mut store, "run")?; 217 func.call_async(&mut store, (vec![1, 2, 3],)).await?; 218 Ok::<_, anyhow::Error>(()) 219 } 220 }; 221 222 execute_across_threads(async move { 223 let mut store = Store::new(&engine, Some(Box::pin(invoke_component))); 224 let poll_once = wasmtime::Func::wrap_async(&mut store, |mut cx, _: ()| { 225 let invoke_component = cx.data_mut().take().unwrap(); 226 Box::new(async move { 227 match PollOnce::new(invoke_component).await { 228 Ok(result) => { 229 result?; 230 Ok(1) 231 } 232 Err(future) => { 233 *cx.data_mut() = Some(future); 234 Ok(0) 235 } 236 } 237 }) 238 }); 239 let poll_once = poll_once.typed::<(), i32>(&mut store)?; 240 while poll_once.call_async(&mut store, ()).await? != 1 { 241 // loop around to call again 242 } 243 Ok::<_, anyhow::Error>(()) 244 }) 245 .await?; 246 Ok(()) 247 } 248 249 /// Test async drop method for host resources. 250 #[tokio::test] 251 #[cfg_attr(miri, ignore)] 252 async fn drop_resource_async() -> Result<()> { 253 use std::sync::Arc; 254 use std::sync::Mutex; 255 256 let engine = super::async_engine(); 257 let c = Component::new( 258 &engine, 259 r#" 260 (component 261 (import "t" (type $t (sub resource))) 262 263 (core func $drop (canon resource.drop $t)) 264 265 (core module $m 266 (import "" "drop" (func $drop (param i32))) 267 (func (export "f") (param i32) 268 (call $drop (local.get 0)) 269 ) 270 ) 271 (core instance $i (instantiate $m 272 (with "" (instance 273 (export "drop" (func $drop)) 274 )) 275 )) 276 277 (func (export "f") (param "x" (own $t)) 278 (canon lift (core func $i "f"))) 279 ) 280 "#, 281 )?; 282 283 struct MyType; 284 285 let mut store = Store::new(&engine, ()); 286 let mut linker = Linker::new(&engine); 287 288 let drop_status = Arc::new(Mutex::new("not dropped")); 289 let ds = drop_status.clone(); 290 291 linker 292 .root() 293 .resource_async("t", ResourceType::host::<MyType>(), move |_, _| { 294 let ds = ds.clone(); 295 Box::new(async move { 296 *ds.lock().unwrap() = "before yield"; 297 tokio::task::yield_now().await; 298 *ds.lock().unwrap() = "after yield"; 299 Ok(()) 300 }) 301 })?; 302 let i = linker.instantiate_async(&mut store, &c).await?; 303 let f = i.get_typed_func::<(Resource<MyType>,), ()>(&mut store, "f")?; 304 305 execute_across_threads(async move { 306 let resource = Resource::new_own(100); 307 f.call_async(&mut store, (resource,)).await?; 308 f.post_return_async(&mut store).await?; 309 Ok::<_, anyhow::Error>(()) 310 }) 311 .await?; 312 313 assert_eq!("after yield", *drop_status.lock().unwrap()); 314 315 Ok(()) 316 } 317 318 /// Test task deletion in three situations, for every combination of lift/lower/(guest/host): 319 /// 1. An explicit thread calls task.return 320 /// 2. An explicit thread suspends indefinitely 321 /// 3. An explicit thread yield loops indefinitely 322 #[tokio::test] 323 #[cfg_attr(miri, ignore)] 324 async fn task_deletion() -> Result<()> { 325 let mut config = Config::new(); 326 config.async_support(true); 327 config.wasm_component_model_async(true); 328 config.wasm_component_model_threading(true); 329 config.wasm_component_model_async_stackful(true); 330 config.wasm_component_model_async_builtins(true); 331 let engine = Engine::new(&config)?; 332 let component = Component::new( 333 &engine, 334 r#"(component 335 (component $C 336 (core module $Memory (memory (export "mem") 1)) 337 (core instance $memory (instantiate $Memory)) 338 ;; Defines the table for the thread start functions 339 (core module $libc 340 (table (export "__indirect_function_table") 3 funcref)) 341 (core module $CM 342 (import "" "mem" (memory 1)) 343 (import "" "task.return" (func $task-return (param i32))) 344 (import "" "task.cancel" (func $task-cancel)) 345 (import "" "thread.new_indirect" (func $thread-new-indirect (param i32 i32) (result i32))) 346 (import "" "thread.suspend" (func $thread-suspend (result i32))) 347 (import "" "thread.suspend-cancellable" (func $thread-suspend-cancellable (result i32))) 348 (import "" "thread.yield-to" (func $thread-yield-to (param i32) (result i32))) 349 (import "" "thread.yield-to-cancellable" (func $thread-yield-to-cancellable (param i32) (result i32))) 350 (import "" "thread.switch-to" (func $thread-switch-to (param i32) (result i32))) 351 (import "" "thread.switch-to-cancellable" (func $thread-switch-to-cancellable (param i32) (result i32))) 352 (import "" "thread.yield" (func $thread-yield (result i32))) 353 (import "" "thread.yield-cancellable" (func $thread-yield-cancellable (result i32))) 354 (import "" "thread.index" (func $thread-index (result i32))) 355 (import "" "thread.resume-later" (func $thread-resume-later (param i32))) 356 (import "" "waitable.join" (func $waitable.join (param i32 i32))) 357 (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 358 (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) 359 (import "libc" "__indirect_function_table" (table $indirect-function-table 3 funcref)) 360 361 ;; Indices into the function table for the thread start functions 362 (global $call-return-ftbl-idx i32 (i32.const 0)) 363 (global $suspend-ftbl-idx i32 (i32.const 1)) 364 (global $yield-loop-ftbl-idx i32 (i32.const 2)) 365 366 (func $call-return (param i32) 367 (call $task-return (local.get 0))) 368 369 (func $suspend (param i32) 370 (drop (call $thread-suspend))) 371 372 (func $yield-loop (param i32) 373 (loop $top 374 (drop (call $thread-yield)) 375 (br $top))) 376 377 (func (export "explicit-thread-calls-return-stackful") 378 (call $thread-resume-later 379 (call $thread-new-indirect (global.get $call-return-ftbl-idx) (i32.const 42)))) 380 381 (func (export "explicit-thread-calls-return-stackless") (result i32) 382 (call $thread-resume-later 383 (call $thread-new-indirect (global.get $call-return-ftbl-idx) (i32.const 42))) 384 (i32.const 0 (; EXIT ;))) 385 386 (func (export "cb") (param i32 i32 i32) (result i32) 387 (unreachable)) 388 389 (func (export "explicit-thread-suspends-sync") (result i32) 390 (call $thread-resume-later 391 (call $thread-new-indirect (global.get $suspend-ftbl-idx) (i32.const 42))) 392 (i32.const 42)) 393 394 (func (export "explicit-thread-suspends-stackful") 395 (call $thread-resume-later 396 (call $thread-new-indirect (global.get $suspend-ftbl-idx) (i32.const 42))) 397 (call $task-return (i32.const 42))) 398 399 (func (export "explicit-thread-suspends-stackless") (result i32) 400 (call $thread-resume-later 401 (call $thread-new-indirect (global.get $suspend-ftbl-idx) (i32.const 42))) 402 (call $task-return (i32.const 42)) 403 (i32.const 0)) 404 405 (func (export "explicit-thread-yield-loops-sync") (result i32) 406 (call $thread-resume-later 407 (call $thread-new-indirect (global.get $yield-loop-ftbl-idx) (i32.const 42))) 408 (i32.const 42)) 409 410 (func (export "explicit-thread-yield-loops-stackful") 411 (call $thread-resume-later 412 (call $thread-new-indirect (global.get $yield-loop-ftbl-idx) (i32.const 42))) 413 (call $task-return (i32.const 42))) 414 415 (func (export "explicit-thread-yield-loops-stackless") (result i32) 416 (call $thread-resume-later 417 (call $thread-new-indirect (global.get $suspend-ftbl-idx) (i32.const 42))) 418 (call $task-return (i32.const 42)) 419 (i32.const 0 (; EXIT ;))) 420 421 422 ;; Initialize the function table that will be used by thread.new_indirect 423 (elem (table $indirect-function-table) (i32.const 0 (; call-return-ftbl-idx ;)) func $call-return) 424 (elem (table $indirect-function-table) (i32.const 1 (; suspend-ftbl-idx ;)) func $suspend) 425 (elem (table $indirect-function-table) (i32.const 2 (; yield-loop-ftbl-idx ;)) func $yield-loop) 426 ) 427 428 ;; Instantiate the libc module to get the table 429 (core instance $libc (instantiate $libc)) 430 ;; Get access to `thread.new_indirect` that uses the table from libc 431 (core type $start-func-ty (func (param i32))) 432 (alias core export $libc "__indirect_function_table" (core table $indirect-function-table)) 433 434 (core func $task-return (canon task.return (result u32))) 435 (core func $task-cancel (canon task.cancel)) 436 (core func $thread-new-indirect 437 (canon thread.new_indirect $start-func-ty (table $indirect-function-table))) 438 (core func $thread-yield (canon thread.yield)) 439 (core func $thread-yield-cancellable (canon thread.yield cancellable)) 440 (core func $thread-index (canon thread.index)) 441 (core func $thread-yield-to (canon thread.yield-to)) 442 (core func $thread-yield-to-cancellable (canon thread.yield-to cancellable)) 443 (core func $thread-resume-later (canon thread.resume-later)) 444 (core func $thread-switch-to (canon thread.switch-to)) 445 (core func $thread-switch-to-cancellable (canon thread.switch-to cancellable)) 446 (core func $thread-suspend (canon thread.suspend)) 447 (core func $thread-suspend-cancellable (canon thread.suspend cancellable)) 448 (core func $waitable-set.new (canon waitable-set.new)) 449 (core func $waitable.join (canon waitable.join)) 450 (core func $waitable-set.wait (canon waitable-set.wait (memory $memory "mem"))) 451 452 ;; Instantiate the main module 453 (core instance $cm ( 454 instantiate $CM 455 (with "" (instance 456 (export "mem" (memory $memory "mem")) 457 (export "task.return" (func $task-return)) 458 (export "task.cancel" (func $task-cancel)) 459 (export "thread.new_indirect" (func $thread-new-indirect)) 460 (export "thread.index" (func $thread-index)) 461 (export "thread.yield-to" (func $thread-yield-to)) 462 (export "thread.yield-to-cancellable" (func $thread-yield-to-cancellable)) 463 (export "thread.yield" (func $thread-yield)) 464 (export "thread.yield-cancellable" (func $thread-yield-cancellable)) 465 (export "thread.switch-to" (func $thread-switch-to)) 466 (export "thread.switch-to-cancellable" (func $thread-switch-to-cancellable)) 467 (export "thread.suspend" (func $thread-suspend)) 468 (export "thread.suspend-cancellable" (func $thread-suspend-cancellable)) 469 (export "thread.resume-later" (func $thread-resume-later)) 470 (export "waitable.join" (func $waitable.join)) 471 (export "waitable-set.wait" (func $waitable-set.wait)) 472 (export "waitable-set.new" (func $waitable-set.new)))) 473 (with "libc" (instance $libc)))) 474 475 (func (export "explicit-thread-calls-return-stackful") (result u32) 476 (canon lift (core func $cm "explicit-thread-calls-return-stackful") async)) 477 (func (export "explicit-thread-calls-return-stackless") (result u32) 478 (canon lift (core func $cm "explicit-thread-calls-return-stackless") async (callback (func $cm "cb")))) 479 (func (export "explicit-thread-suspends-sync") (result u32) 480 (canon lift (core func $cm "explicit-thread-suspends-sync"))) 481 (func (export "explicit-thread-suspends-stackful") (result u32) 482 (canon lift (core func $cm "explicit-thread-suspends-stackful") async)) 483 (func (export "explicit-thread-suspends-stackless") (result u32) 484 (canon lift (core func $cm "explicit-thread-suspends-stackless") async (callback (func $cm "cb")))) 485 (func (export "explicit-thread-yield-loops-sync") (result u32) 486 (canon lift (core func $cm "explicit-thread-yield-loops-sync"))) 487 (func (export "explicit-thread-yield-loops-stackful") (result u32) 488 (canon lift (core func $cm "explicit-thread-yield-loops-stackful") async)) 489 (func (export "explicit-thread-yield-loops-stackless") (result u32) 490 (canon lift (core func $cm "explicit-thread-yield-loops-stackless") async (callback (func $cm "cb")))) 491 ) 492 493 (component $D 494 (import "explicit-thread-calls-return-stackful" (func $explicit-thread-calls-return-stackful (result u32))) 495 (import "explicit-thread-calls-return-stackless" (func $explicit-thread-calls-return-stackless (result u32))) 496 (import "explicit-thread-suspends-sync" (func $explicit-thread-suspends-sync (result u32))) 497 (import "explicit-thread-suspends-stackful" (func $explicit-thread-suspends-stackful (result u32))) 498 (import "explicit-thread-suspends-stackless" (func $explicit-thread-suspends-stackless (result u32))) 499 (import "explicit-thread-yield-loops-sync" (func $explicit-thread-yield-loops-sync (result u32))) 500 (import "explicit-thread-yield-loops-stackful" (func $explicit-thread-yield-loops-stackful (result u32))) 501 (import "explicit-thread-yield-loops-stackless" (func $explicit-thread-yield-loops-stackless (result u32))) 502 503 (core module $Memory (memory (export "mem") 1)) 504 (core instance $memory (instantiate $Memory)) 505 (core module $DM 506 (import "" "mem" (memory 1)) 507 (import "" "subtask.cancel" (func $subtask.cancel (param i32) (result i32))) 508 ;; sync lowered 509 (import "" "explicit-thread-calls-return-stackful" (func $explicit-thread-calls-return-stackful (result i32))) 510 (import "" "explicit-thread-calls-return-stackless" (func $explicit-thread-calls-return-stackless (result i32))) 511 (import "" "explicit-thread-suspends-sync" (func $explicit-thread-suspends-sync (result i32))) 512 (import "" "explicit-thread-suspends-stackful" (func $explicit-thread-suspends-stackful (result i32))) 513 (import "" "explicit-thread-suspends-stackless" (func $explicit-thread-suspends-stackless (result i32))) 514 (import "" "explicit-thread-yield-loops-sync" (func $explicit-thread-yield-loops-sync (result i32))) 515 (import "" "explicit-thread-yield-loops-stackful" (func $explicit-thread-yield-loops-stackful (result i32))) 516 (import "" "explicit-thread-yield-loops-stackless" (func $explicit-thread-yield-loops-stackless (result i32))) 517 ;; async lowered 518 (import "" "explicit-thread-calls-return-stackful-async" (func $explicit-thread-calls-return-stackful-async (param i32) (result i32))) 519 (import "" "explicit-thread-calls-return-stackless-async" (func $explicit-thread-calls-return-stackless-async (param i32) (result i32))) 520 (import "" "explicit-thread-suspends-sync-async" (func $explicit-thread-suspends-sync-async (param i32) (result i32))) 521 (import "" "explicit-thread-suspends-stackful-async" (func $explicit-thread-suspends-stackful-async (param i32) (result i32))) 522 (import "" "explicit-thread-suspends-stackless-async" (func $explicit-thread-suspends-stackless-async (param i32) (result i32))) 523 (import "" "explicit-thread-yield-loops-sync-async" (func $explicit-thread-yield-loops-sync-async (param i32) (result i32))) 524 (import "" "explicit-thread-yield-loops-stackful-async" (func $explicit-thread-yield-loops-stackful-async (param i32) (result i32))) 525 (import "" "explicit-thread-yield-loops-stackless-async" (func $explicit-thread-yield-loops-stackless-async (param i32) (result i32))) 526 (import "" "waitable.join" (func $waitable.join (param i32 i32))) 527 (import "" "waitable-set.new" (func $waitable-set.new (result i32))) 528 (import "" "waitable-set.wait" (func $waitable-set.wait (param i32 i32) (result i32))) 529 (import "" "thread.yield" (func $thread-yield (result i32))) 530 531 (func $check (param i32) 532 (if (i32.ne (local.get 0) (i32.const 42)) 533 (then unreachable)) 534 ) 535 536 (func $check-async (param i32) 537 (local $retp i32) (local $ws i32) (local $ws-retp i32) 538 (local.set $retp (i32.const 8)) 539 (local.set $ws-retp (i32.const 16)) 540 (local.set $ws (call $waitable-set.new)) 541 542 (if (i32.eq (i32.and (local.get 0) (i32.const 0xF)) (i32.const 2 (; RETURNED ;))) 543 (then (call $check (i32.load (local.get $retp)))) 544 (else 545 (call $waitable.join (i32.shr_u (local.get 0) (i32.const 4)) (local.get $ws)) 546 (drop (call $waitable-set.wait (local.get $ws) (local.get $ws-retp))) 547 (call $check (i32.load (local.get $retp))))) 548 ) 549 550 (func $run (export "run") (result i32) 551 (local $retp i32) 552 (local.set $retp (i32.const 8)) 553 (call $check (call $explicit-thread-calls-return-stackless)) 554 (call $check (call $explicit-thread-calls-return-stackful)) 555 (call $check (call $explicit-thread-suspends-sync)) 556 (call $check (call $explicit-thread-suspends-stackful)) 557 (call $check (call $explicit-thread-suspends-stackless)) 558 (call $check (call $explicit-thread-yield-loops-sync)) 559 (call $check (call $explicit-thread-yield-loops-stackful)) 560 (call $check (call $explicit-thread-yield-loops-stackless)) 561 562 (call $check-async (call $explicit-thread-calls-return-stackless-async (local.get $retp))) 563 (call $check-async (call $explicit-thread-calls-return-stackful-async (local.get $retp))) 564 (call $check-async (call $explicit-thread-suspends-sync-async (local.get $retp))) 565 (call $check-async (call $explicit-thread-suspends-stackful-async (local.get $retp))) 566 (call $check-async (call $explicit-thread-suspends-stackless-async (local.get $retp))) 567 (call $check-async (call $explicit-thread-yield-loops-sync-async (local.get $retp))) 568 (call $check-async (call $explicit-thread-yield-loops-stackful-async (local.get $retp))) 569 (call $check-async (call $explicit-thread-yield-loops-stackless-async (local.get $retp))) 570 571 (i32.const 42) 572 ) 573 ) 574 575 (core func $waitable-set.new (canon waitable-set.new)) 576 (core func $waitable-set.wait (canon waitable-set.wait (memory $memory "mem"))) 577 (core func $waitable.join (canon waitable.join)) 578 (core func $subtask.cancel (canon subtask.cancel async)) 579 (core func $thread.yield (canon thread.yield)) 580 ;; sync lowered 581 (canon lower (func $explicit-thread-calls-return-stackful) (memory $memory "mem") (core func $explicit-thread-calls-return-stackful')) 582 (canon lower (func $explicit-thread-calls-return-stackless) (memory $memory "mem") (core func $explicit-thread-calls-return-stackless')) 583 (canon lower (func $explicit-thread-suspends-sync) (memory $memory "mem") (core func $explicit-thread-suspends-sync')) 584 (canon lower (func $explicit-thread-suspends-stackful) (memory $memory "mem") (core func $explicit-thread-suspends-stackful')) 585 (canon lower (func $explicit-thread-suspends-stackless) (memory $memory "mem") (core func $explicit-thread-suspends-stackless')) 586 (canon lower (func $explicit-thread-yield-loops-sync) (memory $memory "mem") (core func $explicit-thread-yield-loops-sync')) 587 (canon lower (func $explicit-thread-yield-loops-stackful) (memory $memory "mem") (core func $explicit-thread-yield-loops-stackful')) 588 (canon lower (func $explicit-thread-yield-loops-stackless) (memory $memory "mem") (core func $explicit-thread-yield-loops-stackless')) 589 ;; async lowered 590 (canon lower (func $explicit-thread-calls-return-stackful) async (memory $memory "mem") (core func $explicit-thread-calls-return-stackful-async')) 591 (canon lower (func $explicit-thread-calls-return-stackless) async (memory $memory "mem") (core func $explicit-thread-calls-return-stackless-async')) 592 (canon lower (func $explicit-thread-suspends-sync) async (memory $memory "mem") (core func $explicit-thread-suspends-sync-async')) 593 (canon lower (func $explicit-thread-suspends-stackful) async (memory $memory "mem") (core func $explicit-thread-suspends-stackful-async')) 594 (canon lower (func $explicit-thread-suspends-stackless) async (memory $memory "mem") (core func $explicit-thread-suspends-stackless-async')) 595 (canon lower (func $explicit-thread-yield-loops-sync) async (memory $memory "mem") (core func $explicit-thread-yield-loops-sync-async')) 596 (canon lower (func $explicit-thread-yield-loops-stackful) async (memory $memory "mem") (core func $explicit-thread-yield-loops-stackful-async')) 597 (canon lower (func $explicit-thread-yield-loops-stackless) async (memory $memory "mem") (core func $explicit-thread-yield-loops-stackless-async')) 598 (core instance $dm (instantiate $DM (with "" (instance 599 (export "mem" (memory $memory "mem")) 600 (export "explicit-thread-calls-return-stackful" (func $explicit-thread-calls-return-stackful')) 601 (export "explicit-thread-calls-return-stackless" (func $explicit-thread-calls-return-stackless')) 602 (export "explicit-thread-suspends-sync" (func $explicit-thread-suspends-sync')) 603 (export "explicit-thread-suspends-stackful" (func $explicit-thread-suspends-stackful')) 604 (export "explicit-thread-suspends-stackless" (func $explicit-thread-suspends-stackless')) 605 (export "explicit-thread-yield-loops-sync" (func $explicit-thread-yield-loops-sync')) 606 (export "explicit-thread-yield-loops-stackful" (func $explicit-thread-yield-loops-stackful')) 607 (export "explicit-thread-yield-loops-stackless" (func $explicit-thread-yield-loops-stackless')) 608 (export "explicit-thread-calls-return-stackful-async" (func $explicit-thread-calls-return-stackful-async')) 609 (export "explicit-thread-calls-return-stackless-async" (func $explicit-thread-calls-return-stackless-async')) 610 (export "explicit-thread-suspends-sync-async" (func $explicit-thread-suspends-sync-async')) 611 (export "explicit-thread-suspends-stackful-async" (func $explicit-thread-suspends-stackful-async')) 612 (export "explicit-thread-suspends-stackless-async" (func $explicit-thread-suspends-stackless-async')) 613 (export "explicit-thread-yield-loops-sync-async" (func $explicit-thread-yield-loops-sync-async')) 614 (export "explicit-thread-yield-loops-stackful-async" (func $explicit-thread-yield-loops-stackful-async')) 615 (export "explicit-thread-yield-loops-stackless-async" (func $explicit-thread-yield-loops-stackless-async')) 616 (export "waitable.join" (func $waitable.join)) 617 (export "waitable-set.new" (func $waitable-set.new)) 618 (export "waitable-set.wait" (func $waitable-set.wait)) 619 (export "subtask.cancel" (func $subtask.cancel)) 620 (export "thread.yield" (func $thread.yield)) 621 )))) 622 (func (export "run") (result u32) (canon lift (core func $dm "run"))) 623 ) 624 625 (instance $c (instantiate $C)) 626 (instance $d (instantiate $D 627 (with "explicit-thread-calls-return-stackful" (func $c "explicit-thread-calls-return-stackful")) 628 (with "explicit-thread-calls-return-stackless" (func $c "explicit-thread-calls-return-stackless")) 629 (with "explicit-thread-suspends-sync" (func $c "explicit-thread-suspends-sync")) 630 (with "explicit-thread-suspends-stackful" (func $c "explicit-thread-suspends-stackful")) 631 (with "explicit-thread-suspends-stackless" (func $c "explicit-thread-suspends-stackless")) 632 (with "explicit-thread-yield-loops-sync" (func $c "explicit-thread-yield-loops-sync")) 633 (with "explicit-thread-yield-loops-stackful" (func $c "explicit-thread-yield-loops-stackful")) 634 (with "explicit-thread-yield-loops-stackless" (func $c "explicit-thread-yield-loops-stackless")) 635 )) 636 (func (export "run") (alias export $d "run")) 637 (func (export "explicit-thread-calls-return-stackful") (alias export $c "explicit-thread-calls-return-stackful")) 638 (func (export "explicit-thread-calls-return-stackless") (alias export $c "explicit-thread-calls-return-stackless")) 639 (func (export "explicit-thread-suspends-sync") (alias export $c "explicit-thread-suspends-sync")) 640 (func (export "explicit-thread-suspends-stackful") (alias export $c "explicit-thread-suspends-stackful")) 641 (func (export "explicit-thread-suspends-stackless") (alias export $c "explicit-thread-suspends-stackless")) 642 (func (export "explicit-thread-yield-loops-sync") (alias export $c "explicit-thread-yield-loops-sync")) 643 (func (export "explicit-thread-yield-loops-stackful") (alias export $c "explicit-thread-yield-loops-stackful")) 644 (func (export "explicit-thread-yield-loops-stackless") (alias export $c "explicit-thread-yield-loops-stackless")) 645 ) 646 "#, 647 )? 648 .serialize()?; 649 650 let component = unsafe { Component::deserialize(&engine, &component)? }; 651 let mut store = Store::new(&engine, ()); 652 let instance = Linker::new(&engine) 653 .instantiate_async(&mut store, &component) 654 .await?; 655 let funcs = vec![ 656 "run", 657 "explicit-thread-calls-return-stackful", 658 "explicit-thread-calls-return-stackless", 659 "explicit-thread-suspends-sync", 660 "explicit-thread-suspends-stackful", 661 "explicit-thread-suspends-stackless", 662 "explicit-thread-yield-loops-sync", 663 "explicit-thread-yield-loops-stackful", 664 "explicit-thread-yield-loops-stackless", 665 ]; 666 for func in funcs { 667 let func = instance.get_typed_func::<(), (u32,)>(&mut store, func)?; 668 assert_eq!(func.call_async(&mut store, ()).await?, (42,)); 669 func.post_return_async(store.as_context_mut()).await?; 670 } 671 672 Ok(()) 673 } 674