Move around some panics in wasmtime (#804)

In preparation for eventual support for wasm interface types this commit
moves around a few panics internally inside of conversions between the
`wasmtime` crate and the underlying jit support crates. This should have
any immediately-visible user changes, but the goal is that this'll help
support interface types which means `wasmtime` will have types that are
not supported by wasmtime itself and we'll be able to more gracefully
support that with error messages instead of accidental panics.
This commit is contained in:
Alex Crichton
2020-01-10 16:27:52 -06:00
committed by GitHub
parent ef2177ed3a
commit a45b037bfc
6 changed files with 99 additions and 57 deletions

View File

@@ -163,8 +163,12 @@ impl Func {
store: &Store,
instance_handle: InstanceHandle,
) -> Self {
// This is only called with `Export::Function`, and since it's coming
// from wasmtime_runtime itself we should support all the types coming
// out of it, so assert such here.
let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
FuncType::from_wasmtime_signature(signature.clone())
.expect("core wasm signature should be supported")
} else {
panic!("expected function export")
};
@@ -258,9 +262,12 @@ impl Global {
let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export {
global
} else {
panic!("wasmtime export is not memory")
panic!("wasmtime export is not global")
};
let ty = GlobalType::from_wasmtime_global(&global);
// The original export is coming from wasmtime_runtime itself we should
// support all the types coming out of it, so assert such here.
let ty = GlobalType::from_wasmtime_global(&global)
.expect("core wasm global type should be supported");
Global {
inner: Rc::new(GlobalInner {
_store: store.clone(),

View File

@@ -132,7 +132,14 @@ impl Instance {
// imported into this store using the from_handle() method.
let _ = store.register_wasmtime_signature(signature);
}
let extern_type = ExternType::from_wasmtime_export(&export);
// We should support everything supported by wasmtime_runtime, or
// otherwise we've got a bug in this crate, so panic if anything
// fails to convert here.
let extern_type = match ExternType::from_wasmtime_export(&export) {
Some(ty) => ty,
None => panic!("unsupported core wasm external type {:?}", export),
};
exports_types.push(ExportType::new(name, extern_type));
exports.push(Extern::from_wasmtime_export(
store,

View File

@@ -3,7 +3,7 @@
use super::create_handle::create_handle;
use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE};
use crate::{Callable, FuncType, Store, Val};
use anyhow::Result;
use anyhow::{bail, Result};
use std::cmp;
use std::convert::TryFrom;
use std::rc::Rc;
@@ -234,7 +234,10 @@ pub fn create_handle_with_function(
func: &Rc<dyn Callable + 'static>,
store: &Store,
) -> Result<InstanceHandle> {
let sig = ft.get_wasmtime_signature().clone();
let sig = match ft.get_wasmtime_signature() {
Some(sig) => sig.clone(),
None => bail!("not a supported core wasm signature {:?}", ft),
};
let isa = {
let isa_builder = native::builder();

View File

@@ -1,6 +1,6 @@
use super::create_handle::create_handle;
use crate::{GlobalType, Mutability, Val};
use anyhow::Result;
use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::{InstanceHandle, VMGlobalDefinition};
@@ -24,7 +24,10 @@ pub fn create_global(gt: &GlobalType, val: Val) -> Result<(wasmtime_runtime::Exp
}
let global = wasm::Global {
ty: gt.content().get_wasmtime_type(),
ty: match gt.content().get_wasmtime_type() {
Some(t) => t,
None => bail!("cannot support {:?} as a wasm global type", gt.content()),
},
mutability: match gt.mutability() {
Mutability::Const => false,
Mutability::Var => true,

View File

@@ -1,6 +1,6 @@
use super::create_handle::create_handle;
use crate::{TableType, ValType};
use anyhow::Result;
use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::InstanceHandle;
@@ -13,7 +13,10 @@ pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle> {
maximum: table.limits().max(),
ty: match table.element() {
ValType::FuncRef => wasm::TableElementType::Func,
_ => wasm::TableElementType::Val(table.element().get_wasmtime_type()),
_ => match table.element().get_wasmtime_type() {
Some(t) => wasm::TableElementType::Val(t),
None => bail!("cannot support {:?} as a table element", table.element()),
},
},
};
let tunable = Default::default();

View File

@@ -84,25 +84,25 @@ impl ValType {
}
}
pub(crate) fn get_wasmtime_type(&self) -> ir::Type {
pub(crate) fn get_wasmtime_type(&self) -> Option<ir::Type> {
match self {
ValType::I32 => ir::types::I32,
ValType::I64 => ir::types::I64,
ValType::F32 => ir::types::F32,
ValType::F64 => ir::types::F64,
ValType::V128 => ir::types::I8X16,
_ => unimplemented!("get_wasmtime_type other"),
ValType::I32 => Some(ir::types::I32),
ValType::I64 => Some(ir::types::I64),
ValType::F32 => Some(ir::types::F32),
ValType::F64 => Some(ir::types::F64),
ValType::V128 => Some(ir::types::I8X16),
_ => None,
}
}
pub(crate) fn from_wasmtime_type(ty: ir::Type) -> ValType {
pub(crate) fn from_wasmtime_type(ty: ir::Type) -> Option<ValType> {
match ty {
ir::types::I32 => ValType::I32,
ir::types::I64 => ValType::I64,
ir::types::F32 => ValType::F32,
ir::types::F64 => ValType::F64,
ir::types::I8X16 => ValType::V128,
_ => unimplemented!("from_wasmtime_type other"),
ir::types::I32 => Some(ValType::I32),
ir::types::I64 => Some(ValType::I64),
ir::types::F32 => Some(ValType::F32),
ir::types::F64 => Some(ValType::F64),
ir::types::I8X16 => Some(ValType::V128),
_ => None,
}
}
}
@@ -153,26 +153,29 @@ impl ExternType {
(Table(TableType) table unwrap_table)
(Memory(MemoryType) memory unwrap_memory)
}
pub(crate) fn from_wasmtime_export(export: &wasmtime_runtime::Export) -> Self {
match export {
/// Returns `None` if the sub-type fails to get converted, see documentation
/// for sub-types about what may fail.
pub(crate) fn from_wasmtime_export(export: &wasmtime_runtime::Export) -> Option<Self> {
Some(match export {
wasmtime_runtime::Export::Function { signature, .. } => {
ExternType::Func(FuncType::from_wasmtime_signature(signature.clone()))
ExternType::Func(FuncType::from_wasmtime_signature(signature.clone())?)
}
wasmtime_runtime::Export::Memory { memory, .. } => {
ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory))
}
wasmtime_runtime::Export::Global { global, .. } => {
ExternType::Global(GlobalType::from_wasmtime_global(&global))
ExternType::Global(GlobalType::from_wasmtime_global(&global)?)
}
wasmtime_runtime::Export::Table { table, .. } => {
ExternType::Table(TableType::from_wasmtime_table(&table.table))
}
}
})
}
}
// Function Types
fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType {
fn from_wasmtime_abiparam(param: &ir::AbiParam) -> Option<ValType> {
assert_eq!(param.purpose, ir::ArgumentPurpose::Normal);
ValType::from_wasmtime_type(param.value_type)
}
@@ -184,7 +187,12 @@ fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType {
pub struct FuncType {
params: Box<[ValType]>,
results: Box<[ValType]>,
signature: ir::Signature,
// `None` if params/results aren't wasm-compatible (e.g. use wasm interface
// types), or if they're not implemented (like anyref at the time of this
// writing)
//
// `Some` if they're all wasm-compatible.
signature: Option<ir::Signature>,
}
impl FuncType {
@@ -196,15 +204,18 @@ impl FuncType {
use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature};
use wasmtime_jit::native;
let call_conv = native::call_conv();
let signature: Signature = {
let mut params = params
let signature = params
.iter()
.map(|p| AbiParam::new(p.get_wasmtime_type()))
.collect::<Vec<_>>();
let returns = results
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Option<Vec<_>>>()
.and_then(|params| {
results
.iter()
.map(|p| AbiParam::new(p.get_wasmtime_type()))
.collect::<Vec<_>>();
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Option<Vec<_>>>()
.map(|results| (params, results))
})
.map(|(mut params, returns)| {
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
Signature {
@@ -212,7 +223,7 @@ impl FuncType {
returns,
call_conv,
}
};
});
FuncType {
params,
results,
@@ -230,27 +241,33 @@ impl FuncType {
&self.results
}
pub(crate) fn get_wasmtime_signature(&self) -> &ir::Signature {
&self.signature
/// Returns `Some` if this function signature was compatible with cranelift,
/// or `None` if one of the types/results wasn't supported or compatible
/// with cranelift.
pub(crate) fn get_wasmtime_signature(&self) -> Option<&ir::Signature> {
self.signature.as_ref()
}
pub(crate) fn from_wasmtime_signature(signature: ir::Signature) -> FuncType {
/// Returns `None` if any types in the signature can't be converted to the
/// types in this crate, but that should very rarely happen and largely only
/// indicate a bug in our cranelift integration.
pub(crate) fn from_wasmtime_signature(signature: ir::Signature) -> Option<FuncType> {
let params = signature
.params
.iter()
.filter(|p| p.purpose == ir::ArgumentPurpose::Normal)
.map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>();
.collect::<Option<Vec<_>>>()?;
let results = signature
.returns
.iter()
.map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>();
FuncType {
.collect::<Option<Vec<_>>>()?;
Some(FuncType {
params: params.into_boxed_slice(),
results: results.into_boxed_slice(),
signature,
}
signature: Some(signature),
})
}
}
@@ -287,14 +304,16 @@ impl GlobalType {
self.mutability
}
pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> GlobalType {
let ty = ValType::from_wasmtime_type(global.ty);
/// Returns `None` if the wasmtime global has a type that we can't
/// represent, but that should only very rarely happen and indicate a bug.
pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> Option<GlobalType> {
let ty = ValType::from_wasmtime_type(global.ty)?;
let mutability = if global.mutability {
Mutability::Var
} else {
Mutability::Const
};
GlobalType::new(ty, mutability)
Some(GlobalType::new(ty, mutability))
}
}