From eb175abdfc9b01335516f5e71f82adacaa7a4c74 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Mar 2020 11:31:58 -0800 Subject: [PATCH] Temporarily remove support for interface types This commit temporarily removes support for interface types from the `wasmtime` CLI and removes the `wasmtime-interface-types` crate. An error is now printed for any input wasm modules that have wasm interface types sections to indicate that support has been removed and references to two issues are printed as well: * #677 - tracking work for re-adding interface types support * #1271 - rationale for removal and links to other discussions Closes #1271 --- Cargo.lock | 18 - Cargo.toml | 1 - crates/api/src/module.rs | 22 ++ crates/interface-types/Cargo.toml | 25 -- crates/interface-types/README.md | 4 - crates/interface-types/src/lib.rs | 490 -------------------------- crates/interface-types/src/value.rs | 66 ---- crates/misc/py/Cargo.toml | 1 - crates/misc/rust/Cargo.toml | 1 - crates/misc/rust/examples/markdown.rs | 13 - crates/misc/rust/src/lib.rs | 8 +- docs/wasm-rust.md | 5 + scripts/publish-all.sh | 1 - scripts/test-all.sh | 1 - src/commands/run.rs | 81 +++-- 15 files changed, 70 insertions(+), 667 deletions(-) delete mode 100644 crates/interface-types/Cargo.toml delete mode 100644 crates/interface-types/README.md delete mode 100644 crates/interface-types/src/lib.rs delete mode 100644 crates/interface-types/src/value.rs delete mode 100644 crates/misc/rust/examples/markdown.rs diff --git a/Cargo.lock b/Cargo.lock index cd71d45b25ab..7229a7389b0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2490,7 +2490,6 @@ dependencies = [ "wasmtime", "wasmtime-debug", "wasmtime-environ", - "wasmtime-interface-types", "wasmtime-jit", "wasmtime-obj", "wasmtime-profiling", @@ -2577,21 +2576,6 @@ dependencies = [ "wat", ] -[[package]] -name = "wasmtime-interface-types" -version = "0.12.0" -dependencies = [ - "anyhow", - "walrus", - "wasm-webidl-bindings", - "wasmparser 0.51.2", - "wasmtime", - "wasmtime-environ", - "wasmtime-jit", - "wasmtime-runtime", - "wasmtime-wasi", -] - [[package]] name = "wasmtime-jit" version = "0.12.0" @@ -2649,7 +2633,6 @@ dependencies = [ "target-lexicon", "wasmparser 0.51.2", "wasmtime", - "wasmtime-interface-types", "wasmtime-wasi", ] @@ -2677,7 +2660,6 @@ version = "0.12.0" dependencies = [ "anyhow", "wasmtime", - "wasmtime-interface-types", "wasmtime-rust-macro", "wasmtime-wasi", ] diff --git a/Cargo.toml b/Cargo.toml index 41f491ad3b41..66b59fe44aac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,6 @@ doc = false wasmtime = { path = "crates/api" } wasmtime-debug = { path = "crates/debug" } wasmtime-environ = { path = "crates/environ" } -wasmtime-interface-types = { path = "crates/interface-types" } wasmtime-jit = { path = "crates/jit" } wasmtime-obj = { path = "crates/obj" } wasmtime-profiling = { path = "crates/profiling" } diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs index cde9abb0a1c2..80c29d9d6921 100644 --- a/crates/api/src/module.rs +++ b/crates/api/src/module.rs @@ -418,6 +418,28 @@ impl Module { } } } + SectionCode::Custom { + name: "webidl-bindings", + .. + } + | SectionCode::Custom { + name: "wasm-interface-types", + .. + } => { + bail!( + "\ +support for interface types has temporarily been removed from `wasmtime` + +for more information about this temoprary you can read on the issue online: + + https://github.com/bytecodealliance/wasmtime/issues/1271 + +and for re-adding support for interface types you can see this issue: + + https://github.com/bytecodealliance/wasmtime/issues/677 +" + ); + } _ => { // skip other sections } diff --git a/crates/interface-types/Cargo.toml b/crates/interface-types/Cargo.toml deleted file mode 100644 index 1ba6fc409499..000000000000 --- a/crates/interface-types/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "wasmtime-interface-types" -version = "0.12.0" -authors = ["The Wasmtime Project Developers"] -description = "Support for wasm interface types with wasmtime" -license = "Apache-2.0 WITH LLVM-exception" -categories = ["wasm"] -keywords = ["webassembly", "wasm"] -repository = "https://github.com/bytecodealliance/wasmtime" -readme = "README.md" -edition = "2018" - -[dependencies] -anyhow = "1.0.19" -walrus = "0.15" -wasmparser = "0.51.2" -wasm-webidl-bindings = "0.8" -wasmtime = { path = "../api", version = "0.12.0" } -wasmtime-jit = { path = "../jit", version = "0.12.0" } -wasmtime-environ = { path = "../environ", version = "0.12.0" } -wasmtime-runtime = { path = "../runtime", version = "0.12.0" } -wasmtime-wasi = { path = "../wasi", version = "0.12.0" } - -[badges] -maintenance = { status = "actively-developed" } diff --git a/crates/interface-types/README.md b/crates/interface-types/README.md deleted file mode 100644 index a8350586f180..000000000000 --- a/crates/interface-types/README.md +++ /dev/null @@ -1,4 +0,0 @@ -This crate implements a prototype of the wasm [interface types] proposal -for Wasmtime. - -[interface types]: https://github.com/WebAssembly/interface-types diff --git a/crates/interface-types/src/lib.rs b/crates/interface-types/src/lib.rs deleted file mode 100644 index 4e650b13c086..000000000000 --- a/crates/interface-types/src/lib.rs +++ /dev/null @@ -1,490 +0,0 @@ -//! A small crate to handle WebAssembly interface types in wasmtime. -//! -//! Note that this is intended to follow the [official proposal][proposal] and -//! is highly susceptible to change/breakage/etc. -//! -//! [proposal]: https://github.com/webassembly/webidl-bindings - -#![deny(missing_docs)] - -use anyhow::{bail, format_err, Result}; -use std::convert::TryFrom; -use std::str; -use wasm_webidl_bindings::ast; -use wasmtime::Val; -use wasmtime_environ::ir; -use wasmtime_runtime::{Export, InstanceHandle}; - -mod value; -pub use value::Value; - -/// A data structure intended to hold a parsed representation of the wasm -/// interface types of a module. -/// -/// The expected usage pattern is to create this next to wasmtime data -/// structures and then use this to process arguments into wasm arguments as -/// appropriate for bound functions. -pub struct ModuleData { - inner: Option, - wasi_module_name: Option, -} - -struct Inner { - module: walrus::Module, -} - -/// Representation of a binding of an exported function. -/// -/// Can be used to learn about binding expressions and/or binding types. -pub struct ExportBinding<'a> { - kind: ExportBindingKind<'a>, -} - -enum ExportBindingKind<'a> { - Rich { - section: &'a ast::WebidlBindings, - binding: &'a ast::ExportBinding, - }, - Raw(ir::Signature), -} - -impl ModuleData { - /// Parses a raw binary wasm file, extracting information about wasm - /// interface types. - /// - /// Returns an error if the wasm file is malformed. - pub fn new(wasm: &[u8]) -> Result { - // Perform a fast search through the module for the right custom - // section. Actually parsing out the interface types data is currently a - // pretty expensive operation so we want to only do that if we actually - // find the right section. - let mut reader = wasmparser::ModuleReader::new(wasm)?; - let mut found = false; - let mut wasi_module_name = None; - while !reader.eof() { - let section = reader.read()?; - - match section.code { - wasmparser::SectionCode::Custom { name, .. } => { - if name == "webidl-bindings" { - found = true; - break; - } - } - - // If we see the import section then see if we can find a wasi - // module import which we can later use to register the wasi - // implementation automatically. - wasmparser::SectionCode::Import => { - let section = section.get_import_section_reader()?; - for import in section { - let import = import?; - if wasmtime_wasi::is_wasi_module(import.module) { - wasi_module_name = Some(import.module.to_string()); - } - } - } - _ => {} - } - } - if !found { - return Ok(ModuleData { - inner: None, - wasi_module_name, - }); - } - - // Ok, perform the more expensive parsing. WebAssembly interface types - // are super experimental and under development. To get something - // quickly up and running we're using the same crate as `wasm-bindgen`, - // a producer of wasm interface types, the `wasm-webidl-bindings` crate. - // This crate relies on `walrus` which has its own IR for a wasm module. - // Ideally we'd do all this during cranelift's own parsing of the wasm - // module and we wouldn't have to reparse here purely for this one use - // case. - // - // For now though this is "fast enough" and good enough for some demos, - // but for full-on production quality engines we'll want to integrate - // this much more tightly with the rest of wasmtime. - let module = walrus::ModuleConfig::new() - .on_parse(wasm_webidl_bindings::binary::on_parse) - .parse(wasm)?; - - Ok(ModuleData { - inner: Some(Inner { module }), - wasi_module_name, - }) - } - - /// Detects if WASI support is needed: returns module name that is requested. - pub fn find_wasi_module_name(&self) -> Option { - self.wasi_module_name.clone() - } - - /// Invokes wasmtime function with a `&[Value]` list. `Value` the set of - /// wasm interface types. - pub fn invoke_export( - &self, - instance: &wasmtime::Instance, - export: &str, - args: &[Value], - ) -> Result> { - let mut handle = instance.handle().clone(); - - let binding = self.binding_for_export(&mut handle, export)?; - let incoming = binding.param_bindings()?; - let outgoing = binding.result_bindings()?; - - let f = instance - .get_export(export) - .ok_or_else(|| format_err!("failed to find export `{}`", export))? - .func() - .ok_or_else(|| format_err!("`{}` is not a function", export))? - .clone(); - - let mut cx = InstanceTranslateContext(instance.clone()); - let wasm_args = translate_incoming(&mut cx, &incoming, args)? - .into_iter() - .map(|rv| rv.into()) - .collect::>(); - let wasm_results = f.call(&wasm_args)?; - translate_outgoing(&mut cx, &outgoing, &wasm_results) - } - - /// Returns an appropriate binding for the `name` export in this module - /// which has also been instantiated as `instance` provided here. - /// - /// Returns an error if `name` is not present in the module. - pub fn binding_for_export( - &self, - instance: &mut InstanceHandle, - name: &str, - ) -> Result> { - if let Some(binding) = self.interface_binding_for_export(name) { - return Ok(binding); - } - let signature = match instance.lookup(name) { - Some(Export::Function { signature, .. }) => signature, - Some(_) => bail!("`{}` is not a function", name), - None => bail!("failed to find export `{}`", name), - }; - Ok(ExportBinding { - kind: ExportBindingKind::Raw(signature), - }) - } - - fn interface_binding_for_export(&self, name: &str) -> Option> { - let inner = self.inner.as_ref()?; - let bindings = inner.module.customs.get_typed::()?; - let export = inner.module.exports.iter().find(|e| e.name == name)?; - let id = match export.item { - walrus::ExportItem::Function(f) => f, - _ => panic!(), - }; - let (_, bind) = bindings.binds.iter().find(|(_, b)| b.func == id)?; - let binding = bindings.bindings.get(bind.binding)?; - let binding = match binding { - ast::FunctionBinding::Export(export) => export, - ast::FunctionBinding::Import(_) => return None, - }; - Some(ExportBinding { - kind: ExportBindingKind::Rich { - binding, - section: bindings, - }, - }) - } -} - -impl ExportBinding<'_> { - /// Returns the list of binding expressions used to create the parameters - /// for this binding. - pub fn param_bindings(&self) -> Result> { - match &self.kind { - ExportBindingKind::Rich { binding, .. } => Ok(binding.params.bindings.clone()), - ExportBindingKind::Raw(sig) => sig - .params - .iter() - .skip(2) // skip the VMContext arguments - .enumerate() - .map(|(i, param)| default_incoming(i, param)) - .collect(), - } - } - - /// Returns the list of scalar types used for this binding - pub fn param_types(&self) -> Result> { - match &self.kind { - ExportBindingKind::Rich { - binding, section, .. - } => { - let id = match binding.webidl_ty { - ast::WebidlTypeRef::Id(id) => id, - ast::WebidlTypeRef::Scalar(_) => { - bail!("webidl types for functions cannot be scalar") - } - }; - let ty = section - .types - .get::(id) - .ok_or_else(|| format_err!("invalid webidl custom section"))?; - let func = match ty { - ast::WebidlCompoundType::Function(f) => f, - _ => bail!("webidl type for function must be of function type"), - }; - func.params - .iter() - .map(|param| match param { - ast::WebidlTypeRef::Id(_) => bail!("function arguments cannot be compound"), - ast::WebidlTypeRef::Scalar(s) => Ok(*s), - }) - .collect() - } - ExportBindingKind::Raw(sig) => sig.params.iter().skip(2).map(abi2ast).collect(), - } - } - - /// Returns the list of binding expressions used to extract the return - /// values of this binding. - pub fn result_bindings(&self) -> Result> { - match &self.kind { - ExportBindingKind::Rich { binding, .. } => Ok(binding.result.bindings.clone()), - ExportBindingKind::Raw(sig) => sig - .returns - .iter() - .enumerate() - .map(|(i, param)| default_outgoing(i, param)) - .collect(), - } - } -} - -fn default_incoming(idx: usize, param: &ir::AbiParam) -> Result { - let get = ast::IncomingBindingExpressionGet { idx: idx as u32 }; - let ty = if param.value_type == ir::types::I32 { - walrus::ValType::I32 - } else if param.value_type == ir::types::I64 { - walrus::ValType::I64 - } else if param.value_type == ir::types::F32 { - walrus::ValType::F32 - } else if param.value_type == ir::types::F64 { - walrus::ValType::F64 - } else { - bail!("unsupported type {:?}", param.value_type) - }; - Ok(ast::IncomingBindingExpressionAs { - ty, - expr: Box::new(get.into()), - } - .into()) -} - -fn default_outgoing(idx: usize, param: &ir::AbiParam) -> Result { - let ty = abi2ast(param)?; - Ok(ast::OutgoingBindingExpressionAs { - ty: ty.into(), - idx: idx as u32, - } - .into()) -} - -fn abi2ast(param: &ir::AbiParam) -> Result { - Ok(if param.value_type == ir::types::I32 { - ast::WebidlScalarType::Long - } else if param.value_type == ir::types::I64 { - ast::WebidlScalarType::LongLong - } else if param.value_type == ir::types::F32 { - ast::WebidlScalarType::UnrestrictedFloat - } else if param.value_type == ir::types::F64 { - ast::WebidlScalarType::UnrestrictedDouble - } else { - bail!("unsupported type {:?}", param.value_type) - }) -} - -trait TranslateContext { - fn invoke_alloc(&mut self, alloc_func_name: &str, len: i32) -> Result; - unsafe fn get_memory(&mut self) -> Result<&mut [u8]>; -} - -struct InstanceTranslateContext(pub wasmtime::Instance); - -impl TranslateContext for InstanceTranslateContext { - fn invoke_alloc(&mut self, alloc_func_name: &str, len: i32) -> Result { - let alloc = self - .0 - .get_export(alloc_func_name) - .ok_or_else(|| format_err!("failed to find alloc function `{}`", alloc_func_name))? - .func() - .ok_or_else(|| format_err!("`{}` is not a (alloc) function", alloc_func_name))? - .clone(); - let alloc_args = vec![wasmtime::Val::I32(len)]; - let results = alloc.call(&alloc_args)?; - if results.len() != 1 { - bail!("allocator function wrong number of results"); - } - Ok(match results[0] { - wasmtime::Val::I32(i) => i, - _ => bail!("allocator function bad return type"), - }) - } - unsafe fn get_memory(&mut self) -> Result<&mut [u8]> { - let memory = self - .0 - .get_export("memory") - .ok_or_else(|| format_err!("failed to find `memory` export"))? - .memory() - .ok_or_else(|| format_err!("`memory` is not a memory"))? - .clone(); - let ptr = memory.data_ptr(); - let len = memory.data_size(); - Ok(std::slice::from_raw_parts_mut(ptr, len)) - } -} - -fn translate_incoming( - cx: &mut dyn TranslateContext, - bindings: &[ast::IncomingBindingExpression], - args: &[Value], -) -> Result> { - let get = |expr: &ast::IncomingBindingExpression| match expr { - ast::IncomingBindingExpression::Get(g) => args - .get(g.idx as usize) - .ok_or_else(|| format_err!("argument index out of bounds: {}", g.idx)), - _ => bail!("unsupported incoming binding expr {:?}", expr), - }; - - let mut copy = |alloc_func_name: &str, bytes: &[u8]| -> Result<(i32, i32)> { - let len = i32::try_from(bytes.len()).map_err(|_| format_err!("length overflow"))?; - let ptr = cx.invoke_alloc(alloc_func_name, len)?; - unsafe { - let raw = cx.get_memory()?; - raw[ptr as usize..][..bytes.len()].copy_from_slice(bytes) - } - - Ok((ptr, len)) - }; - - let mut wasm = Vec::new(); - - for expr in bindings { - match expr { - ast::IncomingBindingExpression::AllocUtf8Str(g) => { - let val = match get(&g.expr)? { - Value::String(s) => s, - _ => bail!("expected a string"), - }; - let (ptr, len) = copy(&g.alloc_func_name, val.as_bytes())?; - wasm.push(Val::I32(ptr)); - wasm.push(Val::I32(len)); - } - ast::IncomingBindingExpression::As(g) => { - let val = get(&g.expr)?; - match g.ty { - walrus::ValType::I32 => match val { - Value::I32(i) => wasm.push(Val::I32(*i)), - Value::U32(i) => wasm.push(Val::I32(*i as i32)), - _ => bail!("cannot convert {:?} to `i32`", val), - }, - walrus::ValType::I64 => match val { - Value::I32(i) => wasm.push(Val::I64((*i).into())), - Value::U32(i) => wasm.push(Val::I64((*i).into())), - Value::I64(i) => wasm.push(Val::I64(*i)), - Value::U64(i) => wasm.push(Val::I64(*i as i64)), - _ => bail!("cannot convert {:?} to `i64`", val), - }, - walrus::ValType::F32 => match val { - Value::F32(i) => wasm.push(Val::F32(i.to_bits())), - _ => bail!("cannot convert {:?} to `f32`", val), - }, - walrus::ValType::F64 => match val { - Value::F32(i) => wasm.push(Val::F64((*i as f64).to_bits())), - Value::F64(i) => wasm.push(Val::F64(i.to_bits())), - _ => bail!("cannot convert {:?} to `f64`", val), - }, - walrus::ValType::V128 | walrus::ValType::Anyref => { - bail!("unsupported `as` type {:?}", g.ty); - } - } - } - _ => bail!("unsupported incoming binding expr {:?}", expr), - } - } - - Ok(wasm) -} - -fn translate_outgoing( - cx: &mut dyn TranslateContext, - bindings: &[ast::OutgoingBindingExpression], - args: &[Val], -) -> Result> { - let mut values = Vec::new(); - - let get = |idx: u32| { - args.get(idx as usize) - .cloned() - .ok_or_else(|| format_err!("argument index out of bounds: {}", idx)) - }; - - for expr in bindings { - match expr { - ast::OutgoingBindingExpression::As(a) => { - let arg = get(a.idx)?; - match a.ty { - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLong) => match arg { - Val::I32(a) => values.push(Value::U32(a as u32)), - _ => bail!("can't convert {:?} to unsigned long", arg), - }, - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Long) => match arg { - Val::I32(a) => values.push(Value::I32(a)), - _ => bail!("can't convert {:?} to long", arg), - }, - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::LongLong) => match arg { - Val::I32(a) => values.push(Value::I64(a as i64)), - Val::I64(a) => values.push(Value::I64(a)), - _ => bail!("can't convert {:?} to long long", arg), - }, - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::UnsignedLongLong) => { - match arg { - Val::I32(a) => values.push(Value::U64(a as u64)), - Val::I64(a) => values.push(Value::U64(a as u64)), - _ => bail!("can't convert {:?} to unsigned long long", arg), - } - } - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Float) => match arg { - Val::F32(a) => values.push(Value::F32(f32::from_bits(a))), - _ => bail!("can't convert {:?} to float", arg), - }, - ast::WebidlTypeRef::Scalar(ast::WebidlScalarType::Double) => match arg { - Val::F32(a) => values.push(Value::F64(f32::from_bits(a) as f64)), - Val::F64(a) => values.push(Value::F64(f64::from_bits(a))), - _ => bail!("can't convert {:?} to double", arg), - }, - _ => bail!("unsupported outgoing binding expr {:?}", expr), - } - } - ast::OutgoingBindingExpression::Utf8Str(e) => { - if e.ty != ast::WebidlScalarType::DomString.into() { - bail!("utf-8 strings must go into dom-string") - } - let offset = match get(e.offset)? { - Val::I32(a) => a, - _ => bail!("offset must be an i32"), - }; - let length = match get(e.length)? { - Val::I32(a) => a, - _ => bail!("length must be an i32"), - }; - let bytes = unsafe { &cx.get_memory()?[offset as usize..][..length as usize] }; - values.push(Value::String(str::from_utf8(bytes).unwrap().to_string())); - } - _ => { - drop(cx); - bail!("unsupported outgoing binding expr {:?}", expr); - } - } - } - - Ok(values) -} diff --git a/crates/interface-types/src/value.rs b/crates/interface-types/src/value.rs deleted file mode 100644 index 84fc08119602..000000000000 --- a/crates/interface-types/src/value.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::convert::TryFrom; -use std::fmt; - -/// The set of all possible WebAssembly Interface Types -#[derive(Debug, Clone)] -#[allow(missing_docs)] -pub enum Value { - String(String), - I32(i32), - U32(u32), - I64(i64), - U64(u64), - F32(f32), - F64(f64), -} - -macro_rules! from { - ($($a:ident => $b:ident,)*) => ($( - impl From<$a> for Value { - fn from(val: $a) -> Value { - Value::$b(val) - } - } - - impl TryFrom for $a { - type Error = anyhow::Error; - - fn try_from(val: Value) -> Result<$a, Self::Error> { - match val { - Value::$b(v) => Ok(v), - v => anyhow::bail!("cannot convert {:?} to {}", v, stringify!($a)), - } - } - } - )*) -} - -from! { - String => String, - i32 => I32, - u32 => U32, - i64 => I64, - u64 => U64, - f32 => F32, - f64 => F64, -} - -impl<'a> From<&'a str> for Value { - fn from(x: &'a str) -> Value { - x.to_string().into() - } -} - -impl fmt::Display for Value { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Value::String(s) => s.fmt(f), - Value::I32(s) => s.fmt(f), - Value::U32(s) => s.fmt(f), - Value::I64(s) => s.fmt(f), - Value::U64(s) => s.fmt(f), - Value::F32(s) => s.fmt(f), - Value::F64(s) => s.fmt(f), - } - } -} diff --git a/crates/misc/py/Cargo.toml b/crates/misc/py/Cargo.toml index 001ae2930dfd..17233ebe3f40 100644 --- a/crates/misc/py/Cargo.toml +++ b/crates/misc/py/Cargo.toml @@ -18,7 +18,6 @@ doc = false [dependencies] wasmtime = { path = "../../api", version = "0.12.0" } -wasmtime-interface-types = { path = "../../interface-types", version = "0.12.0" } wasmtime-wasi = { path = "../../wasi", version = "0.12.0" } target-lexicon = { version = "0.10.0", default-features = false } anyhow = "1.0.19" diff --git a/crates/misc/rust/Cargo.toml b/crates/misc/rust/Cargo.toml index d5d2d5330993..303b71e92f98 100644 --- a/crates/misc/rust/Cargo.toml +++ b/crates/misc/rust/Cargo.toml @@ -15,7 +15,6 @@ test = false doctest = false [dependencies] -wasmtime-interface-types = { path = "../../interface-types", version = "0.12.0" } wasmtime-rust-macro = { path = "./macro", version = "0.12.0" } wasmtime-wasi = { path = "../../wasi", version = "0.12.0" } wasmtime = { path = "../../api", version = "0.12.0" } diff --git a/crates/misc/rust/examples/markdown.rs b/crates/misc/rust/examples/markdown.rs deleted file mode 100644 index dde903c57468..000000000000 --- a/crates/misc/rust/examples/markdown.rs +++ /dev/null @@ -1,13 +0,0 @@ -use wasmtime_rust::wasmtime; - -#[wasmtime] -trait WasmMarkdown { - fn render(&mut self, input: &str) -> String; -} - -fn main() -> anyhow::Result<()> { - let mut markdown = WasmMarkdown::load_file("markdown.wasm")?; - println!("{}", markdown.render("# Hello, Rust!")); - - Ok(()) -} diff --git a/crates/misc/rust/src/lib.rs b/crates/misc/rust/src/lib.rs index d976bf73a064..91b0e011bd1e 100644 --- a/crates/misc/rust/src/lib.rs +++ b/crates/misc/rust/src/lib.rs @@ -5,23 +5,21 @@ pub use wasmtime_rust_macro::wasmtime; pub mod __rt { pub use anyhow; pub use wasmtime; - pub use wasmtime_interface_types; pub use wasmtime_wasi; use std::convert::{TryFrom, TryInto}; - use wasmtime_interface_types::Value; pub trait FromVecValue: Sized { - fn from(list: Vec) -> anyhow::Result; + fn from(list: Vec) -> anyhow::Result; } macro_rules! tuple { ($(($($a:ident),*),)*) => ($( - impl<$($a: TryFrom),*> FromVecValue for ($($a,)*) + impl<$($a: TryFrom),*> FromVecValue for ($($a,)*) where $(anyhow::Error: From<$a::Error>,)* { #[allow(non_snake_case)] - fn from(list: Vec) -> anyhow::Result { + fn from(list: Vec) -> anyhow::Result { let mut iter = list.into_iter(); $( let $a = iter.next() diff --git a/docs/wasm-rust.md b/docs/wasm-rust.md index bb1ade14fb45..fe57e28e1d2d 100644 --- a/docs/wasm-rust.md +++ b/docs/wasm-rust.md @@ -133,6 +133,11 @@ interface types. ## WebAssembly Interface Types +> **Note**: support for interface types has temporarily removed from Wasmtime. +> This documentation is somewhat up to date but will no longer work with recent +> versions of Wasmtime. For more information see +> https://github.com/bytecodealliance/wasmtime/issues/677 + Working with WebAssembly modules at the bare-bones level means that you're only dealing with integers and floats. Many APIs, however, want to work with things like byte arrays, strings, structures, etc. To facilitate these interactions the diff --git a/scripts/publish-all.sh b/scripts/publish-all.sh index 253fafac0d09..8cdb2bf8b8c6 100755 --- a/scripts/publish-all.sh +++ b/scripts/publish-all.sh @@ -27,7 +27,6 @@ for cargo_toml in \ crates/api/Cargo.toml \ crates/wasi/Cargo.toml \ crates/wast/Cargo.toml \ - crates/interface-types/Cargo.toml \ crates/misc/py/Cargo.toml \ crates/misc/rust/macro/Cargo.toml \ crates/misc/rust/Cargo.toml \ diff --git a/scripts/test-all.sh b/scripts/test-all.sh index d1b590f9bc6d..fb270885c884 100755 --- a/scripts/test-all.sh +++ b/scripts/test-all.sh @@ -59,7 +59,6 @@ RUST_BACKTRACE=1 cargo test \ --package wasmtime-environ \ --package wasmtime-runtime \ --package wasmtime-jit \ - --package wasmtime-interface-types \ --package wasmtime-obj \ # Test wasmtime-wasi-c, which doesn't support Windows. diff --git a/src/commands/run.rs b/src/commands/run.rs index c0e9ca13c0fd..769491e6a663 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -10,8 +10,7 @@ use std::{ }; use structopt::{clap::AppSettings, StructOpt}; use wasi_common::preopen_dir; -use wasmtime::{Engine, Instance, Module, Store, Trap}; -use wasmtime_interface_types::ModuleData; +use wasmtime::{Engine, Instance, Module, Store, Trap, Val, ValType}; use wasmtime_wasi::{old::snapshot_0::Wasi as WasiSnapshot0, Wasi}; fn parse_module(s: &OsStr) -> Result { @@ -191,7 +190,7 @@ impl RunCommand { store: &Store, module_registry: &ModuleRegistry, path: &Path, - ) -> Result<(Instance, Module, Vec)> { + ) -> Result<(Instance, Module)> { // Read the wasm module binary either as `*.wat` or a raw binary let data = wat::parse_file(path)?; @@ -223,47 +222,46 @@ impl RunCommand { let instance = Instance::new(&module, &imports) .context(format!("failed to instantiate {:?}", path))?; - Ok((instance, module, data)) + Ok((instance, module)) } fn handle_module(&self, store: &Store, module_registry: &ModuleRegistry) -> Result<()> { - let (instance, module, data) = - Self::instantiate_module(store, module_registry, &self.module)?; + let (instance, module) = Self::instantiate_module(store, module_registry, &self.module)?; // If a function to invoke was given, invoke it. if let Some(name) = self.invoke.as_ref() { - let data = ModuleData::new(&data)?; - self.invoke_export(instance, &data, name)?; + self.invoke_export(instance, name)?; } else if module .exports() .iter() .any(|export| export.name().is_empty()) { // Launch the default command export. - let data = ModuleData::new(&data)?; - self.invoke_export(instance, &data, "")?; + self.invoke_export(instance, "")?; } else { // If the module doesn't have a default command export, launch the // _start function if one is present, as a compatibility measure. - let data = ModuleData::new(&data)?; - self.invoke_export(instance, &data, "_start")?; + self.invoke_export(instance, "_start")?; } Ok(()) } - fn invoke_export(&self, instance: Instance, data: &ModuleData, name: &str) -> Result<()> { - use wasm_webidl_bindings::ast; - use wasmtime_interface_types::Value; - - let mut handle = instance.handle().clone(); - - // Use the binding information in `ModuleData` to figure out what arguments - // need to be passed to the function that we're invoking. Currently we take - // the CLI parameters and attempt to parse them into function arguments for - // the function we'll invoke. - let binding = data.binding_for_export(&mut handle, name)?; - if !binding.param_types()?.is_empty() { + fn invoke_export(&self, instance: Instance, name: &str) -> Result<()> { + let pos = instance + .module() + .exports() + .iter() + .enumerate() + .find(|(_, e)| e.name() == name); + let (ty, export) = match pos { + Some((i, ty)) => match (ty.ty(), &instance.exports()[i]) { + (wasmtime::ExternType::Func(ty), wasmtime::Extern::Func(f)) => (ty, f), + _ => bail!("export of `{}` wasn't a function", name), + }, + None => bail!("failed to find export of `{}` in module", name), + }; + if ty.params().len() > 0 { eprintln!( "warning: using `--invoke` with a function that takes arguments \ is experimental and may break in the future" @@ -271,7 +269,7 @@ impl RunCommand { } let mut args = self.module_args.iter(); let mut values = Vec::new(); - for ty in binding.param_types()? { + for ty in ty.params() { let val = match args.next() { Some(s) => s, None => bail!("not enough arguments for `{}`", name), @@ -280,26 +278,18 @@ impl RunCommand { // TODO: integer parsing here should handle hexadecimal notation // like `0x0...`, but the Rust standard library currently only // parses base-10 representations. - ast::WebidlScalarType::Long => Value::I32(val.parse()?), - ast::WebidlScalarType::LongLong => Value::I64(val.parse()?), - ast::WebidlScalarType::UnsignedLong => Value::U32(val.parse()?), - ast::WebidlScalarType::UnsignedLongLong => Value::U64(val.parse()?), - - ast::WebidlScalarType::Float | ast::WebidlScalarType::UnrestrictedFloat => { - Value::F32(val.parse()?) - } - ast::WebidlScalarType::Double | ast::WebidlScalarType::UnrestrictedDouble => { - Value::F64(val.parse()?) - } - ast::WebidlScalarType::DomString => Value::String(val.to_string()), + ValType::I32 => Val::I32(val.parse()?), + ValType::I64 => Val::I64(val.parse()?), + ValType::F32 => Val::F32(val.parse()?), + ValType::F64 => Val::F64(val.parse()?), t => bail!("unsupported argument type {:?}", t), }); } // Invoke the function and then afterwards print all the results that came // out, if there are any. - let results = data - .invoke_export(&instance, name, &values) + let results = export + .call(&values) .with_context(|| format!("failed to invoke `{}`", name))?; if !results.is_empty() { eprintln!( @@ -307,8 +297,17 @@ impl RunCommand { is experimental and may break in the future" ); } - for result in results { - println!("{}", result); + + for result in results.into_vec() { + match result { + Val::I32(i) => println!("{}", i), + Val::I64(i) => println!("{}", i), + Val::F32(f) => println!("{}", f), + Val::F64(f) => println!("{}", f), + Val::AnyRef(_) => println!(""), + Val::FuncRef(_) => println!(""), + Val::V128(i) => println!("{}", i), + } } Ok(())