Split the ComponentValue trait into... components (#4236)

This commit splits the current `ComponentValue` trait into three
separate traits:

* `ComponentType` - contains size/align/typecheck information in
  addition to the "lower" representation.
* `Lift` - only contains `lift` and `load`
* `Lower` - only contains `lower` and `store`

When describing the original implementation of host functions to Nick he
immediately pointed out this superior solution to the traits involved
with Wasmtime's support for typed parameters/returns in exported and
imported functions. Instead of having dynamic errors at runtime for
things like "you can't lift a `String`" that's instead a static
compile-time error now.

While I was doing this split I also refactored the `ComponentParams`
trait a bit to have `ComponentType` as a supertrait instead of a subtype
which made its implementations a bit more compact. Additionally its impl
blocks were folded into the existing tuple impl blocks.
This commit is contained in:
Alex Crichton
2022-06-07 12:29:26 -05:00
committed by GitHub
parent 511c53703a
commit 11ff9650e5
6 changed files with 348 additions and 422 deletions

View File

@@ -196,8 +196,8 @@ impl Func {
/// ```
pub fn typed<Params, Return, S>(&self, store: S) -> Result<TypedFunc<Params, Return>>
where
Params: ComponentParams,
Return: ComponentValue,
Params: ComponentParams + Lower,
Return: Lift,
S: AsContext,
{
self.typecheck::<Params, Return>(store.as_context().0)?;
@@ -206,16 +206,15 @@ impl Func {
fn typecheck<Params, Return>(&self, store: &StoreOpaque) -> Result<()>
where
Params: ComponentParams,
Return: ComponentValue,
Params: ComponentParams + Lower,
Return: Lift,
{
let data = &store[self.0];
let ty = &data.types[data.ty];
Params::typecheck(&ty.params, &data.types, Op::Lower)
Params::typecheck_params(&ty.params, &data.types)
.context("type mismatch with parameters")?;
Return::typecheck(&ty.result, &data.types, Op::Lift)
.context("type mismatch with result")?;
Return::typecheck(&ty.result, &data.types).context("type mismatch with result")?;
Ok(())
}

View File

@@ -1,5 +1,5 @@
use crate::component::func::{MAX_STACK_PARAMS, MAX_STACK_RESULTS};
use crate::component::{ComponentParams, ComponentValue, Memory, MemoryMut, Op, Options};
use crate::component::{ComponentParams, ComponentType, Lift, Lower, Memory, MemoryMut, Options};
use crate::{AsContextMut, StoreContextMut, ValRaw};
use anyhow::{bail, Context, Result};
use std::any::Any;
@@ -46,8 +46,8 @@ impl HostFunc {
fn new<F, P, R>(func: F, entrypoint: VMLoweringCallee) -> Arc<HostFunc>
where
F: Send + Sync + 'static,
P: ComponentParams,
R: ComponentValue,
P: ComponentParams + Lift,
R: Lower,
{
Arc::new(HostFunc {
entrypoint,
@@ -71,12 +71,12 @@ impl HostFunc {
fn typecheck<P, R>(ty: FuncTypeIndex, types: &ComponentTypes) -> Result<()>
where
P: ComponentParams,
R: ComponentValue,
P: ComponentParams + Lift,
R: Lower,
{
let ty = &types[ty];
P::typecheck(&ty.params, types, Op::Lift).context("type mismatch with parameters")?;
R::typecheck(&ty.result, types, Op::Lower).context("type mismatch with result")?;
P::typecheck_params(&ty.params, types).context("type mismatch with parameters")?;
R::typecheck(&ty.result, types).context("type mismatch with result")?;
Ok(())
}
@@ -110,8 +110,8 @@ unsafe fn call_host<T, Params, Return, F>(
closure: F,
) -> Result<()>
where
Params: ComponentValue,
Return: ComponentValue,
Params: Lift,
Return: Lower,
F: FnOnce(StoreContextMut<'_, T>, Params) -> Result<Return>,
{
/// Representation of arguments to this function when a return pointer is in
@@ -227,7 +227,7 @@ where
}
}
fn validate_inbounds<T: ComponentValue>(memory: &[u8], ptr: &ValRaw) -> Result<usize> {
fn validate_inbounds<T: ComponentType>(memory: &[u8], ptr: &ValRaw) -> Result<usize> {
// FIXME: needs memory64 support
let ptr = usize::try_from(ptr.get_u32())?;
let end = match ptr.checked_add(T::size()) {
@@ -271,8 +271,8 @@ macro_rules! impl_into_component_func {
impl<T, F, $($args,)* R> IntoComponentFunc<T, ($($args,)*), R> for F
where
F: Fn($($args),*) -> Result<R> + Send + Sync + 'static,
($($args,)*): ComponentParams + ComponentValue,
R: ComponentValue,
($($args,)*): ComponentParams + Lift,
R: Lower,
{
extern "C" fn entrypoint(
cx: *mut VMOpaqueContext,
@@ -307,8 +307,8 @@ macro_rules! impl_into_component_func {
impl<T, F, $($args,)* R> IntoComponentFunc<T, (StoreContextMut<'_, T>, $($args,)*), R> for F
where
F: Fn(StoreContextMut<'_, T>, $($args),*) -> Result<R> + Send + Sync + 'static,
($($args,)*): ComponentParams + ComponentValue,
R: ComponentValue,
($($args,)*): ComponentParams + Lift,
R: Lower,
{
extern "C" fn entrypoint(
cx: *mut VMOpaqueContext,

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
use crate::component::func::HostFunc;
use crate::component::{Component, ComponentParams, ComponentValue, Func, TypedFunc};
use crate::component::{Component, ComponentParams, Func, Lift, Lower, TypedFunc};
use crate::instance::OwnedImports;
use crate::store::{StoreOpaque, Stored};
use crate::{AsContextMut, Module, StoreContext, StoreContextMut};
@@ -86,8 +86,8 @@ impl Instance {
name: &str,
) -> Result<TypedFunc<Params, Results>>
where
Params: ComponentParams,
Results: ComponentValue,
Params: ComponentParams + Lower,
Results: Lift,
S: AsContextMut,
{
let f = self

View File

@@ -11,7 +11,8 @@ mod matching;
mod store;
pub use self::component::Component;
pub use self::func::{
ComponentParams, ComponentValue, Func, IntoComponentFunc, Op, TypedFunc, WasmList, WasmStr,
ComponentParams, ComponentType, Func, IntoComponentFunc, Lift, Lower, TypedFunc, WasmList,
WasmStr,
};
pub use self::instance::{Instance, InstancePre};
pub use self::linker::Linker;

View File

@@ -158,10 +158,6 @@ fn typecheck() -> Result<()> {
assert!(thunk.typed::<(u32,), (), _>(&store).is_err());
assert!(thunk.typed::<(), (), _>(&store).is_ok());
assert!(take_string.typed::<(), (), _>(&store).is_err());
assert!(take_string.typed::<(), String, _>(&store).is_err());
assert!(take_string
.typed::<(String, String), String, _>(&store)
.is_err());
assert!(take_string.typed::<(String,), (), _>(&store).is_ok());
assert!(take_string.typed::<(&str,), (), _>(&store).is_ok());
assert!(take_string.typed::<(&[u8],), (), _>(&store).is_err());
@@ -175,11 +171,7 @@ fn typecheck() -> Result<()> {
assert!(ret_tuple1.typed::<(), (u32,), _>(&store).is_ok());
assert!(ret_tuple1.typed::<(), u32, _>(&store).is_err());
assert!(ret_string.typed::<(), (), _>(&store).is_err());
assert!(ret_string.typed::<(), String, _>(&store).is_err());
assert!(ret_string.typed::<(), &str, _>(&store).is_err());
assert!(ret_string.typed::<(), WasmStr, _>(&store).is_ok());
assert!(ret_list_u8.typed::<(), &[u8], _>(&store).is_err());
assert!(ret_list_u8.typed::<(), Vec<u8>, _>(&store).is_err());
assert!(ret_list_u8.typed::<(), WasmList<u16>, _>(&store).is_err());
assert!(ret_list_u8.typed::<(), WasmList<i8>, _>(&store).is_err());
assert!(ret_list_u8.typed::<(), WasmList<u8>, _>(&store).is_ok());