Path: blob/main/tests/all/component_model/import.rs
3067 views
#![cfg(not(miri))]12use super::REALLOC_AND_FREE;3use std::ops::Deref;4use wasmtime::Result;5use wasmtime::component::*;6use wasmtime::{Config, Engine, Store, StoreContextMut, Trap, WasmBacktrace};78#[test]9fn can_compile() -> Result<()> {10let engine = super::engine();11let libc = r#"12(core module $libc13(memory (export "memory") 1)14(func (export "realloc") (param i32 i32 i32 i32) (result i32)15unreachable)16)17(core instance $libc (instantiate $libc))18"#;19Component::new(20&engine,21r#"(component22(import "a" (func $f))23(core func (canon lower (func $f)))24)"#,25)?;26Component::new(27&engine,28format!(29r#"(component30(import "a" (func $f (param "a" string)))31{libc}32(core func (canon lower (func $f) (memory $libc "memory") (realloc (func $libc "realloc"))))33)"#34),35)?;36Component::new(37&engine,38format!(39r#"(component40(import "f1" (func $f1 (param "a" string) (result string)))41{libc}42(core func (canon lower (func $f1) (memory $libc "memory") (realloc (func $libc "realloc"))))4344(import "f2" (func $f2 (param "a" u32) (result (list u8))))45(core instance $libc2 (instantiate $libc))46(core func (canon lower (func $f2) (memory $libc2 "memory") (realloc (func $libc2 "realloc"))))4748(core func (canon lower (func $f1) (memory $libc2 "memory") (realloc (func $libc2 "realloc"))))49(core func (canon lower (func $f2) (memory $libc "memory") (realloc (func $libc "realloc"))))50)"#51),52)?;53Component::new(54&engine,55format!(56r#"(component57(import "log" (func $log (param "a" string)))58{libc}59(core func $log_lower (canon lower (func $log) (memory $libc "memory") (realloc (func $libc "realloc"))))6061(core module $logger62(import "host" "log" (func $log (param i32 i32)))63(import "libc" "memory" (memory 1))6465(func (export "call")66i32.const 067i32.const 068call $log)69)70(core instance $logger (instantiate $logger71(with "host" (instance (export "log" (func $log_lower))))72(with "libc" (instance $libc))73))7475(func (export "call")76(canon lift (core func $logger "call"))77)78)"#79),80)?;81Ok(())82}8384#[test]85fn simple() -> Result<()> {86let component = r#"87(component88(import "a" (func $log (param "a" string)))8990(core module $libc91(memory (export "memory") 1)9293(func (export "realloc") (param i32 i32 i32 i32) (result i32)94unreachable)95)96(core instance $libc (instantiate $libc))97(core func $log_lower98(canon lower (func $log) (memory $libc "memory") (realloc (func $libc "realloc")))99)100(core module $m101(import "libc" "memory" (memory 1))102(import "host" "log" (func $log (param i32 i32)))103104(func (export "call")105i32.const 5106i32.const 11107call $log)108109(data (i32.const 5) "hello world")110)111(core instance $i (instantiate $m112(with "libc" (instance $libc))113(with "host" (instance (export "log" (func $log_lower))))114))115(func (export "call")116(canon lift (core func $i "call"))117)118)119"#;120121let engine = super::engine();122let component = Component::new(&engine, component)?;123let mut store = Store::new(&engine, None);124assert!(store.data().is_none());125126// First, test the static API127128let mut linker = Linker::new(&engine);129linker.root().func_wrap(130"a",131|mut store: StoreContextMut<'_, Option<String>>, (arg,): (WasmStr,)| -> Result<_> {132let s = arg.to_str(&store)?.to_string();133assert!(store.data().is_none());134*store.data_mut() = Some(s);135Ok(())136},137)?;138let instance = linker.instantiate(&mut store, &component)?;139instance140.get_typed_func::<(), ()>(&mut store, "call")?141.call(&mut store, ())?;142assert_eq!(store.data().as_ref().unwrap(), "hello world");143144// Next, test the dynamic API145146*store.data_mut() = None;147let mut linker = Linker::new(&engine);148linker.root().func_new(149"a",150|mut store: StoreContextMut<'_, Option<String>>, _, args, _results| {151if let Val::String(s) = &args[0] {152assert!(store.data().is_none());153*store.data_mut() = Some(s.to_string());154Ok(())155} else {156panic!()157}158},159)?;160let instance = linker.instantiate(&mut store, &component)?;161instance162.get_func(&mut store, "call")163.unwrap()164.call(&mut store, &[], &mut [])?;165assert_eq!(store.data().as_ref().unwrap(), "hello world");166167Ok(())168}169170#[test]171fn functions_in_instances() -> Result<()> {172let component = r#"173(component174(type $import-type (instance175(export "a" (func (param "a" string)))176))177(import (interface "test:test/foo") (instance $import (type $import-type)))178(alias export $import "a" (func $log))179180(core module $libc181(memory (export "memory") 1)182183(func (export "realloc") (param i32 i32 i32 i32) (result i32)184unreachable)185)186(core instance $libc (instantiate $libc))187(core func $log_lower188(canon lower (func $log) (memory $libc "memory") (realloc (func $libc "realloc")))189)190(core module $m191(import "libc" "memory" (memory 1))192(import "host" "log" (func $log (param i32 i32)))193194(func (export "call")195i32.const 5196i32.const 11197call $log)198199(data (i32.const 5) "hello world")200)201(core instance $i (instantiate $m202(with "libc" (instance $libc))203(with "host" (instance (export "log" (func $log_lower))))204))205(func $call206(canon lift (core func $i "call"))207)208(component $c209(import "import-call" (func $f))210(export "call" (func $f))211)212(instance $export (instantiate $c213(with "import-call" (func $call))214))215(export (interface "test:test/foo") (instance $export))216)217"#;218219let engine = super::engine();220let component = Component::new(&engine, component)?;221let instance_index = component.get_export_index(None, "test:test/foo").unwrap();222let func_index = component223.get_export_index(Some(&instance_index), "call")224.unwrap();225let mut store = Store::new(&engine, None);226assert!(store.data().is_none());227228// First, test the static API229230let mut linker = Linker::new(&engine);231linker.instance("test:test/foo")?.func_wrap(232"a",233|mut store: StoreContextMut<'_, Option<String>>, (arg,): (WasmStr,)| -> Result<_> {234let s = arg.to_str(&store)?.to_string();235assert!(store.data().is_none());236*store.data_mut() = Some(s);237Ok(())238},239)?;240let instance = linker.instantiate(&mut store, &component)?;241let func = instance.get_typed_func::<(), ()>(&mut store, &func_index)?;242func.call(&mut store, ())?;243assert_eq!(store.data().as_ref().unwrap(), "hello world");244245// Next, test the dynamic API246247*store.data_mut() = None;248let mut linker = Linker::new(&engine);249linker.instance("test:test/foo")?.func_new(250"a",251|mut store: StoreContextMut<'_, Option<String>>, _, args, _results| {252if let Val::String(s) = &args[0] {253assert!(store.data().is_none());254*store.data_mut() = Some(s.to_string());255Ok(())256} else {257panic!()258}259},260)?;261let instance = linker.instantiate(&mut store, &component)?;262let func = instance.get_func(&mut store, func_index).unwrap();263func.call(&mut store, &[], &mut [])?;264assert_eq!(store.data().as_ref().unwrap(), "hello world");265266Ok(())267}268269#[test]270fn attempt_to_leave_during_malloc() -> Result<()> {271let component = r#"272(component273(import "thunk" (func $thunk))274(import "ret-string" (func $ret_string (result string)))275276(core module $host_shim277(table (export "table") 2 funcref)278(func $shim_thunk (export "thunk")279i32.const 0280call_indirect)281(func $shim_ret_string (export "ret-string") (param i32)282local.get 0283i32.const 1284call_indirect (param i32))285)286(core instance $host_shim (instantiate $host_shim))287288(core module $m289(import "host" "thunk" (func $thunk))290(import "host" "ret-string" (func $ret_string (param i32)))291292(memory (export "memory") 1)293294(func $realloc (export "realloc") (param i32 i32 i32 i32) (result i32)295call $thunk296unreachable)297298(func $run (export "run")299i32.const 8300call $ret_string)301302(func (export "take-string") (param i32 i32)303unreachable)304)305(core instance $m (instantiate $m (with "host" (instance $host_shim))))306307(core module $host_shim_filler_inner308(import "shim" "table" (table 2 funcref))309(import "host" "thunk" (func $thunk))310(import "host" "ret-string" (func $ret_string (param i32)))311(elem (i32.const 0) $thunk $ret_string)312)313314(core func $thunk_lower315(canon lower (func $thunk) (memory $m "memory") (realloc (func $m "realloc")))316)317318(core func $ret_string_lower319(canon lower (func $ret_string) (memory $m "memory") (realloc (func $m "realloc")))320)321322(core instance (instantiate $host_shim_filler_inner323(with "shim" (instance $host_shim))324(with "host" (instance325(export "thunk" (func $thunk_lower))326(export "ret-string" (func $ret_string_lower))327))328))329330(func (export "run")331(canon lift (core func $m "run"))332)333(func (export "take-string") (param "a" string)334(canon lift (core func $m "take-string") (memory $m "memory") (realloc (func $m "realloc")))335)336)337"#;338339let engine = super::engine();340let mut linker = Linker::new(&engine);341linker.root().func_wrap("thunk", |_, _: ()| -> Result<()> {342panic!("should not get here")343})?;344linker345.root()346.func_wrap("ret-string", |_, _: ()| -> Result<_> {347Ok(("hello".to_string(),))348})?;349let component = Component::new(&engine, component)?;350351{352let mut store = Store::new(&engine, ());353354// Assert that during a host import if we return values to wasm that a trap355// happens if we try to leave the instance.356let trap = linker357.instantiate(&mut store, &component)?358.get_typed_func::<(), ()>(&mut store, "run")?359.call(&mut store, ())360.unwrap_err();361assert!(362format!("{trap:?}").contains("cannot leave component instance"),363"bad trap: {trap:?}",364);365366let trace = trap.downcast_ref::<WasmBacktrace>().unwrap().frames();367assert_eq!(trace.len(), 4);368369// This was our entry point...370assert_eq!(trace[3].module().name(), Some("m"));371assert_eq!(trace[3].func_name(), Some("run"));372373// ... which called an imported function which ends up being originally374// defined by the shim instance. The shim instance then does an indirect375// call through a table which goes to the `canon.lower`'d host function376assert_eq!(trace[2].module().name(), Some("host_shim"));377assert_eq!(trace[2].func_name(), Some("shim_ret_string"));378379// ... and the lowered host function will call realloc to allocate space for380// the result381assert_eq!(trace[1].module().name(), Some("m"));382assert_eq!(trace[1].func_name(), Some("realloc"));383384// ... but realloc calls the shim instance and tries to exit the385// component, triggering a dynamic trap386assert_eq!(trace[0].module().name(), Some("host_shim"));387assert_eq!(trace[0].func_name(), Some("shim_thunk"));388}389390{391let mut store = Store::new(&engine, ());392393// In addition to the above trap also ensure that when we enter a wasm394// component if we try to leave while lowering then that's also a dynamic395// trap.396let trap = linker397.instantiate(&mut store, &component)?398.get_typed_func::<(&str,), ()>(&mut store, "take-string")?399.call(&mut store, ("x",))400.unwrap_err();401assert!(402format!("{trap:?}").contains("cannot leave component instance"),403"bad trap: {trap:?}",404);405}406407Ok(())408}409410#[test]411fn attempt_to_reenter_during_host() -> Result<()> {412let component = r#"413(component414(import "thunk" (func $thunk))415(core func $thunk_lower (canon lower (func $thunk)))416417(core module $m418(import "host" "thunk" (func $thunk))419420(func $run (export "run")421call $thunk)422)423(core instance $m (instantiate $m424(with "host" (instance (export "thunk" (func $thunk_lower))))425))426427(func (export "run")428(canon lift (core func $m "run"))429)430)431"#;432433let engine = super::engine();434let component = Component::new(&engine, component)?;435436// First, test the static API437438struct StaticState {439func: Option<TypedFunc<(), ()>>,440}441442let mut store = Store::new(&engine, StaticState { func: None });443let mut linker = Linker::new(&engine);444linker.root().func_wrap(445"thunk",446|mut store: StoreContextMut<'_, StaticState>, _: ()| -> Result<()> {447let func = store.data_mut().func.take().unwrap();448let trap = func.call(&mut store, ()).unwrap_err();449assert_eq!(450trap.downcast_ref(),451Some(&Trap::CannotEnterComponent),452"bad trap: {trap:?}",453);454Ok(())455},456)?;457let instance = linker.instantiate(&mut store, &component)?;458let func = instance.get_typed_func::<(), ()>(&mut store, "run")?;459store.data_mut().func = Some(func);460func.call(&mut store, ())?;461462// Next, test the dynamic API463464struct DynamicState {465func: Option<Func>,466}467468let mut store = Store::new(&engine, DynamicState { func: None });469let mut linker = Linker::new(&engine);470linker.root().func_new(471"thunk",472|mut store: StoreContextMut<'_, DynamicState>, _, _, _| {473let func = store.data_mut().func.take().unwrap();474let trap = func.call(&mut store, &[], &mut []).unwrap_err();475assert_eq!(476trap.downcast_ref(),477Some(&Trap::CannotEnterComponent),478"bad trap: {trap:?}",479);480Ok(())481},482)?;483let instance = linker.instantiate(&mut store, &component)?;484let func = instance.get_func(&mut store, "run").unwrap();485store.data_mut().func = Some(func);486func.call(&mut store, &[], &mut [])?;487488Ok(())489}490491#[tokio::test]492async fn stack_and_heap_args_and_rets() -> Result<()> {493test_stack_and_heap_args_and_rets(false).await494}495496#[tokio::test]497async fn stack_and_heap_args_and_rets_concurrent() -> Result<()> {498test_stack_and_heap_args_and_rets(true).await499}500501async fn test_stack_and_heap_args_and_rets(concurrent: bool) -> Result<()> {502let (body, async_lower_opts, async_lift_opts, async_type) = if concurrent {503(504r#"505(import "host" "f1" (func $f1 (param i32 i32) (result i32)))506(import "host" "f2" (func $f2 (param i32 i32) (result i32)))507(import "host" "f3" (func $f3 (param i32 i32) (result i32)))508(import "host" "f4" (func $f4 (param i32 i32) (result i32)))509510(func $run (export "run") (result i32)511(local $params i32)512(local $results i32)513514block515(local.set $results (call $realloc (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 4)))516(call $f1 (i32.const 1) (local.get $results))517drop518(i32.load offset=0 (local.get $results))519i32.const 2520i32.eq521br_if 0522unreachable523end524525block526(local.set $params (call $allocate_empty_strings))527(local.set $results (call $realloc (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 4)))528(call $f2 (local.get $params) (local.get $results))529drop530(i32.load offset=0 (local.get $results))531i32.const 3532i32.eq533br_if 0534unreachable535end536537block538(local.set $results (call $realloc (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 8)))539(call $f3 (i32.const 8) (local.get $results))540drop541(call $validate_string_ret (local.get $results))542end543544block545(local.set $params (call $allocate_empty_strings))546(local.set $results (call $realloc (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 8)))547(call $f4 (local.get $params) (local.get $results))548drop549(call $validate_string_ret (local.get $results))550end551552(call $task-return)553554i32.const 0555)556"#,557"async",558r#"async (callback (func $m "callback"))"#,559"async",560)561} else {562(563r#"564(import "host" "f1" (func $f1 (param i32) (result i32)))565(import "host" "f2" (func $f2 (param i32) (result i32)))566(import "host" "f3" (func $f3 (param i32 i32)))567(import "host" "f4" (func $f4 (param i32 i32)))568569(func $run (export "run")570block571i32.const 1572call $f1573i32.const 2574i32.eq575br_if 0576unreachable577end578579block580call $allocate_empty_strings581call $f2582i32.const 3583i32.eq584br_if 0585unreachable586end587588block589i32.const 8590i32.const 16000591call $f3592(call $validate_string_ret (i32.const 16000))593end594595block596call $allocate_empty_strings597i32.const 20000598call $f4599(call $validate_string_ret (i32.const 20000))600end601)602"#,603"",604"",605"",606)607};608609let component = format!(610r#"611(component612(type $many_params (tuple613string string string string614string string string string615string))616(import "f1" (func $f1 {async_type} (param "a" u32) (result u32)))617(import "f2" (func $f2 {async_type} (param "a" $many_params) (result u32)))618(import "f3" (func $f3 {async_type} (param "a" u32) (result string)))619(import "f4" (func $f4 {async_type} (param "a" $many_params) (result string)))620621(core module $libc622{REALLOC_AND_FREE}623(memory (export "memory") 1)624)625(core instance $libc (instantiate (module $libc)))626627(core func $f1_lower (canon lower (func $f1)628(memory $libc "memory")629(realloc (func $libc "realloc"))630{async_lower_opts}631))632(core func $f2_lower (canon lower (func $f2)633(memory $libc "memory")634(realloc (func $libc "realloc"))635{async_lower_opts}636))637(core func $f3_lower (canon lower (func $f3)638(memory $libc "memory")639(realloc (func $libc "realloc"))640{async_lower_opts}641))642(core func $f4_lower (canon lower (func $f4)643(memory $libc "memory")644(realloc (func $libc "realloc"))645{async_lower_opts}646))647648(core module $m649(import "libc" "memory" (memory 1))650(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))651(import "host" "task.return" (func $task-return))652{body}653654(func (export "callback") (param i32 i32 i32) (result i32) unreachable)655656(func $allocate_empty_strings (result i32)657(local $ret i32)658(local $offset i32)659(local $cnt i32)660(local.set $ret (i32.const 8000))661(local.set $cnt (i32.const 9))662663loop664(call $setup_str (i32.add (local.get $ret) (local.get $offset)))665(local.set $offset (i32.add (local.get $offset) (i32.const 8)))666667(local.tee $cnt (i32.add (local.get $cnt) (i32.const -1)))668br_if 0669end670671local.get $ret672)673(func $setup_str (param $addr i32)674(i32.store offset=0 (local.get $addr) (i32.const 1000))675(i32.store offset=4 (local.get $addr) (i32.const 3))676)677678(func $validate_string_ret (param $addr i32)679(local $base i32)680(local $len i32)681(local.set $base (i32.load (local.get $addr)))682(local.set $len (i32.load offset=4 (local.get $addr)))683684block685local.get $len686i32.const 3687i32.eq688br_if 0689unreachable690end691692(i32.load8_u offset=0 (local.get $base))693i32.const 120 ;; 'x'694i32.ne695if unreachable end696697(i32.load8_u offset=1 (local.get $base))698i32.const 121 ;; 'y'699i32.ne700if unreachable end701702(i32.load8_u offset=2 (local.get $base))703i32.const 122 ;; 'z'704i32.ne705if unreachable end706)707708(data (i32.const 1000) "abc")709)710(core func $task-return (canon task.return))711(core instance $m (instantiate $m712(with "libc" (instance $libc))713(with "host" (instance714(export "f1" (func $f1_lower))715(export "f2" (func $f2_lower))716(export "f3" (func $f3_lower))717(export "f4" (func $f4_lower))718(export "task.return" (func $task-return))719))720))721722(func (export "run") {async_type}723(canon lift (core func $m "run") {async_lift_opts})724)725)726"#727);728729let mut config = Config::new();730config.wasm_component_model_async(true);731let engine = &Engine::new(&config)?;732let component = Component::new(&engine, component)?;733let mut store = Store::new(&engine, ());734735// First, test the static API736737let mut linker = Linker::new(&engine);738if concurrent {739linker740.root()741.func_wrap_concurrent("f1", |_, (x,): (u32,)| {742assert_eq!(x, 1);743Box::pin(async { Ok((2u32,)) })744})?;745linker.root().func_wrap_concurrent(746"f2",747|accessor,748(arg,): ((749WasmStr,750WasmStr,751WasmStr,752WasmStr,753WasmStr,754WasmStr,755WasmStr,756WasmStr,757WasmStr,758),)| {759accessor.with(|v| assert_eq!(arg.0.to_str(&v).unwrap(), "abc"));760Box::pin(async { Ok((3u32,)) })761},762)?;763linker764.root()765.func_wrap_concurrent("f3", |_, (arg,): (u32,)| {766assert_eq!(arg, 8);767Box::pin(async { Ok(("xyz".to_string(),)) })768})?;769linker.root().func_wrap_concurrent(770"f4",771|accessor,772(arg,): ((773WasmStr,774WasmStr,775WasmStr,776WasmStr,777WasmStr,778WasmStr,779WasmStr,780WasmStr,781WasmStr,782),)| {783accessor.with(|v| assert_eq!(arg.0.to_str(&v).unwrap(), "abc"));784Box::pin(async { Ok(("xyz".to_string(),)) })785},786)?;787} else {788linker789.root()790.func_wrap("f1", |_, (x,): (u32,)| -> Result<(u32,)> {791assert_eq!(x, 1);792Ok((2,))793})?;794linker.root().func_wrap(795"f2",796|cx: StoreContextMut<'_, ()>,797(arg,): ((798WasmStr,799WasmStr,800WasmStr,801WasmStr,802WasmStr,803WasmStr,804WasmStr,805WasmStr,806WasmStr,807),)|808-> Result<(u32,)> {809assert_eq!(arg.0.to_str(&cx).unwrap(), "abc");810Ok((3,))811},812)?;813linker814.root()815.func_wrap("f3", |_, (arg,): (u32,)| -> Result<(String,)> {816assert_eq!(arg, 8);817Ok(("xyz".to_string(),))818})?;819linker.root().func_wrap(820"f4",821|cx: StoreContextMut<'_, ()>,822(arg,): ((823WasmStr,824WasmStr,825WasmStr,826WasmStr,827WasmStr,828WasmStr,829WasmStr,830WasmStr,831WasmStr,832),)|833-> Result<(String,)> {834assert_eq!(arg.0.to_str(&cx).unwrap(), "abc");835Ok(("xyz".to_string(),))836},837)?;838}839840let instance = linker.instantiate_async(&mut store, &component).await?;841let run = instance.get_typed_func::<(), ()>(&mut store, "run")?;842843if concurrent {844store845.run_concurrent(async move |accessor| {846wasmtime::error::Ok(run.call_concurrent(accessor, ()).await?.0)847})848.await??;849} else {850run.call_async(&mut store, ()).await?;851}852853// Next, test the dynamic API854855let mut linker = Linker::new(&engine);856if concurrent {857linker858.root()859.func_new_concurrent("f1", |_, _, args, results| {860if let Val::U32(x) = &args[0] {861assert_eq!(*x, 1);862Box::pin(async {863results[0] = Val::U32(2);864Ok(())865})866} else {867panic!()868}869})?;870linker871.root()872.func_new_concurrent("f2", |_, _, args, results| {873if let Val::Tuple(tuple) = &args[0] {874if let Val::String(s) = &tuple[0] {875assert_eq!(s.deref(), "abc");876Box::pin(async {877results[0] = Val::U32(3);878Ok(())879})880} else {881panic!()882}883} else {884panic!()885}886})?;887linker888.root()889.func_new_concurrent("f3", |_, _, args, results| {890if let Val::U32(x) = &args[0] {891assert_eq!(*x, 8);892Box::pin(async {893results[0] = Val::String("xyz".into());894Ok(())895})896} else {897panic!();898}899})?;900linker901.root()902.func_new_concurrent("f4", |_, _, args, results| {903if let Val::Tuple(tuple) = &args[0] {904if let Val::String(s) = &tuple[0] {905assert_eq!(s.deref(), "abc");906Box::pin(async {907results[0] = Val::String("xyz".into());908Ok(())909})910} else {911panic!()912}913} else {914panic!()915}916})?;917} else {918linker.root().func_new("f1", |_, _, args, results| {919if let Val::U32(x) = &args[0] {920assert_eq!(*x, 1);921results[0] = Val::U32(2);922Ok(())923} else {924panic!()925}926})?;927linker.root().func_new("f2", |_, _, args, results| {928if let Val::Tuple(tuple) = &args[0] {929if let Val::String(s) = &tuple[0] {930assert_eq!(s.deref(), "abc");931results[0] = Val::U32(3);932Ok(())933} else {934panic!()935}936} else {937panic!()938}939})?;940linker.root().func_new("f3", |_, _, args, results| {941if let Val::U32(x) = &args[0] {942assert_eq!(*x, 8);943results[0] = Val::String("xyz".into());944Ok(())945} else {946panic!();947}948})?;949linker.root().func_new("f4", |_, _, args, results| {950if let Val::Tuple(tuple) = &args[0] {951if let Val::String(s) = &tuple[0] {952assert_eq!(s.deref(), "abc");953results[0] = Val::String("xyz".into());954Ok(())955} else {956panic!()957}958} else {959panic!()960}961})?;962}963964let instance = linker.instantiate_async(&mut store, &component).await?;965let run = instance.get_func(&mut store, "run").unwrap();966967if concurrent {968store969.run_concurrent(async |store| {970run.call_concurrent(store, &[], &mut []).await?;971wasmtime::error::Ok(())972})973.await??;974} else {975run.call_async(&mut store, &[], &mut []).await?;976}977978Ok(())979}980981#[test]982fn bad_import_alignment() -> Result<()> {983let component = format!(984r#"985(component986(import "unaligned-retptr" (func $unaligned_retptr (result string)))987(type $many_arg (tuple988string string string string989string string string string990string991))992(import "unaligned-argptr" (func $unaligned_argptr (param "a" $many_arg)))993(core module $libc_panic994(memory (export "memory") 1)995(func (export "realloc") (param i32 i32 i32 i32) (result i32)996unreachable)997)998(core instance $libc_panic (instantiate $libc_panic))9991000(core func $unaligned_retptr_lower1001(canon lower (func $unaligned_retptr) (memory $libc_panic "memory") (realloc (func $libc_panic "realloc")))1002)1003(core func $unaligned_argptr_lower1004(canon lower (func $unaligned_argptr) (memory $libc_panic "memory") (realloc (func $libc_panic "realloc")))1005)10061007(core module $m1008(import "host" "unaligned-retptr" (func $unaligned_retptr (param i32)))1009(import "host" "unaligned-argptr" (func $unaligned_argptr (param i32)))10101011(func (export "unaligned-retptr")1012(call $unaligned_retptr (i32.const 1)))1013(func (export "unaligned-argptr")1014(call $unaligned_argptr (i32.const 1)))1015)1016(core instance $m (instantiate $m1017(with "host" (instance1018(export "unaligned-retptr" (func $unaligned_retptr_lower))1019(export "unaligned-argptr" (func $unaligned_argptr_lower))1020))1021))10221023(func (export "unaligned-retptr2")1024(canon lift (core func $m "unaligned-retptr"))1025)1026(func (export "unaligned-argptr2")1027(canon lift (core func $m "unaligned-argptr"))1028)1029)1030"#1031);10321033let engine = super::engine();1034let mut linker = Linker::new(&engine);1035linker1036.root()1037.func_wrap("unaligned-retptr", |_, _: ()| -> Result<(String,)> {1038Ok((String::new(),))1039})?;1040linker.root().func_wrap(1041"unaligned-argptr",1042|_,1043_: ((1044WasmStr,1045WasmStr,1046WasmStr,1047WasmStr,1048WasmStr,1049WasmStr,1050WasmStr,1051WasmStr,1052WasmStr,1053),)|1054-> Result<()> { unreachable!() },1055)?;1056let component = Component::new(&engine, component)?;10571058{1059let mut store = Store::new(&engine, ());1060let trap = linker1061.instantiate(&mut store, &component)?1062.get_typed_func::<(), ()>(&mut store, "unaligned-retptr2")?1063.call(&mut store, ())1064.unwrap_err();1065assert!(1066format!("{trap:?}").contains("pointer not aligned"),1067"{}",1068trap1069);1070}10711072{1073let mut store = Store::new(&engine, ());1074let trap = linker1075.instantiate(&mut store, &component)?1076.get_typed_func::<(), ()>(&mut store, "unaligned-argptr2")?1077.call(&mut store, ())1078.unwrap_err();1079assert!(1080format!("{trap:?}").contains("pointer not aligned"),1081"{}",1082trap1083);1084}10851086Ok(())1087}10881089#[test]1090fn no_actual_wasm_code() -> Result<()> {1091let component = r#"1092(component1093(import "f" (func $f))10941095(core func $f_lower1096(canon lower (func $f))1097)1098(core module $m1099(import "" "" (func $f))1100(export "f" (func $f))1101)1102(core instance $i (instantiate $m1103(with "" (instance1104(export "" (func $f_lower))1105))1106))1107(func (export "thunk")1108(canon lift1109(core func $i "f")1110)1111)1112)1113"#;11141115let engine = super::engine();1116let component = Component::new(&engine, component)?;1117let mut store = Store::new(&engine, 0);11181119// First, test the static API11201121let mut linker = Linker::new(&engine);1122linker.root().func_wrap(1123"f",1124|mut store: StoreContextMut<'_, u32>, _: ()| -> Result<()> {1125*store.data_mut() += 1;1126Ok(())1127},1128)?;11291130let instance = linker.instantiate(&mut store, &component)?;1131let thunk = instance.get_typed_func::<(), ()>(&mut store, "thunk")?;11321133assert_eq!(*store.data(), 0);1134thunk.call(&mut store, ())?;1135assert_eq!(*store.data(), 1);11361137// Next, test the dynamic API11381139*store.data_mut() = 0;1140let mut linker = Linker::new(&engine);1141linker1142.root()1143.func_new("f", |mut store: StoreContextMut<'_, u32>, _, _, _| {1144*store.data_mut() += 1;1145Ok(())1146})?;11471148let instance = linker.instantiate(&mut store, &component)?;1149let thunk = instance.get_func(&mut store, "thunk").unwrap();11501151assert_eq!(*store.data(), 0);1152thunk.call(&mut store, &[], &mut [])?;1153assert_eq!(*store.data(), 1);11541155Ok(())1156}11571158#[test]1159fn use_types_across_component_boundaries() -> Result<()> {1160// Create a component that exports a function that returns a record1161let engine = super::engine();1162let component = Component::new(1163&engine,1164r#"(component1165(type (;0;) (record (field "a" u8) (field "b" string)))1166(import "my-record" (type $my-record (eq 0)))1167(core module $m1168(memory $memory 17)1169(export "memory" (memory $memory))1170(func (export "my-func") (result i32)1171i32.const 41172return))1173(core instance $instance (instantiate $m))1174(type $func-type (func (result $my-record)))1175(alias core export $instance "my-func" (core func $my-func))1176(alias core export $instance "memory" (core memory $memory))1177(func $my-func (type $func-type) (canon lift (core func $my-func) (memory $memory) string-encoding=utf8))1178(export $export "my-func" (func $my-func))1179)"#,1180)?;1181let mut store = Store::new(&engine, 0);1182let linker = Linker::new(&engine);1183let instance = linker.instantiate(&mut store, &component)?;1184let my_func = instance.get_func(&mut store, "my-func").unwrap();1185let mut results = vec![Val::Bool(false)];1186my_func.call(&mut store, &[], &mut results)?;11871188// Create another component that exports a function that takes that record as an argument1189let component = Component::new(1190&engine,1191format!(1192r#"(component1193(type (;0;) (record (field "a" u8) (field "b" string)))1194(import "my-record" (type $my-record (eq 0)))1195(core module $m1196(memory $memory 17)1197(export "memory" (memory $memory))1198{REALLOC_AND_FREE}1199(func (export "my-func") (param i32 i32 i32)))1200(core instance $instance (instantiate $m))1201(type $func-type (func (param "my-record" $my-record)))1202(alias core export $instance "my-func" (core func $my-func))1203(alias core export $instance "memory" (core memory $memory))1204(func $my-func (type $func-type) (canon lift (core func $my-func) (memory $memory) string-encoding=utf8 (realloc (func $instance "realloc"))))1205(export $export "my-func" (func $my-func))1206)"#1207),1208)?;1209let mut store = Store::new(&engine, 0);1210let linker = Linker::new(&engine);1211let instance = linker.instantiate(&mut store, &component)?;1212let my_func = instance.get_func(&mut store, "my-func").unwrap();1213// Call the exported function with the return values of the call to the previous component's exported function1214my_func.call(&mut store, &results, &mut [])?;12151216Ok(())1217}121812191220