Add *.wast support for invoking components (#4526)

This commit builds on bytecodealliance/wasm-tools#690 to add support to
testing of the component model to execute functions when running
`*.wast` files. This support is all built on #4442 as functions are
invoked through a "dynamic" API. Right now the testing and integration
is fairly crude but I'm hoping that we can try to improve it over time
as necessary. For now this should provide a hopefully more convenient
syntax for unit tests and the like.
This commit is contained in:
Alex Crichton
2022-07-27 16:02:16 -05:00
committed by GitHub
parent 0508932174
commit 174b60dcf7
25 changed files with 1154 additions and 468 deletions

View File

@@ -22,13 +22,13 @@ wasmtime-cranelift = { path = "../cranelift", version = "=0.40.0", optional = tr
wasmtime-component-macro = { path = "../component-macro", version = "=0.40.0", optional = true }
wasmtime-component-util = { path = "../component-util", version = "=0.40.0", optional = true }
target-lexicon = { version = "0.12.0", default-features = false }
wasmparser = "0.87.0"
wasmparser = "0.88.0"
anyhow = "1.0.19"
libc = "0.2"
cfg-if = "1.0"
backtrace = { version = "0.3.61" }
log = "0.4.8"
wat = { version = "1.0.45", optional = true }
wat = { version = "1.0.47", optional = true }
serde = { version = "1.0.94", features = ["derive"] }
bincode = "1.2.1"
indexmap = "1.6"

View File

@@ -73,7 +73,7 @@ impl Record {
}
/// Retrieve the fields of this `record` in declaration order.
pub fn fields(&self) -> impl ExactSizeIterator<Item = Field> {
pub fn fields(&self) -> impl ExactSizeIterator<Item = Field<'_>> {
self.0.types[self.0.index].fields.iter().map(|field| Field {
name: &field.name,
ty: Type::from(&field.ty, &self.0.types),

View File

@@ -30,6 +30,19 @@ impl List {
values,
})
}
/// Returns the corresponding type of this list
pub fn ty(&self) -> &types::List {
&self.ty
}
}
impl Deref for List {
type Target = [Val];
fn deref(&self) -> &[Val] {
&self.values
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -76,6 +89,20 @@ impl Record {
values: values.into(),
})
}
/// Returns the corresponding type of this record.
pub fn ty(&self) -> &types::Record {
&self.ty
}
/// Gets the value of the specified field `name` from this record.
pub fn fields(&self) -> impl Iterator<Item = (&str, &Val)> {
assert_eq!(self.values.len(), self.ty.fields().len());
self.ty
.fields()
.zip(self.values.iter())
.map(|(ty, val)| (ty.name, val))
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -105,6 +132,16 @@ impl Tuple {
values,
})
}
/// Returns the type of this tuple.
pub fn ty(&self) -> &types::Tuple {
&self.ty
}
/// Returns the list of values that this tuple contains.
pub fn values(&self) -> &[Val] {
&self.values
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -139,6 +176,25 @@ impl Variant {
value: Box::new(value),
})
}
/// Returns the type of this variant.
pub fn ty(&self) -> &types::Variant {
&self.ty
}
/// Returns name of the discriminant of this value within the variant type.
pub fn discriminant(&self) -> &str {
self.ty
.cases()
.nth(self.discriminant as usize)
.unwrap()
.name
}
/// Returns the payload value for this variant.
pub fn payload(&self) -> &Val {
&self.value
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -161,6 +217,16 @@ impl Enum {
discriminant,
})
}
/// Returns the type of this value.
pub fn ty(&self) -> &types::Enum {
&self.ty
}
/// Returns name of this enum value.
pub fn discriminant(&self) -> &str {
self.ty.names().nth(self.discriminant as usize).unwrap()
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -190,6 +256,21 @@ impl Union {
))
}
}
/// Returns the type of this value.
pub fn ty(&self) -> &types::Union {
&self.ty
}
/// Returns name of the discriminant of this value within the union type.
pub fn discriminant(&self) -> u32 {
self.discriminant
}
/// Returns the payload value for this union.
pub fn payload(&self) -> &Val {
&self.value
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -216,6 +297,20 @@ impl Option {
value: Box::new(value.unwrap_or(Val::Unit)),
})
}
/// Returns the type of this value.
pub fn ty(&self) -> &types::Option {
&self.ty
}
/// Returns the optional value contained within.
pub fn value(&self) -> std::option::Option<&Val> {
if self.discriminant == 0 {
None
} else {
Some(&self.value)
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -247,6 +342,20 @@ impl Expected {
}),
})
}
/// Returns the type of this value.
pub fn ty(&self) -> &types::Expected {
&self.ty
}
/// Returns the result value contained within.
pub fn value(&self) -> Result<&Val, &Val> {
if self.discriminant == 0 {
Ok(&self.value)
} else {
Err(&self.value)
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -280,6 +389,23 @@ impl Flags {
value: values.into(),
})
}
/// Returns the type of this value.
pub fn ty(&self) -> &types::Flags {
&self.ty
}
/// Returns an iterator over the set of names that this flags set contains.
pub fn flags(&self) -> impl Iterator<Item = &str> {
(0..self.count).filter_map(|i| {
let (idx, bit) = ((i / 32) as usize, i % 32);
if self.value[idx] & (1 << bit) != 0 {
Some(self.ty.names().nth(i as usize).unwrap())
} else {
None
}
})
}
}
/// Represents possible runtime values which a component function can either consume or produce