Files
wasmtime/tests/all/component_model.rs
Alex Crichton 2329ecc341 Add a wasmtime::component::bindgen! macro (#5317)
* Import Wasmtime support from the `wit-bindgen` repo

This commit imports the `wit-bindgen-gen-host-wasmtime-rust` crate from
the `wit-bindgen` repository into the upstream Wasmtime repository. I've
chosen to not import the full history here since the crate is relatively
small and doesn't have a ton of complexity. While the history of the
crate is quite long the current iteration of the crate's history is
relatively short so there's not a ton of import there anyway. The
thinking is that this can now continue to evolve in-tree.

* Refactor `wasmtime-component-macro` a bit

Make room for a `wit_bindgen` macro to slot in.

* Add initial support for a `bindgen` macro

* Add tests for `wasmtime::component::bindgen!`

* Improve error forgetting `async` feature

* Add end-to-end tests for bindgen

* Add an audit of `unicase`

* Add a license to the test-helpers crate

* Add vet entry for `pulldown-cmark`

* Update publish script with new crate

* Try to fix publish script

* Update audits

* Update lock file
2022-12-06 13:06:00 -06:00

205 lines
5.2 KiB
Rust

use anyhow::Result;
use component_test_util::{async_engine, engine, TypedFuncExt};
use std::fmt::Write;
use std::iter;
use wasmtime::component::Component;
use wasmtime_component_util::REALLOC_AND_FREE;
mod aot;
mod r#async;
mod bindgen;
mod dynamic;
mod func;
mod import;
mod instance;
mod macros;
mod nested;
mod post_return;
mod strings;
#[test]
fn components_importing_modules() -> Result<()> {
let engine = engine();
// FIXME: these components should actually get instantiated in `*.wast`
// tests once supplying imports has actually been implemented.
Component::new(
&engine,
r#"
(component
(import "a" (core module))
)
"#,
)?;
Component::new(
&engine,
r#"
(component
(import "a" (core module $m1
(import "" "" (func))
(import "" "x" (global i32))
(export "a" (table 1 funcref))
(export "b" (memory 1))
(export "c" (func (result f32)))
(export "d" (global i64))
))
(core module $m2
(func (export ""))
(global (export "x") i32 i32.const 0)
)
(core instance $i2 (instantiate (module $m2)))
(core instance $i1 (instantiate (module $m1) (with "" (instance $i2))))
(core module $m3
(import "mod" "1" (memory 1))
(import "mod" "2" (table 1 funcref))
(import "mod" "3" (global i64))
(import "mod" "4" (func (result f32)))
)
(core instance $i3 (instantiate (module $m3)
(with "mod" (instance
(export "1" (memory $i1 "b"))
(export "2" (table $i1 "a"))
(export "3" (global $i1 "d"))
(export "4" (func $i1 "c"))
))
))
)
"#,
)?;
Ok(())
}
#[derive(Copy, Clone, PartialEq, Eq)]
enum Type {
S8,
U8,
S16,
U16,
I32,
I64,
F32,
F64,
}
impl Type {
fn store(&self) -> &'static str {
match self {
Self::S8 | Self::U8 => "store8",
Self::S16 | Self::U16 => "store16",
Self::I32 | Self::F32 | Self::I64 | Self::F64 => "store",
}
}
fn primitive(&self) -> &'static str {
match self {
Self::S8 | Self::U8 | Self::S16 | Self::U16 | Self::I32 => "i32",
Self::I64 => "i64",
Self::F32 => "f32",
Self::F64 => "f64",
}
}
}
#[derive(Copy, Clone, PartialEq, Eq)]
struct Param(Type, Option<usize>);
fn make_echo_component(type_definition: &str, type_size: u32) -> String {
let mut offset = 0;
make_echo_component_with_params(
type_definition,
&iter::repeat(Type::I32)
.map(|ty| {
let param = Param(ty, Some(offset));
offset += 4;
param
})
.take(usize::try_from(type_size).unwrap() / 4)
.collect::<Vec<_>>(),
)
}
fn make_echo_component_with_params(type_definition: &str, params: &[Param]) -> String {
let func = if params.len() == 0 {
format!("(func (export \"echo\"))")
} else if params.len() == 1 || params.len() > 16 {
let primitive = if params.len() == 1 {
params[0].0.primitive()
} else {
"i32"
};
format!(
r#"
(func (export "echo") (param {primitive}) (result {primitive})
local.get 0
)"#,
)
} else {
let mut param_string = String::new();
let mut store = String::new();
let mut size = 8;
for (index, Param(ty, offset)) in params.iter().enumerate() {
let primitive = ty.primitive();
write!(&mut param_string, " {primitive}").unwrap();
if let Some(offset) = offset {
write!(
&mut store,
"({primitive}.{} offset={offset} (local.get $base) (local.get {index}))",
ty.store(),
)
.unwrap();
size = size.max(offset + 8);
}
}
format!(
r#"
(func (export "echo") (param{param_string}) (result i32)
(local $base i32)
(local.set $base
(call $realloc
(i32.const 0)
(i32.const 0)
(i32.const 4)
(i32.const {size})))
{store}
local.get $base
)"#
)
};
format!(
r#"
(component
(core module $m
{func}
(memory (export "memory") 1)
{REALLOC_AND_FREE}
)
(core instance $i (instantiate $m))
(type $Foo {type_definition})
(func (export "echo") (param "a" $Foo) (result "b" $Foo)
(canon lift
(core func $i "echo")
(memory $i "memory")
(realloc (func $i "realloc"))
)
)
)"#
)
}