From f6f2b22e8d063cb6f1e838730d50977f1f3e1431 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Feb 2021 09:28:36 -0800 Subject: [PATCH 1/8] Update to the next version of the witx crate This commit updates to the 0.9 version of the witx crate implemented in WebAssembly/wasi#395. This new version drastically changes code generation and how we interface with the crate. The intention is to abstract the code generation aspects and allow code generators to implement much more low-level instructions to enable more flexible APIs in the future. Additionally a bunch of `*.witx` files were updated in the WASI repository. It's worth pointing out, however, that `wasi-common` does not change as a result of this change. The shape of the APIs that we need to implement are effectively the same and the only difference is that the shim functions generated by wiggle are a bit different. --- .gitmodules | 3 +- Cargo.lock | 13 +- crates/wasi-common/WASI | 2 +- crates/wiggle/Cargo.toml | 2 +- crates/wiggle/generate/Cargo.toml | 2 +- crates/wiggle/generate/src/error_transform.rs | 6 +- crates/wiggle/generate/src/funcs.rs | 573 +++++++++--------- crates/wiggle/generate/src/lib.rs | 5 +- crates/wiggle/generate/src/lifetimes.rs | 35 +- crates/wiggle/generate/src/module_trait.rs | 64 +- crates/wiggle/generate/src/names.rs | 82 +-- crates/wiggle/generate/src/types/enum.rs | 120 ---- crates/wiggle/generate/src/types/flags.rs | 46 +- crates/wiggle/generate/src/types/handle.rs | 2 - crates/wiggle/generate/src/types/int.rs | 100 --- crates/wiggle/generate/src/types/mod.rs | 56 +- .../src/types/{struct.rs => record.rs} | 10 +- .../src/types/{union.rs => variant.rs} | 77 ++- crates/wiggle/macro/Cargo.toml | 2 +- crates/wiggle/src/lib.rs | 6 + crates/wiggle/wasmtime/Cargo.toml | 2 +- crates/wiggle/wasmtime/macro/Cargo.toml | 2 +- crates/wiggle/wasmtime/macro/src/config.rs | 53 -- crates/wiggle/wasmtime/macro/src/lib.rs | 41 +- 24 files changed, 504 insertions(+), 800 deletions(-) delete mode 100644 crates/wiggle/generate/src/types/enum.rs delete mode 100644 crates/wiggle/generate/src/types/int.rs rename crates/wiggle/generate/src/types/{struct.rs => record.rs} (94%) rename crates/wiggle/generate/src/types/{union.rs => variant.rs} (50%) diff --git a/.gitmodules b/.gitmodules index ee264b99c477..305858152d30 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,7 +6,8 @@ url = https://github.com/WebAssembly/wasm-c-api [submodule "WASI"] path = crates/wasi-common/WASI - url = https://github.com/WebAssembly/WASI + url = https://github.com/alexcrichton/WASI + branch = abis [submodule "crates/wasi-nn/spec"] path = crates/wasi-nn/spec url = https://github.com/WebAssembly/wasi-nn diff --git a/Cargo.lock b/Cargo.lock index f402f5aef9c2..5675a0971b60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3496,18 +3496,18 @@ dependencies = [ [[package]] name = "wast" -version = "22.0.0" +version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe1220ed7f824992b426a76125a3403d048eaf0f627918e97ade0d9b9d510d20" +checksum = "c24a3ee360d01d60ed0a0f960ab76a6acce64348cdb0bf8699c2a866fad57c7c" dependencies = [ "leb128", ] [[package]] name = "wast" -version = "32.0.0" +version = "33.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24a3ee360d01d60ed0a0f960ab76a6acce64348cdb0bf8699c2a866fad57c7c" +checksum = "1d04fe175c7f78214971293e7d8875673804e736092206a3a4544dbc12811c1b" dependencies = [ "leb128", ] @@ -3631,15 +3631,16 @@ dependencies = [ [[package]] name = "witx" -version = "0.8.8" +version = "0.9.0" dependencies = [ "anyhow", "diff", "log", "pretty_env_logger", + "rayon", "structopt", "thiserror", - "wast 22.0.0", + "wast 33.0.0", ] [[package]] diff --git a/crates/wasi-common/WASI b/crates/wasi-common/WASI index 8deb71ddd095..7c4fd252d084 160000 --- a/crates/wasi-common/WASI +++ b/crates/wasi-common/WASI @@ -1 +1 @@ -Subproject commit 8deb71ddd0955101cb69333b08284e7b01775928 +Subproject commit 7c4fd252d0841488de4a6e724e600f1561797387 diff --git a/crates/wiggle/Cargo.toml b/crates/wiggle/Cargo.toml index d7bba56082e3..88c8315bdce0 100644 --- a/crates/wiggle/Cargo.toml +++ b/crates/wiggle/Cargo.toml @@ -12,7 +12,7 @@ include = ["src/**/*", "LICENSE"] [dependencies] thiserror = "1" -witx = { path = "../wasi-common/WASI/tools/witx", version = "0.8.7", optional = true } +witx = { path = "../wasi-common/WASI/tools/witx", version = "0.9", optional = true } wiggle-macro = { path = "macro", version = "0.23.0" } tracing = "0.1.15" bitflags = "1.2" diff --git a/crates/wiggle/generate/Cargo.toml b/crates/wiggle/generate/Cargo.toml index 54cb70d20d9c..1a7459a519a5 100644 --- a/crates/wiggle/generate/Cargo.toml +++ b/crates/wiggle/generate/Cargo.toml @@ -14,7 +14,7 @@ include = ["src/**/*", "LICENSE"] [lib] [dependencies] -witx = { version = "0.8.7", path = "../../wasi-common/WASI/tools/witx" } +witx = { version = "0.9", path = "../../wasi-common/WASI/tools/witx" } quote = "1.0" proc-macro2 = "1.0" heck = "0.3" diff --git a/crates/wiggle/generate/src/error_transform.rs b/crates/wiggle/generate/src/error_transform.rs index 3598e221de3f..56fa10eaf0ad 100644 --- a/crates/wiggle/generate/src/error_transform.rs +++ b/crates/wiggle/generate/src/error_transform.rs @@ -49,10 +49,14 @@ impl ErrorTransform { pub fn for_abi_error(&self, tref: &TypeRef) -> Option<&UserErrorType> { match tref { - TypeRef::Name(nt) => self.m.iter().find(|u| u.abi_type.name == nt.name), + TypeRef::Name(nt) => self.for_name(nt), TypeRef::Value { .. } => None, } } + + pub fn for_name(&self, nt: &NamedType) -> Option<&UserErrorType> { + self.m.iter().find(|u| u.abi_type.name == nt.name) + } } pub struct UserErrorType { diff --git a/crates/wiggle/generate/src/funcs.rs b/crates/wiggle/generate/src/funcs.rs index 50f5eec64044..8e164f878ba3 100644 --- a/crates/wiggle/generate/src/funcs.rs +++ b/crates/wiggle/generate/src/funcs.rs @@ -1,11 +1,12 @@ -use proc_macro2::TokenStream; -use quote::quote; - use crate::error_transform::ErrorTransform; use crate::lifetimes::anon_lifetime; use crate::module_trait::passed_by_reference; use crate::names::Names; use crate::types::WiggleType; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use std::mem; +use witx::Instruction; pub fn define_func( names: &Names, @@ -13,178 +14,54 @@ pub fn define_func( func: &witx::InterfaceFunc, errxform: &ErrorTransform, ) -> TokenStream { - let funcname = func.name.as_str(); - - let ident = names.func(&func.name); let rt = names.runtime_mod(); + let ident = names.func(&func.name); let ctx_type = names.ctx_type(); - let coretype = func.core_type(); - - let params = coretype.args.iter().map(|arg| { - let name = names.func_core_arg(arg); - let atom = names.atom_type(arg.repr()); - quote!(#name : #atom) - }); - - let abi_args = quote!( - ctx: &#ctx_type, - memory: &dyn #rt::GuestMemory, - #(#params),* - ); - let abi_ret = if let Some(ret) = &coretype.ret { - match ret.signifies { - witx::CoreParamSignifies::Value(atom) => names.atom_type(atom), - _ => unreachable!("ret should always be passed by value"), - } - } else { - quote!(()) - }; - let err_type = coretype.ret.clone().map(|ret| ret.param.tref); - let ret_err = coretype - .ret - .map(|ret| { - let name = names.func_param(&ret.param.name); - let conversion = if let Some(user_err) = errxform.for_abi_error(&ret.param.tref) { - let method = names.user_error_conversion_method(&user_err); - quote!(UserErrorConversion::#method(ctx, e)) - } else { - quote!(Ok(e)) - }; - quote! { - let e = #conversion; - #rt::tracing::event!( - #rt::tracing::Level::TRACE, - #name = #rt::tracing::field::debug(&e), - ); - match e { - Ok(e) => { return Ok(#abi_ret::from(e)); }, - Err(e) => { return Err(e); }, - } - } - }) - .unwrap_or_else(|| quote!(())); - - let error_handling = |location: &str| -> TokenStream { - if let Some(tref) = &err_type { - let abi_ret = match tref.type_().passed_by() { - witx::TypePassedBy::Value(atom) => names.atom_type(atom), - _ => unreachable!("err should always be passed by value"), - }; - let err_typename = names.type_ref(&tref, anon_lifetime()); - let err_method = names.guest_error_conversion_method(&tref); - quote! { - let e = #rt::GuestError::InFunc { funcname: #funcname, location: #location, err: Box::new(e.into()) }; - let err: #err_typename = GuestErrorConversion::#err_method(ctx, e); - return Ok(#abi_ret::from(err)); - } - } else { - quote! { - panic!("error: {:?}", e) - } - } - }; - - let marshal_args = func - .params - .iter() - .map(|p| marshal_arg(names, p, error_handling(p.name.as_str()))); - let trait_args = func.params.iter().map(|param| { - let name = names.func_param(¶m.name); - if passed_by_reference(&*param.tref.type_()) { - quote!(&#name) - } else { - quote!(#name) - } + let (wasm_params, wasm_results) = func.wasm_signature(); + let param_names = (0..wasm_params.len()) + .map(|i| Ident::new(&format!("arg{}", i), Span::call_site())) + .collect::>(); + let abi_params = wasm_params.iter().zip(¶m_names).map(|(arg, name)| { + let wasm = names.wasm_type(*arg); + quote!(#name : #wasm) }); - let log_marshalled_args = if func.params.len() > 0 { - let rt = names.runtime_mod(); - let args = func.params.iter().map(|param| { - let name = names.func_param(¶m.name); - if param.impls_display() { - quote!( #name = #rt::tracing::field::display(&#name) ) - } else { - quote!( #name = #rt::tracing::field::debug(&#name) ) - } - }); - quote! { - #rt::tracing::event!(#rt::tracing::Level::TRACE, #(#args),*); + let abi_ret = match wasm_results.len() { + 0 => quote!(()), + 1 => { + let ty = names.wasm_type(wasm_results[0]); + quote!(#ty) } - } else { - quote!() - }; - - let (trait_rets, trait_bindings) = if func.results.len() < 2 { - (quote!({}), quote!(_)) - } else { - let trait_rets: Vec<_> = func - .results - .iter() - .skip(1) - .map(|result| names.func_param(&result.name)) - .collect(); - let bindings = quote!((#(#trait_rets),*)); - let trace_rets = func.results.iter().skip(1).map(|result| { - let name = names.func_param(&result.name); - if result.tref.impls_display() { - quote!(#name = #rt::tracing::field::display(&#name)) - } else { - quote!(#name = #rt::tracing::field::debug(&#name)) - } - }); - let rets = quote! { - #rt::tracing::event!(#rt::tracing::Level::TRACE, #(#trace_rets),*); - (#(#trait_rets),*) - }; - (rets, bindings) + _ => unimplemented!(), }; - // Return value pointers need to be validated before the api call, then - // assigned to afterwards. marshal_result returns these two statements as a pair. - let marshal_rets = func - .results - .iter() - .skip(1) - .map(|result| marshal_result(names, result, &error_handling)); - let marshal_rets_pre = marshal_rets.clone().map(|(pre, _post)| pre); - let marshal_rets_post = marshal_rets.map(|(_pre, post)| post); - - let success = if let Some(ref err_type) = err_type { - let err_typename = names.type_ref(&err_type, anon_lifetime()); - quote! { - let success:#err_typename = #rt::GuestErrorType::success(); - #rt::tracing::event!( - #rt::tracing::Level::TRACE, - success=#rt::tracing::field::display(&success) - ); - Ok(#abi_ret::from(success)) - } - } else { - quote!(Ok(())) - }; + let mut body = TokenStream::new(); + func.call_interface( + &module.name, + &mut Rust { + src: &mut body, + params: ¶m_names, + block_storage: Vec::new(), + blocks: Vec::new(), + rt: &rt, + names, + module, + funcname: func.name.as_str(), + errxform, + }, + ); - let trait_name = names.trait_name(&module.name); let mod_name = &module.name.as_str(); let func_name = &func.name.as_str(); + quote! { + pub fn #ident( + ctx: &#ctx_type, + memory: &dyn #rt::GuestMemory, + #(#abi_params),* + ) -> Result<#abi_ret, #rt::Trap> { + use std::convert::TryFrom as _; - if func.noreturn { - quote!(pub fn #ident(#abi_args) -> Result<#abi_ret, #rt::Trap> { - let _span = #rt::tracing::span!( - #rt::tracing::Level::TRACE, - "wiggle abi", - module = #mod_name, - function = #func_name - ); - let _enter = _span.enter(); - - #(#marshal_args)* - #log_marshalled_args - let trap = #trait_name::#ident(ctx, #(#trait_args),*); - Err(trap) - }) - } else { - quote!(pub fn #ident(#abi_args) -> Result<#abi_ret, #rt::Trap> { let _span = #rt::tracing::span!( #rt::tracing::Level::TRACE, "wiggle abi", @@ -193,161 +70,259 @@ pub fn define_func( ); let _enter = _span.enter(); - #(#marshal_args)* - #(#marshal_rets_pre)* - #log_marshalled_args - let #trait_bindings = match #trait_name::#ident(ctx, #(#trait_args),*) { - Ok(#trait_bindings) => { #trait_rets }, - Err(e) => { #ret_err }, - }; - #(#marshal_rets_post)* - #success - }) + #body + } } } -fn marshal_arg( - names: &Names, - param: &witx::InterfaceFuncParam, - error_handling: TokenStream, -) -> TokenStream { - let rt = names.runtime_mod(); - let tref = ¶m.tref; - let interface_typename = names.type_ref(&tref, anon_lifetime()); - - let try_into_conversion = { - let name = names.func_param(¶m.name); - quote! { - let #name: #interface_typename = { - use ::std::convert::TryInto; - match #name.try_into() { - Ok(a) => a, - Err(e) => { - #error_handling - } +struct Rust<'a> { + src: &'a mut TokenStream, + params: &'a [Ident], + block_storage: Vec, + blocks: Vec, + rt: &'a TokenStream, + names: &'a Names, + module: &'a witx::Module, + funcname: &'a str, + errxform: &'a ErrorTransform, +} + +impl witx::Bindgen for Rust<'_> { + type Operand = TokenStream; + + fn push_block(&mut self) { + let prev = mem::replace(self.src, TokenStream::new()); + self.block_storage.push(prev); + } + + fn finish_block(&mut self, operand: Option) { + let to_restore = self.block_storage.pop().unwrap(); + let src = mem::replace(self.src, to_restore); + match operand { + None => self.blocks.push(src), + Some(s) => { + if src.is_empty() { + self.blocks.push(s); + } else { + self.blocks.push(quote!({ #src; #s })); } - }; + } } - }; + } - let read_conversion = { - let pointee_type = names.type_ref(tref, anon_lifetime()); - let arg_name = names.func_ptr_binding(¶m.name); - let name = names.func_param(¶m.name); - quote! { - let #name = match #rt::GuestPtr::<#pointee_type>::new(memory, #arg_name as u32).read() { - Ok(r) => r, - Err(e) => { - #error_handling + // This is only used for `call_wasm` at this time. + fn allocate_space(&mut self, _: usize, _: &witx::NamedType) { + unimplemented!() + } + + fn emit( + &mut self, + inst: &Instruction<'_>, + operands: &mut Vec, + results: &mut Vec, + ) { + let rt = self.rt; + let wrap_err = |location: &str| { + let funcname = self.funcname; + quote! { + |e| { + #rt::GuestError::InFunc { + funcname: #funcname, + location: #location, + err: Box::new(#rt::GuestError::from(e)), + } } - }; - } - }; + } + }; + + let mut try_from = |ty: TokenStream| { + let val = operands.pop().unwrap(); + let wrap_err = wrap_err(&format!("convert {}", ty)); + results.push(quote!(#ty::try_from(#val).map_err(#wrap_err)?)); + }; + + match inst { + Instruction::GetArg { nth } => { + let param = &self.params[*nth]; + results.push(quote!(#param)); + } - match &*tref.type_() { - witx::Type::Enum(_e) => try_into_conversion, - witx::Type::Flags(_f) => try_into_conversion, - witx::Type::Int(_i) => try_into_conversion, - witx::Type::Builtin(b) => match b { - witx::BuiltinType::U8 | witx::BuiltinType::U16 | witx::BuiltinType::Char8 => { - try_into_conversion + Instruction::PointerFromI32 { ty } | Instruction::ConstPointerFromI32 { ty } => { + let val = operands.pop().unwrap(); + let pointee_type = self.names.type_ref(ty, anon_lifetime()); + results.push(quote! { + #rt::GuestPtr::<#pointee_type>::new(memory, #val as u32) + }); } - witx::BuiltinType::S8 | witx::BuiltinType::S16 => { - let name = names.func_param(¶m.name); - quote! { - let #name: #interface_typename = match (#name as i32).try_into() { - Ok(a) => a, - Err(e) => { - #error_handling - } + + Instruction::ListFromPointerLength { ty } => { + let ptr = &operands[0]; + let len = &operands[1]; + let ty = match &**ty.type_() { + witx::Type::Builtin(witx::BuiltinType::Char) => quote!(str), + _ => { + let ty = self.names.type_ref(ty, anon_lifetime()); + quote!([#ty]) } - } + }; + results.push(quote! { + #rt::GuestPtr::<#ty>::new(memory, (#ptr as u32, #len as u32)); + }) } - witx::BuiltinType::U32 - | witx::BuiltinType::S32 - | witx::BuiltinType::U64 - | witx::BuiltinType::S64 - | witx::BuiltinType::USize - | witx::BuiltinType::F32 - | witx::BuiltinType::F64 => { - let name = names.func_param(¶m.name); - quote! { - let #name = #name as #interface_typename; + + Instruction::CallInterface { func, .. } => { + // Use the `tracing` crate to log all arguments that are going + // out, and afterwards we call the function with those bindings. + let mut args = Vec::new(); + for (i, param) in func.params.iter().enumerate() { + let name = self.names.func_param(¶m.name); + let val = &operands[i]; + self.src.extend(quote!(let #name = #val;)); + if passed_by_reference(param.tref.type_()) { + args.push(quote!(&#name)); + } else { + args.push(quote!(#name)); + } } - } - witx::BuiltinType::String => { - let lifetime = anon_lifetime(); - let ptr_name = names.func_ptr_binding(¶m.name); - let len_name = names.func_len_binding(¶m.name); - let name = names.func_param(¶m.name); - quote! { - let #name = #rt::GuestPtr::<#lifetime, str>::new(memory, (#ptr_name as u32, #len_name as u32)); + if func.params.len() > 0 { + let args = func + .params + .iter() + .map(|param| { + let name = self.names.func_param(¶m.name); + if param.impls_display() { + quote!( #name = #rt::tracing::field::display(&#name) ) + } else { + quote!( #name = #rt::tracing::field::debug(&#name) ) + } + }) + .collect::>(); + self.src.extend(quote! { + #rt::tracing::event!(#rt::tracing::Level::TRACE, #(#args),*); + }); + } + + let trait_name = self.names.trait_name(&self.module.name); + let ident = self.names.func(&func.name); + self.src.extend(quote! { + let ret = #trait_name::#ident(ctx, #(#args),*); + #rt::tracing::event!( + #rt::tracing::Level::TRACE, + result = #rt::tracing::field::debug(&ret), + ); + }); + + if func.results.len() > 0 { + results.push(quote!(ret)); + } else if func.noreturn { + self.src.extend(quote!(return Err(ret))); } } - }, - witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { - let pointee_type = names.type_ref(pointee, anon_lifetime()); - let name = names.func_param(¶m.name); - quote! { - let #name = #rt::GuestPtr::<#pointee_type>::new(memory, #name as u32); + + // Lowering an enum is typically simple but if we have an error + // transformation registered for this enum then what we're actually + // doing is lowering from a user-defined error type to the error + // enum, and *then* we lower to an i32. + Instruction::EnumLower { ty } => { + let val = operands.pop().unwrap(); + let val = match self.errxform.for_name(ty) { + Some(custom) => { + let method = self.names.user_error_conversion_method(&custom); + quote!(UserErrorConversion::#method(ctx, #val)?) + } + None => val, + }; + results.push(quote!(#val as i32)); } - } - witx::Type::Struct(_) => read_conversion, - witx::Type::Array(arr) => { - let pointee_type = names.type_ref(arr, anon_lifetime()); - let ptr_name = names.func_ptr_binding(¶m.name); - let len_name = names.func_len_binding(¶m.name); - let name = names.func_param(¶m.name); - quote! { - let #name = #rt::GuestPtr::<[#pointee_type]>::new(memory, (#ptr_name as u32, #len_name as u32)); + + Instruction::ResultLower { err: err_ty, .. } => { + let err = self.blocks.pop().unwrap(); + let ok = self.blocks.pop().unwrap(); + let val = operands.pop().unwrap(); + let err_typename = self.names.type_ref(err_ty.unwrap(), anon_lifetime()); + results.push(quote! { + match #val { + Ok(e) => { #ok; <#err_typename as #rt::GuestErrorType>::success() as i32 } + Err(e) => { #err } + } + }); } - } - witx::Type::Union(_u) => read_conversion, - witx::Type::Handle(_h) => { - let name = names.func_param(¶m.name); - let handle_type = names.type_ref(tref, anon_lifetime()); - quote!( let #name = #handle_type::from(#name); ) - } - } -} -fn marshal_result( - names: &Names, - result: &witx::InterfaceFuncParam, - error_handling: F, -) -> (TokenStream, TokenStream) -where - F: Fn(&str) -> TokenStream, -{ - let rt = names.runtime_mod(); - let tref = &result.tref; - - let write_val_to_ptr = { - let pointee_type = names.type_ref(tref, anon_lifetime()); - // core type is given func_ptr_binding name. - let ptr_name = names.func_ptr_binding(&result.name); - let ptr_err_handling = error_handling(&format!("{}:result_ptr_mut", result.name.as_str())); - let pre = quote! { - let #ptr_name = #rt::GuestPtr::<#pointee_type>::new(memory, #ptr_name as u32); - }; - // trait binding returns func_param name. - let val_name = names.func_param(&result.name); - let post = quote! { - if let Err(e) = #ptr_name.write(#val_name) { - #ptr_err_handling + Instruction::VariantPayload => results.push(quote!(e)), + + Instruction::Return { amt: 0 } => {} + Instruction::Return { amt: 1 } => { + let val = operands.pop().unwrap(); + self.src.extend(quote!(return Ok(#val))); } - }; - (pre, post) - }; + Instruction::Return { .. } => unimplemented!(), - match &*tref.type_() { - witx::Type::Builtin(b) => match b { - witx::BuiltinType::String => unimplemented!("string result types"), - _ => write_val_to_ptr, - }, - witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } | witx::Type::Array { .. } => { - unimplemented!("pointer/array result types") + Instruction::TupleLower { amt } => { + let names = (0..*amt) + .map(|i| Ident::new(&format!("t{}", i), Span::call_site())) + .collect::>(); + let val = operands.pop().unwrap(); + self.src.extend(quote!( let (#(#names,)*) = #val;)); + results.extend(names.iter().map(|i| quote!(#i))); + } + + Instruction::Store { ty } => { + let ptr = operands.pop().unwrap(); + let val = operands.pop().unwrap(); + let wrap_err = wrap_err(&format!("write {}", ty.name.as_str())); + let pointee_type = self.names.type_(&ty.name); + self.src.extend(quote! { + #rt::GuestPtr::<#pointee_type>::new(memory, #ptr as u32) + .write(#val) + .map_err(#wrap_err)?; + }); + } + + Instruction::HandleFromI32 { ty } => { + let val = operands.pop().unwrap(); + let ty = self.names.type_(&ty.name); + results.push(quote!(#ty::from(#val))); + } + + // Smaller-than-32 numerical conversions are done with `TryFrom` to + // ensure we're not losing bits. + Instruction::U8FromI32 => try_from(quote!(u8)), + Instruction::S8FromI32 => try_from(quote!(i8)), + Instruction::Char8FromI32 => try_from(quote!(u8)), + Instruction::U16FromI32 => try_from(quote!(u16)), + Instruction::S16FromI32 => try_from(quote!(i16)), + + // Conversions with matching bit-widths but different signededness + // use `as` since we're basically just reinterpreting the bits. + Instruction::U32FromI32 => { + let val = operands.pop().unwrap(); + results.push(quote!(#val as u32)); + } + Instruction::U64FromI64 => { + let val = operands.pop().unwrap(); + results.push(quote!(#val as u64)); + } + + // Conversions to enums/bitflags use `TryFrom` to ensure that the + // values are valid coming in. + Instruction::EnumLift { ty } + | Instruction::BitflagsFromI64 { ty } + | Instruction::BitflagsFromI32 { ty } => { + let ty = self.names.type_(&ty.name); + try_from(quote!(#ty)) + } + + // No conversions necessary for these, the native wasm type matches + // our own representation. + Instruction::If32FromF32 + | Instruction::If64FromF64 + | Instruction::S32FromI32 + | Instruction::S64FromI64 => results.push(operands.pop().unwrap()), + + // There's a number of other instructions we could implement but + // they're not exercised by WASI at this time. As necessary we can + // add code to implement them. + other => panic!("no implementation for {:?}", other), } - _ => write_val_to_ptr, } } diff --git a/crates/wiggle/generate/src/lib.rs b/crates/wiggle/generate/src/lib.rs index b9a07f93ce26..3eb359bc670c 100644 --- a/crates/wiggle/generate/src/lib.rs +++ b/crates/wiggle/generate/src/lib.rs @@ -6,11 +6,10 @@ mod module_trait; mod names; mod types; +use lifetimes::anon_lifetime; use proc_macro2::TokenStream; use quote::quote; -use lifetimes::anon_lifetime; - pub use config::Config; pub use error_transform::{ErrorTransform, UserErrorType}; pub use funcs::define_func; @@ -67,6 +66,8 @@ pub fn generate(doc: &witx::Document, names: &Names, errs: &ErrorTransform) -> T quote!( pub mod types { + use std::convert::TryFrom; + #(#types)* #guest_error_conversion #user_error_conversion diff --git a/crates/wiggle/generate/src/lifetimes.rs b/crates/wiggle/generate/src/lifetimes.rs index 75b102209c02..87b1aad9a479 100644 --- a/crates/wiggle/generate/src/lifetimes.rs +++ b/crates/wiggle/generate/src/lifetimes.rs @@ -19,46 +19,37 @@ impl LifetimeExt for witx::Type { fn is_transparent(&self) -> bool { match self { witx::Type::Builtin(b) => b.is_transparent(), - witx::Type::Struct(s) => s.is_transparent(), - witx::Type::Enum { .. } - | witx::Type::Flags { .. } - | witx::Type::Int { .. } - | witx::Type::Handle { .. } => true, - witx::Type::Union { .. } + witx::Type::Record(s) => s.is_transparent(), + witx::Type::Handle { .. } => true, + witx::Type::Variant { .. } | witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } - | witx::Type::Array { .. } => false, + | witx::Type::List { .. } => false, } } fn needs_lifetime(&self) -> bool { match self { witx::Type::Builtin(b) => b.needs_lifetime(), - witx::Type::Struct(s) => s.needs_lifetime(), - witx::Type::Union(u) => u.needs_lifetime(), - witx::Type::Enum { .. } - | witx::Type::Flags { .. } - | witx::Type::Int { .. } - | witx::Type::Handle { .. } => false, + witx::Type::Record(s) => s.needs_lifetime(), + witx::Type::Variant(u) => u.needs_lifetime(), + witx::Type::Handle { .. } => false, witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } - | witx::Type::Array { .. } => true, + | witx::Type::List { .. } => true, } } } impl LifetimeExt for witx::BuiltinType { fn is_transparent(&self) -> bool { - !self.needs_lifetime() + true } fn needs_lifetime(&self) -> bool { - match self { - witx::BuiltinType::String => true, - _ => false, - } + false } } -impl LifetimeExt for witx::StructDatatype { +impl LifetimeExt for witx::RecordDatatype { fn is_transparent(&self) -> bool { self.members.iter().all(|m| m.tref.is_transparent()) } @@ -67,12 +58,12 @@ impl LifetimeExt for witx::StructDatatype { } } -impl LifetimeExt for witx::UnionDatatype { +impl LifetimeExt for witx::Variant { fn is_transparent(&self) -> bool { false } fn needs_lifetime(&self) -> bool { - self.variants + self.cases .iter() .any(|m| m.tref.as_ref().map(|t| t.needs_lifetime()).unwrap_or(false)) } diff --git a/crates/wiggle/generate/src/module_trait.rs b/crates/wiggle/generate/src/module_trait.rs index a7a7289d09ee..92e503ddda90 100644 --- a/crates/wiggle/generate/src/module_trait.rs +++ b/crates/wiggle/generate/src/module_trait.rs @@ -7,17 +7,9 @@ use crate::names::Names; use witx::Module; pub fn passed_by_reference(ty: &witx::Type) -> bool { - let passed_by = match ty.passed_by() { - witx::TypePassedBy::Value { .. } => false, - witx::TypePassedBy::Pointer { .. } | witx::TypePassedBy::PointerLengthPair { .. } => true, - }; match ty { - witx::Type::Builtin(b) => match &*b { - witx::BuiltinType::String => true, - _ => passed_by, - }, - witx::Type::Pointer(_) | witx::Type::ConstPointer(_) | witx::Type::Array(_) => true, - _ => passed_by, + witx::Type::Pointer(_) | witx::Type::ConstPointer(_) | witx::Type::List(_) => true, + _ => false, } } @@ -49,28 +41,36 @@ pub fn define_module_trait(names: &Names, m: &Module, errxform: &ErrorTransform) quote!(#arg_name: #arg_type) }); - let result = if !f.noreturn { - let rets = f - .results - .iter() - .skip(1) - .map(|ret| names.type_ref(&ret.tref, lifetime.clone())); - let err = f - .results - .get(0) - .map(|err_result| { - if let Some(custom_err) = errxform.for_abi_error(&err_result.tref) { - let tn = custom_err.typename(); - quote!(super::#tn) - } else { - names.type_ref(&err_result.tref, lifetime.clone()) - } - }) - .unwrap_or(quote!(())); - quote!( Result<(#(#rets),*), #err> ) - } else { - let rt = names.runtime_mod(); - quote!(#rt::Trap) + let rt = names.runtime_mod(); + let result = match f.results.len() { + 0 if f.noreturn => quote!(#rt::Trap), + 0 => quote!(()), + 1 => { + let (ok, err) = match &**f.results[0].tref.type_() { + witx::Type::Variant(v) => match v.as_expected() { + Some(p) => p, + None => unimplemented!("anonymous variant ref {:?}", v), + }, + _ => unimplemented!(), + }; + + let ok = match ok { + Some(ty) => names.type_ref(ty, lifetime.clone()), + None => quote!(()), + }; + let err = match err { + Some(ty) => match errxform.for_abi_error(ty) { + Some(custom) => { + let tn = custom.typename(); + quote!(super::#tn) + } + None => names.type_ref(ty, lifetime.clone()), + }, + None => quote!(()), + }; + quote!(Result<#ok, #err>) + } + _ => unimplemented!(), }; if is_anonymous { diff --git a/crates/wiggle/generate/src/names.rs b/crates/wiggle/generate/src/names.rs index f6266ec41f97..b9eb9e47528f 100644 --- a/crates/wiggle/generate/src/names.rs +++ b/crates/wiggle/generate/src/names.rs @@ -2,7 +2,7 @@ use escaping::{escape_id, handle_2big_enum_variant, NamingConvention}; use heck::{ShoutySnakeCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; -use witx::{AtomType, BuiltinType, Id, Type, TypeRef}; +use witx::{BuiltinType, Id, Type, TypeRef, WasmType}; use crate::{lifetimes::LifetimeExt, UserErrorType}; @@ -32,15 +32,11 @@ impl Names { quote!(#ident) } - pub fn builtin_type(&self, b: BuiltinType, lifetime: TokenStream) -> TokenStream { + pub fn builtin_type(&self, b: BuiltinType) -> TokenStream { match b { - BuiltinType::String => { - let rt = self.runtime_mod(); - quote!(#rt::GuestPtr<#lifetime, str>) - } - BuiltinType::U8 => quote!(u8), + BuiltinType::U8 { .. } => quote!(u8), BuiltinType::U16 => quote!(u16), - BuiltinType::U32 => quote!(u32), + BuiltinType::U32 { .. } => quote!(u32), BuiltinType::U64 => quote!(u64), BuiltinType::S8 => quote!(i8), BuiltinType::S16 => quote!(i16), @@ -48,16 +44,16 @@ impl Names { BuiltinType::S64 => quote!(i64), BuiltinType::F32 => quote!(f32), BuiltinType::F64 => quote!(f64), - BuiltinType::Char8 => quote!(u8), - BuiltinType::USize => quote!(u32), + BuiltinType::Char => quote!(char), } } - pub fn atom_type(&self, atom: AtomType) -> TokenStream { - match atom { - AtomType::I32 => quote!(i32), - AtomType::I64 => quote!(i64), - AtomType::F32 => quote!(f32), - AtomType::F64 => quote!(f64), + + pub fn wasm_type(&self, ty: WasmType) -> TokenStream { + match ty { + WasmType::I32 => quote!(i32), + WasmType::I64 => quote!(i64), + WasmType::F32 => quote!(f32), + WasmType::F64 => quote!(f64), } } @@ -72,16 +68,44 @@ impl Names { } } TypeRef::Value(ty) => match &**ty { - Type::Builtin(builtin) => self.builtin_type(*builtin, lifetime.clone()), + Type::Builtin(builtin) => self.builtin_type(*builtin), Type::Pointer(pointee) | Type::ConstPointer(pointee) => { let rt = self.runtime_mod(); let pointee_type = self.type_ref(&pointee, lifetime.clone()); quote!(#rt::GuestPtr<#lifetime, #pointee_type>) } - Type::Array(pointee) => { - let rt = self.runtime_mod(); - let pointee_type = self.type_ref(&pointee, lifetime.clone()); - quote!(#rt::GuestPtr<#lifetime, [#pointee_type]>) + Type::List(pointee) => match &**pointee.type_() { + Type::Builtin(BuiltinType::Char) => { + let rt = self.runtime_mod(); + quote!(#rt::GuestPtr<#lifetime, str>) + } + _ => { + let rt = self.runtime_mod(); + let pointee_type = self.type_ref(&pointee, lifetime.clone()); + quote!(#rt::GuestPtr<#lifetime, [#pointee_type]>) + } + }, + Type::Variant(v) => match v.as_expected() { + Some((ok, err)) => { + let ok = match ok { + Some(ty) => self.type_ref(ty, lifetime.clone()), + None => quote!(()), + }; + let err = match err { + Some(ty) => self.type_ref(ty, lifetime.clone()), + None => quote!(()), + }; + quote!(Result<#ok, #err>) + } + None => unimplemented!("anonymous variant ref {:?}", tref), + }, + Type::Record(r) if r.is_tuple() => { + let types = r + .members + .iter() + .map(|m| self.type_ref(&m.tref, lifetime.clone())) + .collect::>(); + quote!((#(#types,)*)) } _ => unimplemented!("anonymous type ref {:?}", tref), }, @@ -144,14 +168,6 @@ impl Names { escape_id(id, NamingConvention::SnakeCase) } - pub fn func_core_arg(&self, arg: &witx::CoreParamType) -> Ident { - match arg.signifies { - witx::CoreParamSignifies::Value { .. } => self.func_param(&arg.param.name), - witx::CoreParamSignifies::PointerTo => self.func_ptr_binding(&arg.param.name), - witx::CoreParamSignifies::LengthOf => self.func_len_binding(&arg.param.name), - } - } - /// For when you need a {name}_ptr binding for passing a value by reference: pub fn func_ptr_binding(&self, id: &Id) -> Ident { format_ident!("{}_ptr", id.as_str().to_snake_case()) @@ -164,10 +180,9 @@ impl Names { fn builtin_name(b: &BuiltinType) -> &'static str { match b { - BuiltinType::String => "string", - BuiltinType::U8 => "u8", + BuiltinType::U8 { .. } => "u8", BuiltinType::U16 => "u16", - BuiltinType::U32 => "u32", + BuiltinType::U32 { .. } => "u32", BuiltinType::U64 => "u64", BuiltinType::S8 => "i8", BuiltinType::S16 => "i16", @@ -175,8 +190,7 @@ impl Names { BuiltinType::S64 => "i64", BuiltinType::F32 => "f32", BuiltinType::F64 => "f64", - BuiltinType::Char8 => "char8", - BuiltinType::USize => "usize", + BuiltinType::Char => "char", } } diff --git a/crates/wiggle/generate/src/types/enum.rs b/crates/wiggle/generate/src/types/enum.rs deleted file mode 100644 index cef56065effb..000000000000 --- a/crates/wiggle/generate/src/types/enum.rs +++ /dev/null @@ -1,120 +0,0 @@ -use super::{atom_token, int_repr_tokens}; -use crate::names::Names; - -use proc_macro2::TokenStream; -use quote::quote; - -pub(super) fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenStream { - let ident = names.type_(&name); - let rt = names.runtime_mod(); - - let repr = int_repr_tokens(e.repr); - let abi_repr = atom_token(match e.repr { - witx::IntRepr::U8 | witx::IntRepr::U16 | witx::IntRepr::U32 => witx::AtomType::I32, - witx::IntRepr::U64 => witx::AtomType::I64, - }); - - let mut variant_names = vec![]; - let mut tryfrom_repr_cases = vec![]; - let mut to_repr_cases = vec![]; - let mut to_display = vec![]; - - for (n, variant) in e.variants.iter().enumerate() { - let variant_name = names.enum_variant(&variant.name); - let docs = variant.docs.trim(); - let ident_str = ident.to_string(); - let variant_str = variant_name.to_string(); - tryfrom_repr_cases.push(quote!(#n => Ok(#ident::#variant_name))); - to_repr_cases.push(quote!(#ident::#variant_name => #n as #repr)); - to_display.push(quote!(#ident::#variant_name => format!("{} ({}::{}({}))", #docs, #ident_str, #variant_str, #repr::from(*self)))); - variant_names.push(variant_name); - } - - quote! { - #[repr(#repr)] - #[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)] - pub enum #ident { - #(#variant_names),* - } - - impl ::std::fmt::Display for #ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - let to_str = match self { - #(#to_display,)* - }; - write!(f, "{}", to_str) - } - } - - impl ::std::convert::TryFrom<#repr> for #ident { - type Error = #rt::GuestError; - fn try_from(value: #repr) -> Result<#ident, #rt::GuestError> { - match value as usize { - #(#tryfrom_repr_cases),*, - _ => Err( #rt::GuestError::InvalidEnumValue(stringify!(#ident))), - } - } - } - - impl ::std::convert::TryFrom<#abi_repr> for #ident { - type Error = #rt::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, #rt::GuestError> { - #ident::try_from(value as #repr) - } - } - - impl From<#ident> for #repr { - fn from(e: #ident) -> #repr { - match e { - #(#to_repr_cases),* - } - } - } - - impl From<#ident> for #abi_repr { - fn from(e: #ident) -> #abi_repr { - #repr::from(e) as #abi_repr - } - } - - impl<'a> #rt::GuestType<'a> for #ident { - fn guest_size() -> u32 { - #repr::guest_size() - } - - fn guest_align() -> usize { - #repr::guest_align() - } - - fn read(location: & #rt::GuestPtr<#ident>) -> Result<#ident, #rt::GuestError> { - use std::convert::TryFrom; - let reprval = #repr::read(&location.cast())?; - let value = #ident::try_from(reprval)?; - Ok(value) - } - - fn write(location: & #rt::GuestPtr<'_, #ident>, val: Self) - -> Result<(), #rt::GuestError> - { - #repr::write(&location.cast(), #repr::from(val)) - } - } - - unsafe impl <'a> #rt::GuestTypeTransparent<'a> for #ident { - #[inline] - fn validate(location: *mut #ident) -> Result<(), #rt::GuestError> { - use std::convert::TryFrom; - // Validate value in memory using #ident::try_from(reprval) - let reprval = unsafe { (location as *mut #repr).read() }; - let _val = #ident::try_from(reprval)?; - Ok(()) - } - } - } -} - -impl super::WiggleType for witx::EnumDatatype { - fn impls_display(&self) -> bool { - true - } -} diff --git a/crates/wiggle/generate/src/types/flags.rs b/crates/wiggle/generate/src/types/flags.rs index cda13a2bfa1e..6082ed5f7384 100644 --- a/crates/wiggle/generate/src/types/flags.rs +++ b/crates/wiggle/generate/src/types/flags.rs @@ -1,27 +1,24 @@ -use super::{atom_token, int_repr_tokens}; use crate::names::Names; use proc_macro2::{Literal, TokenStream}; use quote::quote; -use std::convert::TryFrom; -pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> TokenStream { +pub(super) fn define_flags( + names: &Names, + name: &witx::Id, + repr: witx::IntRepr, + record: &witx::RecordDatatype, +) -> TokenStream { let rt = names.runtime_mod(); let ident = names.type_(&name); - let repr = int_repr_tokens(f.repr); - let abi_repr = atom_token(match f.repr { - witx::IntRepr::U8 | witx::IntRepr::U16 | witx::IntRepr::U32 => witx::AtomType::I32, - witx::IntRepr::U64 => witx::AtomType::I64, - }); + let abi_repr = names.wasm_type(repr.into()); + let repr = super::int_repr_tokens(repr); let mut names_ = vec![]; let mut values_ = vec![]; - for (i, f) in f.flags.iter().enumerate() { - let name = names.flag_member(&f.name); - let value = 1u128 - .checked_shl(u32::try_from(i).expect("flag value overflow")) - .expect("flag value overflow"); - let value_token = Literal::u128_unsuffixed(value); + for (i, member) in record.members.iter().enumerate() { + let name = names.flag_member(&member.name); + let value_token = Literal::usize_unsuffixed(1 << i); names_.push(name); values_.push(value_token); } @@ -45,7 +42,7 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } } - impl ::std::convert::TryFrom<#repr> for #ident { + impl TryFrom<#repr> for #ident { type Error = #rt::GuestError; fn try_from(value: #repr) -> Result { if #repr::from(!#ident::all()) & value != 0 { @@ -56,10 +53,10 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } } - impl ::std::convert::TryFrom<#abi_repr> for #ident { + impl TryFrom<#abi_repr> for #ident { type Error = #rt::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, #rt::GuestError> { - #ident::try_from(value as #repr) + fn try_from(value: #abi_repr) -> Result { + #ident::try_from(#repr::try_from(value)?) } } @@ -69,12 +66,6 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty } } - impl From<#ident> for #abi_repr { - fn from(e: #ident) -> #abi_repr { - #repr::from(e) as #abi_repr - } - } - impl<'a> #rt::GuestType<'a> for #ident { fn guest_size() -> u32 { #repr::guest_size() @@ -106,12 +97,5 @@ pub(super) fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDataty Ok(()) } } - - } -} - -impl super::WiggleType for witx::FlagsDatatype { - fn impls_display(&self) -> bool { - true } } diff --git a/crates/wiggle/generate/src/types/handle.rs b/crates/wiggle/generate/src/types/handle.rs index 310c9e7d6e8b..0f23419b0d9c 100644 --- a/crates/wiggle/generate/src/types/handle.rs +++ b/crates/wiggle/generate/src/types/handle.rs @@ -78,8 +78,6 @@ pub(super) fn define_handle( Ok(()) } } - - } } diff --git a/crates/wiggle/generate/src/types/int.rs b/crates/wiggle/generate/src/types/int.rs deleted file mode 100644 index d916b65b7064..000000000000 --- a/crates/wiggle/generate/src/types/int.rs +++ /dev/null @@ -1,100 +0,0 @@ -use super::{atom_token, int_repr_tokens}; -use crate::names::Names; - -use proc_macro2::TokenStream; -use quote::quote; - -pub(super) fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) -> TokenStream { - let rt = names.runtime_mod(); - let ident = names.type_(&name); - let repr = int_repr_tokens(i.repr); - let abi_repr = atom_token(match i.repr { - witx::IntRepr::U8 | witx::IntRepr::U16 | witx::IntRepr::U32 => witx::AtomType::I32, - witx::IntRepr::U64 => witx::AtomType::I64, - }); - let consts = i - .consts - .iter() - .map(|r#const| { - let const_ident = names.int_member(&r#const.name); - let value = r#const.value; - quote!(pub const #const_ident: #ident = #ident(#value)) - }) - .collect::>(); - - quote! { - #[repr(transparent)] - #[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)] - pub struct #ident(#repr); - - impl #ident { - #(#consts;)* - } - - impl ::std::fmt::Display for #ident { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "{:?}", self) - } - } - - impl ::std::convert::TryFrom<#repr> for #ident { - type Error = #rt::GuestError; - fn try_from(value: #repr) -> Result { - Ok(#ident(value)) - } - } - - impl ::std::convert::TryFrom<#abi_repr> for #ident { - type Error = #rt::GuestError; - fn try_from(value: #abi_repr) -> Result<#ident, #rt::GuestError> { - #ident::try_from(value as #repr) - } - } - - impl From<#ident> for #repr { - fn from(e: #ident) -> #repr { - e.0 - } - } - - impl From<#ident> for #abi_repr { - fn from(e: #ident) -> #abi_repr { - #repr::from(e) as #abi_repr - } - } - - impl<'a> #rt::GuestType<'a> for #ident { - fn guest_size() -> u32 { - #repr::guest_size() - } - - fn guest_align() -> usize { - #repr::guest_align() - } - - fn read(location: &#rt::GuestPtr<'a, #ident>) -> Result<#ident, #rt::GuestError> { - Ok(#ident(#repr::read(&location.cast())?)) - - } - - fn write(location: &#rt::GuestPtr<'_, #ident>, val: Self) -> Result<(), #rt::GuestError> { - #repr::write(&location.cast(), val.0) - } - } - - unsafe impl<'a> #rt::GuestTypeTransparent<'a> for #ident { - #[inline] - fn validate(_location: *mut #ident) -> Result<(), #rt::GuestError> { - // All bit patterns accepted - Ok(()) - } - } - - } -} - -impl super::WiggleType for witx::IntDatatype { - fn impls_display(&self) -> bool { - true - } -} diff --git a/crates/wiggle/generate/src/types/mod.rs b/crates/wiggle/generate/src/types/mod.rs index 6ed29af94b8c..255c2ce7b223 100644 --- a/crates/wiggle/generate/src/types/mod.rs +++ b/crates/wiggle/generate/src/types/mod.rs @@ -1,9 +1,8 @@ -mod r#enum; +// mod r#enum; mod flags; mod handle; -mod int; -mod r#struct; -mod union; +mod record; +mod variant; use crate::lifetimes::LifetimeExt; use crate::names::Names; @@ -15,11 +14,11 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea match &namedtype.tref { witx::TypeRef::Name(alias_to) => define_alias(names, &namedtype.name, &alias_to), witx::TypeRef::Value(v) => match &**v { - witx::Type::Enum(e) => r#enum::define_enum(names, &namedtype.name, &e), - witx::Type::Int(i) => int::define_int(names, &namedtype.name, &i), - witx::Type::Flags(f) => flags::define_flags(names, &namedtype.name, &f), - witx::Type::Struct(s) => r#struct::define_struct(names, &namedtype.name, &s), - witx::Type::Union(u) => union::define_union(names, &namedtype.name, &u), + witx::Type::Record(r) => match r.bitflags_repr() { + Some(repr) => flags::define_flags(names, &namedtype.name, repr, &r), + None => record::define_struct(names, &namedtype.name, &r), + }, + witx::Type::Variant(v) => variant::define_variant(names, &namedtype.name, &v), witx::Type::Handle(h) => handle::define_handle(names, &namedtype.name, &h), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Pointer(p) => { @@ -30,7 +29,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea let rt = names.runtime_mod(); define_witx_pointer(names, &namedtype.name, quote!(#rt::GuestPtr), p) } - witx::Type::Array(arr) => define_witx_array(names, &namedtype.name, &arr), + witx::Type::List(arr) => define_witx_list(names, &namedtype.name, &arr), }, } } @@ -47,12 +46,8 @@ fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenSt fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream { let ident = names.type_(name); - let built = names.builtin_type(builtin, quote!('a)); - if builtin.needs_lifetime() { - quote!(pub type #ident<'a> = #built;) - } else { - quote!(pub type #ident = #built;) - } + let built = names.builtin_type(builtin); + quote!(pub type #ident = #built;) } fn define_witx_pointer( @@ -67,14 +62,14 @@ fn define_witx_pointer( quote!(pub type #ident<'a> = #pointer_type<'a, #pointee_type>;) } -fn define_witx_array(names: &Names, name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream { +fn define_witx_list(names: &Names, name: &witx::Id, arr_raw: &witx::TypeRef) -> TokenStream { let ident = names.type_(name); let rt = names.runtime_mod(); let pointee_type = names.type_ref(arr_raw, quote!('a)); quote!(pub type #ident<'a> = #rt::GuestPtr<'a, [#pointee_type]>;) } -fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { +pub fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { match int_repr { witx::IntRepr::U8 => quote!(u8), witx::IntRepr::U16 => quote!(u16), @@ -83,15 +78,6 @@ fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { } } -fn atom_token(atom: witx::AtomType) -> TokenStream { - match atom { - witx::AtomType::I32 => quote!(i32), - witx::AtomType::I64 => quote!(i64), - witx::AtomType::F32 => quote!(f32), - witx::AtomType::F64 => quote!(f64), - } -} - pub trait WiggleType { fn impls_display(&self) -> bool; } @@ -114,16 +100,13 @@ impl WiggleType for witx::NamedType { impl WiggleType for witx::Type { fn impls_display(&self) -> bool { match self { - witx::Type::Enum(x) => x.impls_display(), - witx::Type::Int(x) => x.impls_display(), - witx::Type::Flags(x) => x.impls_display(), - witx::Type::Struct(x) => x.impls_display(), - witx::Type::Union(x) => x.impls_display(), + witx::Type::Record(x) => x.impls_display(), + witx::Type::Variant(x) => x.impls_display(), witx::Type::Handle(x) => x.impls_display(), witx::Type::Builtin(x) => x.impls_display(), witx::Type::Pointer { .. } | witx::Type::ConstPointer { .. } - | witx::Type::Array { .. } => false, + | witx::Type::List { .. } => false, } } } @@ -136,11 +119,6 @@ impl WiggleType for witx::BuiltinType { impl WiggleType for witx::InterfaceFuncParam { fn impls_display(&self) -> bool { - match &*self.tref.type_() { - witx::Type::Struct { .. } - | witx::Type::Union { .. } - | witx::Type::Builtin(witx::BuiltinType::String { .. }) => false, - _ => self.tref.impls_display(), - } + self.tref.impls_display() } } diff --git a/crates/wiggle/generate/src/types/struct.rs b/crates/wiggle/generate/src/types/record.rs similarity index 94% rename from crates/wiggle/generate/src/types/struct.rs rename to crates/wiggle/generate/src/types/record.rs index 2a79a6e9accb..eaabcc6426ad 100644 --- a/crates/wiggle/generate/src/types/struct.rs +++ b/crates/wiggle/generate/src/types/record.rs @@ -8,7 +8,7 @@ use witx::Layout; pub(super) fn define_struct( names: &Names, name: &witx::Id, - s: &witx::StructDatatype, + s: &witx::RecordDatatype, ) -> TokenStream { let rt = names.runtime_mod(); let ident = names.type_(name); @@ -28,7 +28,7 @@ pub(super) fn define_struct( } } witx::TypeRef::Value(ty) => match &**ty { - witx::Type::Builtin(builtin) => names.builtin_type(*builtin, quote!('a)), + witx::Type::Builtin(builtin) => names.builtin_type(*builtin), witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { let pointee_type = names.type_ref(&pointee, quote!('a)); quote!(#rt::GuestPtr<'a, #pointee_type>) @@ -52,9 +52,9 @@ pub(super) fn define_struct( } witx::TypeRef::Value(ty) => match &**ty { witx::Type::Builtin(builtin) => { - let type_ = names.builtin_type(*builtin, anon_lifetime()); + let type_ = names.builtin_type(*builtin); quote! { - let #name = <#type_ as #rt::GuestType>::read(&#location)?; + let #name = <#type_ as #rt::GuestType>::read(&#location)?; } } witx::Type::Pointer(pointee) | witx::Type::ConstPointer(pointee) => { @@ -141,7 +141,7 @@ pub(super) fn define_struct( } } -impl super::WiggleType for witx::StructDatatype { +impl super::WiggleType for witx::RecordDatatype { fn impls_display(&self) -> bool { false } diff --git a/crates/wiggle/generate/src/types/union.rs b/crates/wiggle/generate/src/types/variant.rs similarity index 50% rename from crates/wiggle/generate/src/types/union.rs rename to crates/wiggle/generate/src/types/variant.rs index ecc3253f3c52..6568228dedc5 100644 --- a/crates/wiggle/generate/src/types/union.rs +++ b/crates/wiggle/generate/src/types/variant.rs @@ -1,23 +1,23 @@ use crate::lifetimes::LifetimeExt; use crate::names::Names; -use proc_macro2::TokenStream; +use proc_macro2::{Literal, TokenStream}; use quote::quote; use witx::Layout; -pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> TokenStream { +pub(super) fn define_variant(names: &Names, name: &witx::Id, v: &witx::Variant) -> TokenStream { let rt = names.runtime_mod(); let ident = names.type_(name); - let size = u.mem_size_align().size as u32; - let align = u.mem_size_align().align as usize; - let ulayout = u.union_layout(); - let contents_offset = ulayout.contents_offset as u32; + let size = v.mem_size_align().size as u32; + let align = v.mem_size_align().align as usize; + let contents_offset = v.payload_offset() as u32; let lifetime = quote!('a); + let tag_ty = super::int_repr_tokens(v.tag_repr); - let variants = u.variants.iter().map(|v| { - let var_name = names.enum_variant(&v.name); - if let Some(tref) = &v.tref { + let variants = v.cases.iter().map(|c| { + let var_name = names.enum_variant(&c.name); + if let Some(tref) = &c.tref { let var_type = names.type_ref(&tref, lifetime.clone()); quote!(#var_name(#var_type)) } else { @@ -25,30 +25,29 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty } }); - let tagname = names.type_(&u.tag.name); - - let read_variant = u.variants.iter().map(|v| { - let variantname = names.enum_variant(&v.name); - if let Some(tref) = &v.tref { + let read_variant = v.cases.iter().enumerate().map(|(i, c)| { + let i = Literal::usize_unsuffixed(i); + let variantname = names.enum_variant(&c.name); + if let Some(tref) = &c.tref { let varianttype = names.type_ref(tref, lifetime.clone()); quote! { - #tagname::#variantname => { + #i => { let variant_ptr = location.cast::().add(#contents_offset)?; let variant_val = <#varianttype as #rt::GuestType>::read(&variant_ptr.cast())?; Ok(#ident::#variantname(variant_val)) } } } else { - quote! { #tagname::#variantname => Ok(#ident::#variantname), } + quote! { #i => Ok(#ident::#variantname), } } }); - let write_variant = u.variants.iter().map(|v| { - let variantname = names.enum_variant(&v.name); + let write_variant = v.cases.iter().enumerate().map(|(i, c)| { + let variantname = names.enum_variant(&c.name); let write_tag = quote! { - location.cast().write(#tagname::#variantname)?; + location.cast().write(#i as #tag_ty)?; }; - if let Some(tref) = &v.tref { + if let Some(tref) = &c.tref { let varianttype = names.type_ref(tref, lifetime.clone()); quote! { #ident::#variantname(contents) => { @@ -66,7 +65,36 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty } }); - let (enum_lifetime, extra_derive) = if u.needs_lifetime() { + let enum_try_from = if v.cases.iter().all(|c| c.tref.is_none()) { + let tryfrom_repr_cases = v.cases.iter().enumerate().map(|(i, c)| { + let variant_name = names.enum_variant(&c.name); + let n = Literal::usize_unsuffixed(i); + quote!(#n => Ok(#ident::#variant_name)) + }); + let abi_ty = names.wasm_type(v.tag_repr.into()); + quote! { + impl TryFrom<#tag_ty> for #ident { + type Error = #rt::GuestError; + fn try_from(value: #tag_ty) -> Result<#ident, #rt::GuestError> { + match value { + #(#tryfrom_repr_cases),*, + _ => Err( #rt::GuestError::InvalidEnumValue(stringify!(#ident))), + } + } + } + + impl TryFrom<#abi_ty> for #ident { + type Error = #rt::GuestError; + fn try_from(value: #abi_ty) -> Result<#ident, #rt::GuestError> { + #ident::try_from(#tag_ty::try_from(value)?) + } + } + } + } else { + quote!() + }; + + let (enum_lifetime, extra_derive) = if v.needs_lifetime() { (quote!(<'a>), quote!()) } else { (quote!(), quote!(, PartialEq)) @@ -78,6 +106,8 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty #(#variants),* } + #enum_try_from + impl<'a> #rt::GuestType<'a> for #ident #enum_lifetime { fn guest_size() -> u32 { #size @@ -90,9 +120,10 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty fn read(location: &#rt::GuestPtr<'a, Self>) -> Result { - let tag = location.cast().read()?; + let tag = location.cast::<#tag_ty>().read()?; match tag { #(#read_variant)* + _ => Err(#rt::GuestError::InvalidEnumValue(stringify!(#ident))), } } @@ -109,7 +140,7 @@ pub(super) fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDataty } } -impl super::WiggleType for witx::UnionDatatype { +impl super::WiggleType for witx::Variant { fn impls_display(&self) -> bool { false } diff --git a/crates/wiggle/macro/Cargo.toml b/crates/wiggle/macro/Cargo.toml index c18c3dee745f..baee8ce1647c 100644 --- a/crates/wiggle/macro/Cargo.toml +++ b/crates/wiggle/macro/Cargo.toml @@ -22,7 +22,7 @@ doctest = false [dependencies] wiggle-generate = { path = "../generate", version = "0.23.0" } -witx = { path = "../../wasi-common/WASI/tools/witx", version = "0.8.7" } +witx = { version = "0.9", path = "../../wasi-common/WASI/tools/witx" } quote = "1.0" syn = { version = "1.0", features = ["full"] } diff --git a/crates/wiggle/src/lib.rs b/crates/wiggle/src/lib.rs index 4ecbf27da543..24a4ca7c4077 100644 --- a/crates/wiggle/src/lib.rs +++ b/crates/wiggle/src/lib.rs @@ -942,3 +942,9 @@ pub enum Trap { /// Any other Trap is just an unstructured String, for reporting and debugging. String(String), } + +impl From for Trap { + fn from(err: GuestError) -> Trap { + Trap::String(err.to_string()) + } +} diff --git a/crates/wiggle/wasmtime/Cargo.toml b/crates/wiggle/wasmtime/Cargo.toml index 97ca34ebc77b..31f45eeaf3e5 100644 --- a/crates/wiggle/wasmtime/Cargo.toml +++ b/crates/wiggle/wasmtime/Cargo.toml @@ -13,7 +13,7 @@ include = ["src/**/*", "LICENSE"] [dependencies] wasmtime = { path = "../../wasmtime", version = "0.23.0", default-features = false } wasmtime-wiggle-macro = { path = "./macro", version = "0.23.0" } -witx = { path = "../../wasi-common/WASI/tools/witx", version = "0.8.7", optional = true } +witx = { version = "0.9", path = "../../wasi-common/WASI/tools/witx", optional = true } wiggle = { path = "..", version = "0.23.0" } wiggle-borrow = { path = "../borrow", version = "0.23.0" } diff --git a/crates/wiggle/wasmtime/macro/Cargo.toml b/crates/wiggle/wasmtime/macro/Cargo.toml index 2ac0b1465dbd..fd4b365f0d2e 100644 --- a/crates/wiggle/wasmtime/macro/Cargo.toml +++ b/crates/wiggle/wasmtime/macro/Cargo.toml @@ -15,7 +15,7 @@ proc-macro = true test = false [dependencies] -witx = { path = "../../../wasi-common/WASI/tools/witx", version = "0.8.7" } +witx = { version = "0.9", path = "../../../wasi-common/WASI/tools/witx" } wiggle-generate = { path = "../../generate", version = "0.23.0" } quote = "1.0" syn = { version = "1.0", features = ["full", "extra-traits"] } diff --git a/crates/wiggle/wasmtime/macro/src/config.rs b/crates/wiggle/wasmtime/macro/src/config.rs index 6359ed0ec483..5e95bad957fb 100644 --- a/crates/wiggle/wasmtime/macro/src/config.rs +++ b/crates/wiggle/wasmtime/macro/src/config.rs @@ -144,7 +144,6 @@ impl Parse for TargetConf { enum ModuleConfField { Name(Ident), Docs(String), - FunctionOverride(FunctionOverrideConf), } impl Parse for ModuleConfField { @@ -159,10 +158,6 @@ impl Parse for ModuleConfField { input.parse::()?; let docs: syn::LitStr = input.parse()?; Ok(ModuleConfField::Docs(docs.value())) - } else if lookahead.peek(kw::function_override) { - input.parse::()?; - input.parse::()?; - Ok(ModuleConfField::FunctionOverride(input.parse()?)) } else { Err(lookahead.error()) } @@ -173,14 +168,12 @@ impl Parse for ModuleConfField { pub struct ModuleConf { pub name: Ident, pub docs: Option, - pub function_override: FunctionOverrideConf, } impl ModuleConf { fn build(fields: impl Iterator, err_loc: Span) -> Result { let mut name = None; let mut docs = None; - let mut function_override = None; for f in fields { match f { ModuleConfField::Name(c) => { @@ -195,18 +188,11 @@ impl ModuleConf { } docs = Some(c); } - ModuleConfField::FunctionOverride(c) => { - if function_override.is_some() { - return Err(Error::new(err_loc, "duplicate `function_override` field")); - } - function_override = Some(c); - } } } Ok(ModuleConf { name: name.ok_or_else(|| Error::new(err_loc, "`name` field required"))?, docs, - function_override: function_override.unwrap_or_default(), }) } } @@ -248,42 +234,3 @@ impl Parse for ModulesConf { }) } } - -#[derive(Debug, Clone, Default)] -pub struct FunctionOverrideConf { - pub funcs: Vec, -} -impl FunctionOverrideConf { - pub fn find(&self, name: &str) -> Option<&Ident> { - self.funcs - .iter() - .find(|f| f.name == name) - .map(|f| &f.replacement) - } -} - -impl Parse for FunctionOverrideConf { - fn parse(input: ParseStream) -> Result { - let contents; - let _lbrace = braced!(contents in input); - let fields: Punctuated = - contents.parse_terminated(FunctionOverrideField::parse)?; - Ok(FunctionOverrideConf { - funcs: fields.into_iter().collect(), - }) - } -} - -#[derive(Debug, Clone)] -pub struct FunctionOverrideField { - pub name: String, - pub replacement: Ident, -} -impl Parse for FunctionOverrideField { - fn parse(input: ParseStream) -> Result { - let name = input.parse::()?.to_string(); - input.parse::]>()?; - let replacement = input.parse::()?; - Ok(FunctionOverrideField { name, replacement }) - } -} diff --git a/crates/wiggle/wasmtime/macro/src/lib.rs b/crates/wiggle/wasmtime/macro/src/lib.rs index 7f13308f167b..a2d05f729d39 100644 --- a/crates/wiggle/wasmtime/macro/src/lib.rs +++ b/crates/wiggle/wasmtime/macro/src/lib.rs @@ -1,5 +1,5 @@ use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; use quote::quote; use syn::parse_macro_input; use wiggle_generate::Names; @@ -88,14 +88,9 @@ fn generate_module( let module_id = names.module(&module.name); let target_module = quote! { #target_path::#module_id }; - let ctor_externs = module.funcs().map(|f| { - if let Some(func_override) = module_conf.function_override.find(&f.name.as_str()) { - let name_ident = names.func(&f.name); - quote! { let #name_ident = wasmtime::Func::wrap(store, #func_override); } - } else { - generate_func(&f, names, &target_module) - } - }); + let ctor_externs = module + .funcs() + .map(|f| generate_func(&f, names, &target_module)); let type_name = module_conf.name.clone(); let type_docs = module_conf @@ -158,23 +153,21 @@ fn generate_func( ) -> TokenStream2 { let name_ident = names.func(&func.name); - let coretype = func.core_type(); + let (params, results) = func.wasm_signature(); - let arg_decls = coretype.args.iter().map(|arg| { - let name = names.func_core_arg(arg); - let atom = names.atom_type(arg.repr()); - quote! { #name: #atom } + let arg_names = (0..params.len()) + .map(|i| Ident::new(&format!("arg{}", i), Span::call_site())) + .collect::>(); + let arg_decls = params.iter().enumerate().map(|(i, ty)| { + let name = &arg_names[i]; + let wasm = names.wasm_type(*ty); + quote! { #name: #wasm } }); - let arg_names = coretype.args.iter().map(|arg| names.func_core_arg(arg)); - - let ret_ty = if let Some(ret) = &coretype.ret { - let ret_ty = match ret.signifies { - witx::CoreParamSignifies::Value(atom) => names.atom_type(atom), - _ => unreachable!("coretype ret should always be passed by value"), - }; - quote! { #ret_ty } - } else { - quote! {()} + + let ret_ty = match results.len() { + 0 => quote!(()), + 1 => names.wasm_type(results[0]), + _ => unimplemented!(), }; let runtime = names.runtime_mod(); From 4e8f63e7d1d28189cb619cb512822e5f6867f4dc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Feb 2021 13:42:41 -0800 Subject: [PATCH 2/8] Fix wiggle tests --- crates/wasi-common/WASI | 2 +- crates/wiggle/generate/src/funcs.rs | 20 ++- crates/wiggle/generate/src/lib.rs | 17 ++- crates/wiggle/generate/src/module_trait.rs | 2 + crates/wiggle/generate/src/types/variant.rs | 4 +- crates/wiggle/tests/arrays.rs | 14 +-- crates/wiggle/tests/arrays.witx | 24 ++-- crates/wiggle/tests/atoms.rs | 4 +- crates/wiggle/tests/atoms.witx | 5 +- crates/wiggle/tests/errno.witx | 2 +- crates/wiggle/tests/errors.rs | 18 +-- crates/wiggle/tests/excuse.witx | 2 +- crates/wiggle/tests/flags.rs | 4 +- crates/wiggle/tests/flags.witx | 5 +- crates/wiggle/tests/handles.rs | 6 +- crates/wiggle/tests/handles.witx | 5 +- crates/wiggle/tests/ints.rs | 8 +- crates/wiggle/tests/ints.witx | 13 +- crates/wiggle/tests/keywords.rs | 6 +- crates/wiggle/tests/keywords_union.witx | 8 +- crates/wiggle/tests/pointers.rs | 7 +- crates/wiggle/tests/pointers.witx | 2 +- crates/wiggle/tests/strings.rs | 6 +- crates/wiggle/tests/strings.witx | 9 +- crates/wiggle/tests/structs.rs | 12 +- crates/wiggle/tests/structs.witx | 31 +++-- crates/wiggle/tests/typenames.witx | 76 +++++------ crates/wiggle/tests/union.rs | 8 +- crates/wiggle/tests/union.witx | 21 ++-- crates/wiggle/tests/wasi.rs | 2 +- crates/wiggle/tests/wasi.witx | 132 ++++++++------------ 31 files changed, 236 insertions(+), 239 deletions(-) diff --git a/crates/wasi-common/WASI b/crates/wasi-common/WASI index 7c4fd252d084..3b684dd2fcbf 160000 --- a/crates/wasi-common/WASI +++ b/crates/wasi-common/WASI @@ -1 +1 @@ -Subproject commit 7c4fd252d0841488de4a6e724e600f1561797387 +Subproject commit 3b684dd2fcbf87e9854cf6a5c66651ca15e619e3 diff --git a/crates/wiggle/generate/src/funcs.rs b/crates/wiggle/generate/src/funcs.rs index 8e164f878ba3..187178e8b6f7 100644 --- a/crates/wiggle/generate/src/funcs.rs +++ b/crates/wiggle/generate/src/funcs.rs @@ -55,6 +55,7 @@ pub fn define_func( let mod_name = &module.name.as_str(); let func_name = &func.name.as_str(); quote! { + #[allow(unreachable_code)] // deals with warnings in noreturn functions pub fn #ident( ctx: &#ctx_type, memory: &dyn #rt::GuestMemory, @@ -215,7 +216,7 @@ impl witx::Bindgen for Rust<'_> { if func.results.len() > 0 { results.push(quote!(ret)); } else if func.noreturn { - self.src.extend(quote!(return Err(ret))); + self.src.extend(quote!(return Err(ret);)); } } @@ -250,7 +251,9 @@ impl witx::Bindgen for Rust<'_> { Instruction::VariantPayload => results.push(quote!(e)), - Instruction::Return { amt: 0 } => {} + Instruction::Return { amt: 0 } => { + self.src.extend(quote!(return Ok(()))); + } Instruction::Return { amt: 1 } => { let val = operands.pop().unwrap(); self.src.extend(quote!(return Ok(#val))); @@ -278,6 +281,17 @@ impl witx::Bindgen for Rust<'_> { }); } + Instruction::Load { ty } => { + let ptr = operands.pop().unwrap(); + let wrap_err = wrap_err(&format!("read {}", ty.name.as_str())); + let pointee_type = self.names.type_(&ty.name); + results.push(quote! { + #rt::GuestPtr::<#pointee_type>::new(memory, #ptr as u32) + .read() + .map_err(#wrap_err)? + }); + } + Instruction::HandleFromI32 { ty } => { let val = operands.pop().unwrap(); let ty = self.names.type_(&ty.name); @@ -294,7 +308,7 @@ impl witx::Bindgen for Rust<'_> { // Conversions with matching bit-widths but different signededness // use `as` since we're basically just reinterpreting the bits. - Instruction::U32FromI32 => { + Instruction::U32FromI32 | Instruction::UsizeFromI32 => { let val = operands.pop().unwrap(); results.push(quote!(#val as u32)); } diff --git a/crates/wiggle/generate/src/lib.rs b/crates/wiggle/generate/src/lib.rs index 3eb359bc670c..2e172633dfaf 100644 --- a/crates/wiggle/generate/src/lib.rs +++ b/crates/wiggle/generate/src/lib.rs @@ -6,8 +6,9 @@ mod module_trait; mod names; mod types; +use heck::ShoutySnakeCase; use lifetimes::anon_lifetime; -use proc_macro2::TokenStream; +use proc_macro2::{Literal, TokenStream}; use quote::quote; pub use config::Config; @@ -24,6 +25,19 @@ pub fn generate(doc: &witx::Document, names: &Names, errs: &ErrorTransform) -> T let types = doc.typenames().map(|t| define_datatype(&names, &t)); + let constants = doc.constants().map(|c| { + let name = quote::format_ident!( + "{}_{}", + c.ty.as_str().to_shouty_snake_case(), + c.name.as_str().to_shouty_snake_case() + ); + let ty = names.type_(&c.ty); + let value = Literal::u64_unsuffixed(c.value); + quote! { + pub const #name: #ty = #value; + } + }); + let guest_error_methods = doc.error_types().map(|t| { let typename = names.type_ref(&t, anon_lifetime()); let err_method = names.guest_error_conversion_method(&t); @@ -69,6 +83,7 @@ pub fn generate(doc: &witx::Document, names: &Names, errs: &ErrorTransform) -> T use std::convert::TryFrom; #(#types)* + #(#constants)* #guest_error_conversion #user_error_conversion } diff --git a/crates/wiggle/generate/src/module_trait.rs b/crates/wiggle/generate/src/module_trait.rs index 92e503ddda90..30dae0007668 100644 --- a/crates/wiggle/generate/src/module_trait.rs +++ b/crates/wiggle/generate/src/module_trait.rs @@ -9,6 +9,8 @@ use witx::Module; pub fn passed_by_reference(ty: &witx::Type) -> bool { match ty { witx::Type::Pointer(_) | witx::Type::ConstPointer(_) | witx::Type::List(_) => true, + witx::Type::Record(r) => r.bitflags_repr().is_none(), + witx::Type::Variant(v) => !v.is_enum(), _ => false, } } diff --git a/crates/wiggle/generate/src/types/variant.rs b/crates/wiggle/generate/src/types/variant.rs index 6568228dedc5..93df4edb1d78 100644 --- a/crates/wiggle/generate/src/types/variant.rs +++ b/crates/wiggle/generate/src/types/variant.rs @@ -65,6 +65,7 @@ pub(super) fn define_variant(names: &Names, name: &witx::Id, v: &witx::Variant) } }); + let mut extra_derive = quote!(); let enum_try_from = if v.cases.iter().all(|c| c.tref.is_none()) { let tryfrom_repr_cases = v.cases.iter().enumerate().map(|(i, c)| { let variant_name = names.enum_variant(&c.name); @@ -72,6 +73,7 @@ pub(super) fn define_variant(names: &Names, name: &witx::Id, v: &witx::Variant) quote!(#n => Ok(#ident::#variant_name)) }); let abi_ty = names.wasm_type(v.tag_repr.into()); + extra_derive = quote!(, Copy); quote! { impl TryFrom<#tag_ty> for #ident { type Error = #rt::GuestError; @@ -97,7 +99,7 @@ pub(super) fn define_variant(names: &Names, name: &witx::Id, v: &witx::Variant) let (enum_lifetime, extra_derive) = if v.needs_lifetime() { (quote!(<'a>), quote!()) } else { - (quote!(), quote!(, PartialEq)) + (quote!(), quote!(, PartialEq #extra_derive)) }; quote! { diff --git a/crates/wiggle/tests/arrays.rs b/crates/wiggle/tests/arrays.rs index b796a212d799..f5e577ba2940 100644 --- a/crates/wiggle/tests/arrays.rs +++ b/crates/wiggle/tests/arrays.rs @@ -105,7 +105,7 @@ impl ReduceExcusesExcercise { self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "reduce excuses errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "reduce excuses errno"); let expected = *self .excuse_values @@ -183,7 +183,7 @@ impl PopulateExcusesExcercise { self.array_ptr_loc.ptr as i32, self.elements.len() as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "populate excuses errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "populate excuses errno"); let arr: GuestPtr<'_, [GuestPtr<'_, types::Excuse>]> = host_memory.ptr((self.array_ptr_loc.ptr, self.elements.len() as u32)); @@ -309,7 +309,7 @@ impl SumElementsExercise { self.start_ix as i32, self.return_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "sum_of_element errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "sum_of_element errno"); let result_ptr = host_memory.ptr::(self.return_loc.ptr); let result = result_ptr.read().expect("read result"); @@ -330,7 +330,7 @@ impl SumElementsExercise { ); assert_eq!( res, - Ok(types::Errno::InvalidArg.into()), + Ok(types::Errno::InvalidArg as i32), "out of bounds sum_of_element errno" ); @@ -346,7 +346,7 @@ impl SumElementsExercise { if self.start_ix <= self.end_ix { assert_eq!( res, - Ok(types::Errno::Ok.into()), + Ok(types::Errno::Ok as i32), "expected ok sum_of_elements errno" ); let result_ptr = host_memory.ptr::(self.return_loc.ptr); @@ -367,7 +367,7 @@ impl SumElementsExercise { } else { assert_eq!( res, - Ok(types::Errno::InvalidArg.into()), + Ok(types::Errno::InvalidArg as i32), "expected error out-of-bounds sum_of_elements" ); } @@ -384,7 +384,7 @@ impl SumElementsExercise { ); assert_eq!( res, - Ok(types::Errno::InvalidArg.into()), + Ok(types::Errno::InvalidArg as i32), "out of bounds sum_of_elements errno" ); } diff --git a/crates/wiggle/tests/arrays.witx b/crates/wiggle/tests/arrays.witx index 4b6a1f14c56c..3522fc40961b 100644 --- a/crates/wiggle/tests/arrays.witx +++ b/crates/wiggle/tests/arrays.witx @@ -1,36 +1,36 @@ (use "errno.witx") (use "excuse.witx") -(typename $const_excuse_array (array (@witx const_pointer $excuse))) -(typename $excuse_array (array (@witx pointer $excuse))) +(typename $const_excuse_array (list (@witx const_pointer $excuse))) +(typename $excuse_array (list (@witx pointer $excuse))) (module $arrays (@interface func (export "reduce_excuses") (param $excuses $const_excuse_array) - (result $error $errno) - (result $reduced $excuse) + (result $error (expected $excuse (error $errno))) ) (@interface func (export "populate_excuses") (param $excuses $excuse_array) - (result $error $errno) + (result $error (expected (error $errno))) ) ) (typename $pair_ints - (struct + (record (field $first s32) (field $second s32))) +(typename $s32 s32) + (module $array_traversal (@interface func (export "sum_of_element") - (param $elements (array $pair_ints)) + (param $elements (list $pair_ints)) (param $index (@witx usize)) - (result $error $errno) - (result $sum s32)) + (result $error (expected $s32 (error $errno)))) (@interface func (export "sum_of_elements") - (param $elements (array $pair_ints)) + (param $elements (list $pair_ints)) (param $start (@witx usize)) (param $end (@witx usize)) - (result $error $errno) - (result $sum s32))) + (result $error (expected $s32 (error $errno)))) +) diff --git a/crates/wiggle/tests/atoms.rs b/crates/wiggle/tests/atoms.rs index f2da4827a80b..b39bec5b1559 100644 --- a/crates/wiggle/tests/atoms.rs +++ b/crates/wiggle/tests/atoms.rs @@ -34,7 +34,7 @@ impl IntFloatExercise { let e = atoms::int_float_args(&ctx, &host_memory, self.an_int as i32, self.an_float); - assert_eq!(e, Ok(types::Errno::Ok.into()), "int_float_args error"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "int_float_args error"); } pub fn strat() -> BoxedStrategy { @@ -72,7 +72,7 @@ impl DoubleIntExercise { .ptr::(self.return_loc.ptr) .read() .expect("failed to read return"); - assert_eq!(e, Ok(types::Errno::Ok.into()), "errno"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "errno"); assert_eq!(return_val, (self.input as f32) * 2.0, "return val"); } diff --git a/crates/wiggle/tests/atoms.witx b/crates/wiggle/tests/atoms.witx index 932d7c9ffdf2..87144fc3eeac 100644 --- a/crates/wiggle/tests/atoms.witx +++ b/crates/wiggle/tests/atoms.witx @@ -6,9 +6,8 @@ (@interface func (export "int_float_args") (param $an_int u32) (param $an_float f32) - (result $error $errno)) + (result $error (expected (error $errno)))) (@interface func (export "double_int_return_float") (param $an_int u32) - (result $error $errno) - (result $doubled_it $alias_to_float)) + (result $error (expected $alias_to_float (error $errno)))) ) diff --git a/crates/wiggle/tests/errno.witx b/crates/wiggle/tests/errno.witx index 36ee67622eec..845e2389ed7a 100644 --- a/crates/wiggle/tests/errno.witx +++ b/crates/wiggle/tests/errno.witx @@ -1,5 +1,5 @@ (typename $errno - (enum u32 + (enum (@witx tag u32) ;;; Success $ok ;;; Invalid argument diff --git a/crates/wiggle/tests/errors.rs b/crates/wiggle/tests/errors.rs index 425296246967..53d39a233d97 100644 --- a/crates/wiggle/tests/errors.rs +++ b/crates/wiggle/tests/errors.rs @@ -17,11 +17,11 @@ mod convert_just_errno { // trivial function. wiggle::from_witx!({ witx_literal: " -(typename $errno (enum u8 $ok $invalid_arg $picket_line)) +(typename $errno (enum (@witx tag u8) $ok $invalid_arg $picket_line)) (module $one_error_conversion (@interface func (export \"foo\") (param $strike u32) - (result $err $errno))) + (result $err (expected (error $errno))))) ", ctx: WasiCtx, errors: { errno => RichError }, @@ -68,7 +68,7 @@ mod convert_just_errno { let r0 = one_error_conversion::foo(&ctx, &host_memory, 0); assert_eq!( r0, - Ok(i32::from(types::Errno::Ok)), + Ok(types::Errno::Ok as i32), "Expected return value for strike=0" ); assert!(ctx.log.borrow().is_empty(), "No error log for strike=0"); @@ -77,7 +77,7 @@ mod convert_just_errno { let r1 = one_error_conversion::foo(&ctx, &host_memory, 1); assert_eq!( r1, - Ok(i32::from(types::Errno::PicketLine)), + Ok(types::Errno::PicketLine as i32), "Expected return value for strike=1" ); assert_eq!( @@ -90,7 +90,7 @@ mod convert_just_errno { let r2 = one_error_conversion::foo(&ctx, &host_memory, 2); assert_eq!( r2, - Ok(i32::from(types::Errno::InvalidArg)), + Ok(types::Errno::InvalidArg as i32), "Expected return value for strike=2" ); assert_eq!( @@ -120,15 +120,15 @@ mod convert_multiple_error_types { // Additionally, test that the function "baz" marked noreturn always returns a wiggle::Trap. wiggle::from_witx!({ witx_literal: " -(typename $errno (enum u8 $ok $invalid_arg $picket_line)) -(typename $errno2 (enum u8 $ok $too_much_coffee)) +(typename $errno (enum (@witx tag u8) $ok $invalid_arg $picket_line)) +(typename $errno2 (enum (@witx tag u8) $ok $too_much_coffee)) (module $two_error_conversions (@interface func (export \"foo\") (param $strike u32) - (result $err $errno)) + (result $err (expected (error $errno)))) (@interface func (export \"bar\") (param $drink u32) - (result $err $errno2)) + (result $err (expected (error $errno2)))) (@interface func (export \"baz\") (param $drink u32) (@witx noreturn))) diff --git a/crates/wiggle/tests/excuse.witx b/crates/wiggle/tests/excuse.witx index 14a927164eb6..1aacc92709f4 100644 --- a/crates/wiggle/tests/excuse.witx +++ b/crates/wiggle/tests/excuse.witx @@ -1,5 +1,5 @@ (typename $excuse - (enum u8 + (enum (@witx tag u8) $dog_ate $traffic $sleeping)) diff --git a/crates/wiggle/tests/flags.rs b/crates/wiggle/tests/flags.rs index 1a2bb0019fdb..b97285a94a71 100644 --- a/crates/wiggle/tests/flags.rs +++ b/crates/wiggle/tests/flags.rs @@ -75,11 +75,11 @@ impl ConfigureCarExercise { let res = flags::configure_car( &ctx, &host_memory, - self.old_config.into(), + self.old_config.bits() as i32, self.other_config_by_ptr.ptr as i32, self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "configure car errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "configure car errno"); let res_config = host_memory .ptr::(self.return_ptr_loc.ptr) diff --git a/crates/wiggle/tests/flags.witx b/crates/wiggle/tests/flags.witx index b46f73d5b5b2..98dbf911e9d7 100644 --- a/crates/wiggle/tests/flags.witx +++ b/crates/wiggle/tests/flags.witx @@ -1,7 +1,7 @@ (use "errno.witx") (typename $car_config - (flags u8 + (flags (@witx repr u8) $automatic $awd $suv)) @@ -10,7 +10,6 @@ (@interface func (export "configure_car") (param $old_config $car_config) (param $old_config_by_ptr (@witx const_pointer $car_config)) - (result $error $errno) - (result $new_config $car_config) + (result $error (expected $car_config (error $errno))) ) ) diff --git a/crates/wiggle/tests/handles.rs b/crates/wiggle/tests/handles.rs index 4ad9085a42da..d562e0bb14f6 100644 --- a/crates/wiggle/tests/handles.rs +++ b/crates/wiggle/tests/handles.rs @@ -37,7 +37,7 @@ impl HandleExercise { let e = handle_examples::fd_create(&ctx, &host_memory, self.return_loc.ptr as i32); - assert_eq!(e, Ok(types::Errno::Ok.into()), "fd_create error"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "fd_create error"); let h_got: u32 = host_memory .ptr(self.return_loc.ptr) @@ -48,13 +48,13 @@ impl HandleExercise { let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32); - assert_eq!(e, Ok(types::Errno::Ok.into()), "fd_consume error"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "fd_consume error"); let e = handle_examples::fd_consume(&ctx, &host_memory, h_got as i32 + 1); assert_eq!( e, - Ok(types::Errno::InvalidArg.into()), + Ok(types::Errno::InvalidArg as i32), "fd_consume invalid error" ); } diff --git a/crates/wiggle/tests/handles.witx b/crates/wiggle/tests/handles.witx index 69c1b0546ea1..6991d9dc2223 100644 --- a/crates/wiggle/tests/handles.witx +++ b/crates/wiggle/tests/handles.witx @@ -4,9 +4,8 @@ (module $handle_examples (@interface func (export "fd_create") - (result $error $errno) - (result $fd $fd)) + (result $error (expected $fd (error $errno)))) (@interface func (export "fd_consume") (param $fd $fd) - (result $error $errno)) + (result $error (expected (error $errno)))) ) diff --git a/crates/wiggle/tests/ints.rs b/crates/wiggle/tests/ints.rs index 82d04a4a00db..d09615cca697 100644 --- a/crates/wiggle/tests/ints.rs +++ b/crates/wiggle/tests/ints.rs @@ -12,7 +12,7 @@ impl_errno!(types::Errno, types::GuestErrorConversion); impl<'a> ints::Ints for WasiCtx<'a> { fn cookie_cutter(&self, init_cookie: types::Cookie) -> Result { - let res = if init_cookie == types::Cookie::START { + let res = if init_cookie == types::COOKIE_START { types::Bool::True } else { types::Bool::False @@ -50,10 +50,10 @@ impl CookieCutterExercise { let res = ints::cookie_cutter( &ctx, &host_memory, - self.cookie.into(), + self.cookie as i64, self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "cookie cutter errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "cookie cutter errno"); let is_cookie_start = host_memory .ptr::(self.return_ptr_loc.ptr) @@ -66,7 +66,7 @@ impl CookieCutterExercise { } else { false }, - self.cookie == types::Cookie::START, + self.cookie == types::COOKIE_START, "returned Bool should test if input was Cookie::START", ); } diff --git a/crates/wiggle/tests/ints.witx b/crates/wiggle/tests/ints.witx index 09dc62f5ec97..2ad73600a206 100644 --- a/crates/wiggle/tests/ints.witx +++ b/crates/wiggle/tests/ints.witx @@ -1,18 +1,13 @@ (use "errno.witx") -(typename $cookie - (int u64 - (const $start 0))) +(typename $cookie u64) +(@witx const $cookie $start 0) -(typename $bool - (enum u8 - $false - $true)) +(typename $bool bool) (module $ints (@interface func (export "cookie_cutter") (param $init_cookie $cookie) - (result $error $errno) - (result $is_start $bool) + (result $error (expected $bool (error $errno))) ) ) diff --git a/crates/wiggle/tests/keywords.rs b/crates/wiggle/tests/keywords.rs index bc1ee4edce04..1aa84e188ae6 100644 --- a/crates/wiggle/tests/keywords.rs +++ b/crates/wiggle/tests/keywords.rs @@ -8,7 +8,7 @@ mod enum_test { wiggle::from_witx!({ witx_literal: "(typename $self - (enum u8 + (enum (@witx tag u8) $self $2big ) @@ -35,7 +35,7 @@ mod module_trait_fn_and_arg_test { }); impl<'a> self_::Self_ for WasiCtx<'a> { #[allow(unused_variables)] - fn fn_(&self, use_: u32, virtual_: u32) -> Result<(), ()> { + fn fn_(&self, use_: u32, virtual_: u32) { unimplemented!(); } } @@ -46,7 +46,7 @@ mod struct_test { wiggle::from_witx!({ witx_literal: "(typename $self - (struct + (record (field $become s32) (field $mut s32) ) diff --git a/crates/wiggle/tests/keywords_union.witx b/crates/wiggle/tests/keywords_union.witx index 14d29b70ddef..7e3dcf99bfe9 100644 --- a/crates/wiggle/tests/keywords_union.witx +++ b/crates/wiggle/tests/keywords_union.witx @@ -1,15 +1,15 @@ (typename $union - (enum u8 + (enum (@witx tag u8) $self $power ) ) (typename $self - (union $union + (variant (@witx tag $union) ;; A union variant that will expand to a strict keyword `Self`. - (field $self (@witx pointer f32)) + (case $self (@witx pointer f32)) ;; Oh it's true, that there's power in a union! - (field $power (@witx pointer f32)) + (case $power (@witx pointer f32)) ) ) diff --git a/crates/wiggle/tests/pointers.rs b/crates/wiggle/tests/pointers.rs index 5bc271948036..ebae550fc3f1 100644 --- a/crates/wiggle/tests/pointers.rs +++ b/crates/wiggle/tests/pointers.rs @@ -152,12 +152,12 @@ impl PointersAndEnumsExercise { let e = pointers::pointers_and_enums( &ctx, &host_memory, - self.input1.into(), + self.input1 as i32, self.input2_loc.ptr as i32, self.input3_loc.ptr as i32, self.input4_ptr_loc.ptr as i32, ); - assert_eq!(e, Ok(types::Errno::Ok.into()), "errno"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "errno"); // Implementation of pointers_and_enums writes input3 to the input2_loc: let written_to_input2_loc: i32 = host_memory @@ -166,8 +166,7 @@ impl PointersAndEnumsExercise { .expect("input2 ref"); assert_eq!( - written_to_input2_loc, - self.input3.into(), + written_to_input2_loc, self.input3 as i32, "pointers_and_enums written to input2" ); diff --git a/crates/wiggle/tests/pointers.witx b/crates/wiggle/tests/pointers.witx index 9a73a3752054..f5243b667eaa 100644 --- a/crates/wiggle/tests/pointers.witx +++ b/crates/wiggle/tests/pointers.witx @@ -7,5 +7,5 @@ (param $an_excuse_by_reference (@witx pointer $excuse)) (param $a_lamer_excuse (@witx const_pointer $excuse)) (param $two_layers_of_excuses (@witx pointer (@witx const_pointer $excuse))) - (result $error $errno)) + (result $error (expected (error $errno)))) ) diff --git a/crates/wiggle/tests/strings.rs b/crates/wiggle/tests/strings.rs index a55917e4dff7..0caeb73782d4 100644 --- a/crates/wiggle/tests/strings.rs +++ b/crates/wiggle/tests/strings.rs @@ -88,7 +88,7 @@ impl HelloStringExercise { self.test_word.len() as i32, self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "hello string errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "hello string errno"); let given = host_memory .ptr::(self.return_ptr_loc.ptr) @@ -209,7 +209,7 @@ impl MultiStringExercise { self.c.len() as i32, self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "multi string errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "multi string errno"); let given = host_memory .ptr::(self.return_ptr_loc.ptr) @@ -287,7 +287,7 @@ impl OverlappingStringExercise { a_len - self.offset_c as i32, self.return_ptr_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "multi string errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "multi string errno"); let given = host_memory .ptr::(self.return_ptr_loc.ptr) diff --git a/crates/wiggle/tests/strings.witx b/crates/wiggle/tests/strings.witx index b3531e87bb21..918c1b327a27 100644 --- a/crates/wiggle/tests/strings.witx +++ b/crates/wiggle/tests/strings.witx @@ -1,16 +1,17 @@ (use "errno.witx") + +(typename $ret u32) + (module $strings (@interface func (export "hello_string") (param $a_string string) - (result $error $errno) - (result $total_bytes u32) + (result $error (expected $ret (error $errno))) ) (@interface func (export "multi_string") (param $a string) (param $b string) (param $c string) - (result $error $errno) - (result $total_bytes u32) + (result $error (expected $ret (error $errno))) ) ) diff --git a/crates/wiggle/tests/structs.rs b/crates/wiggle/tests/structs.rs index 9e92f1b86e3c..537ac0afb56d 100644 --- a/crates/wiggle/tests/structs.rs +++ b/crates/wiggle/tests/structs.rs @@ -118,7 +118,7 @@ impl SumOfPairExercise { self.return_loc.ptr as i32, ); - assert_eq!(sum_err, Ok(types::Errno::Ok.into()), "sum errno"); + assert_eq!(sum_err, Ok(types::Errno::Ok as i32), "sum errno"); let return_val: i64 = host_memory .ptr(self.return_loc.ptr) @@ -218,7 +218,7 @@ impl SumPairPtrsExercise { assert_eq!( res, - Ok(types::Errno::Ok.into()), + Ok(types::Errno::Ok as i32), "sum of pair of ptrs errno" ); @@ -299,7 +299,7 @@ impl SumIntAndPtrExercise { self.return_loc.ptr as i32, ); - assert_eq!(res, Ok(types::Errno::Ok.into()), "sum of int and ptr errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "sum of int and ptr errno"); let doubled: i64 = host_memory .ptr(self.return_loc.ptr) @@ -338,7 +338,7 @@ impl ReturnPairInts { let err = structs::return_pair_ints(&ctx, &host_memory, self.return_loc.ptr as i32); - assert_eq!(err, Ok(types::Errno::Ok.into()), "return struct errno"); + assert_eq!(err, Ok(types::Errno::Ok as i32), "return struct errno"); let return_struct: types::PairInts = host_memory .ptr(self.return_loc.ptr) @@ -420,7 +420,7 @@ impl ReturnPairPtrsExercise { assert_eq!( res, - Ok(types::Errno::Ok.into()), + Ok(types::Errno::Ok as i32), "return pair of ptrs errno" ); @@ -530,7 +530,7 @@ impl SumArrayExercise { ); // should be no error - if hostcall did a GuestError it should eprintln it. - assert_eq!(res, Ok(types::Errno::Ok.into()), "reduce excuses errno"); + assert_eq!(res, Ok(types::Errno::Ok as i32), "reduce excuses errno"); // Sum is inputs upcasted to u16 let expected: u16 = self.inputs.iter().map(|v| *v as u16).sum(); diff --git a/crates/wiggle/tests/structs.witx b/crates/wiggle/tests/structs.witx index 2a64b125f943..16f5ced8ec84 100644 --- a/crates/wiggle/tests/structs.witx +++ b/crates/wiggle/tests/structs.witx @@ -2,49 +2,46 @@ (use "errno.witx") (typename $pair_ints - (struct + (record (field $first s32) (field $second s32))) (typename $pair_int_ptrs - (struct + (record (field $first (@witx const_pointer s32)) (field $second (@witx const_pointer s32)))) (typename $pair_int_and_ptr - (struct + (record (field $first (@witx const_pointer s32)) (field $second s32))) -(typename $some_bytes (array u8)) +(typename $some_bytes (list u8)) (typename $struct_of_array - (struct + (record (field $arr $some_bytes))) +(typename $s64 s64) +(typename $u16 u16) + (module $structs (@interface func (export "sum_of_pair") (param $an_pair $pair_ints) - (result $error $errno) - (result $doubled s64)) + (result $error (expected $s64 (error $errno)))) (@interface func (export "sum_of_pair_of_ptrs") (param $an_pair $pair_int_ptrs) - (result $error $errno) - (result $doubled s64)) + (result $error (expected $s64 (error $errno)))) (@interface func (export "sum_of_int_and_ptr") (param $an_pair $pair_int_and_ptr) - (result $error $errno) - (result $double s64)) + (result $error (expected $s64 (error $errno)))) (@interface func (export "return_pair_ints") - (result $error $errno) - (result $an_pair $pair_ints)) + (result $error (expected $pair_ints (error $errno)))) (@interface func (export "return_pair_of_ptrs") (param $first (@witx const_pointer s32)) (param $second (@witx const_pointer s32)) - (result $error $errno) - (result $an_pair $pair_int_ptrs)) + (result $error (expected $pair_int_ptrs (error $errno)))) (@interface func (export "sum_array") (param $an_arr $struct_of_array) - (result $error $errno) - (result $doubled u16)) + (result $error (expected $u16 (error $errno)))) ) diff --git a/crates/wiggle/tests/typenames.witx b/crates/wiggle/tests/typenames.witx index 1351fc4e13ce..df60c5c34e17 100644 --- a/crates/wiggle/tests/typenames.witx +++ b/crates/wiggle/tests/typenames.witx @@ -15,7 +15,7 @@ ;;; Identifiers for clocks. (typename $clockid - (enum u32 + (enum (@witx tag u32) ;;; The clock measuring real time. Time value zero corresponds with ;;; 1970-01-01T00:00:00Z. $realtime @@ -36,7 +36,7 @@ ;;; API; some are used in higher-level library layers, and others are provided ;;; merely for alignment with POSIX. (typename $errno - (enum u16 + (enum (@witx tag u16) ;;; No error occurred. System call completed successfully. $success ;;; Argument list too long. @@ -196,7 +196,7 @@ ;;; File descriptor rights, determining which actions may be performed. (typename $rights - (flags u64 + (flags (@witx repr u64) ;;; The right to invoke `fd_datasync`. ;; ;;; If `path_open` is set, includes the right to invoke @@ -278,7 +278,7 @@ ;;; A region of memory for scatter/gather reads. (typename $iovec - (struct + (record ;;; The address of the buffer to be filled. (field $buf (@witx pointer u8)) ;;; The length of the buffer to be filled. @@ -288,7 +288,7 @@ ;;; A region of memory for scatter/gather writes. (typename $ciovec - (struct + (record ;;; The address of the buffer to be written. (field $buf (@witx const_pointer u8)) ;;; The length of the buffer to be written. @@ -296,15 +296,15 @@ ) ) -(typename $iovec_array (array $iovec)) -(typename $ciovec_array (array $ciovec)) +(typename $iovec_array (list $iovec)) +(typename $ciovec_array (list $ciovec)) ;;; Relative offset within a file. (typename $filedelta s64) ;;; The position relative to which to set the offset of the file descriptor. (typename $whence - (enum u8 + (enum (@witx tag u8) ;;; Seek relative to start-of-file. $set ;;; Seek relative to current position. @@ -327,7 +327,7 @@ ;;; The type of a file descriptor or file. (typename $filetype - (enum u8 + (enum (@witx tag u8) ;;; The type of the file descriptor or file is unknown or is different from any of the other types specified. $unknown ;;; The file descriptor or file refers to a block device inode. @@ -349,7 +349,7 @@ ;;; A directory entry. (typename $dirent - (struct + (record ;;; The offset of the next directory entry stored in this directory. (field $d_next $dircookie) ;;; The serial number of the file referred to by this directory entry. @@ -363,7 +363,7 @@ ;;; File or memory access pattern advisory information. (typename $advice - (enum u8 + (enum (@witx tag u8) ;;; The application has no advice to give on its behavior with respect to the specified data. $normal ;;; The application expects to access the specified data sequentially from lower offsets to higher offsets. @@ -381,7 +381,7 @@ ;;; File descriptor flags. (typename $fdflags - (flags u16 + (flags (@witx repr u16) ;;; Append mode: Data written to the file is always appended to the file's end. $append ;;; Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. @@ -399,7 +399,7 @@ ;;; File descriptor attributes. (typename $fdstat - (struct + (record ;;; File type. (field $fs_filetype $filetype) ;;; File descriptor flags. @@ -418,7 +418,7 @@ ;;; Which file time attributes to adjust. (typename $fstflags - (flags u16 + (flags (@witx repr u16) ;;; Adjust the last data access timestamp to the value stored in `filestat::atim`. $atim ;;; Adjust the last data access timestamp to the time of clock `clockid::realtime`. @@ -432,7 +432,7 @@ ;;; Flags determining the method of how paths are resolved. (typename $lookupflags - (flags u32 + (flags (@witx repr u32) ;;; As long as the resolved path corresponds to a symbolic link, it is expanded. $symlink_follow ) @@ -440,7 +440,7 @@ ;;; Open flags used by `path_open`. (typename $oflags - (flags u16 + (flags (@witx repr u16) ;;; Create file if it does not exist. $creat ;;; Fail if not a directory. @@ -457,7 +457,7 @@ ;;; File attributes. (typename $filestat - (struct + (record ;;; Device ID of device containing the file. (field $dev $device) ;;; File serial number. @@ -483,7 +483,7 @@ ;;; Type of a subscription to an event or its occurrence. (typename $eventtype - (enum u8 + (enum (@witx tag u8) ;;; The time value of clock `subscription_clock::id` has ;;; reached timestamp `subscription_clock::timeout`. $clock @@ -499,7 +499,7 @@ ;;; The state of the file descriptor subscribed to with ;;; `eventtype::fd_read` or `eventtype::fd_write`. (typename $eventrwflags - (flags u16 + (flags (@witx repr u16) ;;; The peer of this socket has closed or disconnected. $fd_readwrite_hangup ) @@ -508,7 +508,7 @@ ;;; The contents of an $event when type is `eventtype::fd_read` or ;;; `eventtype::fd_write`. (typename $event_fd_readwrite - (struct + (record ;;; The number of bytes available for reading or writing. (field $nbytes $filesize) ;;; The state of the file descriptor. @@ -518,7 +518,7 @@ ;;; An event that occurred. (typename $event - (struct + (record ;;; User-provided value that got attached to `subscription::userdata`. (field $userdata $userdata) ;;; If non-zero, an error that occurred while processing the subscription request. @@ -534,7 +534,7 @@ ;;; Flags determining how to interpret the timestamp provided in ;;; `subscription_clock::timeout`. (typename $subclockflags - (flags u16 + (flags (@witx repr u16) ;;; If set, treat the timestamp provided in ;;; `subscription_clock::timeout` as an absolute timestamp of clock ;;; `subscription_clock::id`. If clear, treat the timestamp @@ -546,7 +546,7 @@ ;;; The contents of a `subscription` when type is `eventtype::clock`. (typename $subscription_clock - (struct + (record ;;; The clock against which to compare the timestamp. (field $id $clockid) ;;; The absolute or relative timestamp. @@ -562,7 +562,7 @@ ;;; The contents of a `subscription` when type is type is ;;; `eventtype::fd_read` or `eventtype::fd_write`. (typename $subscription_fd_readwrite - (struct + (record ;;; The file descriptor on which to wait for it to become ready for reading or writing. (field $file_descriptor $fd) ) @@ -570,16 +570,16 @@ ;;; The contents of a `subscription`. (typename $subscription_u - (union $eventtype - (field $clock $subscription_clock) - (field $fd_read $subscription_fd_readwrite) - (field $fd_write $subscription_fd_readwrite) + (union (@witx tag $eventtype) + $subscription_clock + $subscription_fd_readwrite + $subscription_fd_readwrite ) ) ;;; Subscription to an event. (typename $subscription - (struct + (record ;;; User-provided value that is attached to the subscription in the ;;; implementation and returned through `event::userdata`. (field $userdata $userdata) @@ -593,7 +593,7 @@ ;;; Signal condition. (typename $signal - (enum u8 + (enum (@witx tag u8) ;;; No signal. Note that POSIX has special semantics for `kill(pid, 0)`, ;;; so this value is reserved. $none @@ -606,7 +606,7 @@ ;;; Terminal quit signal. ;;; Action: Terminates the process. $quit - ;;; Illegal instruction. + ;;; Illegal inrecordion. ;;; Action: Terminates the process. $ill ;;; Trace/breakpoint trap. @@ -692,7 +692,7 @@ ;;; Flags provided to `sock_recv`. (typename $riflags - (flags u16 + (flags (@witx repr u16) ;;; Returns the message without removing it from the socket's receive queue. $recv_peek ;;; On byte-stream sockets, block until the full amount of data can be returned. @@ -702,7 +702,7 @@ ;;; Flags returned by `sock_recv`. (typename $roflags - (flags u16 + (flags (@witx repr u16) ;;; Returned by `sock_recv`: Message data has been truncated. $recv_data_truncated ) @@ -714,7 +714,7 @@ ;;; Which channels on a socket to shut down. (typename $sdflags - (flags u8 + (flags (@witx repr u8) ;;; Disables further receive operations. $rd ;;; Disables further send operations. @@ -724,7 +724,7 @@ ;;; Identifiers for preopened capabilities. (typename $preopentype - (enum u8 + (enum (@witx tag u8) ;;; A pre-opened directory. $dir ) @@ -732,7 +732,7 @@ ;;; The contents of a $prestat when type is `preopentype::dir`. (typename $prestat_dir - (struct + (record ;;; The length of the directory name for use with `fd_prestat_dir_name`. (field $pr_name_len $size) ) @@ -740,7 +740,7 @@ ;;; Information about a pre-opened capability. (typename $prestat - (union $preopentype - (field $dir $prestat_dir) + (union (@witx tag $preopentype) + $prestat_dir ) ) diff --git a/crates/wiggle/tests/union.rs b/crates/wiggle/tests/union.rs index 22a9f967ec1c..04a1f4cce06b 100644 --- a/crates/wiggle/tests/union.rs +++ b/crates/wiggle/tests/union.rs @@ -108,7 +108,7 @@ impl GetTagExercise { let ctx = WasiCtx::new(); let host_memory = HostMemory::new(); - let discriminant: u8 = reason_tag(&self.input).into(); + let discriminant = reason_tag(&self.input) as u8; host_memory .ptr(self.input_loc.ptr) .write(discriminant) @@ -133,7 +133,7 @@ impl GetTagExercise { self.return_loc.ptr as i32, ); - assert_eq!(e, Ok(types::Errno::Ok.into()), "get_tag errno"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "get_tag errno"); let return_val: types::Excuse = host_memory .ptr(self.return_loc.ptr) @@ -185,7 +185,7 @@ impl ReasonMultExercise { let ctx = WasiCtx::new(); let host_memory = HostMemory::new(); - let discriminant: u8 = reason_tag(&self.input).into(); + let discriminant = reason_tag(&self.input) as u8; host_memory .ptr(self.input_loc.ptr) .write(discriminant) @@ -217,7 +217,7 @@ impl ReasonMultExercise { self.multiply_by as i32, ); - assert_eq!(e, Ok(types::Errno::Ok.into()), "reason_mult errno"); + assert_eq!(e, Ok(types::Errno::Ok as i32), "reason_mult errno"); match self.input { types::Reason::DogAte(f) => { diff --git a/crates/wiggle/tests/union.witx b/crates/wiggle/tests/union.witx index d76f150ddda0..0559666b8aed 100644 --- a/crates/wiggle/tests/union.witx +++ b/crates/wiggle/tests/union.witx @@ -5,27 +5,26 @@ ;; Fight for the full product of your labor! (typename $reason - (union $excuse - (field $dog_ate f32) - (field $traffic s32) - (empty $sleeping))) + (variant (@witx tag $excuse) + (case $dog_ate f32) + (case $traffic s32) + (case $sleeping))) (typename $reason_mut - (union $excuse - (field $dog_ate (@witx pointer f32)) - (field $traffic (@witx pointer s32)) - (empty $sleeping))) + (variant (@witx tag $excuse) + (case $dog_ate (@witx pointer f32)) + (case $traffic (@witx pointer s32)) + (case $sleeping))) (module $union_example (@interface func (export "get_tag") (param $r $reason) - (result $error $errno) - (result $t $excuse) + (result $error (expected $excuse (error $errno))) ) (@interface func (export "reason_mult") (param $r $reason_mut) (param $multiply_by u32) - (result $error $errno) + (result $error (expected (error $errno))) ) ) diff --git a/crates/wiggle/tests/wasi.rs b/crates/wiggle/tests/wasi.rs index 07b56db62ae5..95c146152680 100644 --- a/crates/wiggle/tests/wasi.rs +++ b/crates/wiggle/tests/wasi.rs @@ -322,7 +322,7 @@ impl<'a> crate::wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx<'a> { unimplemented!("poll_oneoff") } - fn proc_exit(&self, _rval: types::Exitcode) -> std::result::Result<(), ()> { + fn proc_exit(&self, _rval: types::Exitcode) -> wiggle::Trap { unimplemented!("proc_exit") } diff --git a/crates/wiggle/tests/wasi.witx b/crates/wiggle/tests/wasi.witx index 98cd94787843..df3c670f3eee 100644 --- a/crates/wiggle/tests/wasi.witx +++ b/crates/wiggle/tests/wasi.witx @@ -17,15 +17,13 @@ (@interface func (export "args_get") (param $argv (@witx pointer (@witx pointer u8))) (param $argv_buf (@witx pointer u8)) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Return command-line argument data sizes. (@interface func (export "args_sizes_get") - (result $error $errno) - ;;; The number of arguments. - (result $argc $size) - ;;; The size of the argument string data. - (result $argv_buf_size $size) + ;;; Returns the number of arguments and the size of the argument string + ;;; data, or an error. + (result $error (expected (tuple $size $size) (error $errno))) ) ;;; Read environment variable data. @@ -33,15 +31,13 @@ (@interface func (export "environ_get") (param $environ (@witx pointer (@witx pointer u8))) (param $environ_buf (@witx pointer u8)) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Return environment variable data sizes. (@interface func (export "environ_sizes_get") - (result $error $errno) - ;;; The number of environment variable arguments. - (result $environc $size) - ;;; The size of the environment variable data. - (result $environ_buf_size $size) + ;;; Returns the number of environment variable arguments and the size of the + ;;; environment variable data. + (result $error (expected (tuple $size $size) (error $errno))) ) ;;; Return the resolution of a clock. @@ -51,9 +47,8 @@ (@interface func (export "clock_res_get") ;;; The clock for which to return the resolution. (param $id $clockid) - (result $error $errno) - ;;; The resolution of the clock. - (result $resolution $timestamp) + ;;; The resolution of the clock, or an error if one happened. + (result $error (expected $timestamp (error $errno))) ) ;;; Return the time value of a clock. ;;; Note: This is similar to `clock_gettime` in POSIX. @@ -62,9 +57,8 @@ (param $id $clockid) ;;; The maximum lag (exclusive) that the returned time value may have, compared to its actual value. (param $precision $timestamp) - (result $error $errno) ;;; The time value of the clock. - (result $time $timestamp) + (result $error (expected $timestamp (error $errno))) ) ;;; Provide file advisory information on a file descriptor. @@ -77,7 +71,7 @@ (param $len $filesize) ;;; The advice. (param $advice $advice) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Force the allocation of space in a file. @@ -88,30 +82,29 @@ (param $offset $filesize) ;;; The length of the area that is allocated. (param $len $filesize) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Close a file descriptor. ;;; Note: This is similar to `close` in POSIX. (@interface func (export "fd_close") (param $fd $fd) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Synchronize the data of a file to disk. ;;; Note: This is similar to `fdatasync` in POSIX. (@interface func (export "fd_datasync") (param $fd $fd) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Get the attributes of a file descriptor. ;;; Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. (@interface func (export "fd_fdstat_get") (param $fd $fd) - (result $error $errno) ;;; The buffer where the file descriptor's attributes are stored. - (result $stat $fdstat) + (result $error (expected $fdstat (error $errno))) ) ;;; Adjust the flags associated with a file descriptor. @@ -120,7 +113,7 @@ (param $fd $fd) ;;; The desired values of the file descriptor flags. (param $flags $fdflags) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Adjust the rights associated with a file descriptor. @@ -130,15 +123,14 @@ ;;; The desired rights of the file descriptor. (param $fs_rights_base $rights) (param $fs_rights_inheriting $rights) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Return the attributes of an open file. (@interface func (export "fd_filestat_get") (param $fd $fd) - (result $error $errno) ;;; The buffer where the file's attributes are stored. - (result $buf $filestat) + (result $error (expected $filestat (error $errno))) ) ;;; Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. @@ -147,7 +139,7 @@ (param $fd $fd) ;;; The desired file size. (param $size $filesize) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Adjust the timestamps of an open file or directory. @@ -160,7 +152,7 @@ (param $mtim $timestamp) ;;; A bitmask indicating which timestamps to adjust. (param $fst_flags $fstflags) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Read from a file descriptor, without using and updating the file descriptor's offset. @@ -171,17 +163,15 @@ (param $iovs $iovec_array) ;;; The offset within the file at which to read. (param $offset $filesize) - (result $error $errno) ;;; The number of bytes read. - (result $nread $size) + (result $error (expected $size (error $errno))) ) ;;; Return a description of the given preopened file descriptor. (@interface func (export "fd_prestat_get") (param $fd $fd) - (result $error $errno) ;;; The buffer where the description is stored. - (result $buf $prestat) + (result $error (expected $prestat (error $errno))) ) ;;; Return a description of the given preopened file descriptor. @@ -190,7 +180,7 @@ ;;; A buffer into which to write the preopened directory name. (param $path (@witx pointer u8)) (param $path_len $size) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Write to a file descriptor, without using and updating the file descriptor's offset. @@ -201,9 +191,8 @@ (param $iovs $ciovec_array) ;;; The offset within the file at which to write. (param $offset $filesize) - (result $error $errno) ;;; The number of bytes written. - (result $nwritten $size) + (result $error (expected $size (error $errno))) ) ;;; Read from a file descriptor. @@ -212,15 +201,14 @@ (param $fd $fd) ;;; List of scatter/gather vectors to which to store data. (param $iovs $iovec_array) - (result $error $errno) ;;; The number of bytes read. - (result $nread $size) + (result $error (expected $size (error $errno))) ) ;;; Read directory entries from a directory. ;;; When successful, the contents of the output buffer consist of a sequence of - ;;; directory entries. Each directory entry consists of a dirent_t object, - ;;; followed by dirent_t::d_namlen bytes holding the name of the directory + ;;; directory entries. Each directory entry consists of a `dirent` object, + ;;; followed by `dirent::d_namlen` bytes holding the name of the directory ;;; entry. ;; ;;; This function fills the output buffer as much as possible, potentially @@ -234,9 +222,8 @@ (param $buf_len $size) ;;; The location within the directory to start reading (param $cookie $dircookie) - (result $error $errno) ;;; The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. - (result $bufused $size) + (result $error (expected $size (error $errno))) ) ;;; Atomically replace a file descriptor by renumbering another file descriptor. @@ -253,7 +240,7 @@ (param $fd $fd) ;;; The file descriptor to overwrite. (param $to $fd) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Move the offset of a file descriptor. @@ -264,25 +251,23 @@ (param $offset $filedelta) ;;; The base from which the offset is relative. (param $whence $whence) - (result $error $errno) ;;; The new offset of the file descriptor, relative to the start of the file. - (result $newoffset $filesize) + (result $error (expected $filesize (error $errno))) ) ;;; Synchronize the data and metadata of a file to disk. ;;; Note: This is similar to `fsync` in POSIX. (@interface func (export "fd_sync") (param $fd $fd) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Return the current offset of a file descriptor. ;;; Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. (@interface func (export "fd_tell") (param $fd $fd) - (result $error $errno) ;;; The current offset of the file descriptor, relative to the start of the file. - (result $offset $filesize) + (result $error (expected $filesize (error $errno))) ) ;;; Write to a file descriptor. @@ -291,9 +276,7 @@ (param $fd $fd) ;;; List of scatter/gather vectors from which to retrieve data. (param $iovs $ciovec_array) - (result $error $errno) - ;;; The number of bytes written. - (result $nwritten $size) + (result $error (expected $size (error $errno))) ) ;;; Create a directory. @@ -302,7 +285,7 @@ (param $fd $fd) ;;; The path at which to create the directory. (param $path string) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Return the attributes of a file or directory. @@ -313,9 +296,8 @@ (param $flags $lookupflags) ;;; The path of the file or directory to inspect. (param $path string) - (result $error $errno) ;;; The buffer where the file's attributes are stored. - (result $buf $filestat) + (result $error (expected $filestat (error $errno))) ) ;;; Adjust the timestamps of a file or directory. @@ -332,7 +314,7 @@ (param $mtim $timestamp) ;;; A bitmask indicating which timestamps to adjust. (param $fst_flags $fstflags) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Create a hard link. @@ -347,7 +329,7 @@ (param $new_fd $fd) ;;; The destination path at which to create the hard link. (param $new_path string) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Open a file or directory. @@ -377,11 +359,10 @@ ;;; descriptor itself, while the *inheriting* rights are rights that apply to ;;; file descriptors derived from it. (param $fs_rights_base $rights) - (param $fs_rights_inherting $rights) + (param $fs_rights_inheriting $rights) (param $fdflags $fdflags) - (result $error $errno) ;;; The file descriptor of the file that has been opened. - (result $opened_fd $fd) + (result $error (expected $fd (error $errno))) ) ;;; Read the contents of a symbolic link. @@ -393,9 +374,8 @@ ;;; The buffer to which to write the contents of the symbolic link. (param $buf (@witx pointer u8)) (param $buf_len $size) - (result $error $errno) ;;; The number of bytes placed in the buffer. - (result $bufused $size) + (result $error (expected $size (error $errno))) ) ;;; Remove a directory. @@ -405,7 +385,7 @@ (param $fd $fd) ;;; The path to a directory to remove. (param $path string) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Rename a file or directory. @@ -418,7 +398,7 @@ (param $new_fd $fd) ;;; The destination path to which to rename the file or directory. (param $new_path string) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Create a symbolic link. @@ -429,7 +409,7 @@ (param $fd $fd) ;;; The destination path at which to create the symbolic link. (param $new_path string) - (result $error $errno) + (result $error (expected (error $errno))) ) @@ -440,7 +420,7 @@ (param $fd $fd) ;;; The path to a file to unlink. (param $path string) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Concurrently poll for the occurrence of a set of events. @@ -451,9 +431,8 @@ (param $out (@witx pointer $event)) ;;; Both the number of subscriptions and events. (param $nsubscriptions $size) - (result $error $errno) ;;; The number of events stored. - (result $nevents $size) + (result $error (expected $size (error $errno))) ) ;;; Terminate the process normally. An exit code of 0 indicates successful @@ -462,6 +441,7 @@ (@interface func (export "proc_exit") ;;; The exit code returned by the process. (param $rval $exitcode) + (@witx noreturn) ) ;;; Send a signal to the process of the calling thread. @@ -469,13 +449,13 @@ (@interface func (export "proc_raise") ;;; The signal condition to trigger. (param $sig $signal) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Temporarily yield execution of the calling thread. ;;; Note: This is similar to `sched_yield` in POSIX. (@interface func (export "sched_yield") - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Write high-quality random data into a buffer. @@ -488,7 +468,7 @@ ;;; The buffer to fill with random data. (param $buf (@witx pointer u8)) (param $buf_len $size) - (result $error $errno) + (result $error (expected (error $errno))) ) ;;; Receive a message from a socket. @@ -500,11 +480,8 @@ (param $ri_data $iovec_array) ;;; Message flags. (param $ri_flags $riflags) - (result $error $errno) - ;;; Number of bytes stored in ri_data. - (result $ro_datalen $size) - ;;; Message flags. - (result $ro_flags $roflags) + ;;; Number of bytes stored in ri_data and message flags. + (result $error (expected (tuple $size $roflags) (error $errno))) ) ;;; Send a message on a socket. @@ -516,9 +493,8 @@ (param $si_data $ciovec_array) ;;; Message flags. (param $si_flags $siflags) - (result $error $errno) ;;; Number of bytes transmitted. - (result $so_datalen $size) + (result $error (expected $size (error $errno))) ) ;;; Shut down socket send and receive channels. @@ -527,6 +503,6 @@ (param $fd $fd) ;;; Which channels on the socket to shut down. (param $how $sdflags) - (result $error $errno) + (result $error (expected (error $errno))) ) ) From e4fe03611c8528efb0a597962b4764e371b8a175 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Feb 2021 14:16:18 -0800 Subject: [PATCH 3/8] Fix build of wasi-nn --- .gitmodules | 3 ++- crates/wasi-nn/spec | 2 +- crates/wasi-nn/src/impl.rs | 2 +- crates/wasi-nn/src/lib.rs | 1 - crates/wasi-nn/src/witx.rs | 12 ++++++------ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.gitmodules b/.gitmodules index 305858152d30..17229a28cefb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,8 @@ branch = abis [submodule "crates/wasi-nn/spec"] path = crates/wasi-nn/spec - url = https://github.com/WebAssembly/wasi-nn + url = https://github.com/alexcrichton/wasi-nn + branch = witx-next [submodule "crates/wasi-crypto/spec"] path = crates/wasi-crypto/spec url = https://github.com/WebAssembly/wasi-crypto.git diff --git a/crates/wasi-nn/spec b/crates/wasi-nn/spec index 793d4cd888ab..9e7c3277ca99 160000 --- a/crates/wasi-nn/spec +++ b/crates/wasi-nn/spec @@ -1 +1 @@ -Subproject commit 793d4cd888ab74e3b7bf018bcc6ab2a2426a1004 +Subproject commit 9e7c3277ca995d1ae07967b3298d6d3958914214 diff --git a/crates/wasi-nn/src/impl.rs b/crates/wasi-nn/src/impl.rs index fb8e781dd183..e18caafdc2d6 100644 --- a/crates/wasi-nn/src/impl.rs +++ b/crates/wasi-nn/src/impl.rs @@ -12,7 +12,7 @@ use wiggle::GuestPtr; #[derive(Debug, Error)] pub enum UsageError { - #[error("Only OpenVINO's IR is currently supported, passed encoding: {0}")] + #[error("Only OpenVINO's IR is currently supported, passed encoding: {0:?}")] InvalidEncoding(GraphEncoding), #[error("OpenVINO expects only two buffers (i.e. [ir, weights]), passed: {0}")] InvalidNumberOfBuilders(u32), diff --git a/crates/wasi-nn/src/lib.rs b/crates/wasi-nn/src/lib.rs index 2e2c08b0376b..68999d9310d3 100644 --- a/crates/wasi-nn/src/lib.rs +++ b/crates/wasi-nn/src/lib.rs @@ -18,7 +18,6 @@ wasmtime_wiggle::wasmtime_integration!({ wasi_ephemeral_nn => { name: WasiNn, docs: "An instantiated instance of the wasi-nn exports.", - function_override: {} } }, }); diff --git a/crates/wasi-nn/src/witx.rs b/crates/wasi-nn/src/witx.rs index b686fcd0913e..011c173ad85f 100644 --- a/crates/wasi-nn/src/witx.rs +++ b/crates/wasi-nn/src/witx.rs @@ -6,23 +6,23 @@ use crate::ctx::WasiNnError; wiggle::from_witx!({ witx: ["$WASI_ROOT/phases/ephemeral/witx/wasi_ephemeral_nn.witx"], ctx: WasiNnCtx, - errors: { errno => WasiNnError } + errors: { nn_errno => WasiNnError } }); -use types::Errno; +use types::NnErrno; /// Wiggle generates code that performs some input validation on the arguments passed in by users of /// wasi-nn. Here we convert the validation error into one (or more, eventually) of the error /// variants defined in the witx. impl types::GuestErrorConversion for WasiNnCtx { - fn into_errno(&self, e: wiggle::GuestError) -> Errno { + fn into_nn_errno(&self, e: wiggle::GuestError) -> NnErrno { eprintln!("Guest error: {:?}", e); - Errno::InvalidArgument + NnErrno::InvalidArgument } } impl<'a> types::UserErrorConversion for WasiNnCtx { - fn errno_from_wasi_nn_error(&self, e: WasiNnError) -> Result { + fn nn_errno_from_wasi_nn_error(&self, e: WasiNnError) -> Result { eprintln!("Host error: {:?}", e); match e { WasiNnError::OpenvinoError(_) => unimplemented!(), @@ -33,7 +33,7 @@ impl<'a> types::UserErrorConversion for WasiNnCtx { } /// Additionally, we must let Wiggle know which of our error codes represents a successful operation. -impl wiggle::GuestErrorType for Errno { +impl wiggle::GuestErrorType for NnErrno { fn success() -> Self { Self::Success } From 0c5744e0f34d0d5781fcf5a90b2521c97a7fe77d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Feb 2021 14:29:38 -0800 Subject: [PATCH 4/8] Update the wasi-crypto spec --- .gitmodules | 3 ++- crates/wasi-crypto/spec | 2 +- .../src/wiggle_interfaces/asymmetric_common.rs | 10 ++++++---- crates/wasi-crypto/src/wiggle_interfaces/common.rs | 14 +------------- .../wasi-crypto/src/wiggle_interfaces/symmetric.rs | 8 ++++---- 5 files changed, 14 insertions(+), 23 deletions(-) diff --git a/.gitmodules b/.gitmodules index 17229a28cefb..b3d1bfc0bfea 100644 --- a/.gitmodules +++ b/.gitmodules @@ -14,4 +14,5 @@ branch = witx-next [submodule "crates/wasi-crypto/spec"] path = crates/wasi-crypto/spec - url = https://github.com/WebAssembly/wasi-crypto.git + url = https://github.com/alexcrichton/wasi-crypto.git + branch = witx-next diff --git a/crates/wasi-crypto/spec b/crates/wasi-crypto/spec index 6d7821dec301..3ed3f0796db3 160000 --- a/crates/wasi-crypto/spec +++ b/crates/wasi-crypto/spec @@ -1 +1 @@ -Subproject commit 6d7821dec301a11dcf3c0d50e5a51af5169eaee3 +Subproject commit 3ed3f0796db3c24e170cb86fe70d86a9e1c5d683 diff --git a/crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs b/crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs index ea94966b3316..79cef9d68cb9 100644 --- a/crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs +++ b/crates/wasi-crypto/src/wiggle_interfaces/asymmetric_common.rs @@ -1,7 +1,9 @@ use super::{guest_types, WasiCryptoCtx}; use std::convert::TryInto; -use wasi_crypto::{ensure, CryptoError, KeyPairEncoding, PublicKeyEncoding, SecretKeyEncoding}; +use wasi_crypto::{ + ensure, CryptoError, KeyPairEncoding, PublicKeyEncoding, SecretKeyEncoding, Version, +}; impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetricCommon for WasiCryptoCtx @@ -57,7 +59,7 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr kp_old_handle.into(), kp_new_handle.into(), )? - .into()) + .0) } fn keypair_from_id( @@ -69,7 +71,7 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr ) -> Result { let kp_id = &*kp_id_ptr.as_array(kp_id_len).as_slice()?; Ok(self - .keypair_from_id(secrets_manager_handle.into(), kp_id, kp_version.into())? + .keypair_from_id(secrets_manager_handle.into(), kp_id, Version(kp_version))? .into()) } @@ -116,7 +118,7 @@ impl super::wasi_ephemeral_crypto_asymmetric_common::WasiEphemeralCryptoAsymmetr let (kp_id, version) = self.keypair_id(kp_handle.into())?; ensure!(kp_id.len() <= kp_id_buf.len(), CryptoError::Overflow.into()); kp_id_buf.copy_from_slice(&kp_id); - Ok((kp_id.len().try_into()?, version.into())) + Ok((kp_id.len().try_into()?, version.0)) } fn keypair_export( diff --git a/crates/wasi-crypto/src/wiggle_interfaces/common.rs b/crates/wasi-crypto/src/wiggle_interfaces/common.rs index 25969df1c9e1..be7b49b30a54 100644 --- a/crates/wasi-crypto/src/wiggle_interfaces/common.rs +++ b/crates/wasi-crypto/src/wiggle_interfaces/common.rs @@ -111,7 +111,7 @@ impl super::wasi_ephemeral_crypto_common::WasiEphemeralCryptoCommon for WasiCryp Ok(self.secrets_manager_invalidate( secrets_manager_handle.into(), key_id, - key_version.into(), + Version(key_version), )?) } } @@ -125,15 +125,3 @@ impl From for AlgorithmType { } } } - -impl From for Version { - fn from(version: guest_types::Version) -> Self { - Version(version.into()) - } -} - -impl From for guest_types::Version { - fn from(version: Version) -> Self { - version.into() - } -} diff --git a/crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs b/crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs index b14abc34b3ec..89d33ce8ec67 100644 --- a/crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs +++ b/crates/wasi-crypto/src/wiggle_interfaces/symmetric.rs @@ -1,7 +1,7 @@ use super::{guest_types, WasiCryptoCtx}; use std::convert::TryInto; -use wasi_crypto::{ensure, CryptoError}; +use wasi_crypto::{ensure, CryptoError, Version}; impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for WasiCryptoCtx { // --- secrets_manager @@ -55,7 +55,7 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa symmetric_key_old_handle.into(), symmetric_key_new_handle.into(), )? - .into()) + .0) } fn symmetric_key_from_id( @@ -72,7 +72,7 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa .symmetric_key_from_id( secrets_manager_handle.into(), symmetric_key_id, - symmetric_key_version.into(), + Version(symmetric_key_version), )? .into()) } @@ -129,7 +129,7 @@ impl super::wasi_ephemeral_crypto_symmetric::WasiEphemeralCryptoSymmetric for Wa CryptoError::Overflow.into() ); key_id_buf.copy_from_slice(&key_id); - Ok((key_id.len().try_into()?, version.into())) + Ok((key_id.len().try_into()?, version.0)) } fn symmetric_key_close( From 1f2db30cdabc48bb6367bacf53d2f10fb868e317 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Feb 2021 14:35:11 -0800 Subject: [PATCH 5/8] Fix a bug in wasi --- crates/wasi-common/WASI | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasi-common/WASI b/crates/wasi-common/WASI index 3b684dd2fcbf..449b38179e39 160000 --- a/crates/wasi-common/WASI +++ b/crates/wasi-common/WASI @@ -1 +1 @@ -Subproject commit 3b684dd2fcbf87e9854cf6a5c66651ca15e619e3 +Subproject commit 449b38179e39d6cf1e575967527315f87aa677d4 From 6fa95d474bd461cb6c97e6bee0735b556ce801db Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 17 Feb 2021 14:56:00 -0800 Subject: [PATCH 6/8] Fix wiggle trace example --- crates/wiggle/test-helpers/examples/tracing.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/crates/wiggle/test-helpers/examples/tracing.rs b/crates/wiggle/test-helpers/examples/tracing.rs index 0f06e1850905..fe2dd51d8e7e 100644 --- a/crates/wiggle/test-helpers/examples/tracing.rs +++ b/crates/wiggle/test-helpers/examples/tracing.rs @@ -15,15 +15,14 @@ pub enum RichError { // trivial function. wiggle::from_witx!({ witx_literal: " -(typename $errno (enum u8 $ok $invalid_arg $picket_line)) -(typename $s (struct (field $f1 (@witx usize)) (field $f2 (@witx pointer u8)))) -(typename $t (struct (field $f1 u32) (field $f2 f32))) +(typename $errno (enum (@witx tag u8) $ok $invalid_arg $picket_line)) +(typename $s (record (field $f1 (@witx usize)) (field $f2 (@witx pointer u8)))) +(typename $t (record (field $f1 u32) (field $f2 f32))) (module $one_error_conversion (@interface func (export \"foo\") (param $strike u32) (param $s $s) - (result $err $errno) - (result $t $t))) + (result $err (expected $t (error $errno))))) ", ctx: WasiCtx, errors: { errno => RichError }, @@ -90,7 +89,7 @@ fn main() { let r0 = one_error_conversion::foo(&ctx, &host_memory, 0, 0, 8); assert_eq!( r0, - Ok(i32::from(types::Errno::Ok)), + Ok(types::Errno::Ok as i32), "Expected return value for strike=0" ); assert!(ctx.log.borrow().is_empty(), "No error log for strike=0"); @@ -99,7 +98,7 @@ fn main() { let r1 = one_error_conversion::foo(&ctx, &host_memory, 1, 0, 8); assert_eq!( r1, - Ok(i32::from(types::Errno::PicketLine)), + Ok(types::Errno::PicketLine as i32), "Expected return value for strike=1" ); assert_eq!( @@ -112,7 +111,7 @@ fn main() { let r2 = one_error_conversion::foo(&ctx, &host_memory, 2, 0, 8); assert_eq!( r2, - Ok(i32::from(types::Errno::InvalidArg)), + Ok(types::Errno::InvalidArg as i32), "Expected return value for strike=2" ); assert_eq!( From a6b9cabe9b872d39dacea90098035c9708187faa Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 18 Feb 2021 09:50:35 -0800 Subject: [PATCH 7/8] Update submodules --- .gitmodules | 6 ++---- crates/wasi-common/WASI | 2 +- crates/wasi-crypto/spec | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.gitmodules b/.gitmodules index b3d1bfc0bfea..a53aa38a76aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -6,13 +6,11 @@ url = https://github.com/WebAssembly/wasm-c-api [submodule "WASI"] path = crates/wasi-common/WASI - url = https://github.com/alexcrichton/WASI - branch = abis + url = https://github.com/WebAssembly/WASI [submodule "crates/wasi-nn/spec"] path = crates/wasi-nn/spec url = https://github.com/alexcrichton/wasi-nn branch = witx-next [submodule "crates/wasi-crypto/spec"] path = crates/wasi-crypto/spec - url = https://github.com/alexcrichton/wasi-crypto.git - branch = witx-next + url = https://github.com/WebAssembly/wasi-crypto.git diff --git a/crates/wasi-common/WASI b/crates/wasi-common/WASI index 449b38179e39..ef8c1a53feb2 160000 --- a/crates/wasi-common/WASI +++ b/crates/wasi-common/WASI @@ -1 +1 @@ -Subproject commit 449b38179e39d6cf1e575967527315f87aa677d4 +Subproject commit ef8c1a53feb2dfb763d4ea5c7d9e0a0126b45579 diff --git a/crates/wasi-crypto/spec b/crates/wasi-crypto/spec index 3ed3f0796db3..1f3078088bd0 160000 --- a/crates/wasi-crypto/spec +++ b/crates/wasi-crypto/spec @@ -1 +1 @@ -Subproject commit 3ed3f0796db3c24e170cb86fe70d86a9e1c5d683 +Subproject commit 1f3078088bd0de36a0bc96859a1724e7d338a832 From fb44ab8d83cbb35627accf7ce21fe3b7a8469cf5 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 18 Feb 2021 10:01:48 -0800 Subject: [PATCH 8/8] Update wasi-nn submodule --- .gitmodules | 3 +-- crates/wasi-nn/spec | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitmodules b/.gitmodules index a53aa38a76aa..ee264b99c477 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,8 +9,7 @@ url = https://github.com/WebAssembly/WASI [submodule "crates/wasi-nn/spec"] path = crates/wasi-nn/spec - url = https://github.com/alexcrichton/wasi-nn - branch = witx-next + url = https://github.com/WebAssembly/wasi-nn [submodule "crates/wasi-crypto/spec"] path = crates/wasi-crypto/spec url = https://github.com/WebAssembly/wasi-crypto.git diff --git a/crates/wasi-nn/spec b/crates/wasi-nn/spec index 9e7c3277ca99..8adc5b9b3bb8 160000 --- a/crates/wasi-nn/spec +++ b/crates/wasi-nn/spec @@ -1 +1 @@ -Subproject commit 9e7c3277ca995d1ae07967b3298d6d3958914214 +Subproject commit 8adc5b9b3bb8f885d44f55b464718e24af892c94