Path: blob/main/crates/wizer/tests/all/component.rs
2459 views
use anyhow::{Context, Result, bail};1use wasmtime::component::{Component, Instance, Linker, Val};2use wasmtime::{Config, Engine, Store};3use wasmtime_wizer::Wizer;45fn fail_wizening(msg: &str, wasm: &[u8]) -> Result<()> {6let _ = env_logger::try_init();78let wasm = wat::parse_bytes(wasm)?;9log::debug!(10"testing wizening failure for wasm:\n{}",11wasmprinter::print_bytes(&wasm)?12);13match Wizer::new().instrument_component(&wasm) {14Ok(_) => bail!("expected wizening to fail"),15Err(e) => {16let err = format!("{e}");17if !err.contains(msg) {18bail!("unexpected error: {err}");19}20Ok(())21}22}23}2425#[test]26fn unsupported_constructs() -> Result<()> {27fail_wizening(28"does not currently support component imports",29br#"(component30(import "x" (component))31)"#,32)?;3334fail_wizening(35"nested components with modules not currently supported",36br#"(component37(component (core module))38)"#,39)?;40fail_wizening(41"nested components with modules not currently supported",42br#"(component43(component)44(component (core module))45)"#,46)?;47fail_wizening(48"wizer does not currently support module imports",49br#"(component50(component (import "x" (core module)))51)"#,52)?;53fail_wizening(54"wizer does not currently support module aliases",55br#"(component56(core module $a)57(component58(core instance (instantiate $a))59)60)"#,61)?;62fail_wizening(63"wizer does not currently support component aliases",64br#"(component65(component $a)66(component67(instance (instantiate $a))68)69)"#,70)?;7172fail_wizening(73"does not currently support component aliases",74br#"(component75(import "x" (instance $i (export "x" (component))))76(alias export $i "x" (component $c))77)"#,78)?;7980fail_wizening(81"does not currently support module imports",82br#"(component83(import "x" (core module))84)"#,85)?;8687fail_wizening(88"does not currently support module exports",89br#"(component90(core module $x)91(export "x" (core module $x))92)"#,93)?;9495fail_wizening(96"does not currently support module aliases",97br#"(component98(import "x" (instance $i (export "x" (core module))))99(alias export $i "x" (core module $c))100)"#,101)?;102fail_wizening(103"does not currently support component start functions",104br#"(component105(import "f" (func $f))106(start $f)107)"#,108)?;109110fail_wizening(111"modules may be instantiated at most once",112br#"(component113(core module $a)114(core instance $a1 (instantiate $a))115(core instance $a2 (instantiate $a))116)"#,117)?;118119Ok(())120}121122fn store() -> Result<Store<()>> {123let mut config = Config::new();124config.async_support(true);125let engine = Engine::new(&config)?;126Ok(Store::new(&engine, ()))127}128129async fn instantiate(store: &mut Store<()>, component: &Component) -> Result<Instance> {130let mut linker = Linker::new(store.engine());131linker.define_unknown_imports_as_traps(component)?;132linker.instantiate_async(store, component).await133}134135async fn wizen(wat: &str) -> Result<Vec<u8>> {136let _ = env_logger::try_init();137let wasm = wat::parse_str(wat)?;138139log::debug!(140"=== PreWizened Wasm ==========================================================\n\141{}\n\142===========================================================================",143wasmprinter::print_bytes(&wasm).unwrap()144);145let mut store = store()?;146let wasm = Wizer::new()147.run_component(&mut store, &wasm, instantiate)148.await?;149log::debug!(150"=== Wizened Wasm ==========================================================\n\151{}\n\152===========================================================================",153wasmprinter::print_bytes(&wasm).unwrap()154);155if log::log_enabled!(log::Level::Debug) {156std::fs::write("test.wasm", &wasm).unwrap();157}158159Ok(wasm)160}161162async fn wizen_and_run_wasm(expected: u32, wat: &str) -> Result<()> {163let wasm = wizen(wat).await?;164165let mut store = store()?;166let module =167Component::new(store.engine(), wasm).context("Wasm test case failed to compile")?;168169let linker = Linker::new(store.engine());170let instance = linker.instantiate_async(&mut store, &module).await?;171172let run = instance.get_func(&mut store, "run").ok_or_else(|| {173anyhow::anyhow!("the test Wasm component does not export a `run` function")174})?;175176let mut actual = [Val::U8(0)];177run.call_async(&mut store, &[], &mut actual).await?;178let actual = match actual[0] {179Val::U32(x) => x,180_ => anyhow::bail!("expected an u32 result"),181};182anyhow::ensure!(183expected == actual,184"expected `{expected}`, found `{actual}`",185);186187Ok(())188}189190#[tokio::test]191async fn simple() -> Result<()> {192wizen_and_run_wasm(19342,194r#"(component195(core module $m196(func (export "init"))197198(func (export "run") (result i32)199i32.const 42200)201)202(core instance $i (instantiate $m))203(func (export "run") (result u32) (canon lift (core func $i "run")))204(func (export "wizer-initialize") (canon lift (core func $i "init")))205)"#,206)207.await?;208209Ok(())210}211212#[tokio::test]213async fn snapshot_global_i32() -> Result<()> {214wizen_and_run_wasm(2151,216r#"(component217(core module $m218(global $g (mut i32) i32.const 0)219(func (export "init") (global.set $g (i32.const 1)))220(func (export "run") (result i32) global.get $g)221)222(core instance $i (instantiate $m))223(func (export "run") (result u32) (canon lift (core func $i "run")))224(func (export "wizer-initialize") (canon lift (core func $i "init")))225)"#,226)227.await?;228229Ok(())230}231232#[tokio::test]233async fn snapshot_global_i64() -> Result<()> {234wizen_and_run_wasm(2351,236r#"(component237(core module $m238(global $g (mut i64) i64.const 0)239(func (export "init") (global.set $g (i64.const 1)))240(func (export "run") (result i32)241global.get $g242i32.wrap_i64243)244)245(core instance $i (instantiate $m))246(func (export "run") (result u32) (canon lift (core func $i "run")))247(func (export "wizer-initialize") (canon lift (core func $i "init")))248)"#,249)250.await?;251252Ok(())253}254255#[tokio::test]256async fn snapshot_global_f32() -> Result<()> {257wizen_and_run_wasm(2581,259r#"(component260(core module $m261(global $g (mut f32) f32.const 0)262(func (export "init") (global.set $g (f32.const 1)))263(func (export "run") (result i32)264global.get $g265i32.trunc_f32_s)266)267(core instance $i (instantiate $m))268(func (export "run") (result u32) (canon lift (core func $i "run")))269(func (export "wizer-initialize") (canon lift (core func $i "init")))270)"#,271)272.await?;273274Ok(())275}276277#[tokio::test]278async fn snapshot_global_f64() -> Result<()> {279wizen_and_run_wasm(2801,281r#"(component282(core module $m283(global $g (mut f64) f64.const 0)284(func (export "init") (global.set $g (f64.const 1)))285(func (export "run") (result i32)286global.get $g287i32.trunc_f64_s)288)289(core instance $i (instantiate $m))290(func (export "run") (result u32) (canon lift (core func $i "run")))291(func (export "wizer-initialize") (canon lift (core func $i "init")))292)"#,293)294.await?;295296Ok(())297}298299#[test]300fn v128_globals() -> Result<()> {301fail_wizening(302"component wizening does not support v128 globals",303br#"(component304(core module $a305(global (export "x") (mut v128) (v128.const i32x4 1 2 3 4))306)307(core instance (instantiate $a))308)"#,309)310}311312#[tokio::test]313async fn snapshot_memory() -> Result<()> {314wizen_and_run_wasm(315201,316r#"(component317(core module $m318(memory 1)319(func (export "init")320i32.const 200321i32.const 100322i32.store323i32.const 300324i32.const 101325i32.store326)327(func (export "run") (result i32)328i32.const 200329i32.load330i32.const 300331i32.load332i32.add333)334)335(core instance $i (instantiate $m))336(func (export "run") (result u32) (canon lift (core func $i "run")))337(func (export "wizer-initialize") (canon lift (core func $i "init")))338)"#,339)340.await?;341342Ok(())343}344345#[tokio::test]346async fn nested_components() -> Result<()> {347wizen_and_run_wasm(34842,349r#"(component350(component $a)351(instance (instantiate $a))352(instance (export "hi") (instantiate $a))353354(component $b355(type $t string)356(import "x" (type (eq $t)))357(component $a)358(instance (instantiate $a))359(instance (export "hi") (instantiate $a))360)361(type $x string)362(instance (instantiate $b363(with "x" (type $x))364))365(instance (export "hi2") (instantiate $b366(with "x" (type $x))367))368369(core module $m370(func (export "init"))371(func (export "run") (result i32) i32.const 42)372)373(core instance $i (instantiate $m))374(func (export "run") (result u32) (canon lift (core func $i "run")))375(func (export "wizer-initialize") (canon lift (core func $i "init")))376)"#,377)378.await?;379380Ok(())381}382383#[tokio::test]384async fn multiple_modules() -> Result<()> {385wizen_and_run_wasm(386100 + 101 + 200 + 201 + 7 + 112,387r#"(component388(core module $a389(memory 1)390(global $g (export "g") (mut i32) (i32.const 0))391392(func (export "init")393i32.const 200394i32.const 100395i32.store396i32.const 300397i32.const 101398i32.store399)400401(func (export "run") (result i32)402i32.const 200403i32.load404i32.const 300405i32.load406i32.add407global.get $g408i32.add409)410)411(core instance $a (instantiate $a))412413(core module $b414(import "a" "g" (global $g (mut i32)))415(import "a" "init" (func $init))416(import "a" "run" (func $run (result i32)))417(memory (export "mem") 1)418(func (export "init")419call $init420i32.const 400421i32.const 200422i32.store423i32.const 500424i32.const 201425i32.store426427i32.const 111428global.set $g429)430(func (export "run") (result i32)431i32.const 400432i32.load433i32.const 500434i32.load435i32.add436call $run437i32.add438)439)440(core instance $b (instantiate $b (with "a" (instance $a))))441442(core module $c443(import "a" "g" (global $g (mut i32)))444(import "b" "init" (func $init))445(import "b" "run" (func $run (result i32)))446(import "b" "mem" (memory 1))447448(func (export "init")449call $init450451i32.const 1452memory.grow453i32.const -1454i32.eq455if unreachable end456457i32.const 65536458i32.const 7459i32.store460461;; overwrite a#init with a different value, make sure this462;; one is snapshot463i32.const 112464global.set $g465)466(func (export "run") (result i32)467i32.const 65536468i32.load469call $run470i32.add471)472)473(core instance $c (instantiate $c474(with "a" (instance $a))475(with "b" (instance $b))476))477478(func (export "run") (result u32) (canon lift (core func $c "run")))479(func (export "wizer-initialize") (canon lift (core func $c "init")))480)"#,481)482.await?;483484Ok(())485}486487#[tokio::test]488async fn export_is_removed() -> Result<()> {489let wasm = wizen(490r#"(component491(core module $a492(func (export "init"))493)494(core instance $a (instantiate $a))495(func $a (canon lift (core func $a "init")))496(export "wizer-initialize" (func $a))497)"#,498)499.await?;500501let names = exports(&wasm);502assert!(names.is_empty());503504let wasm = wizen(505r#"(component506(core module $a507(func (export "init"))508)509(core instance $a (instantiate $a))510(func $a (canon lift (core func $a "init")))511(export "other" (func $a))512(export "wizer-initialize" (func $a))513)"#,514)515.await?;516let names = exports(&wasm);517assert_eq!(names, ["other"]);518519let wasm = wizen(520r#"(component521(core module $a522(func (export "init"))523)524(core instance $a (instantiate $a))525(func $a (canon lift (core func $a "init")))526(export "other1" (func $a))527(export "wizer-initialize" (func $a))528(export "other2" (func $a))529)"#,530)531.await?;532let names = exports(&wasm);533assert_eq!(names, ["other1", "other2"]);534535let wasm = wizen(536r#"(component537(core module $a538(func (export "init"))539)540(core instance $a (instantiate $a))541(func $a (canon lift (core func $a "init")))542(export "other1" (func $a))543(export "other2" (func $a))544(export "wizer-initialize" (func $a))545)"#,546)547.await?;548let names = exports(&wasm);549assert_eq!(names, ["other1", "other2"]);550551let wasm = wizen(552r#"(component553(core module $a554(func (export "init"))555)556(core instance $a (instantiate $a))557(func $a (canon lift (core func $a "init")))558(export "wizer-initialize" (func $a))559(export "other1" (func $a))560(export "other2" (func $a))561)"#,562)563.await?;564let names = exports(&wasm);565assert_eq!(names, ["other1", "other2"]);566567let wasm = wizen(568r#"(component569(core module $a570(func (export "init"))571)572(core instance $a (instantiate $a))573(func $a (canon lift (core func $a "init")))574(export $x "other1" (func $a))575(export "wizer-initialize" (func $a))576(export "other2" (func $x))577)"#,578)579.await?;580let names = exports(&wasm);581assert_eq!(names, ["other1", "other2"]);582583let wasm = wizen(584r#"(component585(import "x" (func))586(core module $a587(func (export "init"))588)589(core instance $a (instantiate $a))590(func $a (canon lift (core func $a "init")))591(export $x "other1" (func $a))592(export "wizer-initialize" (func $a))593(export "other2" (func $x))594)"#,595)596.await?;597let names = exports(&wasm);598assert_eq!(names, ["other1", "other2"]);599600return Ok(());601602fn exports(wasm: &[u8]) -> Vec<&str> {603wasmparser::Parser::new(0)604.parse_all(&wasm)605.filter_map(|r| r.ok())606.filter_map(|payload| match payload {607wasmparser::Payload::ComponentExportSection(s) => Some(s),608_ => None,609})610.flat_map(|section| section.into_iter().map(|e| e.unwrap().name.0))611.collect()612}613}614615616