diff --git a/crates/api/src/externals.rs b/crates/api/src/externals.rs index 98afc5a691..0062b60b1d 100644 --- a/crates/api/src/externals.rs +++ b/crates/api/src/externals.rs @@ -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(), diff --git a/crates/api/src/instance.rs b/crates/api/src/instance.rs index 49a51ba588..145e25f2c2 100644 --- a/crates/api/src/instance.rs +++ b/crates/api/src/instance.rs @@ -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, diff --git a/crates/api/src/trampoline/func.rs b/crates/api/src/trampoline/func.rs index 8ace580382..328a325490 100644 --- a/crates/api/src/trampoline/func.rs +++ b/crates/api/src/trampoline/func.rs @@ -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, store: &Store, ) -> Result { - 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(); diff --git a/crates/api/src/trampoline/global.rs b/crates/api/src/trampoline/global.rs index f1b610559d..f53701f167 100644 --- a/crates/api/src/trampoline/global.rs +++ b/crates/api/src/trampoline/global.rs @@ -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, diff --git a/crates/api/src/trampoline/table.rs b/crates/api/src/trampoline/table.rs index 5d2441bf92..713de1b43a 100644 --- a/crates/api/src/trampoline/table.rs +++ b/crates/api/src/trampoline/table.rs @@ -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 { 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(); diff --git a/crates/api/src/types.rs b/crates/api/src/types.rs index 36fde8ff20..5162c49c54 100644 --- a/crates/api/src/types.rs +++ b/crates/api/src/types.rs @@ -84,25 +84,25 @@ impl ValType { } } - pub(crate) fn get_wasmtime_type(&self) -> ir::Type { + pub(crate) fn get_wasmtime_type(&self) -> Option { 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 { 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 { + 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 { 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, } impl FuncType { @@ -196,23 +204,26 @@ 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 - .iter() - .map(|p| AbiParam::new(p.get_wasmtime_type())) - .collect::>(); - let returns = results - .iter() - .map(|p| AbiParam::new(p.get_wasmtime_type())) - .collect::>(); - params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); + let signature = params + .iter() + .map(|p| p.get_wasmtime_type().map(AbiParam::new)) + .collect::>>() + .and_then(|params| { + results + .iter() + .map(|p| p.get_wasmtime_type().map(AbiParam::new)) + .collect::>>() + .map(|results| (params, results)) + }) + .map(|(mut params, returns)| { + params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); - Signature { - params, - returns, - call_conv, - } - }; + Signature { + params, + 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 { let params = signature .params .iter() .filter(|p| p.purpose == ir::ArgumentPurpose::Normal) .map(|p| from_wasmtime_abiparam(p)) - .collect::>(); + .collect::>>()?; let results = signature .returns .iter() .map(|p| from_wasmtime_abiparam(p)) - .collect::>(); - FuncType { + .collect::>>()?; + 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 { + 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)) } }