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. 99
      crates/api/src/types.rs

11
crates/api/src/externals.rs

@ -163,8 +163,12 @@ impl Func {
store: &Store, store: &Store,
instance_handle: InstanceHandle, instance_handle: InstanceHandle,
) -> Self { ) -> 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 { let ty = if let wasmtime_runtime::Export::Function { signature, .. } = &export {
FuncType::from_wasmtime_signature(signature.clone()) FuncType::from_wasmtime_signature(signature.clone())
.expect("core wasm signature should be supported")
} else { } else {
panic!("expected function export") panic!("expected function export")
}; };
@ -258,9 +262,12 @@ impl Global {
let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export { let global = if let wasmtime_runtime::Export::Global { ref global, .. } = export {
global global
} else { } 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 { Global {
inner: Rc::new(GlobalInner { inner: Rc::new(GlobalInner {
_store: store.clone(), _store: store.clone(),

9
crates/api/src/instance.rs

@ -132,7 +132,14 @@ impl Instance {
// imported into this store using the from_handle() method. // imported into this store using the from_handle() method.
let _ = store.register_wasmtime_signature(signature); 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_types.push(ExportType::new(name, extern_type));
exports.push(Extern::from_wasmtime_export( exports.push(Extern::from_wasmtime_export(
store, store,

7
crates/api/src/trampoline/func.rs

@ -3,7 +3,7 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE}; use super::trap::{record_api_trap, TrapSink, API_TRAP_CODE};
use crate::{Callable, FuncType, Store, Val}; use crate::{Callable, FuncType, Store, Val};
use anyhow::Result; use anyhow::{bail, Result};
use std::cmp; use std::cmp;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
@ -234,7 +234,10 @@ pub fn create_handle_with_function(
func: &Rc<dyn Callable + 'static>, func: &Rc<dyn Callable + 'static>,
store: &Store, store: &Store,
) -> Result<InstanceHandle> { ) -> 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 = {
let isa_builder = native::builder(); let isa_builder = native::builder();

7
crates/api/src/trampoline/global.rs

@ -1,6 +1,6 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use crate::{GlobalType, Mutability, Val}; use crate::{GlobalType, Mutability, Val};
use anyhow::Result; use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module}; use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::{InstanceHandle, VMGlobalDefinition}; 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 { 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: match gt.mutability() {
Mutability::Const => false, Mutability::Const => false,
Mutability::Var => true, Mutability::Var => true,

7
crates/api/src/trampoline/table.rs

@ -1,6 +1,6 @@
use super::create_handle::create_handle; use super::create_handle::create_handle;
use crate::{TableType, ValType}; use crate::{TableType, ValType};
use anyhow::Result; use anyhow::{bail, Result};
use wasmtime_environ::entity::PrimaryMap; use wasmtime_environ::entity::PrimaryMap;
use wasmtime_environ::{wasm, Module}; use wasmtime_environ::{wasm, Module};
use wasmtime_runtime::InstanceHandle; use wasmtime_runtime::InstanceHandle;
@ -13,7 +13,10 @@ pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle> {
maximum: table.limits().max(), maximum: table.limits().max(),
ty: match table.element() { ty: match table.element() {
ValType::FuncRef => wasm::TableElementType::Func, 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(); let tunable = Default::default();

99
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 { match self {
ValType::I32 => ir::types::I32, ValType::I32 => Some(ir::types::I32),
ValType::I64 => ir::types::I64, ValType::I64 => Some(ir::types::I64),
ValType::F32 => ir::types::F32, ValType::F32 => Some(ir::types::F32),
ValType::F64 => ir::types::F64, ValType::F64 => Some(ir::types::F64),
ValType::V128 => ir::types::I8X16, ValType::V128 => Some(ir::types::I8X16),
_ => unimplemented!("get_wasmtime_type other"), _ => None,
} }
} }
pub(crate) fn from_wasmtime_type(ty: ir::Type) -> ValType { pub(crate) fn from_wasmtime_type(ty: ir::Type) -> Option<ValType> {
match ty { match ty {
ir::types::I32 => ValType::I32, ir::types::I32 => Some(ValType::I32),
ir::types::I64 => ValType::I64, ir::types::I64 => Some(ValType::I64),
ir::types::F32 => ValType::F32, ir::types::F32 => Some(ValType::F32),
ir::types::F64 => ValType::F64, ir::types::F64 => Some(ValType::F64),
ir::types::I8X16 => ValType::V128, ir::types::I8X16 => Some(ValType::V128),
_ => unimplemented!("from_wasmtime_type other"), _ => None,
} }
} }
} }
@ -153,26 +153,29 @@ impl ExternType {
(Table(TableType) table unwrap_table) (Table(TableType) table unwrap_table)
(Memory(MemoryType) memory unwrap_memory) (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, .. } => { 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, .. } => { wasmtime_runtime::Export::Memory { memory, .. } => {
ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory)) ExternType::Memory(MemoryType::from_wasmtime_memory(&memory.memory))
} }
wasmtime_runtime::Export::Global { global, .. } => { wasmtime_runtime::Export::Global { global, .. } => {
ExternType::Global(GlobalType::from_wasmtime_global(&global)) ExternType::Global(GlobalType::from_wasmtime_global(&global)?)
} }
wasmtime_runtime::Export::Table { table, .. } => { wasmtime_runtime::Export::Table { table, .. } => {
ExternType::Table(TableType::from_wasmtime_table(&table.table)) ExternType::Table(TableType::from_wasmtime_table(&table.table))
} }
} })
} }
} }
// Function Types // 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); assert_eq!(param.purpose, ir::ArgumentPurpose::Normal);
ValType::from_wasmtime_type(param.value_type) ValType::from_wasmtime_type(param.value_type)
} }
@ -184,7 +187,12 @@ fn from_wasmtime_abiparam(param: &ir::AbiParam) -> ValType {
pub struct FuncType { pub struct FuncType {
params: Box<[ValType]>, params: Box<[ValType]>,
results: 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 { impl FuncType {
@ -196,15 +204,18 @@ impl FuncType {
use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature}; use wasmtime_environ::ir::{types, AbiParam, ArgumentPurpose, Signature};
use wasmtime_jit::native; use wasmtime_jit::native;
let call_conv = native::call_conv(); let call_conv = native::call_conv();
let signature: Signature = { let signature = params
let mut params = params
.iter() .iter()
.map(|p| AbiParam::new(p.get_wasmtime_type())) .map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()
let returns = results .and_then(|params| {
results
.iter() .iter()
.map(|p| AbiParam::new(p.get_wasmtime_type())) .map(|p| p.get_wasmtime_type().map(AbiParam::new))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()
.map(|results| (params, results))
})
.map(|(mut params, returns)| {
params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext)); params.insert(0, AbiParam::special(types::I64, ArgumentPurpose::VMContext));
Signature { Signature {
@ -212,7 +223,7 @@ impl FuncType {
returns, returns,
call_conv, call_conv,
} }
}; });
FuncType { FuncType {
params, params,
results, results,
@ -230,27 +241,33 @@ impl FuncType {
&self.results &self.results
} }
pub(crate) fn get_wasmtime_signature(&self) -> &ir::Signature { /// Returns `Some` if this function signature was compatible with cranelift,
&self.signature /// 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 let params = signature
.params .params
.iter() .iter()
.filter(|p| p.purpose == ir::ArgumentPurpose::Normal) .filter(|p| p.purpose == ir::ArgumentPurpose::Normal)
.map(|p| from_wasmtime_abiparam(p)) .map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()?;
let results = signature let results = signature
.returns .returns
.iter() .iter()
.map(|p| from_wasmtime_abiparam(p)) .map(|p| from_wasmtime_abiparam(p))
.collect::<Vec<_>>(); .collect::<Option<Vec<_>>>()?;
FuncType { Some(FuncType {
params: params.into_boxed_slice(), params: params.into_boxed_slice(),
results: results.into_boxed_slice(), results: results.into_boxed_slice(),
signature, signature: Some(signature),
} })
} }
} }
@ -287,14 +304,16 @@ impl GlobalType {
self.mutability self.mutability
} }
pub(crate) fn from_wasmtime_global(global: &wasm::Global) -> GlobalType { /// Returns `None` if the wasmtime global has a type that we can't
let ty = ValType::from_wasmtime_type(global.ty); /// 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 { let mutability = if global.mutability {
Mutability::Var Mutability::Var
} else { } else {
Mutability::Const Mutability::Const
}; };
GlobalType::new(ty, mutability) Some(GlobalType::new(ty, mutability))
} }
} }

Loading…
Cancel
Save