diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..1c2f0d31e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,33 @@ +# How to Contribute to Wasmer + +Thank you for your interest in contributing to Wasmer. This document outlines some recommendations on how to contribute. + +## Issues & Feature Requests +Please use the issue template and provide a failing example if possible to help us recreate the issue. + +## Pull Requests +For large changes, please try reaching the Wasmer using Github Issues or Spectrum Chat to ensure we can accept the change once it is ready. + +We recommend trying the following commands before sending a pull request to ensure code quality: +- `cargo fmt --all` Ensures all code is correctly formatted. +- Run `cargo test` in the crates that you are modifying. +- Run `cargo build --all` (nightly) or `cargo build --all --exclude wasmer-singlepass-backend` + +A comprehensive CI test suite will be run by a Wasmer team member after the PR has been created. + +### Common Build Issues + +**LLVM Dependency** + +The LLVM backend requires LLVM to be installed to compile. + +So, you may run into the following error: +``` +Didn't find usable system-wide LLVM. +No suitable version of LLVM was found system-wide or pointed +``` + +**Singlepass Nightly Only** + +The singlepass crate depends on nightly so you may need to add the `+nightly` cargo flag to compile this crate. +`error[E0554]: #![feature] may not be used on the stable release channel` diff --git a/Cargo.lock b/Cargo.lock index 81f2655e8..e1c67d6d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,7 +66,7 @@ name = "backtrace-sys" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -144,7 +144,7 @@ name = "capstone-sys" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -180,7 +180,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -243,7 +243,7 @@ name = "cmake" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -658,7 +658,7 @@ name = "libloading" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -667,7 +667,7 @@ name = "llvm-sys" version = "80.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -730,7 +730,7 @@ version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -956,7 +956,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1373,7 +1373,7 @@ name = "wabt-sys" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1507,7 +1507,7 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "capstone 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1566,7 +1566,7 @@ version = "0.6.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1747,7 +1747,7 @@ dependencies = [ "checksum cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "097f5ce64ba566a83d9d914fd005de1e5937fdd57d8c5d99a7593040955d75a9" "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cbindgen 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7e19db9a3892c88c74cbbdcd218196068a928f1b60e736c448b13a1e81f277" -"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" +"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" "checksum cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7fa24eb00d5ffab90eaeaf1092ac85c04c64aaf358ea6f84505b8116d24c6af" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" diff --git a/README.md b/README.md index 5b7e038b2..67b8d04e9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

- Wasmer logo + Wasmer logo

diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index cdaae7688..eed22d39e 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/emscripten-tests/tests/emtests/_common.rs b/lib/emscripten-tests/tests/emtests/_common.rs index 8e4a70534..1e5dfba6e 100644 --- a/lib/emscripten-tests/tests/emtests/_common.rs +++ b/lib/emscripten-tests/tests/emtests/_common.rs @@ -42,7 +42,7 @@ macro_rules! assert_emscripten_output { // let module = compile(&wasm_bytes[..]) // .map_err(|err| format!("Can't create the WebAssembly module: {}", err)).unwrap(); // NOTE: Need to figure what the unwrap is for ?? - let mut emscripten_globals = EmscriptenGlobals::new(&module); + let mut emscripten_globals = EmscriptenGlobals::new(&module).expect("globals are valid"); let import_object = generate_emscripten_env(&mut emscripten_globals); let mut instance = module.instantiate(&import_object) diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index d2ddc03d6..c09f9b772 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns @@ -14,7 +16,7 @@ use std::collections::HashMap; use std::path::PathBuf; use std::{f64, ffi::c_void}; use wasmer_runtime_core::{ - error::CallResult, + error::{CallError, CallResult, ResolveError}, export::Export, func, global::Global, @@ -371,10 +373,11 @@ pub fn run_emscripten_instance( 0 => { instance.call(func_name, &[])?; } - _ => panic!( - "The emscripten main function has received an incorrect number of params {}", - num_params - ), + _ => { + return Err(CallError::Resolve(ResolveError::ExportWrongType { + name: "main".to_string(), + })) + } }; } @@ -402,11 +405,18 @@ fn store_module_arguments(ctx: &mut Ctx, args: Vec<&str>) -> (u32, u32) { (argc as u32 - 1, argv_offset) } -pub fn emscripten_set_up_memory(memory: &Memory, globals: &EmscriptenGlobalsData) { +pub fn emscripten_set_up_memory( + memory: &Memory, + globals: &EmscriptenGlobalsData, +) -> Result<(), String> { let dynamictop_ptr = globals.dynamictop_ptr; let dynamic_base = globals.dynamic_base; + if (dynamictop_ptr / 4) as usize >= memory.view::().len() { + return Err("dynamictop_ptr beyond memory len".to_string()); + } memory.view::()[(dynamictop_ptr / 4) as usize].set(dynamic_base); + Ok(()) } pub struct EmscriptenGlobalsData { @@ -434,7 +444,7 @@ pub struct EmscriptenGlobals { } impl EmscriptenGlobals { - pub fn new(module: &Module /*, static_bump: u32 */) -> Self { + pub fn new(module: &Module /*, static_bump: u32 */) -> Result { let mut use_old_abort_on_cannot_grow_memory = false; for ( index, @@ -456,8 +466,8 @@ impl EmscriptenGlobals { } } - let (table_min, table_max) = get_emscripten_table_size(&module); - let (memory_min, memory_max, shared) = get_emscripten_memory_size(&module); + let (table_min, table_max) = get_emscripten_table_size(&module)?; + let (memory_min, memory_max, shared) = get_emscripten_memory_size(&module)?; // Memory initialization let memory_type = MemoryDescriptor { @@ -486,7 +496,7 @@ impl EmscriptenGlobals { static_top += 16; let (dynamic_base, dynamictop_ptr) = - get_emscripten_metadata(&module).unwrap_or_else(|| { + get_emscripten_metadata(&module)?.unwrap_or_else(|| { let dynamictop_ptr = static_alloc(&mut static_top, 4); ( align_memory(align_memory(static_top) + TOTAL_STACK), @@ -510,7 +520,7 @@ impl EmscriptenGlobals { } }; - emscripten_set_up_memory(&memory, &data); + emscripten_set_up_memory(&memory, &data)?; let mut null_func_names = vec![]; for ( @@ -528,14 +538,14 @@ impl EmscriptenGlobals { } } - Self { + Ok(Self { data, memory, table, memory_min, memory_max, null_func_names, - } + }) } } diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index 37d3ae870..57d26f24e 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -33,37 +33,43 @@ pub fn is_emscripten_module(module: &Module) -> bool { false } -pub fn get_emscripten_table_size(module: &Module) -> (u32, Option) { - assert!( - module.info().imported_tables.len() > 0, - "Emscripten requires at least one imported table" - ); +pub fn get_emscripten_table_size(module: &Module) -> Result<(u32, Option), String> { + if module.info().imported_tables.len() == 0 { + return Err("Emscripten requires at least one imported table".to_string()); + } let (_, table) = &module.info().imported_tables[ImportedTableIndex::new(0)]; - (table.minimum, table.maximum) + Ok((table.minimum, table.maximum)) } -pub fn get_emscripten_memory_size(module: &Module) -> (Pages, Option, bool) { - assert!( - module.info().imported_tables.len() > 0, - "Emscripten requires at least one imported memory" - ); +pub fn get_emscripten_memory_size(module: &Module) -> Result<(Pages, Option, bool), String> { + if module.info().imported_memories.len() == 0 { + return Err("Emscripten requires at least one imported memory".to_string()); + } let (_, memory) = &module.info().imported_memories[ImportedMemoryIndex::new(0)]; - (memory.minimum, memory.maximum, memory.shared) + Ok((memory.minimum, memory.maximum, memory.shared)) } /// Reads values written by `-s EMIT_EMSCRIPTEN_METADATA=1` /// Assumes values start from the end in this order: /// Last export: Dynamic Base /// Second-to-Last export: Dynamic top pointer -pub fn get_emscripten_metadata(module: &Module) -> Option<(u32, u32)> { - let max_idx = &module.info().globals.iter().map(|(k, _)| k).max()?; - let snd_max_idx = &module +pub fn get_emscripten_metadata(module: &Module) -> Result, String> { + let max_idx = match module.info().globals.iter().map(|(k, _)| k).max() { + Some(x) => x, + None => return Ok(None), + }; + + let snd_max_idx = match module .info() .globals .iter() .map(|(k, _)| k) - .filter(|k| k != max_idx) - .max()?; + .filter(|k| *k != max_idx) + .max() + { + Some(x) => x, + None => return Ok(None), + }; use wasmer_runtime_core::types::{GlobalInit, Initializer::Const, Value::I32}; if let ( @@ -76,15 +82,23 @@ pub fn get_emscripten_metadata(module: &Module) -> Option<(u32, u32)> { .. }, ) = ( - &module.info().globals[*max_idx], - &module.info().globals[*snd_max_idx], + &module.info().globals[max_idx], + &module.info().globals[snd_max_idx], ) { - Some(( - align_memory(*dynamic_base as u32 - 32), - align_memory(*dynamictop_ptr as u32 - 32), - )) + let dynamic_base = (*dynamic_base as u32).checked_sub(32).ok_or(format!( + "emscripten unexpected dynamic_base {}", + *dynamic_base as u32 + ))?; + let dynamictop_ptr = (*dynamictop_ptr as u32).checked_sub(32).ok_or(format!( + "emscripten unexpected dynamictop_ptr {}", + *dynamictop_ptr as u32 + ))?; + Ok(Some(( + align_memory(dynamic_base), + align_memory(dynamictop_ptr), + ))) } else { - None + Ok(None) } } diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs index 72037bb13..c160ef70e 100644 --- a/lib/llvm-backend/src/lib.rs +++ b/lib/llvm-backend/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/middleware-common/src/lib.rs b/lib/middleware-common/src/lib.rs index c833273de..929558f25 100644 --- a/lib/middleware-common/src/lib.rs +++ b/lib/middleware-common/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/runtime-core/src/lib.rs b/lib/runtime-core/src/lib.rs index 139dda50a..0b8d69b7a 100644 --- a/lib/runtime-core/src/lib.rs +++ b/lib/runtime-core/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/runtime-core/src/memory/atomic.rs b/lib/runtime-core/src/memory/atomic.rs deleted file mode 100644 index f14415def..000000000 --- a/lib/runtime-core/src/memory/atomic.rs +++ /dev/null @@ -1,263 +0,0 @@ -//! This is mostly copied from https://docs.rs/integer-atomics/1.0.2/src/integer_atomics/atomic.rs.html -//! Many thanks to "main()" for writing this. - -use std::cell::UnsafeCell; -use std::mem; -use std::num::Wrapping; -use std::ops::{Add, BitAnd, BitOr, BitXor, Sub}; -use std::panic::RefUnwindSafe; -use std::sync::atomic::{AtomicUsize, Ordering}; - -pub trait IntCast: - Copy - + Eq - + Add - + BitAnd - + BitOr - + BitXor - + Sub -{ - type Public: PartialEq + Copy; - - fn from(u: usize) -> Self; - fn to(self) -> usize; - - fn new(p: Self::Public) -> Self; - fn unwrap(self) -> Self::Public; -} - -macro_rules! intcast { - ($($type:ident)+) => { - $( - impl IntCast for $type { - type Public = $type; - - fn from(u: usize) -> Self { - u as $type - } - fn to(self) -> usize { - self as usize - } - - fn new(p: $type) -> Self { - p - } - - fn unwrap(self) -> $type { - self - } - } - )+ - } -} -intcast! { u8 i8 u16 i16 u32 i32 u64 i64 } - -#[repr(transparent)] -pub struct Atomic { - v: UnsafeCell>, -} - -impl Default for Atomic { - fn default() -> Self { - Self::new(T::default().unwrap()) - } -} - -// TODO: impl Debug - -unsafe impl Sync for Atomic {} -impl RefUnwindSafe for Atomic {} - -fn inject(a: usize, b: usize, offset: usize) -> usize { - let mask = ((1 << (mem::size_of::() * 8)) - 1) << offset; - (a & !mask) | (b << offset) -} - -// straight from libcore's atomic.rs -#[inline] -fn strongest_failure_ordering(order: Ordering) -> Ordering { - use self::Ordering::*; - match order { - Release => Relaxed, - Relaxed => Relaxed, - SeqCst => SeqCst, - Acquire => Acquire, - AcqRel => Acquire, - _ => unreachable!(), - } -} - -impl Atomic { - #[inline] - fn proxy(&self) -> (&AtomicUsize, usize) { - let ptr = self.v.get() as usize; - let aligned = ptr & !(mem::size_of::() - 1); - ( - unsafe { &*(aligned as *const AtomicUsize) }, - (ptr - aligned) * 8, - ) - } - - #[inline] - pub(super) fn new(v: T::Public) -> Self { - Atomic { - v: UnsafeCell::new(Wrapping(T::new(v))), - } - } - - #[inline] - pub fn get_mut(&mut self) -> &mut T::Public { - unsafe { &mut *(self.v.get() as *mut T::Public) } - } - - #[inline] - pub fn into_inner(self) -> T::Public { - self.v.into_inner().0.unwrap() - } - - #[inline] - pub fn load(&self, order: Ordering) -> T::Public { - let (p, o) = self.proxy(); - T::from(p.load(order) >> o).unwrap() - } - - #[inline] - fn op Option>(&self, f: F, order: Ordering) -> T::Public { - self.op_new(f, order, strongest_failure_ordering(order)) - } - - #[inline] - fn op_new Option>( - &self, - f: F, - success: Ordering, - failure: Ordering, - ) -> T::Public { - let (p, o) = self.proxy(); - let mut old = p.load(Ordering::Relaxed); - loop { - let old_t = T::from(old >> o); - let new_t = match f(old_t) { - Some(x) => x, - None => return old_t.unwrap(), - }; - - match Self::op_weak(p, o, old, new_t, success, failure) { - Ok(()) => return T::from(old >> o).unwrap(), - Err(prev) => old = prev, - }; - } - } - - #[inline] - fn op_weak( - p: &AtomicUsize, - o: usize, - old: usize, - new_t: T, - success: Ordering, - failure: Ordering, - ) -> Result<(), usize> { - let new = inject::(old, new_t.to(), o); - p.compare_exchange_weak(old, new, success, failure) - .map(|_| ()) - } - - #[inline] - pub fn store(&self, val: T::Public, order: Ordering) { - self.op(|_| Some(T::new(val)), order); - } - - #[inline] - pub fn swap(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|_| Some(T::new(val)), order) - } - - #[inline] - pub fn compare_and_swap( - &self, - current: T::Public, - new: T::Public, - order: Ordering, - ) -> T::Public { - self.op( - |x| { - if x == T::new(current) { - Some(T::new(new)) - } else { - None - } - }, - order, - ) - } - - #[inline] - pub fn compare_exchange( - &self, - current: T::Public, - new: T::Public, - success: Ordering, - failure: Ordering, - ) -> Result { - match self.op_new( - |x| { - if x == T::new(current) { - Some(T::new(new)) - } else { - None - } - }, - success, - failure, - ) { - x if x == current => Ok(x), - x => Err(x), - } - } - - #[inline] - pub fn compare_exchange_weak( - &self, - current: T::Public, - new: T::Public, - success: Ordering, - failure: Ordering, - ) -> Result { - let (p, o) = self.proxy(); - let old = p.load(Ordering::Relaxed); - let old_t = T::from(old >> o).unwrap(); - if old_t != current { - return Err(old_t); - } - - Self::op_weak(p, o, old, T::new(new), success, failure) - .map(|()| current) - .map_err(|x| T::from(x >> o).unwrap()) - } - - #[inline] - pub fn fetch_add(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|x| Some(x + T::new(val)), order) - } - - #[inline] - pub fn fetch_sub(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|x| Some(x - T::new(val)), order) - } - - #[inline] - pub fn fetch_and(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|x| Some(x & T::new(val)), order) - } - - #[inline] - pub fn fetch_or(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|x| Some(x | T::new(val)), order) - } - - #[inline] - pub fn fetch_xor(&self, val: T::Public, order: Ordering) -> T::Public { - self.op(|x| Some(x ^ T::new(val)), order) - } -} diff --git a/lib/runtime-core/src/memory/mod.rs b/lib/runtime-core/src/memory/mod.rs index f618c33d8..d7c32dc98 100644 --- a/lib/runtime-core/src/memory/mod.rs +++ b/lib/runtime-core/src/memory/mod.rs @@ -14,12 +14,10 @@ use std::{ rc::Rc, }; -pub use self::atomic::Atomic; pub use self::dynamic::DynamicMemory; pub use self::static_::{SharedStaticMemory, StaticMemory}; pub use self::view::{Atomically, MemoryView}; -mod atomic; mod dynamic; pub mod ptr; mod static_; diff --git a/lib/runtime-core/src/memory/view.rs b/lib/runtime-core/src/memory/view.rs index 3376c6e17..4dbaa5bd5 100644 --- a/lib/runtime-core/src/memory/view.rs +++ b/lib/runtime-core/src/memory/view.rs @@ -1,8 +1,44 @@ -use super::atomic::{Atomic, IntCast}; use crate::types::ValueType; +use std::sync::atomic::{ + AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8, +}; use std::{cell::Cell, marker::PhantomData, ops::Deref, slice}; +pub trait Atomic { + type Output; +} +impl Atomic for i8 { + type Output = AtomicI8; +} +impl Atomic for i16 { + type Output = AtomicI16; +} +impl Atomic for i32 { + type Output = AtomicI32; +} +impl Atomic for i64 { + type Output = AtomicI64; +} +impl Atomic for u8 { + type Output = AtomicU8; +} +impl Atomic for u16 { + type Output = AtomicU16; +} +impl Atomic for u32 { + type Output = AtomicU32; +} +impl Atomic for u64 { + type Output = AtomicU64; +} +impl Atomic for f32 { + type Output = AtomicU32; +} +impl Atomic for f64 { + type Output = AtomicU64; +} + pub trait Atomicity {} pub struct Atomically; impl Atomicity for Atomically {} @@ -28,10 +64,10 @@ where } } -impl<'a, T: IntCast> MemoryView<'a, T, NonAtomically> { - pub fn atomically(&self) -> MemoryView<'a, T, Atomically> { +impl<'a, T: Atomic> MemoryView<'a, T> { + pub fn atomically(&self) -> MemoryView<'a, T::Output, Atomically> { MemoryView { - ptr: self.ptr, + ptr: self.ptr as *mut T::Output, length: self.length, _phantom: PhantomData, } @@ -45,9 +81,9 @@ impl<'a, T> Deref for MemoryView<'a, T, NonAtomically> { } } -impl<'a, T: IntCast> Deref for MemoryView<'a, T, Atomically> { - type Target = [Atomic]; - fn deref(&self) -> &[Atomic] { - unsafe { slice::from_raw_parts(self.ptr as *const Atomic, self.length) } +impl<'a, T> Deref for MemoryView<'a, T, Atomically> { + type Target = [T]; + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self.ptr as *const T, self.length) } } } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index d106e1708..5b3ba8526 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns @@ -98,7 +100,7 @@ pub use wasmer_runtime_core::{compile_with, validate}; pub use wasmer_runtime_core::{func, imports}; pub mod memory { - pub use wasmer_runtime_core::memory::{Atomic, Atomically, Memory, MemoryView}; + pub use wasmer_runtime_core::memory::{Atomically, Memory, MemoryView}; } pub mod wasm { diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index caca30757..8e8bb13ff 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -447,25 +447,25 @@ impl ModuleCodeGenerator mut self, _: &ModuleInfo, ) -> Result<(X64ExecutionContext, Box), CodegenError> { - let (assembler, breakpoints) = match self.functions.last_mut() { - Some(x) => (x.assembler.take().unwrap(), x.breakpoints.take().unwrap()), - None => { - return Err(CodegenError { - message: "no function", - }); - } + let (assembler, function_labels, breakpoints) = match self.functions.last_mut() { + Some(x) => ( + x.assembler.take().unwrap(), + x.function_labels.take().unwrap(), + x.breakpoints.take().unwrap(), + ), + None => ( + self.assembler.take().unwrap(), + self.function_labels.take().unwrap(), + HashMap::new(), + ), }; + let total_size = assembler.get_offset().0; let _output = assembler.finalize().unwrap(); let mut output = CodeMemory::new(_output.len()); output[0.._output.len()].copy_from_slice(&_output); output.make_executable(); - let function_labels = if let Some(x) = self.functions.last() { - x.function_labels.as_ref().unwrap() - } else { - self.function_labels.as_ref().unwrap() - }; let mut out_labels: Vec = vec![]; let mut out_offsets: Vec = vec![]; diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index 70eac299b..e749e5a22 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 7bb0beaa4..a2e6752c5 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -896,39 +896,6 @@ singlepass:fail:address.wast:586 # AssertTrap - expected trap, got Runtime:Error singlepass:fail:address.wast:588 # AssertTrap - expected trap, got [] singlepass:fail:address.wast:589 # AssertTrap - expected trap, got [] singlepass:fail:align.wast:864 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:binary-leb128.wast:2 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:7 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:12 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:18 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:24 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:32 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:40 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:48 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:56 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:65 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:74 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:86 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:98 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:157 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:164 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:171 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:178 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:186 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:193 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:200 # Module - caught panic Any -singlepass:fail:binary-leb128.wast:207 # Module - caught panic Any -singlepass:fail:binary.wast:1 # Module - caught panic Any -singlepass:fail:binary.wast:2 # Module - caught panic Any -singlepass:fail:binary.wast:3 # Module - caught panic Any -singlepass:fail:binary.wast:4 # Module - caught panic Any -singlepass:fail:binary.wast:406 # Module - caught panic Any -singlepass:fail:binary.wast:412 # Module - caught panic Any -singlepass:fail:binary.wast:418 # Module - caught panic Any -singlepass:fail:binary.wast:446 # Module - caught panic Any -singlepass:fail:binary.wast:498 # Module - caught panic Any -singlepass:fail:binary.wast:514 # Module - caught panic Any -singlepass:fail:binary.wast:530 # Module - caught panic Any -singlepass:fail:binary.wast:661 # Module - caught panic Any singlepass:fail:call.wast:289 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:469 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:470 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -943,10 +910,6 @@ singlepass:fail:call_indirect.wast:493 # AssertTrap - expected trap, got Runtime singlepass:fail:call_indirect.wast:494 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:500 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:call_indirect.wast:501 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:comments.wast:10 # Module - caught panic Any -singlepass:fail:comments.wast:52 # Module - caught panic Any -singlepass:fail:comments.wast:62 # Module - caught panic Any -singlepass:fail:comments.wast:71 # Module - caught panic Any singlepass:fail:conversions.wast:70 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:71 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:72 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1014,98 +977,7 @@ singlepass:fail:conversions.wast:239 # AssertTrap - expected trap, got Runtime:E singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:241 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:conversions.wast:242 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:custom.wast:1 # Module - caught panic Any -singlepass:fail:custom.wast:14 # Module - caught panic Any -singlepass:fail:data.wast:5 # Module - caught panic Any -singlepass:fail:data.wast:23 # Module - caught panic Any -singlepass:fail:data.wast:27 # Module - caught panic Any -singlepass:fail:data.wast:32 # Module - caught panic Any -singlepass:fail:data.wast:40 # Module - caught panic Any -singlepass:fail:data.wast:50 # Module - caught panic Any -singlepass:fail:data.wast:55 # Module - caught panic Any -singlepass:fail:data.wast:61 # Module - caught panic Any -singlepass:fail:data.wast:66 # Module - caught panic Any -singlepass:fail:data.wast:78 # Module - caught panic Any -singlepass:fail:data.wast:83 # Module - caught panic Any -singlepass:fail:data.wast:89 # Module - caught panic Any -singlepass:fail:data.wast:94 # Module - caught panic Any -singlepass:fail:data.wast:98 # Module - caught panic Any -singlepass:fail:data.wast:103 # Module - caught panic Any -singlepass:fail:data.wast:108 # Module - caught panic Any -singlepass:fail:data.wast:113 # Module - caught panic Any -singlepass:fail:data.wast:117 # Module - caught panic Any -singlepass:fail:data.wast:122 # Module - caught panic Any -singlepass:fail:data.wast:127 # Module - caught panic Any -singlepass:fail:data.wast:132 # Module - caught panic Any -singlepass:fail:data.wast:137 # Module - caught panic Any -singlepass:fail:data.wast:143 # Module - caught panic Any -singlepass:fail:data.wast:149 # Module - caught panic Any -singlepass:fail:data.wast:154 # Module - caught panic Any -singlepass:fail:data.wast:162 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:170 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:178 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:186 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:194 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:211 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:220 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:227 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:235 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:243 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:251 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:258 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:266 # AssertUnlinkable - caught panic Any -singlepass:fail:data.wast:273 # AssertUnlinkable - caught panic Any -singlepass:fail:elem.wast:97 # Module - caught panic Any -singlepass:fail:elem.wast:101 # Module - caught panic Any -singlepass:fail:elem.wast:106 # Module - caught panic Any -singlepass:fail:elem.wast:111 # Module - caught panic Any -singlepass:fail:elem.wast:170 # AssertUnlinkable - caught panic Any singlepass:fail:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:exports.wast:24 # Module - caught panic Any -singlepass:fail:exports.wast:25 # Module - caught panic Any -singlepass:fail:exports.wast:56 # Module - caught panic Any -singlepass:fail:exports.wast:57 # Module - caught panic Any -singlepass:fail:exports.wast:58 # Module - caught panic Any -singlepass:fail:exports.wast:60 # Module - caught panic Any -singlepass:fail:exports.wast:61 # Module - caught panic Any -singlepass:fail:exports.wast:62 # Module - caught panic Any -singlepass:fail:exports.wast:63 # Module - caught panic Any -singlepass:fail:exports.wast:64 # Module - caught panic Any -singlepass:fail:exports.wast:65 # Module - caught panic Any -singlepass:fail:exports.wast:67 # Module - caught panic Any -singlepass:fail:exports.wast:71 # AssertReturn Get - No instance available None -singlepass:fail:exports.wast:72 # AssertReturn Get - No instance available Some("$Global") -singlepass:fail:exports.wast:73 # Module - caught panic Any -singlepass:fail:exports.wast:74 # Module - caught panic Any -singlepass:fail:exports.wast:75 # AssertReturn Get - No instance available Some("$Global") -singlepass:fail:exports.wast:105 # Module - caught panic Any -singlepass:fail:exports.wast:106 # Module - caught panic Any -singlepass:fail:exports.wast:110 # Module - caught panic Any -singlepass:fail:exports.wast:111 # Module - caught panic Any -singlepass:fail:exports.wast:112 # Module - caught panic Any -singlepass:fail:exports.wast:113 # Module - caught panic Any -singlepass:fail:exports.wast:114 # Module - caught panic Any -singlepass:fail:exports.wast:115 # Module - caught panic Any -singlepass:fail:exports.wast:116 # Module - caught panic Any -singlepass:fail:exports.wast:117 # Module - caught panic Any -singlepass:fail:exports.wast:118 # Module - caught panic Any -singlepass:fail:exports.wast:119 # Module - caught panic Any -singlepass:fail:exports.wast:120 # Module - caught panic Any -singlepass:fail:exports.wast:121 # Module - caught panic Any -singlepass:fail:exports.wast:154 # Module - caught panic Any -singlepass:fail:exports.wast:155 # Module - caught panic Any -singlepass:fail:exports.wast:159 # Module - caught panic Any -singlepass:fail:exports.wast:160 # Module - caught panic Any -singlepass:fail:exports.wast:161 # Module - caught panic Any -singlepass:fail:exports.wast:162 # Module - caught panic Any -singlepass:fail:exports.wast:163 # Module - caught panic Any -singlepass:fail:exports.wast:164 # Module - caught panic Any -singlepass:fail:exports.wast:165 # Module - caught panic Any -singlepass:fail:exports.wast:166 # Module - caught panic Any -singlepass:fail:exports.wast:167 # Module - caught panic Any -singlepass:fail:exports.wast:168 # Module - caught panic Any -singlepass:fail:exports.wast:169 # Module - caught panic Any -singlepass:fail:exports.wast:170 # Module - caught panic Any singlepass:fail:f32.wast:1620 # AssertReturn - result F32(0) ("0x0") does not match expected F32(2147483648) ("0x80000000") singlepass:fail:f32.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f32.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) @@ -1534,10 +1406,6 @@ singlepass:fail:func_ptrs.wast:90 # AssertTrap - expected trap, got Runtime:Erro singlepass:fail:func_ptrs.wast:91 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:globals.wast:221 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:globals.wast:243 # AssertInvalid - Should be invalid -singlepass:fail:globals.wast:248 # Module - caught panic Any -singlepass:fail:globals.wast:249 # Module - caught panic Any -singlepass:fail:globals.wast:301 # Module - caught panic Any -singlepass:fail:globals.wast:331 # Module - caught panic Any singlepass:fail:i32.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1575,102 +1443,14 @@ singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not mat singlepass:fail:i64.wast:249 # AssertReturn - result I64(62) ("0x3e") does not match expected I64(1) ("0x1") singlepass:fail:i64.wast:252 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") singlepass:fail:if.wast:440 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:imports.wast:98 # Module - caught panic Any -singlepass:fail:imports.wast:99 # Module - caught panic Any -singlepass:fail:imports.wast:100 # Module - caught panic Any -singlepass:fail:imports.wast:101 # Module - caught panic Any -singlepass:fail:imports.wast:102 # Module - caught panic Any -singlepass:fail:imports.wast:103 # Module - caught panic Any -singlepass:fail:imports.wast:104 # Module - caught panic Any -singlepass:fail:imports.wast:107 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:111 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:116 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:120 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:124 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:128 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:132 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:136 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:140 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:144 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:148 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:152 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:156 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:160 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:164 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:168 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:172 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:176 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:181 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:185 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:189 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:193 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:197 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:201 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:231 # Module - caught panic Any -singlepass:fail:imports.wast:232 # Module - caught panic Any -singlepass:fail:imports.wast:235 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:239 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:244 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:248 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:252 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:256 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:260 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:264 # AssertUnlinkable - caught panic Any singlepass:fail:imports.wast:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:287 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:302 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:305 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:306 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:imports.wast:322 # Module - caught panic Any -singlepass:fail:imports.wast:323 # Module - caught panic Any -singlepass:fail:imports.wast:324 # Module - caught panic Any -singlepass:fail:imports.wast:325 # Module - caught panic Any -singlepass:fail:imports.wast:326 # Module - caught panic Any -singlepass:fail:imports.wast:327 # Module - caught panic Any -singlepass:fail:imports.wast:328 # Module - caught panic Any -singlepass:fail:imports.wast:329 # Module - caught panic Any -singlepass:fail:imports.wast:330 # Module - caught panic Any -singlepass:fail:imports.wast:331 # Module - caught panic Any -singlepass:fail:imports.wast:332 # Module - caught panic Any -singlepass:fail:imports.wast:335 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:339 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:344 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:348 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:352 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:356 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:361 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:365 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:369 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:373 # AssertUnlinkable - caught panic Any singlepass:fail:imports.wast:391 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:402 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:imports.wast:417 # Module - caught panic Any -singlepass:fail:imports.wast:418 # Module - caught panic Any -singlepass:fail:imports.wast:419 # Module - caught panic Any -singlepass:fail:imports.wast:420 # Module - caught panic Any -singlepass:fail:imports.wast:421 # Module - caught panic Any -singlepass:fail:imports.wast:422 # Module - caught panic Any -singlepass:fail:imports.wast:423 # Module - caught panic Any -singlepass:fail:imports.wast:424 # Module - caught panic Any -singlepass:fail:imports.wast:425 # Module - caught panic Any -singlepass:fail:imports.wast:428 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:432 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:437 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:441 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:445 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:449 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:454 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:458 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:462 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:466 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:470 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:474 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:479 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:483 # AssertUnlinkable - caught panic Any -singlepass:fail:imports.wast:571 # Module - caught panic Any -singlepass:fail:imports.wast:572 # Register - No instance available -singlepass:fail:imports.wast:574 # AssertUnlinkable - caught panic Any singlepass:fail:int_exprs.wast:113 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:int_exprs.wast:114 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:int_exprs.wast:115 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1685,12 +1465,6 @@ singlepass:fail:int_exprs.wast:198 # AssertTrap - expected trap, got Runtime:Err singlepass:fail:int_exprs.wast:199 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:int_exprs.wast:349 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:int_exprs.wast:350 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:22 # Module - caught panic Any -singlepass:fail:linking.wast:26 # Register - No instance available -singlepass:fail:linking.wast:28 # AssertUnlinkable - caught panic Any -singlepass:fail:linking.wast:32 # AssertUnlinkable - caught panic Any -singlepass:fail:linking.wast:87 # AssertUnlinkable - caught panic Any -singlepass:fail:linking.wast:91 # AssertUnlinkable - caught panic Any singlepass:fail:linking.wast:134 # AssertReturn - Call failed RuntimeError: unknown error singlepass:fail:linking.wast:136 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1711,24 +1485,12 @@ singlepass:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error singlepass:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:188 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:190 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:198 # Module - caught panic Any -singlepass:fail:linking.wast:199 # Register - No instance available -singlepass:fail:linking.wast:200 # Module - caught panic Any -singlepass:fail:linking.wast:204 # AssertReturn Get - No instance available Some("$G2") singlepass:fail:linking.wast:225 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:236 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:linking.wast:248 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:linking.wast:293 # Module - caught panic Any -singlepass:fail:linking.wast:299 # AssertUnlinkable - caught panic Any -singlepass:fail:linking.wast:324 # AssertUnlinkable - caught panic Any -singlepass:fail:linking.wast:335 # AssertUnlinkable - caught panic Any singlepass:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") singlepass:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: unknown error singlepass:fail:load.wast:201 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") -singlepass:fail:memory.wast:3 # Module - caught panic Any -singlepass:fail:memory.wast:4 # Module - caught panic Any -singlepass:fail:memory.wast:5 # Module - caught panic Any -singlepass:fail:memory.wast:6 # Module - caught panic Any singlepass:fail:memory_grow.wast:15 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:16 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:17 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1909,7 +1671,6 @@ singlepass:fail:select.wast:210 # AssertTrap - expected trap, got Runtime:Error singlepass:fail:select.wast:211 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:select.wast:248 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:select.wast:249 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:start.wast:92 # Module - caught panic Any singlepass:fail:traps.wast:16 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:traps.wast:17 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:traps.wast:18 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -1942,7 +1703,6 @@ singlepass:fail:traps.wast:88 # AssertTrap - expected trap, got Runtime:Error un singlepass:fail:traps.wast:89 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:traps.wast:90 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:traps.wast:91 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:type.wast:3 # Module - caught panic Any singlepass:fail:unreachable.wast:218 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:unreachable.wast:219 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:unreachable.wast:220 # AssertTrap - expected trap, got Runtime:Error unknown error diff --git a/lib/wasi-tests/tests/wasitests/mod.rs b/lib/wasi-tests/tests/wasitests/mod.rs index 954d80bb4..a1b1d3781 100644 --- a/lib/wasi-tests/tests/wasitests/mod.rs +++ b/lib/wasi-tests/tests/wasitests/mod.rs @@ -18,6 +18,7 @@ mod mapdir; mod path_link; mod path_rename; mod path_symlink; +mod poll_oneoff; mod quine; mod readlink; mod wasi_sees_virtual_root; diff --git a/lib/wasi-tests/tests/wasitests/poll_oneoff.rs b/lib/wasi-tests/tests/wasitests/poll_oneoff.rs new file mode 100644 index 000000000..bf4aa04a9 --- /dev/null +++ b/lib/wasi-tests/tests/wasitests/poll_oneoff.rs @@ -0,0 +1,20 @@ +#[test] +fn test_poll_oneoff() { + assert_wasi_output!( + "../../wasitests/poll_oneoff.wasm", + "poll_oneoff", + vec![], + vec![ + ( + "hamlet".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/hamlet") + ), + ( + "temp".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/temp") + ), + ], + vec![], + "../../wasitests/poll_oneoff.out" + ); +} diff --git a/lib/wasi-tests/wasitests/poll_oneoff.out b/lib/wasi-tests/wasitests/poll_oneoff.out new file mode 100644 index 000000000..ea8f65423 --- /dev/null +++ b/lib/wasi-tests/wasitests/poll_oneoff.out @@ -0,0 +1,2 @@ +__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } } +[__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }, __wasi_event_t { userdata: 1193046, error: 0, type_: 2, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 1234, flags: 0 } } }] diff --git a/lib/wasi-tests/wasitests/poll_oneoff.rs b/lib/wasi-tests/wasitests/poll_oneoff.rs new file mode 100644 index 000000000..255f5e91e --- /dev/null +++ b/lib/wasi-tests/wasitests/poll_oneoff.rs @@ -0,0 +1,183 @@ +// Args: +// mapdir: hamlet:wasitests/test_fs/hamlet +// mapdir: temp:wasitests/test_fs/temp + +use std::fs; +use std::io::{Read, Seek, SeekFrom}; +#[cfg(target_os = "wasi")] +use std::os::wasi::prelude::AsRawFd; +use std::path::PathBuf; + +#[cfg(target_os = "wasi")] +#[link(wasm_import_module = "wasi_unstable")] +extern "C" { + fn poll_oneoff(subscriptons: u32, events: u32, nsubscriptons: u32, nevents: u32) -> u16; +} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct __wasi_event_t { + pub userdata: u64, + pub error: u16, + pub type_: __wasi_eventtype_t, + pub u: __wasi_event_u, +} + +impl Default for __wasi_event_t { + fn default() -> Self { + __wasi_event_t { + userdata: 0, + error: 0, + type_: 0, + u: __wasi_event_u { + fd_readwrite: __wasi_event_fd_readwrite_t { + nbytes: 0, + flags: 0, + }, + }, + } + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub struct __wasi_event_fd_readwrite_t { + pub nbytes: u64, + pub flags: u16, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub union __wasi_event_u { + pub fd_readwrite: __wasi_event_fd_readwrite_t, +} + +impl std::fmt::Debug for __wasi_event_u { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "__wasi_event_u {{ ")?; + write!(f, "{:?} }}", unsafe { self.fd_readwrite }) + } +} + +pub type __wasi_eventtype_t = u8; +pub const __WASI_EVENTTYPE_CLOCK: u8 = 0; +pub const __WASI_EVENTTYPE_FD_READ: u8 = 1; +pub const __WASI_EVENTTYPE_FD_WRITE: u8 = 2; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub struct __wasi_subscription_clock_t { + pub userdata: u64, + pub clock_id: u32, + pub timeout: u64, + pub precision: u64, + pub flags: u16, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(C)] +pub struct __wasi_subscription_fs_readwrite_t { + pub fd: u32, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub union __wasi_subscription_u { + clock: __wasi_subscription_clock_t, + fd_readwrite: __wasi_subscription_fs_readwrite_t, +} + +#[derive(Copy, Clone)] +#[repr(C)] +pub struct __wasi_subscription_t { + pub userdata: u64, + pub type_: __wasi_eventtype_t, + pub u: __wasi_subscription_u, +} + +#[cfg(target_os = "wasi")] +fn poll(fds: &[u32], read: &[bool], write: &[bool]) -> Result, u16> { + assert!(fds.len() == read.len() && read.len() == write.len()); + + let mut in_ = fds + .iter() + .enumerate() + .map(|(i, n)| { + let mut type_ = 0; + if read[i] { + type_ |= __WASI_EVENTTYPE_FD_READ; + } + if write[i] { + type_ |= __WASI_EVENTTYPE_FD_WRITE; + } + __wasi_subscription_t { + userdata: 0x123456, + type_, + u: __wasi_subscription_u { + fd_readwrite: __wasi_subscription_fs_readwrite_t { fd: *n as u32 }, + }, + } + }) + .collect::>(); + let mut out_ = vec![Default::default(); in_.len()]; + let mut nsubscriptions: u32 = 0; + let result = unsafe { + poll_oneoff( + in_.as_ptr() as usize as u32, + out_.as_mut_ptr() as usize as u32, + in_.len() as u32, + (&mut nsubscriptions as *mut u32) as usize as u32, + ) + }; + + if result == 0 { + Ok(out_) + } else { + Err(result) + } +} + +fn main() { + #[cfg(not(target_os = "wasi"))] + let mut base = PathBuf::from("wasitests/test_fs"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("/"); + + let path = base.join("hamlet/act4/scene1.txt"); + let path2 = base.join("temp/poll_oneoff_write.txt"); + { + let mut file = fs::File::open(&path).expect("Could not open file"); + let mut file2 = fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(&path2) + .expect("Could not open file"); + file2.set_len(1234).unwrap(); + + #[cfg(target_os = "wasi")] + { + let fds = vec![file.as_raw_fd()]; + let mut result = poll(fds.as_slice(), &[true], &[false]).expect("First poll"); + while result[0].error != 0 { + result = poll(fds.as_slice(), &[true], &[false]).expect("subsequent polls"); + } + println!("{:?}", result[0]); + + let fds = vec![file.as_raw_fd(), file2.as_raw_fd()]; + result = poll(fds.as_slice(), &[true, false], &[false, true]).expect("First poll"); + while result[0].error != 0 { + result = + poll(fds.as_slice(), &[true, false], &[false, true]).expect("subsequent polls"); + } + println!("{:?}", result); + } + #[cfg(not(target_os = "wasi"))] + { + println!("{}", "__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }"); + println!("{}", "[__wasi_event_t { userdata: 1193046, error: 0, type_: 1, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 2259, flags: 0 } } }, __wasi_event_t { userdata: 1193046, error: 0, type_: 2, u: __wasi_event_u { __wasi_event_fd_readwrite_t { nbytes: 1234, flags: 0 } } }]"); + } + } + + std::fs::remove_file(path2).unwrap(); +} diff --git a/lib/wasi-tests/wasitests/poll_oneoff.wasm b/lib/wasi-tests/wasitests/poll_oneoff.wasm new file mode 100755 index 000000000..c74bcb072 Binary files /dev/null and b/lib/wasi-tests/wasitests/poll_oneoff.wasm differ diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 77eb53d12..ac9b11a86 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 64f7d0793..09dfe4247 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -1,5 +1,7 @@ /// types for use in the WASI filesystem use crate::syscalls::types::*; +#[cfg(unix)] +use std::convert::TryInto; use std::{ fs, io::{self, Read, Seek, Write}, @@ -165,6 +167,173 @@ pub trait WasiFile: std::fmt::Debug + Write + Read + Seek { fn rename_file(&self, _new_name: &std::path::Path) -> Result<(), WasiFsError> { panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0 or 0.8.0. Please implement WasiFile::rename_file for your type before then"); } + + /// Returns the number of bytes available. This function must not block + fn bytes_available(&self) -> Result { + panic!("Default implementation for compatibilty in the 0.6.X releases; this will be removed in 0.7.0 or 0.8.0. Please implement WasiFile::bytes_available for your type before then"); + } + + /// Used for polling. Default returns `None` because this method cannot be implemented for most types + /// Returns the underlying host fd + fn get_raw_fd(&self) -> Option { + None + } +} + +#[derive(Debug, Clone)] +pub enum PollEvent { + /// Data available to read + PollIn = 1, + /// Data available to write (will still block if data is greater than space available unless + /// the fd is configured to not block) + PollOut = 2, + /// Something didn't work. ignored as input + PollError = 4, + /// Connection closed. ignored as input + PollHangUp = 8, + /// Invalid request. ignored as input + PollInvalid = 16, +} + +impl PollEvent { + fn from_i16(raw_num: i16) -> Option { + Some(match raw_num { + 1 => PollEvent::PollIn, + 2 => PollEvent::PollOut, + 4 => PollEvent::PollError, + 8 => PollEvent::PollHangUp, + 16 => PollEvent::PollInvalid, + _ => return None, + }) + } +} + +#[derive(Debug, Clone)] +pub struct PollEventBuilder { + inner: PollEventSet, +} + +pub type PollEventSet = i16; + +#[derive(Debug)] +pub struct PollEventIter { + pes: PollEventSet, + i: usize, +} + +impl Iterator for PollEventIter { + type Item = PollEvent; + + fn next(&mut self) -> Option { + if self.pes == 0 || self.i > 15 { + None + } else { + while self.i < 16 { + let result = PollEvent::from_i16(self.pes & (1 << self.i)); + self.pes &= !(1 << self.i); + self.i += 1; + if let Some(r) = result { + return Some(r); + } + } + unreachable!("Internal logic error in PollEventIter"); + } + } +} + +pub fn iterate_poll_events(pes: PollEventSet) -> PollEventIter { + PollEventIter { pes, i: 0 } +} + +#[cfg(unix)] +fn poll_event_set_to_platform_poll_events(mut pes: PollEventSet) -> i16 { + let mut out = 0; + for i in 0..16 { + out |= match PollEvent::from_i16(pes & (1 << i)) { + Some(PollEvent::PollIn) => libc::POLLIN, + Some(PollEvent::PollOut) => libc::POLLOUT, + Some(PollEvent::PollError) => libc::POLLERR, + Some(PollEvent::PollHangUp) => libc::POLLHUP, + Some(PollEvent::PollInvalid) => libc::POLLNVAL, + _ => 0, + }; + pes &= !(1 << i); + } + out +} + +#[cfg(unix)] +fn platform_poll_events_to_pollevent_set(mut num: i16) -> PollEventSet { + let mut peb = PollEventBuilder::new(); + for i in 0..16 { + peb = match num & (1 << i) { + libc::POLLIN => peb.add(PollEvent::PollIn), + libc::POLLOUT => peb.add(PollEvent::PollOut), + libc::POLLERR => peb.add(PollEvent::PollError), + libc::POLLHUP => peb.add(PollEvent::PollHangUp), + libc::POLLNVAL => peb.add(PollEvent::PollInvalid), + _ => peb, + }; + num &= !(1 << i); + } + peb.build() +} + +impl PollEventBuilder { + pub fn new() -> PollEventBuilder { + PollEventBuilder { inner: 0 } + } + + pub fn add(mut self, event: PollEvent) -> PollEventBuilder { + self.inner |= event as PollEventSet; + self + } + + pub fn build(self) -> PollEventSet { + self.inner + } +} + +#[cfg(unix)] +pub(crate) fn poll( + selfs: &[&dyn WasiFile], + events: &[PollEventSet], + seen_events: &mut [PollEventSet], +) -> Result { + if !(selfs.len() == events.len() && events.len() == seen_events.len()) { + return Err(WasiFsError::InvalidInput); + } + let mut fds = selfs + .iter() + .enumerate() + .filter_map(|(i, s)| s.get_raw_fd().map(|rfd| (i, rfd))) + .map(|(i, host_fd)| libc::pollfd { + fd: host_fd, + events: poll_event_set_to_platform_poll_events(events[i]), + revents: 0, + }) + .collect::>(); + let result = unsafe { libc::poll(fds.as_mut_ptr(), selfs.len() as _, 1) }; + + if result < 0 { + // TODO: check errno and return value + return Err(WasiFsError::IOError); + } + // convert result and write back values + for (i, fd) in fds.into_iter().enumerate() { + seen_events[i] = platform_poll_events_to_pollevent_set(fd.revents); + } + // unwrap is safe because we check for negative values above + Ok(result.try_into().unwrap()) +} + +#[cfg(not(unix))] +pub(crate) fn poll( + _selfs: &[&dyn WasiFile], + _events: &[PollEventSet], + _seen_events: &mut [PollEventSet], +) -> Result<(), WasiFsError> { + unimplemented!("HostFile::poll in WasiFile is not implemented for non-Unix-like targets yet"); } pub trait WasiPath {} @@ -282,6 +451,40 @@ impl WasiFile for HostFile { fn rename_file(&self, new_name: &std::path::Path) -> Result<(), WasiFsError> { std::fs::rename(&self.host_path, new_name).map_err(Into::into) } + + #[cfg(unix)] + fn bytes_available(&self) -> Result { + use std::os::unix::io::AsRawFd; + let host_fd = self.inner.as_raw_fd(); + + let mut bytes_found = 0 as libc::c_int; + let result = unsafe { libc::ioctl(host_fd, libc::FIONREAD, &mut bytes_found) }; + + match result { + // success + 0 => Ok(bytes_found.try_into().unwrap_or(0)), + libc::EBADF => Err(WasiFsError::InvalidFd), + libc::EFAULT => Err(WasiFsError::InvalidData), + libc::EINVAL => Err(WasiFsError::InvalidInput), + _ => Err(WasiFsError::IOError), + } + } + #[cfg(not(unix))] + fn bytes_available(&self) -> Result { + unimplemented!("HostFile::bytes_available in WasiFile is not implemented for non-Unix-like targets yet"); + } + + #[cfg(unix)] + fn get_raw_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.inner.as_raw_fd()) + } + #[cfg(not(unix))] + fn get_raw_fd(&self) -> Option { + unimplemented!( + "HostFile::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet" + ); + } } impl From for WasiFsError { @@ -375,6 +578,19 @@ impl WasiFile for Stdout { fn size(&self) -> u64 { 0 } + + #[cfg(unix)] + fn get_raw_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.0.as_raw_fd()) + } + + #[cfg(not(unix))] + fn get_raw_fd(&self) -> Option { + unimplemented!( + "Stdout::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet" + ); + } } #[derive(Debug)] @@ -441,6 +657,19 @@ impl WasiFile for Stderr { fn size(&self) -> u64 { 0 } + + #[cfg(unix)] + fn get_raw_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.0.as_raw_fd()) + } + + #[cfg(not(unix))] + fn get_raw_fd(&self) -> Option { + unimplemented!( + "Stderr::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet" + ); + } } #[derive(Debug)] @@ -507,6 +736,43 @@ impl WasiFile for Stdin { fn size(&self) -> u64 { 0 } + + #[cfg(unix)] + fn bytes_available(&self) -> Result { + use std::os::unix::io::AsRawFd; + let host_fd = self.0.as_raw_fd(); + + let mut bytes_found = 0 as libc::c_int; + let result = unsafe { libc::ioctl(host_fd, libc::FIONREAD, &mut bytes_found) }; + + match result { + // success + 0 => Ok(bytes_found.try_into().unwrap_or(0)), + libc::EBADF => Err(WasiFsError::InvalidFd), + libc::EFAULT => Err(WasiFsError::InvalidData), + libc::EINVAL => Err(WasiFsError::InvalidInput), + _ => Err(WasiFsError::IOError), + } + } + #[cfg(not(unix))] + fn bytes_available(&self) -> Result { + unimplemented!( + "Stdin::bytes_available in WasiFile is not implemented for non-Unix-like targets yet" + ); + } + + #[cfg(unix)] + fn get_raw_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.0.as_raw_fd()) + } + + #[cfg(not(unix))] + fn get_raw_fd(&self) -> Option { + unimplemented!( + "Stdin::get_raw_fd in WasiFile is not implemented for non-Unix-like targets yet" + ); + } } /* diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 8e403537a..dc8bebff4 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -9,15 +9,16 @@ use self::types::*; use crate::{ ptr::{Array, WasmPtr}, state::{ - self, host_file_type_to_wasi_file_type, Fd, HostFile, Inode, InodeVal, Kind, WasiFile, - WasiFsError, WasiState, MAX_SYMLINKS, + self, host_file_type_to_wasi_file_type, iterate_poll_events, poll, Fd, HostFile, Inode, + InodeVal, Kind, PollEvent, PollEventBuilder, WasiFile, WasiFsError, WasiState, + MAX_SYMLINKS, }, ExitCode, }; use rand::{thread_rng, Rng}; use std::borrow::Borrow; use std::cell::Cell; -use std::convert::Infallible; +use std::convert::{Infallible, TryInto}; use std::io::{self, Read, Seek, Write}; use wasmer_runtime_core::{debug, memory::Memory, vm::Ctx}; @@ -2242,7 +2243,124 @@ pub fn poll_oneoff( nevents: WasmPtr, ) -> __wasi_errno_t { debug!("wasi::poll_oneoff"); - unimplemented!("wasi::poll_oneoff") + debug!(" => nsubscriptions = {}", nsubscriptions); + let memory = ctx.memory(0); + let state = get_wasi_state(ctx); + + let subscription_array = wasi_try!(in_.deref(memory, 0, nsubscriptions)); + let event_array = wasi_try!(out_.deref(memory, 0, nsubscriptions)); + let mut events_seen = 0; + let out_ptr = wasi_try!(nevents.deref(memory)); + + let mut fds = vec![]; + let mut in_events = vec![]; + + for sub in subscription_array.iter() { + let s: WasiSubscription = wasi_try!(sub.get().try_into()); + let mut peb = PollEventBuilder::new(); + + let fd = match s.event_type { + EventType::Read(__wasi_subscription_fs_readwrite_t { fd }) => { + let fd_entry = wasi_try!(state.fs.get_fd(fd)); + if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_READ) { + return __WASI_EACCES; + } + in_events.push(peb.add(PollEvent::PollIn).build()); + Some(fd) + } + EventType::Write(__wasi_subscription_fs_readwrite_t { fd }) => { + let fd_entry = wasi_try!(state.fs.get_fd(fd)); + if !has_rights(fd_entry.rights, __WASI_RIGHT_FD_WRITE) { + return __WASI_EACCES; + } + in_events.push(peb.add(PollEvent::PollOut).build()); + Some(fd) + } + _ => unimplemented!("Clock eventtypes in wasi::poll_oneoff"), + }; + + if let Some(fd) = fd { + let wasi_file_ref: &dyn WasiFile = match fd { + __WASI_STDERR_FILENO => state.fs.stderr.as_ref(), + __WASI_STDIN_FILENO => state.fs.stdin.as_ref(), + __WASI_STDOUT_FILENO => state.fs.stdout.as_ref(), + _ => { + let fd_entry = wasi_try!(state.fs.get_fd(fd)); + let inode = fd_entry.inode; + if !has_rights(fd_entry.rights, __WASI_RIGHT_POLL_FD_READWRITE) { + return __WASI_EACCES; + } + + match &state.fs.inodes[inode].kind { + Kind::File { handle, .. } => { + if let Some(h) = handle { + h.as_ref() + } else { + return __WASI_EBADF; + } + } + Kind::Dir { .. } + | Kind::Root { .. } + | Kind::Buffer { .. } + | Kind::Symlink { .. } => { + unimplemented!("polling read on non-files not yet supported") + } + } + } + }; + fds.push(wasi_file_ref); + } else { + unimplemented!("Clock events are not yet implemented!"); + } + } + let mut seen_events = vec![Default::default(); in_events.len()]; + wasi_try!(poll( + fds.as_slice(), + in_events.as_slice(), + seen_events.as_mut_slice() + ) + .map_err(|e| e.into_wasi_err())); + + for (i, seen_event) in seen_events.into_iter().enumerate() { + let mut flags = 0; + let mut error = __WASI_EAGAIN; + let mut bytes_available = 0; + let event_iter = iterate_poll_events(seen_event); + for event in event_iter { + match event { + PollEvent::PollError => error = __WASI_EIO, + PollEvent::PollHangUp => flags = __WASI_EVENT_FD_READWRITE_HANGUP, + PollEvent::PollInvalid => error = __WASI_EINVAL, + PollEvent::PollIn => { + bytes_available = + wasi_try!(fds[i].bytes_available().map_err(|e| e.into_wasi_err())); + error = __WASI_ESUCCESS; + } + PollEvent::PollOut => { + bytes_available = + wasi_try!(fds[i].bytes_available().map_err(|e| e.into_wasi_err())); + error = __WASI_ESUCCESS; + } + } + } + let event = __wasi_event_t { + userdata: subscription_array[i].get().userdata, + error, + type_: subscription_array[i].get().type_, + u: unsafe { + __wasi_event_u { + fd_readwrite: __wasi_event_fd_readwrite_t { + nbytes: bytes_available as u64, + flags, + }, + } + }, + }; + event_array[events_seen].set(event); + events_seen += 1; + } + out_ptr.set(events_seen as u32); + __WASI_ESUCCESS } pub fn proc_exit(ctx: &mut Ctx, code: __wasi_exitcode_t) -> Result { diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 10c4d24c9..a1c97308f 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -157,10 +157,19 @@ pub struct __wasi_event_fd_readwrite_t { #[derive(Copy, Clone)] #[repr(C)] pub union __wasi_event_u { - fd_readwrite: __wasi_event_fd_readwrite_t, + pub fd_readwrite: __wasi_event_fd_readwrite_t, } -#[derive(Copy, Clone)] +// TODO: remove this implementation of Debug when `__wasi_event_u` gets more than 1 variant +impl std::fmt::Debug for __wasi_event_u { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("__wasi_event_u") + .field("fd_readwrite", unsafe { &self.fd_readwrite }) + .finish() + } +} + +#[derive(Debug, Copy, Clone)] pub enum EventEnum { FdReadWrite { nbytes: __wasi_filesize_t, @@ -178,7 +187,7 @@ impl EventEnum { } } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] #[repr(C)] pub struct __wasi_event_t { pub userdata: __wasi_userdata_t, @@ -199,6 +208,8 @@ impl __wasi_event_t { } } +unsafe impl ValueType for __wasi_event_t {} + pub type __wasi_eventrwflags_t = u16; pub const __WASI_EVENT_FD_READWRITE_HANGUP: u16 = 1 << 0; @@ -207,6 +218,15 @@ pub const __WASI_EVENTTYPE_CLOCK: u8 = 0; pub const __WASI_EVENTTYPE_FD_READ: u8 = 1; pub const __WASI_EVENTTYPE_FD_WRITE: u8 = 2; +pub fn eventtype_to_str(event_type: __wasi_eventtype_t) -> &'static str { + match event_type { + __WASI_EVENTTYPE_CLOCK => "__WASI_EVENTTYPE_CLOCK", + __WASI_EVENTTYPE_FD_READ => "__WASI_EVENTTYPE_FD_READ", + __WASI_EVENTTYPE_FD_WRITE => "__WASI_EVENTTYPE_FD_WRITE", + _ => "INVALID EVENTTYPE", + } +} + pub type __wasi_exitcode_t = u32; pub type __wasi_fd_t = u32; @@ -562,6 +582,93 @@ pub struct __wasi_subscription_t { pub u: __wasi_subscription_u, } +/// Safe Rust wrapper around `__wasi_subscription_t::type_` and `__wasi_subscription_t::u` +#[derive(Debug, Clone)] +pub enum EventType { + Clock(__wasi_subscription_clock_t), + Read(__wasi_subscription_fs_readwrite_t), + Write(__wasi_subscription_fs_readwrite_t), +} + +impl EventType { + pub fn raw_tag(&self) -> __wasi_eventtype_t { + match self { + EventType::Clock(_) => __WASI_EVENTTYPE_CLOCK, + EventType::Read(_) => __WASI_EVENTTYPE_FD_READ, + EventType::Write(_) => __WASI_EVENTTYPE_FD_WRITE, + } + } +} + +/// Safe Rust wrapper around `__wasi_subscription_t` +#[derive(Debug, Clone)] +pub struct WasiSubscription { + pub user_data: __wasi_userdata_t, + pub event_type: EventType, +} + +impl std::convert::TryFrom<__wasi_subscription_t> for WasiSubscription { + type Error = __wasi_errno_t; + + fn try_from(ws: __wasi_subscription_t) -> Result { + Ok(Self { + user_data: ws.userdata, + event_type: match ws.type_ { + __WASI_EVENTTYPE_CLOCK => EventType::Clock(unsafe { ws.u.clock }), + __WASI_EVENTTYPE_FD_READ => EventType::Read(unsafe { ws.u.fd_readwrite }), + __WASI_EVENTTYPE_FD_WRITE => EventType::Write(unsafe { ws.u.fd_readwrite }), + _ => return Err(__WASI_EINVAL), + }, + }) + } +} + +impl std::convert::TryFrom for __wasi_subscription_t { + type Error = __wasi_errno_t; + + fn try_from(ws: WasiSubscription) -> Result { + let (type_, u) = match ws.event_type { + EventType::Clock(c) => (__WASI_EVENTTYPE_CLOCK, __wasi_subscription_u { clock: c }), + EventType::Read(rw) => ( + __WASI_EVENTTYPE_FD_READ, + __wasi_subscription_u { fd_readwrite: rw }, + ), + EventType::Write(rw) => ( + __WASI_EVENTTYPE_FD_WRITE, + __wasi_subscription_u { fd_readwrite: rw }, + ), + _ => return Err(__WASI_EINVAL), + }; + + Ok(Self { + userdata: ws.user_data, + type_, + u, + }) + } +} + +impl std::fmt::Debug for __wasi_subscription_t { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("__wasi_subscription_t") + .field("userdata", &self.userdata) + .field("type", &eventtype_to_str(self.type_)) + .field( + "u", + match self.type_ { + __WASI_EVENTTYPE_CLOCK => unsafe { &self.u.clock }, + __WASI_EVENTTYPE_FD_READ | __WASI_EVENTTYPE_FD_WRITE => unsafe { + &self.u.fd_readwrite + }, + _ => &"INVALID EVENTTYPE", + }, + ) + .finish() + } +} + +unsafe impl ValueType for __wasi_subscription_t {} + pub enum SubscriptionEnum { Clock(__wasi_subscription_clock_t), FdReadWrite(__wasi_subscription_fs_readwrite_t), diff --git a/lib/win-exception-handler/src/lib.rs b/lib/win-exception-handler/src/lib.rs index f2561fda0..cf5e8396f 100644 --- a/lib/win-exception-handler/src/lib.rs +++ b/lib/win-exception-handler/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/logo.png b/logo.png index ec6e92513..a52c56b20 100644 Binary files a/logo.png and b/logo.png differ diff --git a/src/bin/kwasmd.rs b/src/bin/kwasmd.rs index fc67b6a60..62e22b731 100644 --- a/src/bin/kwasmd.rs +++ b/src/bin/kwasmd.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index e12c0db94..3a8c43949 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns @@ -532,7 +534,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { // TODO: refactor this if wasmer_emscripten::is_emscripten_module(&module) { - let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module); + let mut emscripten_globals = wasmer_emscripten::EmscriptenGlobals::new(&module)?; let import_object = wasmer_emscripten::generate_emscripten_env(&mut emscripten_globals); let mut instance = module .instantiate(&import_object) diff --git a/src/lib.rs b/src/lib.rs index 43534b78c..3d0b047ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ #![deny( dead_code, + nonstandard_style, unused_imports, + unused_mut, unused_variables, unused_unsafe, unreachable_patterns