Add array generation to wiggle-generate crate (#9)

* Add array generation to wiggle-generate crate

This commit:
* adds array generation to `wiggle-generate` crate which implies
  that we can now generate arrays from `witx` files
* introduces two test interface functions `foo::reduce_excuses` and
  `foo::populate_excuses`, and adds matching prop-tests
* adds an out-of-boundary check to `HostMemory::mem_area_strat` since
  now, given we're generating arrays for testing with an arbitrary
  but bounded number of elements, it is possible to violate the boundary
* refactors `Region::extend` to a new signature `extend(times: u32)`
  which multiplies the current pointer `len` by `times`
* fixes bug in `GuestArray::as_ref` and `GuestArrayMut::as_ref_mut` methods
  where we were not validating the first element (we always started the
  validation from the second element)

* Fix generation of arrays in witx

This commit fixes how `arrays` are auto-generated from `witx` files.
In particular, the changes include:
* Since by design every `array` in `witx` represents an immutable
  slab of memory, we will only ever operate on `GuestArray` in which
  case I've gone ahead and removed `GuestArrayMut` so as to unclutter
  the code somewhat. If we find ourselves in need for it in the future,
  I reckon it will be better to write it from scratch (since the codebase
  will inevitably evolve by then considerably) rather than maintaining an
  unused implementation.
* I've rewritten `GuestArrayRef<T>` to be a wrapper for `Vec<GuestRef<T>>`.
  Also, `GuestArray::as_ref` now borrows each underlying "element" of the
  array one-by-one rather than borrowing the entire chunk of memory at once.
  This change is motivated by the inability to coerce type parameter `T` in
  `GuestArray<T>` in more complicated cases such as arrays of guest pointers
  `GuestPtr<T>` to `*const T` for reuse in `std::slice::from_raw_parts` call.
  (In general, the size of Wasm32 pointer is 4 bytes, while

```
std::mem::size_of::<T>() == std::mem::size_of::<GuestPtr<S>>() == 16
```

  which is problematic; i.e., I can't see how I could properly extract guest
  pointers from slices of 4 bytes and at the same time not allocate.)
* I've augmented fuzz tests by (re-)defining two `array` types:

```
(typename $const_excuse_array (array (@witx const_pointer $excuse)))
(typename $excuse_array (array (@witx pointer $excuse)))
```

  This should hopefully emulate and test the `iovec` and `ciovec` arrays
  present in WASI spec.
This commit is contained in:
Jakub Konka
2020-02-19 10:58:55 +01:00
committed by GitHub
parent 48a218b5c5
commit 2ad77538f5
9 changed files with 395 additions and 251 deletions

View File

@@ -82,7 +82,7 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
match param.tref.type_().passed_by() {
witx::TypePassedBy::Value { .. } => quote!(#name),
witx::TypePassedBy::Pointer { .. } => quote!(&#name),
witx::TypePassedBy::PointerLengthPair { .. } => unimplemented!(),
witx::TypePassedBy::PointerLengthPair { .. } => quote!(&#name),
}
});
@@ -242,6 +242,36 @@ fn marshal_arg(
};
}
}
witx::Type::Array(arr) => {
let pointee_type = names.type_ref(arr, anon_lifetime());
let ptr_name = names.func_ptr_binding(&param.name);
let len_name = names.func_len_binding(&param.name);
let name = names.func_param(&param.name);
quote! {
let num_elems = match memory.ptr::<u32>(#len_name as u32) {
Ok(p) => match p.as_ref() {
Ok(r) => r,
Err(e) => {
#error_handling
}
}
Err(e) => {
#error_handling
}
};
let #name = match memory.ptr::<#pointee_type>(#ptr_name as u32) {
Ok(p) => match p.array(*num_elems) {
Ok(s) => s,
Err(e) => {
#error_handling
}
}
Err(e) => {
#error_handling
}
};
}
}
_ => unimplemented!("argument type marshalling"),
}
}

View File

@@ -15,7 +15,7 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream {
let arg_type = match arg.tref.type_().passed_by() {
witx::TypePassedBy::Value { .. } => quote!(#arg_typename),
witx::TypePassedBy::Pointer { .. } => quote!(&#arg_typename),
witx::TypePassedBy::PointerLengthPair { .. } => unimplemented!(),
witx::TypePassedBy::PointerLengthPair { .. } => quote!(&#arg_typename),
};
quote!(#arg_name: #arg_type)
});

View File

@@ -30,7 +30,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea
witx::Type::ConstPointer(p) => {
define_witx_pointer(names, &namedtype.name, quote!(wiggle_runtime::GuestPtr), p)
}
witx::Type::Array { .. } => unimplemented!("array types"),
witx::Type::Array(arr) => define_witx_array(names, &namedtype.name, &arr),
},
}
}
@@ -156,7 +156,7 @@ pub fn type_needs_lifetime(tref: &witx::TypeRef) -> bool {
witx::Type::Struct(s) => !struct_is_copy(&s),
witx::Type::Union { .. } => true,
witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } => true,
witx::Type::Array { .. } => unimplemented!(),
witx::Type::Array { .. } => true,
}
}
@@ -380,6 +380,12 @@ fn define_witx_pointer(
quote!(pub type #ident<'a> = #pointer_type<'a, #pointee_type>;)
}
fn define_witx_array(names: &Names, name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream {
let ident = names.type_(name);
let pointee_type = names.type_ref(arr_raw, quote!('a));
quote!(pub type #ident<'a> = wiggle_runtime::GuestArray<'a, #pointee_type>;)
}
fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream {
match int_repr {
witx::IntRepr::U8 => quote!(u8),