Browse Source

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.
pull/811/head
Alex Crichton 5 years ago
committed by GitHub
parent
commit
a45b037bfc
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      crates/api/src/externals.rs
  2. 9
      crates/api/src/instance.rs
  3. 7
      crates/api/src/trampoline/func.rs
  4. 7
      crates/api/src/trampoline/global.rs
  5. 7
      crates/api/src/trampoline/table.rs
  6. 117
      crates/api/src/types.rs

11
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(),

9
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,

7
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<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();

7
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,

7
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<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();

117
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<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,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::<Vec<_>>();
let returns = results
.iter()
.map(|p| AbiParam::new(p.get_wasmtime_type()))
.collect::<Vec<_>>();
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
Signature {
params,
returns,
call_conv,
}
};
let signature = params
.iter()
.map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Option<Vec<_>>>()
.and_then(|params| {
results
.iter()
.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 {
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<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))
}
}

Loading…
Cancel
Save