From b45b1c12f14b05af43a8618049283e61a2d36796 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 1 Oct 2019 12:08:45 -0700 Subject: [PATCH 001/122] Add WASI support to runtime-c-api --- Cargo.lock | 1 + lib/runtime-c-api/Cargo.toml | 9 ++- lib/runtime-c-api/src/import.rs | 104 ++++++++++++++++++++++++++++++++ lib/runtime-c-api/src/lib.rs | 20 ++++++ lib/runtime-c-api/wasmer.h | 36 +++++++++++ lib/runtime-c-api/wasmer.hh | 26 ++++++++ 6 files changed, 195 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fb642644e..c104006bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1639,6 +1639,7 @@ dependencies = [ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.7.0", "wasmer-runtime-core 0.7.0", + "wasmer-wasi 0.7.0", ] [[package]] diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index bcfa4bec5..75d421414 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -24,12 +24,19 @@ default-features = false path = "../runtime-core" version = "0.7.0" +[dependencies.wasmer-wasi] +default-features = false +path = "../wasi" +version = "0.7.0" +optional = true + [features] -default = ["cranelift-backend"] +default = ["cranelift-backend", "wasi"] debug = ["wasmer-runtime/debug"] cranelift-backend = ["wasmer-runtime/cranelift", "wasmer-runtime/default-backend-cranelift"] llvm-backend = ["wasmer-runtime/llvm", "wasmer-runtime/default-backend-llvm"] singlepass-backend = ["wasmer-runtime/singlepass", "wasmer-runtime/default-backend-singlepass"] +wasi = ["wasmer-wasi"] [build-dependencies] cbindgen = "0.9" diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index 2d6f9e99d..abd35c9d0 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -51,6 +51,110 @@ pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object Box::into_raw(import_object) as *mut wasmer_import_object_t } +#[cfg(feature = "wasi")] +mod wasi { + use super::*; + use std::path::PathBuf; + + /// Opens a directory that's visible to the WASI module as `alias` but + /// is backed by the host file at `host_file_path` + #[repr(C)] + pub struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + pub alias: wasmer_byte_array, + /// The backing file that the WASI module will interact with via the alias + pub host_file_path: wasmer_byte_array, + } + + impl wasmer_wasi_map_dir_entry_t { + /// Converts the data into owned, Rust types + pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), std::str::Utf8Error> { + let alias = self.alias.as_str()?.to_owned(); + let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?); + + Ok((alias, host_path)) + } + } + + /// Creates a WASI import object + #[no_mangle] + pub unsafe extern "C" fn wasmer_wasi_generate_import_object( + args: *const wasmer_byte_array, + args_len: c_uint, + envs: *const wasmer_byte_array, + envs_len: c_uint, + preopened_files: *const wasmer_byte_array, + preopened_files_len: c_uint, + mapped_dirs: *const wasmer_wasi_map_dir_entry_t, + mapped_dirs_len: c_uint, + ) -> *mut wasmer_import_object_t { + let arg_list = std::slice::from_raw_parts(args, args_len as usize); + let env_list = std::slice::from_raw_parts(envs, envs_len as usize); + let preopened_file_list = + std::slice::from_raw_parts(preopened_files, preopened_files_len as usize); + let mapped_dir_list = std::slice::from_raw_parts(mapped_dirs, mapped_dirs_len as usize); + + wasmer_wasi_generate_import_object_inner( + arg_list, + env_list, + preopened_file_list, + mapped_dir_list, + ) + .unwrap_or(std::ptr::null_mut()) + } + + /// Inner function that wraps error handling + fn wasmer_wasi_generate_import_object_inner( + arg_list: &[wasmer_byte_array], + env_list: &[wasmer_byte_array], + preopened_file_list: &[wasmer_byte_array], + mapped_dir_list: &[wasmer_wasi_map_dir_entry_t], + ) -> Result<*mut wasmer_import_object_t, std::str::Utf8Error> { + let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect(); + let env_vec = env_list + .iter() + .map(|env_var| unsafe { env_var.as_vec() }) + .collect(); + let po_file_vec = preopened_file_list + .iter() + .map(|po_file| Ok(unsafe { po_file.as_str()? }.to_owned())) + .collect::, _>>()?; + let mapped_dir_vec = mapped_dir_list + .iter() + .map(|entry| unsafe { entry.as_tuple() }) + .collect::, _>>()?; + + let import_object = Box::new(wasmer_wasi::generate_import_object( + arg_vec, + env_vec, + po_file_vec, + mapped_dir_vec, + )); + Ok(Box::into_raw(import_object) as *mut wasmer_import_object_t) + } + + /// Convenience function that creates a WASI import object with no arguments, + /// environment variables, preopened files, or mapped directories. + /// + /// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all + /// empty values. + #[no_mangle] + pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object( + ) -> *mut wasmer_import_object_t { + let import_object = Box::new(wasmer_wasi::generate_import_object( + vec![], + vec![], + vec![], + vec![], + )); + + Box::into_raw(import_object) as *mut wasmer_import_object_t + } +} + +#[cfg(feature = "wasi")] +pub use self::wasi::*; + /// Extends an existing import object with new imports #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index 4dae18cd5..a2433afa2 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -129,3 +129,23 @@ pub struct wasmer_byte_array { pub bytes: *const u8, pub bytes_len: u32, } + +impl wasmer_byte_array { + /// Get the data as a slice + pub unsafe fn as_slice<'a>(&self) -> &'a [u8] { + std::slice::from_raw_parts(self.bytes, self.bytes_len as usize) + } + + /// Copy the data into an owned Vec + pub unsafe fn as_vec(&self) -> Vec { + let mut out = Vec::with_capacity(self.bytes_len as usize); + out.extend_from_slice(self.as_slice()); + + out + } + + /// Read the data as a &str, returns an error if the string is not valid UTF8 + pub unsafe fn as_str<'a>(&self) -> Result<&'a str, std::str::Utf8Error> { + std::str::from_utf8(self.as_slice()) + } +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 447d31075..a13a40c92 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -170,6 +170,21 @@ typedef struct { } wasmer_trampoline_buffer_t; +/** + * Opens a directory that's visible to the WASI module as `alias` but + * is backed by the host file at `host_file_path` + */ +typedef struct { + /** + * What the WASI module will see in its virtual root + */ + wasmer_byte_array alias; + /** + * The backing file that the WASI module will interact with via the alias + */ + wasmer_byte_array host_file_path; +} wasmer_wasi_map_dir_entry_t; + /** * Creates a new Module from the given wasm bytes. * @@ -756,4 +771,25 @@ void *wasmer_trampoline_get_context(void); */ bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/** + * Convenience function that creates a WASI import object with no arguments, + * environment variables, preopened files, or mapped directories. + * + * This function is the same as calling [`wasmer_wasi_generate_import_object`] with all + * empty values. + */ +wasmer_import_object_t *wasmer_wasi_generate_default_import_object(void); + +/** + * Creates a WASI import object + */ +wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); + #endif /* WASMER_H */ diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index d372d8eb3..51cdaa5c9 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -154,6 +154,15 @@ struct wasmer_trampoline_buffer_t { }; +/// Opens a directory that's visible to the WASI module as `alias` but +/// is backed by the host file at `host_file_path` +struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + wasmer_byte_array alias; + /// The backing file that the WASI module will interact with via the alias + wasmer_byte_array host_file_path; +}; + extern "C" { /// Creates a new Module from the given wasm bytes. @@ -590,6 +599,23 @@ void *wasmer_trampoline_get_context(); /// Returns true for valid wasm bytes and false for invalid bytes bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); +/// Convenience function that creates a WASI import object with no arguments, +/// environment variables, preopened files, or mapped directories. +/// +/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all +/// empty values. +wasmer_import_object_t *wasmer_wasi_generate_default_import_object(); + +/// Creates a WASI import object +wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, + unsigned int args_len, + const wasmer_byte_array *envs, + unsigned int envs_len, + const wasmer_byte_array *preopened_files, + unsigned int preopened_files_len, + const wasmer_wasi_map_dir_entry_t *mapped_dirs, + unsigned int mapped_dirs_len); + } // extern "C" #endif // WASMER_H From 4b3880c88b37f084e20fbf6bfd5cfd8d38a16913 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Thu, 3 Oct 2019 11:26:54 +0200 Subject: [PATCH 002/122] add details when calling unimplemented! --- lib/clif-backend/src/code.rs | 2 +- lib/clif-backend/src/relocation.rs | 12 ++++----- lib/clif-backend/src/signal/unix.rs | 5 +++- lib/clif-backend/src/signal/windows.rs | 2 +- lib/clif-backend/src/trampoline.rs | 2 +- lib/emscripten/src/exception.rs | 8 +++--- lib/emscripten/src/io/mod.rs | 8 +++--- lib/emscripten/src/io/windows.rs | 4 +-- lib/emscripten/src/syscalls/unix.rs | 4 +-- lib/emscripten/src/syscalls/windows.rs | 36 +++++++++++++------------- lib/runtime-core/src/loader.rs | 10 +++---- lib/runtime-core/src/vm.rs | 6 ++--- lib/runtime-core/src/vmcalls.rs | 4 +-- lib/wasi/src/state/mod.rs | 2 +- 14 files changed, 54 insertions(+), 51 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index b2ccc6652..92302c484 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -279,7 +279,7 @@ impl ModuleCodeGenerator ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), - _ => unimplemented!(), + _ => unimplemented!("unimplemented type {}", param), }; } diff --git a/lib/clif-backend/src/relocation.rs b/lib/clif-backend/src/relocation.rs index bb07c7c59..a86bdeec9 100644 --- a/lib/clif-backend/src/relocation.rs +++ b/lib/clif-backend/src/relocation.rs @@ -105,7 +105,7 @@ impl binemit::RelocSink for RelocSink { _ebb_offset: binemit::CodeOffset, ) { // This should use the `offsets` field of `ir::Function`. - unimplemented!(); + unimplemented!("RelocSink::reloc_ebb"); } fn reloc_external( &mut self, @@ -146,7 +146,7 @@ impl binemit::RelocSink for RelocSink { DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow, DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize, - _ => unimplemented!(), + _ => unimplemented!("reloc_external VmCall::Local {}", index), })), IMPORT_NAMESPACE => RelocationType::VmCall(VmCall::Import(match index { STATIC_MEM_GROW => VmCallKind::StaticMemoryGrow, @@ -157,10 +157,10 @@ impl binemit::RelocSink for RelocSink { DYNAMIC_MEM_GROW => VmCallKind::DynamicMemoryGrow, DYNAMIC_MEM_SIZE => VmCallKind::DynamicMemorySize, - _ => unimplemented!(), + _ => unimplemented!("reloc_external VmCall::Import {}", index), })), SIG_NAMESPACE => RelocationType::Signature(SigIndex::new(index as usize)), - _ => unimplemented!(), + _ => unimplemented!("reloc_external SigIndex {}", index), }; self.external_relocs.push(ExternalRelocation { reloc, @@ -204,7 +204,7 @@ impl binemit::RelocSink for RelocSink { } fn reloc_constant(&mut self, _: u32, _: cranelift_codegen::binemit::Reloc, _: u32) { - unimplemented!() + unimplemented!("RelocSink::reloc_constant") } fn reloc_jt( @@ -213,7 +213,7 @@ impl binemit::RelocSink for RelocSink { _reloc: binemit::Reloc, _jt: ir::JumpTable, ) { - unimplemented!(); + unimplemented!("RelocSink::reloc_jt"); } } diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index 39f3aa893..e300da131 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -98,7 +98,10 @@ pub fn call_protected( }, Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds, Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic, - _ => unimplemented!(), + _ => unimplemented!( + "WasmTrapInfo::Unknown signal:{}", + Signal::from_c_int(signum) + ), })) } else { let signal = match Signal::from_c_int(signum) { diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index d755cd575..52dc3e966 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -110,5 +110,5 @@ pub fn call_protected( pub unsafe fn trigger_trap() -> ! { // TODO - unimplemented!(); + unimplemented!("windows::trigger_trap"); } diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index a6fc6572b..f9c7245e9 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -22,7 +22,7 @@ impl RelocSink for NullRelocSink { fn reloc_external(&mut self, _: u32, _: Reloc, _: &ir::ExternalName, _: i64) {} fn reloc_constant(&mut self, _: u32, _: Reloc, _: u32) { - unimplemented!() + unimplemented!("RelocSink::reloc_constant") } fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {} diff --git a/lib/emscripten/src/exception.rs b/lib/emscripten/src/exception.rs index 09f04a798..09ae286f8 100644 --- a/lib/emscripten/src/exception.rs +++ b/lib/emscripten/src/exception.rs @@ -10,22 +10,22 @@ pub fn ___cxa_allocate_exception(ctx: &mut Ctx, size: u32) -> u32 { pub fn ___cxa_current_primary_exception(_ctx: &mut Ctx) -> u32 { debug!("emscripten::___cxa_current_primary_exception"); - unimplemented!() + unimplemented!("emscripten::___cxa_current_primary_exception") } pub fn ___cxa_decrement_exception_refcount(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_decrement_exception_refcount({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_decrement_exception_refcount({})", _a) } pub fn ___cxa_increment_exception_refcount(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_increment_exception_refcount({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_increment_exception_refcount({})", _a) } pub fn ___cxa_rethrow_primary_exception(_ctx: &mut Ctx, _a: u32) { debug!("emscripten::___cxa_rethrow_primary_exception({})", _a); - unimplemented!() + unimplemented!("emscripten::___cxa_rethrow_primary_exception({})", _a) } /// emscripten: ___cxa_throw diff --git a/lib/emscripten/src/io/mod.rs b/lib/emscripten/src/io/mod.rs index 6666cd5af..bad5935fe 100644 --- a/lib/emscripten/src/io/mod.rs +++ b/lib/emscripten/src/io/mod.rs @@ -15,13 +15,13 @@ use wasmer_runtime_core::vm::Ctx; /// getprotobyname pub fn getprotobyname(_ctx: &mut Ctx, _name_ptr: i32) -> i32 { debug!("emscripten::getprotobyname"); - unimplemented!() + unimplemented!("emscripten::getprotobyname") } /// getprotobynumber pub fn getprotobynumber(_ctx: &mut Ctx, _one: i32) -> i32 { debug!("emscripten::getprotobynumber"); - unimplemented!() + unimplemented!("emscripten::getprotobynumber") } /// sigdelset @@ -53,11 +53,11 @@ pub fn sigfillset(ctx: &mut Ctx, set: i32) -> i32 { /// tzset pub fn tzset(_ctx: &mut Ctx) { debug!("emscripten::tzset - stub"); - //unimplemented!() + //unimplemented!("emscripten::tzset - stub") } /// strptime pub fn strptime(_ctx: &mut Ctx, _one: i32, _two: i32, _three: i32) -> i32 { debug!("emscripten::strptime"); - unimplemented!() + unimplemented!("emscripten::strptime") } diff --git a/lib/emscripten/src/io/windows.rs b/lib/emscripten/src/io/windows.rs index a3c6f70aa..a7d6dc60b 100644 --- a/lib/emscripten/src/io/windows.rs +++ b/lib/emscripten/src/io/windows.rs @@ -36,11 +36,11 @@ pub fn printf(_ctx: &mut Ctx, memory_offset: i32, extra: i32) -> i32 { /// chroot pub fn chroot(_ctx: &mut Ctx, _name_ptr: i32) -> i32 { debug!("emscripten::chroot"); - unimplemented!() + unimplemented!("emscripten::chroot") } /// getpwuid pub fn getpwuid(_ctx: &mut Ctx, _uid: i32) -> i32 { debug!("emscripten::getpwuid"); - unimplemented!() + unimplemented!("emscripten::getpwuid") } diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index efcff0a5e..cb015af3a 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -259,7 +259,7 @@ pub fn ___syscall194(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in ftruncate64(_fd, _length) } #[cfg(target_os = "macos")] - unimplemented!() + unimplemented!("emscripten::___syscall194 (ftruncate64) {}", _which) } /// lchown @@ -1111,6 +1111,6 @@ pub fn ___syscall324(ctx: &mut Ctx, _which: c_int, mut varargs: VarArgs) -> c_in } #[cfg(target_os = "macos")] { - unimplemented!() + unimplemented!("emscripten::___syscall324 (fallocate) {}", _which) } } diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index f6a867356..3c1f32dac 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -66,13 +66,13 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { /// link pub fn ___syscall9(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall9 (link) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall9 (link) {}", _which); } /// ftruncate64 pub fn ___syscall194(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall194 - stub"); - unimplemented!() + unimplemented!("emscripten::___syscall194 - stub") } // chown @@ -86,13 +86,13 @@ pub fn ___syscall212(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// access pub fn ___syscall33(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall33 (access) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall33 (access) {}", _which); } /// nice pub fn ___syscall34(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall34 (nice) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall34 (nice) {}", _which); } // mkdir @@ -113,19 +113,19 @@ pub fn ___syscall39(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int /// dup pub fn ___syscall41(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall41 (dup) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall41 (dup) {}", _which); } /// getrusage pub fn ___syscall77(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall77 (getrusage) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall77 (getrusage) {}", _which); } /// symlink pub fn ___syscall83(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall83 (symlink) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall83 (symlink) {}", _which); } /// readlink @@ -143,38 +143,38 @@ pub fn ___syscall132(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_ /// lchown pub fn ___syscall198(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall198 (lchown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall198 (lchown) {}", _which); } /// getgid32 pub fn ___syscall200(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall200 (getgid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall200 (getgid32)"); } // geteuid32 pub fn ___syscall201(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { debug!("emscripten::___syscall201 (geteuid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall201 (geteuid32)"); } // getegid32 pub fn ___syscall202(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 { // gid_t debug!("emscripten::___syscall202 (getegid32)"); - unimplemented!(); + unimplemented!("emscripten::___syscall202 (getegid32)"); } /// getgroups pub fn ___syscall205(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall205 (getgroups) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall205 (getgroups) {}", _which); } /// madvise pub fn ___syscall219(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall212 (chown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall212 (chown) {}", _which); } /// dup3 @@ -194,7 +194,7 @@ pub fn ___syscall54(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_in /// fchmod pub fn ___syscall94(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall118 (fchmod) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall118 (fchmod) {}", _which); } // socketcall @@ -209,7 +209,7 @@ pub fn ___syscall102(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// fsync pub fn ___syscall118(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall118 (fsync) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall118 (fsync) {}", _which); } // pread @@ -247,7 +247,7 @@ pub fn ___syscall142(_ctx: &mut Ctx, which: c_int, mut _varargs: VarArgs) -> c_i /// fdatasync pub fn ___syscall148(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall148 (fdatasync) {}", _which); - unimplemented!(); + unimplemented!("emscripten::___syscall148 (fdatasync) {}", _which); } // setpgid @@ -300,11 +300,11 @@ pub fn ___syscall221(_ctx: &mut Ctx, _which: c_int, mut _varargs: VarArgs) -> c_ /// fchown pub fn ___syscall207(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall207 (fchown) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall207 (fchown) {}", _which) } /// fallocate pub fn ___syscall324(_ctx: &mut Ctx, _which: c_int, _varargs: VarArgs) -> c_int { debug!("emscripten::___syscall324 (fallocate) {}", _which); - unimplemented!() + unimplemented!("emscripten::___syscall324 (fallocate) {}", _which) } diff --git a/lib/runtime-core/src/loader.rs b/lib/runtime-core/src/loader.rs index 4f843a54d..f50d3a7a0 100644 --- a/lib/runtime-core/src/loader.rs +++ b/lib/runtime-core/src/loader.rs @@ -22,11 +22,11 @@ pub trait Instance { type Error: Debug; fn call(&mut self, id: usize, args: &[Value]) -> Result; fn read_memory(&mut self, _offset: u32, _len: u32) -> Result, Self::Error> { - unimplemented!() + unimplemented!("Instance::read_memory") } fn write_memory(&mut self, _offset: u32, _len: u32, _buf: &[u8]) -> Result<(), Self::Error> { - unimplemented!() + unimplemented!("Instance::write_memory") } } @@ -122,15 +122,15 @@ unsafe impl Sync for CodeMemory {} #[cfg(not(unix))] impl CodeMemory { pub fn new(_size: usize) -> CodeMemory { - unimplemented!(); + unimplemented!("CodeMemory::new"); } pub fn make_executable(&self) { - unimplemented!(); + unimplemented!("CodeMemory::make_executable"); } pub fn make_writable(&self) { - unimplemented!(); + unimplemented!("CodeMemory::make_writable"); } } diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index fd8cebbec..2bb734a04 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -916,15 +916,15 @@ mod vm_ctx_tests { } fn get_trampoline(&self, _module: &ModuleInfo, _sig_index: SigIndex) -> Option { - unimplemented!() + unimplemented!("generate_module::get_trampoline") } unsafe fn do_early_trap(&self, _: Box) -> ! { - unimplemented!() + unimplemented!("generate_module::do_early_trap") } } impl CacheGen for Placeholder { fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - unimplemented!() + unimplemented!("generate_module::generate_cache") } } diff --git a/lib/runtime-core/src/vmcalls.rs b/lib/runtime-core/src/vmcalls.rs index 5205a0d69..21c99dbf5 100644 --- a/lib/runtime-core/src/vmcalls.rs +++ b/lib/runtime-core/src/vmcalls.rs @@ -150,11 +150,11 @@ pub unsafe extern "C" fn local_table_grow( let _ = table_index; let _ = delta; let _ = ctx; - unimplemented!() + unimplemented!("vmcalls::local_table_grow") } pub unsafe extern "C" fn local_table_size(ctx: &vm::Ctx, table_index: LocalTableIndex) -> u32 { let _ = table_index; let _ = ctx; - unimplemented!() + unimplemented!("vmcalls::local_table_size") } diff --git a/lib/wasi/src/state/mod.rs b/lib/wasi/src/state/mod.rs index 39fd38378..2410cc177 100644 --- a/lib/wasi/src/state/mod.rs +++ b/lib/wasi/src/state/mod.rs @@ -793,7 +793,7 @@ impl WasiFs { } // TODO: verify this behavior Kind::Dir { .. } => return Err(__WASI_EISDIR), - Kind::Symlink { .. } => unimplemented!(), + Kind::Symlink { .. } => unimplemented!("WasiFs::flush Kind::Symlink"), Kind::Buffer { .. } => (), _ => return Err(__WASI_EIO), } From ba1b55d6c8c4274dbbd5c9aa923687c146ec5947 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Thu, 3 Oct 2019 11:34:40 +0200 Subject: [PATCH 003/122] add changelog entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11365bb9..e40e0cb06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#861](https://github.com/wasmerio/wasmer/pull/861) Add information when `unimplemented!` macro is called + ## 0.8.0 - 2019-10-02 Special thanks to @jdanford for their contributions! From 70b55b801d4990f9931fd748856bb3e490e1dfb8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 3 Oct 2019 10:50:07 -0700 Subject: [PATCH 004/122] Check argument pointers for null to WASI calls --- lib/runtime-c-api/src/import.rs | 16 ++++++++++------ lib/runtime-c-api/src/lib.rs | 13 ++++++++++++- lib/runtime-c-api/wasmer.h | 6 +++++- lib/runtime-c-api/wasmer.hh | 6 +++++- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index abd35c9d0..bdbc1bea3 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -54,6 +54,7 @@ pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object #[cfg(feature = "wasi")] mod wasi { use super::*; + use crate::get_slice_checked; use std::path::PathBuf; /// Opens a directory that's visible to the WASI module as `alias` but @@ -76,7 +77,11 @@ mod wasi { } } - /// Creates a WASI import object + /// Creates a WASI import object. + /// + /// This function treats null pointers as empty collections. + /// For example, passing null for a string in `args`, will lead to a zero + /// length argument in that position. #[no_mangle] pub unsafe extern "C" fn wasmer_wasi_generate_import_object( args: *const wasmer_byte_array, @@ -88,11 +93,10 @@ mod wasi { mapped_dirs: *const wasmer_wasi_map_dir_entry_t, mapped_dirs_len: c_uint, ) -> *mut wasmer_import_object_t { - let arg_list = std::slice::from_raw_parts(args, args_len as usize); - let env_list = std::slice::from_raw_parts(envs, envs_len as usize); - let preopened_file_list = - std::slice::from_raw_parts(preopened_files, preopened_files_len as usize); - let mapped_dir_list = std::slice::from_raw_parts(mapped_dirs, mapped_dirs_len as usize); + let arg_list = get_slice_checked(args, args_len as usize); + let env_list = get_slice_checked(envs, envs_len as usize); + let preopened_file_list = get_slice_checked(preopened_files, preopened_files_len as usize); + let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); wasmer_wasi_generate_import_object_inner( arg_list, diff --git a/lib/runtime-c-api/src/lib.rs b/lib/runtime-c-api/src/lib.rs index a2433afa2..17e96a4c3 100644 --- a/lib/runtime-c-api/src/lib.rs +++ b/lib/runtime-c-api/src/lib.rs @@ -133,7 +133,7 @@ pub struct wasmer_byte_array { impl wasmer_byte_array { /// Get the data as a slice pub unsafe fn as_slice<'a>(&self) -> &'a [u8] { - std::slice::from_raw_parts(self.bytes, self.bytes_len as usize) + get_slice_checked(self.bytes, self.bytes_len as usize) } /// Copy the data into an owned Vec @@ -149,3 +149,14 @@ impl wasmer_byte_array { std::str::from_utf8(self.as_slice()) } } + +/// Gets a slice from a pointer and a length, returning an empty slice if the +/// pointer is null +#[inline] +pub(crate) unsafe fn get_slice_checked<'a, T>(ptr: *const T, len: usize) -> &'a [T] { + if ptr.is_null() { + &[] + } else { + std::slice::from_raw_parts(ptr, len) + } +} diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index a13a40c92..23caa54cc 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -781,7 +781,11 @@ bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); wasmer_import_object_t *wasmer_wasi_generate_default_import_object(void); /** - * Creates a WASI import object + * Creates a WASI import object. + * + * This function treats null pointers as empty collections. + * For example, passing null for a string in `args`, will lead to a zero + * length argument in that position. */ wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, unsigned int args_len, diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 51cdaa5c9..da8e39118 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -606,7 +606,11 @@ bool wasmer_validate(const uint8_t *wasm_bytes, uint32_t wasm_bytes_len); /// empty values. wasmer_import_object_t *wasmer_wasi_generate_default_import_object(); -/// Creates a WASI import object +/// Creates a WASI import object. +/// +/// This function treats null pointers as empty collections. +/// For example, passing null for a string in `args`, will lead to a zero +/// length argument in that position. wasmer_import_object_t *wasmer_wasi_generate_import_object(const wasmer_byte_array *args, unsigned int args_len, const wasmer_byte_array *envs, From bfb9d3849c7cf6b776adade45cbdb943174a4528 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 3 Oct 2019 11:58:06 -0700 Subject: [PATCH 005/122] Fix merge --- lib/runtime-c-api/Cargo.toml | 2 +- lib/runtime-c-api/src/import.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 05660a8b9..91815e7a7 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -27,7 +27,7 @@ version = "0.8.0" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.7.0" +version = "0.8.0" optional = true [features] diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index bdbc1bea3..19f415722 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -121,7 +121,7 @@ mod wasi { .collect(); let po_file_vec = preopened_file_list .iter() - .map(|po_file| Ok(unsafe { po_file.as_str()? }.to_owned())) + .map(|po_file| Ok(unsafe { PathBuf::from(po_file.as_str()?) }.to_owned())) .collect::, _>>()?; let mapped_dir_vec = mapped_dir_list .iter() From 1a7f00f0afe9f4756f6e5d236218143dc8377015 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 3 Oct 2019 18:19:12 -0700 Subject: [PATCH 006/122] Rewrite Min/Max to handle all cases correctly. Fixes 545 spectest failures. --- lib/llvm-backend/src/code.rs | 374 +++++++++++++++++--- lib/llvm-backend/src/intrinsics.rs | 10 +- lib/spectests/tests/excludes.txt | 548 ----------------------------- 3 files changed, 343 insertions(+), 589 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8ac76fe26..a1c69c082 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2693,31 +2693,139 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32Min => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f32_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F64Min => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f64_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F32x4Min => { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } @@ -2725,41 +2833,187 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F32Max => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f32_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F64Max => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f64_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F32x4Max => { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_zero.as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } @@ -2767,11 +3021,51 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_zero.as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 278e087bb..afd3bf8ad 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -6,7 +6,9 @@ use inkwell::{ types::{ BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType, }, - values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue}, + values::{ + BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue, VectorValue, + }, AddressSpace, }; use std::collections::HashMap; @@ -125,6 +127,8 @@ pub struct Intrinsics { pub i128_zero: IntValue, pub f32_zero: FloatValue, pub f64_zero: FloatValue, + pub f32x4_zero: VectorValue, + pub f64x2_zero: VectorValue, pub trap_unreachable: BasicValueEnum, pub trap_call_indirect_sig: BasicValueEnum, @@ -191,6 +195,8 @@ impl Intrinsics { let i128_zero = i128_ty.const_int(0, false); let f32_zero = f32_ty.const_float(0.0); let f64_zero = f64_ty.const_float(0.0); + let f32x4_zero = f32x4_ty.const_zero(); + let f64x2_zero = f64x2_ty.const_zero(); let i1_ty_basic = i1_ty.as_basic_type_enum(); let i32_ty_basic = i32_ty.as_basic_type_enum(); @@ -455,6 +461,8 @@ impl Intrinsics { i128_zero, f32_zero, f64_zero, + f32x4_zero, + f64x2_zero, trap_unreachable: i32_zero.as_basic_value_enum(), trap_call_indirect_sig: i32_ty.const_int(1, false).as_basic_value_enum(), diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 56c6a2d56..cb641ea53 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -265,554 +265,6 @@ clif:fail:data.wast:266:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:186:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:194:windows # AssertUnlinkable - caught panic Any -# LLVM bug with min/max over NaNs -llvm:skip:f32.wast:1651 -llvm:skip:f32.wast:1652 -llvm:skip:f32.wast:1653 -llvm:skip:f32.wast:1654 -llvm:skip:f32.wast:1655 -llvm:skip:f32.wast:1656 -llvm:skip:f32.wast:1657 -llvm:skip:f32.wast:1658 -llvm:skip:f32.wast:1691 -llvm:skip:f32.wast:1692 -llvm:skip:f32.wast:1693 -llvm:skip:f32.wast:1694 -llvm:skip:f32.wast:1695 -llvm:skip:f32.wast:1696 -llvm:skip:f32.wast:1697 -llvm:skip:f32.wast:1698 -llvm:skip:f32.wast:1731 -llvm:skip:f32.wast:1732 -llvm:skip:f32.wast:1733 -llvm:skip:f32.wast:1734 -llvm:skip:f32.wast:1735 -llvm:skip:f32.wast:1736 -llvm:skip:f32.wast:1737 -llvm:skip:f32.wast:1738 -llvm:skip:f32.wast:1771 -llvm:skip:f32.wast:1772 -llvm:skip:f32.wast:1773 -llvm:skip:f32.wast:1774 -llvm:skip:f32.wast:1775 -llvm:skip:f32.wast:1776 -llvm:skip:f32.wast:1777 -llvm:skip:f32.wast:1778 -llvm:skip:f32.wast:1811 -llvm:skip:f32.wast:1812 -llvm:skip:f32.wast:1813 -llvm:skip:f32.wast:1814 -llvm:skip:f32.wast:1815 -llvm:skip:f32.wast:1816 -llvm:skip:f32.wast:1817 -llvm:skip:f32.wast:1818 -llvm:skip:f32.wast:1851 -llvm:skip:f32.wast:1852 -llvm:skip:f32.wast:1853 -llvm:skip:f32.wast:1854 -llvm:skip:f32.wast:1855 -llvm:skip:f32.wast:1856 -llvm:skip:f32.wast:1857 -llvm:skip:f32.wast:1858 -llvm:skip:f32.wast:1891 -llvm:skip:f32.wast:1892 -llvm:skip:f32.wast:1893 -llvm:skip:f32.wast:1894 -llvm:skip:f32.wast:1895 -llvm:skip:f32.wast:1896 -llvm:skip:f32.wast:1897 -llvm:skip:f32.wast:1898 -llvm:skip:f32.wast:1931 -llvm:skip:f32.wast:1932 -llvm:skip:f32.wast:1933 -llvm:skip:f32.wast:1934 -llvm:skip:f32.wast:1935 -llvm:skip:f32.wast:1936 -llvm:skip:f32.wast:1937 -llvm:skip:f32.wast:1938 -llvm:skip:f32.wast:1939 -llvm:skip:f32.wast:1940 -llvm:skip:f32.wast:1941 -llvm:skip:f32.wast:1942 -llvm:skip:f32.wast:1943 -llvm:skip:f32.wast:1944 -llvm:skip:f32.wast:1945 -llvm:skip:f32.wast:1946 -llvm:skip:f32.wast:1947 -llvm:skip:f32.wast:1948 -llvm:skip:f32.wast:1949 -llvm:skip:f32.wast:1950 -llvm:skip:f32.wast:1951 -llvm:skip:f32.wast:1952 -llvm:skip:f32.wast:1953 -llvm:skip:f32.wast:1954 -llvm:skip:f32.wast:1955 -llvm:skip:f32.wast:1956 -llvm:skip:f32.wast:1957 -llvm:skip:f32.wast:1958 -llvm:skip:f32.wast:1959 -llvm:skip:f32.wast:1960 -llvm:skip:f32.wast:1961 -llvm:skip:f32.wast:1962 -llvm:skip:f32.wast:1963 -llvm:skip:f32.wast:1964 -llvm:skip:f32.wast:1965 -llvm:skip:f32.wast:1966 -llvm:skip:f32.wast:1967 -llvm:skip:f32.wast:1968 -llvm:skip:f32.wast:1969 -llvm:skip:f32.wast:1970 -llvm:skip:f32.wast:1971 -llvm:skip:f32.wast:1972 -llvm:skip:f32.wast:1973 -llvm:skip:f32.wast:1974 -llvm:skip:f32.wast:1975 -llvm:skip:f32.wast:1976 -llvm:skip:f32.wast:1977 -llvm:skip:f32.wast:1978 -llvm:skip:f32.wast:1979 -llvm:skip:f32.wast:1980 -llvm:skip:f32.wast:1981 -llvm:skip:f32.wast:1982 -llvm:skip:f32.wast:1983 -llvm:skip:f32.wast:1984 -llvm:skip:f32.wast:1985 -llvm:skip:f32.wast:1986 -llvm:skip:f32.wast:1987 -llvm:skip:f32.wast:1988 -llvm:skip:f32.wast:1989 -llvm:skip:f32.wast:1990 -llvm:skip:f32.wast:1991 -llvm:skip:f32.wast:1992 -llvm:skip:f32.wast:1993 -llvm:skip:f32.wast:1994 -llvm:skip:f32.wast:1995 -llvm:skip:f32.wast:1996 -llvm:skip:f32.wast:1997 -llvm:skip:f32.wast:1998 -llvm:skip:f32.wast:1999 -llvm:skip:f32.wast:2000 -llvm:skip:f32.wast:2001 -llvm:skip:f32.wast:2002 -llvm:skip:f32.wast:2005 -llvm:skip:f32.wast:2006 -llvm:skip:f32.wast:2009 -llvm:skip:f32.wast:2010 -llvm:skip:f32.wast:2013 -llvm:skip:f32.wast:2014 -llvm:skip:f32.wast:2017 -llvm:skip:f32.wast:2018 -llvm:skip:f32.wast:2051 -llvm:skip:f32.wast:2052 -llvm:skip:f32.wast:2053 -llvm:skip:f32.wast:2054 -llvm:skip:f32.wast:2055 -llvm:skip:f32.wast:2056 -llvm:skip:f32.wast:2057 -llvm:skip:f32.wast:2058 -llvm:skip:f32.wast:2091 -llvm:skip:f32.wast:2092 -llvm:skip:f32.wast:2093 -llvm:skip:f32.wast:2094 -llvm:skip:f32.wast:2095 -llvm:skip:f32.wast:2096 -llvm:skip:f32.wast:2097 -llvm:skip:f32.wast:2098 -llvm:skip:f32.wast:2131 -llvm:skip:f32.wast:2132 -llvm:skip:f32.wast:2133 -llvm:skip:f32.wast:2134 -llvm:skip:f32.wast:2135 -llvm:skip:f32.wast:2136 -llvm:skip:f32.wast:2137 -llvm:skip:f32.wast:2138 -llvm:skip:f32.wast:2171 -llvm:skip:f32.wast:2172 -llvm:skip:f32.wast:2173 -llvm:skip:f32.wast:2174 -llvm:skip:f32.wast:2175 -llvm:skip:f32.wast:2176 -llvm:skip:f32.wast:2177 -llvm:skip:f32.wast:2178 -llvm:skip:f32.wast:2211 -llvm:skip:f32.wast:2212 -llvm:skip:f32.wast:2213 -llvm:skip:f32.wast:2214 -llvm:skip:f32.wast:2215 -llvm:skip:f32.wast:2216 -llvm:skip:f32.wast:2217 -llvm:skip:f32.wast:2218 -llvm:skip:f32.wast:2251 -llvm:skip:f32.wast:2252 -llvm:skip:f32.wast:2253 -llvm:skip:f32.wast:2254 -llvm:skip:f32.wast:2255 -llvm:skip:f32.wast:2256 -llvm:skip:f32.wast:2257 -llvm:skip:f32.wast:2258 -llvm:skip:f32.wast:2291 -llvm:skip:f32.wast:2292 -llvm:skip:f32.wast:2293 -llvm:skip:f32.wast:2294 -llvm:skip:f32.wast:2295 -llvm:skip:f32.wast:2296 -llvm:skip:f32.wast:2297 -llvm:skip:f32.wast:2298 -llvm:skip:f32.wast:2331 -llvm:skip:f32.wast:2332 -llvm:skip:f32.wast:2333 -llvm:skip:f32.wast:2334 -llvm:skip:f32.wast:2335 -llvm:skip:f32.wast:2336 -llvm:skip:f32.wast:2337 -llvm:skip:f32.wast:2338 -llvm:skip:f32.wast:2339 -llvm:skip:f32.wast:2340 -llvm:skip:f32.wast:2341 -llvm:skip:f32.wast:2342 -llvm:skip:f32.wast:2343 -llvm:skip:f32.wast:2344 -llvm:skip:f32.wast:2345 -llvm:skip:f32.wast:2346 -llvm:skip:f32.wast:2347 -llvm:skip:f32.wast:2348 -llvm:skip:f32.wast:2349 -llvm:skip:f32.wast:2350 -llvm:skip:f32.wast:2351 -llvm:skip:f32.wast:2352 -llvm:skip:f32.wast:2353 -llvm:skip:f32.wast:2354 -llvm:skip:f32.wast:2355 -llvm:skip:f32.wast:2356 -llvm:skip:f32.wast:2357 -llvm:skip:f32.wast:2358 -llvm:skip:f32.wast:2359 -llvm:skip:f32.wast:2360 -llvm:skip:f32.wast:2361 -llvm:skip:f32.wast:2362 -llvm:skip:f32.wast:2363 -llvm:skip:f32.wast:2364 -llvm:skip:f32.wast:2365 -llvm:skip:f32.wast:2366 -llvm:skip:f32.wast:2367 -llvm:skip:f32.wast:2368 -llvm:skip:f32.wast:2369 -llvm:skip:f32.wast:2370 -llvm:skip:f32.wast:2371 -llvm:skip:f32.wast:2372 -llvm:skip:f32.wast:2373 -llvm:skip:f32.wast:2374 -llvm:skip:f32.wast:2375 -llvm:skip:f32.wast:2376 -llvm:skip:f32.wast:2377 -llvm:skip:f32.wast:2378 -llvm:skip:f32.wast:2379 -llvm:skip:f32.wast:2380 -llvm:skip:f32.wast:2381 -llvm:skip:f32.wast:2382 -llvm:skip:f32.wast:2383 -llvm:skip:f32.wast:2384 -llvm:skip:f32.wast:2385 -llvm:skip:f32.wast:2386 -llvm:skip:f32.wast:2387 -llvm:skip:f32.wast:2388 -llvm:skip:f32.wast:2389 -llvm:skip:f32.wast:2390 -llvm:skip:f32.wast:2391 -llvm:skip:f32.wast:2392 -llvm:skip:f32.wast:2393 -llvm:skip:f32.wast:2394 -llvm:skip:f32.wast:2395 -llvm:skip:f32.wast:2396 -llvm:skip:f32.wast:2397 -llvm:skip:f32.wast:2398 -llvm:skip:f32.wast:2399 -llvm:skip:f32.wast:2400 -llvm:skip:f32.wast:2401 -llvm:skip:f32.wast:2402 -llvm:skip:f32.wast:2403 -llvm:skip:f32.wast:2404 -llvm:skip:f32.wast:2405 -llvm:skip:f32.wast:2406 -llvm:skip:f32.wast:2409 -llvm:skip:f32.wast:2410 -llvm:skip:f32.wast:2413 -llvm:skip:f32.wast:2414 -llvm:skip:f32.wast:2417 -llvm:skip:f32.wast:2418 -llvm:skip:f64.wast:1651 -llvm:skip:f64.wast:1652 -llvm:skip:f64.wast:1653 -llvm:skip:f64.wast:1654 -llvm:skip:f64.wast:1655 -llvm:skip:f64.wast:1656 -llvm:skip:f64.wast:1657 -llvm:skip:f64.wast:1658 -llvm:skip:f64.wast:1691 -llvm:skip:f64.wast:1692 -llvm:skip:f64.wast:1693 -llvm:skip:f64.wast:1694 -llvm:skip:f64.wast:1695 -llvm:skip:f64.wast:1696 -llvm:skip:f64.wast:1697 -llvm:skip:f64.wast:1698 -llvm:skip:f64.wast:1731 -llvm:skip:f64.wast:1732 -llvm:skip:f64.wast:1733 -llvm:skip:f64.wast:1734 -llvm:skip:f64.wast:1735 -llvm:skip:f64.wast:1736 -llvm:skip:f64.wast:1737 -llvm:skip:f64.wast:1738 -llvm:skip:f64.wast:1771 -llvm:skip:f64.wast:1772 -llvm:skip:f64.wast:1773 -llvm:skip:f64.wast:1774 -llvm:skip:f64.wast:1775 -llvm:skip:f64.wast:1776 -llvm:skip:f64.wast:1777 -llvm:skip:f64.wast:1778 -llvm:skip:f64.wast:1811 -llvm:skip:f64.wast:1812 -llvm:skip:f64.wast:1813 -llvm:skip:f64.wast:1814 -llvm:skip:f64.wast:1815 -llvm:skip:f64.wast:1816 -llvm:skip:f64.wast:1817 -llvm:skip:f64.wast:1818 -llvm:skip:f64.wast:1851 -llvm:skip:f64.wast:1852 -llvm:skip:f64.wast:1853 -llvm:skip:f64.wast:1854 -llvm:skip:f64.wast:1855 -llvm:skip:f64.wast:1856 -llvm:skip:f64.wast:1857 -llvm:skip:f64.wast:1858 -llvm:skip:f64.wast:1891 -llvm:skip:f64.wast:1892 -llvm:skip:f64.wast:1893 -llvm:skip:f64.wast:1894 -llvm:skip:f64.wast:1895 -llvm:skip:f64.wast:1896 -llvm:skip:f64.wast:1897 -llvm:skip:f64.wast:1898 -llvm:skip:f64.wast:1931 -llvm:skip:f64.wast:1932 -llvm:skip:f64.wast:1933 -llvm:skip:f64.wast:1934 -llvm:skip:f64.wast:1935 -llvm:skip:f64.wast:1936 -llvm:skip:f64.wast:1937 -llvm:skip:f64.wast:1938 -llvm:skip:f64.wast:1939 -llvm:skip:f64.wast:1940 -llvm:skip:f64.wast:1941 -llvm:skip:f64.wast:1942 -llvm:skip:f64.wast:1943 -llvm:skip:f64.wast:1944 -llvm:skip:f64.wast:1945 -llvm:skip:f64.wast:1946 -llvm:skip:f64.wast:1947 -llvm:skip:f64.wast:1948 -llvm:skip:f64.wast:1949 -llvm:skip:f64.wast:1950 -llvm:skip:f64.wast:1951 -llvm:skip:f64.wast:1952 -llvm:skip:f64.wast:1953 -llvm:skip:f64.wast:1954 -llvm:skip:f64.wast:1955 -llvm:skip:f64.wast:1956 -llvm:skip:f64.wast:1957 -llvm:skip:f64.wast:1958 -llvm:skip:f64.wast:1959 -llvm:skip:f64.wast:1960 -llvm:skip:f64.wast:1961 -llvm:skip:f64.wast:1962 -llvm:skip:f64.wast:1963 -llvm:skip:f64.wast:1964 -llvm:skip:f64.wast:1965 -llvm:skip:f64.wast:1966 -llvm:skip:f64.wast:1967 -llvm:skip:f64.wast:1968 -llvm:skip:f64.wast:1969 -llvm:skip:f64.wast:1970 -llvm:skip:f64.wast:1971 -llvm:skip:f64.wast:1972 -llvm:skip:f64.wast:1973 -llvm:skip:f64.wast:1974 -llvm:skip:f64.wast:1975 -llvm:skip:f64.wast:1976 -llvm:skip:f64.wast:1977 -llvm:skip:f64.wast:1978 -llvm:skip:f64.wast:1979 -llvm:skip:f64.wast:1980 -llvm:skip:f64.wast:1981 -llvm:skip:f64.wast:1982 -llvm:skip:f64.wast:1983 -llvm:skip:f64.wast:1984 -llvm:skip:f64.wast:1985 -llvm:skip:f64.wast:1986 -llvm:skip:f64.wast:1987 -llvm:skip:f64.wast:1988 -llvm:skip:f64.wast:1989 -llvm:skip:f64.wast:1990 -llvm:skip:f64.wast:1991 -llvm:skip:f64.wast:1992 -llvm:skip:f64.wast:1993 -llvm:skip:f64.wast:1994 -llvm:skip:f64.wast:1995 -llvm:skip:f64.wast:1996 -llvm:skip:f64.wast:1997 -llvm:skip:f64.wast:1998 -llvm:skip:f64.wast:1999 -llvm:skip:f64.wast:2000 -llvm:skip:f64.wast:2001 -llvm:skip:f64.wast:2002 -llvm:skip:f64.wast:2005 -llvm:skip:f64.wast:2006 -llvm:skip:f64.wast:2009 -llvm:skip:f64.wast:2010 -llvm:skip:f64.wast:2013 -llvm:skip:f64.wast:2014 -llvm:skip:f64.wast:2017 -llvm:skip:f64.wast:2018 -llvm:skip:f64.wast:2051 -llvm:skip:f64.wast:2052 -llvm:skip:f64.wast:2053 -llvm:skip:f64.wast:2054 -llvm:skip:f64.wast:2055 -llvm:skip:f64.wast:2056 -llvm:skip:f64.wast:2057 -llvm:skip:f64.wast:2058 -llvm:skip:f64.wast:2091 -llvm:skip:f64.wast:2092 -llvm:skip:f64.wast:2093 -llvm:skip:f64.wast:2094 -llvm:skip:f64.wast:2095 -llvm:skip:f64.wast:2096 -llvm:skip:f64.wast:2097 -llvm:skip:f64.wast:2098 -llvm:skip:f64.wast:2131 -llvm:skip:f64.wast:2132 -llvm:skip:f64.wast:2133 -llvm:skip:f64.wast:2134 -llvm:skip:f64.wast:2135 -llvm:skip:f64.wast:2136 -llvm:skip:f64.wast:2137 -llvm:skip:f64.wast:2138 -llvm:skip:f64.wast:2171 -llvm:skip:f64.wast:2172 -llvm:skip:f64.wast:2173 -llvm:skip:f64.wast:2174 -llvm:skip:f64.wast:2175 -llvm:skip:f64.wast:2176 -llvm:skip:f64.wast:2177 -llvm:skip:f64.wast:2178 -llvm:skip:f64.wast:2211 -llvm:skip:f64.wast:2212 -llvm:skip:f64.wast:2213 -llvm:skip:f64.wast:2214 -llvm:skip:f64.wast:2215 -llvm:skip:f64.wast:2216 -llvm:skip:f64.wast:2217 -llvm:skip:f64.wast:2218 -llvm:skip:f64.wast:2251 -llvm:skip:f64.wast:2252 -llvm:skip:f64.wast:2253 -llvm:skip:f64.wast:2254 -llvm:skip:f64.wast:2255 -llvm:skip:f64.wast:2256 -llvm:skip:f64.wast:2257 -llvm:skip:f64.wast:2258 -llvm:skip:f64.wast:2291 -llvm:skip:f64.wast:2292 -llvm:skip:f64.wast:2293 -llvm:skip:f64.wast:2294 -llvm:skip:f64.wast:2295 -llvm:skip:f64.wast:2296 -llvm:skip:f64.wast:2297 -llvm:skip:f64.wast:2298 -llvm:skip:f64.wast:2331 -llvm:skip:f64.wast:2332 -llvm:skip:f64.wast:2333 -llvm:skip:f64.wast:2334 -llvm:skip:f64.wast:2335 -llvm:skip:f64.wast:2336 -llvm:skip:f64.wast:2337 -llvm:skip:f64.wast:2338 -llvm:skip:f64.wast:2339 -llvm:skip:f64.wast:2340 -llvm:skip:f64.wast:2341 -llvm:skip:f64.wast:2342 -llvm:skip:f64.wast:2343 -llvm:skip:f64.wast:2344 -llvm:skip:f64.wast:2345 -llvm:skip:f64.wast:2346 -llvm:skip:f64.wast:2347 -llvm:skip:f64.wast:2348 -llvm:skip:f64.wast:2349 -llvm:skip:f64.wast:2350 -llvm:skip:f64.wast:2351 -llvm:skip:f64.wast:2352 -llvm:skip:f64.wast:2353 -llvm:skip:f64.wast:2354 -llvm:skip:f64.wast:2355 -llvm:skip:f64.wast:2356 -llvm:skip:f64.wast:2357 -llvm:skip:f64.wast:2358 -llvm:skip:f64.wast:2359 -llvm:skip:f64.wast:2360 -llvm:skip:f64.wast:2361 -llvm:skip:f64.wast:2362 -llvm:skip:f64.wast:2363 -llvm:skip:f64.wast:2364 -llvm:skip:f64.wast:2365 -llvm:skip:f64.wast:2366 -llvm:skip:f64.wast:2367 -llvm:skip:f64.wast:2368 -llvm:skip:f64.wast:2369 -llvm:skip:f64.wast:2370 -llvm:skip:f64.wast:2371 -llvm:skip:f64.wast:2372 -llvm:skip:f64.wast:2373 -llvm:skip:f64.wast:2374 -llvm:skip:f64.wast:2375 -llvm:skip:f64.wast:2376 -llvm:skip:f64.wast:2377 -llvm:skip:f64.wast:2378 -llvm:skip:f64.wast:2379 -llvm:skip:f64.wast:2380 -llvm:skip:f64.wast:2381 -llvm:skip:f64.wast:2382 -llvm:skip:f64.wast:2383 -llvm:skip:f64.wast:2384 -llvm:skip:f64.wast:2385 -llvm:skip:f64.wast:2386 -llvm:skip:f64.wast:2387 -llvm:skip:f64.wast:2388 -llvm:skip:f64.wast:2389 -llvm:skip:f64.wast:2390 -llvm:skip:f64.wast:2391 -llvm:skip:f64.wast:2392 -llvm:skip:f64.wast:2393 -llvm:skip:f64.wast:2394 -llvm:skip:f64.wast:2395 -llvm:skip:f64.wast:2396 -llvm:skip:f64.wast:2397 -llvm:skip:f64.wast:2398 -llvm:skip:f64.wast:2399 -llvm:skip:f64.wast:2400 -llvm:skip:f64.wast:2401 -llvm:skip:f64.wast:2402 -llvm:skip:f64.wast:2405 -llvm:skip:f64.wast:2406 -llvm:skip:f64.wast:2409 -llvm:skip:f64.wast:2410 -llvm:skip:f64.wast:2413 -llvm:skip:f64.wast:2414 -llvm:skip:f64.wast:2417 -llvm:skip:f64.wast:2418 - # LLVM llvm:skip:br_table.wast:1255 llvm:skip:imports.wast:391 # Running forever From da0cfb8fc2b135a621d1b84763858e941bf50173 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 11:36:38 -0700 Subject: [PATCH 007/122] Add changelog entry. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11365bb9..49d90aaae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. + ## 0.8.0 - 2019-10-02 Special thanks to @jdanford for their contributions! From 749691ca2ad79eda60a66527aac0aab0d6ed0a0f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 11:50:11 -0700 Subject: [PATCH 008/122] Add a comment explaining why we don't use the intrinsics for these. --- lib/llvm-backend/src/code.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index a1c69c082..13dcd2bd9 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2692,6 +2692,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(bits); } Operator::F32Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2735,6 +2738,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2778,6 +2784,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); @@ -2830,6 +2839,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64x2Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); @@ -2882,6 +2894,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2924,6 +2939,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2966,6 +2984,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); @@ -3018,6 +3039,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64x2Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); From ed615c4878e2d7cbc6bc4832b867b5c4ddc8f0a6 Mon Sep 17 00:00:00 2001 From: Patrick Ventuzelo Date: Mon, 7 Oct 2019 12:56:55 +0200 Subject: [PATCH 009/122] fix build error docs --- lib/clif-backend/src/signal/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index e300da131..79b6619d3 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -99,7 +99,7 @@ pub fn call_protected( Ok(SIGSEGV) | Ok(SIGBUS) => WasmTrapInfo::MemoryOutOfBounds, Ok(SIGFPE) => WasmTrapInfo::IllegalArithmetic, _ => unimplemented!( - "WasmTrapInfo::Unknown signal:{}", + "WasmTrapInfo::Unknown signal:{:?}", Signal::from_c_int(signum) ), })) From 4d99963640d57349128add31f0353b4af863b691 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 7 Oct 2019 12:11:10 -0700 Subject: [PATCH 010/122] Replace "be the i32 type" with "be an i32" in error messages. --- lib/runtime-core/src/backing.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index e69943002..ff21e9195 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -148,7 +148,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -209,7 +209,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -282,7 +282,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer must be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { @@ -340,7 +340,7 @@ impl LocalBacking { Initializer::Const(Value::I32(offset)) => offset as u32, Initializer::Const(_) => { return Err(vec![LinkError::Generic { - message: "a const initializer must be the i32 type".to_string(), + message: "a const initializer be an i32".to_string(), }]); } Initializer::GetGlobal(import_global_index) => { From 158db4cee12a528d29d63355ae47aa1878f159cf Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 7 Oct 2019 15:11:09 -0700 Subject: [PATCH 011/122] Remove exclusions for tests that appear to be passing right now. --- lib/spectests/tests/excludes.txt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 56c6a2d56..ca9b078d0 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -24,7 +24,6 @@ clif:skip:simd_binaryen.wast:* # SIMD not implemented # linking.wast:387,388 appear to be related to WABT issue: https://github.com/pepyakin/wabt-rs/issues/51 -clif:fail:globals.wast:243 # AssertInvalid - Should be invalid clif:fail:linking.wast:137 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:139 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:142 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" @@ -814,28 +813,12 @@ llvm:skip:f64.wast:2417 llvm:skip:f64.wast:2418 # LLVM -llvm:skip:br_table.wast:1255 -llvm:skip:imports.wast:391 # Running forever -llvm:skip:imports.wast:402 # Running forever -llvm:skip:call.wast:273 # Spec running forever -llvm:skip:call_indirect.wast:556 # Spec running forever -llvm:skip:call_indirect.wast:557 # Spec running forever -llvm:skip:fac.wast:89 # Spec running forever -llvm:skip:skip-stack-guard-page.wast:* # Spec running forever or (signal: 4, SIGILL: illegal instruction) -llvm:skip:linking.wast:236 # terminating with uncaught exception of type WasmTrap -llvm:skip:linking.wast:248 # terminating with uncaught exception of type WasmTrap - llvm:fail:f32.wast:1621 # AssertReturn - result F32(0) ("0x0") does not match expected F32(2147483648) ("0x80000000") llvm:fail:f32.wast:2020 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") llvm:fail:f64.wast:1621 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") llvm:fail:f64.wast:2020 # AssertReturn - result F64(9223372036854775808) ("0x8000000000000000") does not match expected F64(0) ("0x0") -llvm:fail:i32.wast:243 # AssertReturn - result I32(283816271) ("0x10eab14f") does not match expected I32(32) ("0x20") -llvm:fail:i32.wast:252 # AssertReturn - result I32(283816288) ("0x10eab160") does not match expected I32(32) ("0x20") -llvm:fail:i64.wast:243 # AssertReturn - result I64(4578783727) ("0x110eab1ef") does not match expected I64(64) ("0x40") -llvm:fail:i64.wast:252 # AssertReturn - result I64(4578783712) ("0x110eab1e0") does not match expected I64(64) ("0x40") llvm:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") llvm:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: incorrect `call_indirect` signature -llvm:fail:load.wast:201 # AssertReturn - result I32(285315103) ("0x1101901f") does not match expected I32(32) ("0x20") # LLVM Windows llvm:skip:address.wast:*:windows From 9cdfb48d0c4fb6b92d20f9d6757697ac52450fcd Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 7 Oct 2019 17:11:59 -0700 Subject: [PATCH 012/122] The i1 argument is actually named "is_zero_undef" which we want to be false. Fixes the test failures that showed up on mac. --- lib/llvm-backend/src/code.rs | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8ac76fe26..27cffe059 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2420,14 +2420,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32Clz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.ctlz_i32, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2437,14 +2434,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I64Clz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.ctlz_i64, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2454,14 +2448,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I32Ctz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.cttz_i32, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() @@ -2471,14 +2462,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::I64Ctz => { let input = state.pop1()?; - let ensure_defined_zero = intrinsics - .i1_ty - .const_int(1 as u64, false) - .as_basic_value_enum(); + let is_zero_undef = intrinsics.i1_zero.as_basic_value_enum(); let res = builder .build_call( intrinsics.cttz_i64, - &[input, ensure_defined_zero], + &[input, is_zero_undef], &state.var_name(), ) .try_as_basic_value() From afddbb2b2a84814cc9758d5f9e92f4b3f97220ff Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 11:40:21 -0700 Subject: [PATCH 013/122] Remove unused value warning due to inkwell API change. NFC. --- lib/llvm-backend/src/code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8ac76fe26..5731d1feb 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -935,7 +935,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let signal_mem = ctx.signal_mem(); let iv = builder .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); - iv.set_volatile(true); + iv.set_volatile(true).unwrap(); finalize_opcode_stack_map( intrinsics, builder, From ebd71672e0833d43bb67a4d2b9c7167ef52afeb8 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 8 Oct 2019 11:23:18 -0700 Subject: [PATCH 014/122] Pass llvm debug flags to the llvm backend. This was accidentally removed in 124ad73e8ae2c6864bad3ebe5572d79736cfd688 . --- src/bin/wasmer.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 72bc2e8bc..b6107b48c 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -23,7 +23,7 @@ use structopt::StructOpt; use wasmer::*; use wasmer_clif_backend::CraneliftCompiler; #[cfg(feature = "backend-llvm")] -use wasmer_llvm_backend::LLVMCompiler; +use wasmer_llvm_backend::{LLVMCompiler, LLVMOptions}; use wasmer_runtime::{ cache::{Cache as BaseCache, FileSystemCache, WasmHash}, Func, Value, VERSION, @@ -109,7 +109,7 @@ pub struct LLVMCLIOptions { post_opt_ir: Option, /// Emit LLVM generated native code object file. - #[structopt(long = "backend-llvm-object-file", parse(from_os_str))] + #[structopt(long = "llvm-object-file", parse(from_os_str))] obj_file: Option, } @@ -405,6 +405,20 @@ fn execute_wasm(options: &Run) -> Result<(), String> { None => return Err("the requested backend is not enabled".into()), }; + #[cfg(feature = "backend-llvm")] + { + if options.backend == Backend::LLVM { + let options = options.backend_llvm_options.clone(); + unsafe { + wasmer_llvm_backend::GLOBAL_OPTIONS = LLVMOptions { + pre_opt_ir: options.pre_opt_ir, + post_opt_ir: options.post_opt_ir, + obj_file: options.obj_file, + } + } + } + } + let track_state = !options.no_track_state; #[cfg(feature = "loader-kernel")] From c61cbf6c0b3d56a936f3657aff9291377d03305d Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 8 Oct 2019 11:25:10 -0700 Subject: [PATCH 015/122] Add a comment. --- lib/llvm-backend/src/code.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 5731d1feb..435171504 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -935,6 +935,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let signal_mem = ctx.signal_mem(); let iv = builder .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); + // Any 'store' can be made volatile. iv.set_volatile(true).unwrap(); finalize_opcode_stack_map( intrinsics, From 0567845ead5d44cd597b7007feb8519cb49811de Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 8 Oct 2019 11:29:03 -0700 Subject: [PATCH 016/122] cargo fmt --- src/bin/wasmer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index b6107b48c..4c51d9770 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -407,7 +407,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { #[cfg(feature = "backend-llvm")] { - if options.backend == Backend::LLVM { + if options.backend == Backend::LLVM { let options = options.backend_llvm_options.clone(); unsafe { wasmer_llvm_backend::GLOBAL_OPTIONS = LLVMOptions { @@ -418,7 +418,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { } } } - + let track_state = !options.no_track_state; #[cfg(feature = "loader-kernel")] From 913354adb3b38f829db49e36638540bb5e5b19b2 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 9 Oct 2019 17:29:27 -0700 Subject: [PATCH 017/122] Add function to get export from ns/name via ImportObject to C API --- lib/runtime-c-api/src/export.rs | 37 ++++++++-- lib/runtime-c-api/src/import.rs | 114 +++++++++++++++++++++++++++++- lib/runtime-c-api/src/instance.rs | 1 + lib/runtime-c-api/wasmer.h | 24 +++++-- lib/runtime-c-api/wasmer.hh | 22 ++++-- 5 files changed, 184 insertions(+), 14 deletions(-) diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index d6dfa5d97..3112b6178 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -85,12 +85,39 @@ pub union wasmer_import_export_value { /// List of export/import kinds. #[allow(non_camel_case_types)] #[repr(u32)] -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] +// ================ +// ! DANGER ! +// ================ +// Do not modify these values without updating the `TryFrom` implementation below pub enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, +} + +impl wasmer_import_export_kind { + pub fn to_str(&self) -> &'static str { + match self { + Self::WASM_FUNCTION => "function", + Self::WASM_GLOBAL => "global", + Self::WASM_MEMORY => "memory", + Self::WASM_TABLE => "table", + } + } +} + +impl std::convert::TryFrom for wasmer_import_export_kind { + type Error = (); + + fn try_from(value: u32) -> Result { + if value > 3 { + Err(()) + } else { + Ok(unsafe { std::mem::transmute(value) }) + } + } } /// Gets export descriptors for the given module diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index 19f415722..52d196dd0 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -9,7 +9,7 @@ use crate::{ wasmer_byte_array, wasmer_result_t, }; use libc::c_uint; -use std::{ffi::c_void, ptr, slice, sync::Arc}; +use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ export::{Context, Export, FuncPointer}, @@ -159,6 +159,118 @@ mod wasi { #[cfg(feature = "wasi")] pub use self::wasi::*; +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores an immutable reference to `name` and `namespace` in `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`, `import_export_value` must be +/// initialized to point to the type specified by `tag`. Failure to do so may result +/// in data corruption or undefined behavior. +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_get_import( + import_object: *const wasmer_import_object_t, + namespace: wasmer_byte_array, + name: wasmer_byte_array, + import: *mut wasmer_import_t, + import_export_value: *mut wasmer_import_export_value, + tag: u32, +) -> wasmer_result_t { + let tag: wasmer_import_export_kind = if let Ok(t) = TryFrom::try_from(tag) { + t + } else { + update_last_error(CApiError { + msg: "wasmer_import_export_tag out of range".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); + let namespace_str = if let Ok(ns) = namespace.as_str() { + ns + } else { + update_last_error(CApiError { + msg: "error converting namespace to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + let name_str = if let Ok(name) = name.as_str() { + name + } else { + update_last_error(CApiError { + msg: "error converting name to UTF-8 string".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + }; + if import.is_null() || import_export_value.is_null() { + update_last_error(CApiError { + msg: "pointer to import and import_export_value must not be null".to_string(), + }); + return wasmer_result_t::WASMER_ERROR; + } + let import_out = &mut *import; + let import_export_value_out = &mut *import_export_value; + if let Some(export) = + import_object.maybe_with_namespace(namespace_str, |ns| ns.get_export(name_str)) + { + match export { + Export::Function { .. } => { + if tag != wasmer_import_export_kind::WASM_FUNCTION { + update_last_error(CApiError { + msg: format!("Found function, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_FUNCTION; + let writer = import_export_value_out.func as *mut Export; + *writer = export.clone(); + } + Export::Memory(memory) => { + if tag != wasmer_import_export_kind::WASM_MEMORY { + update_last_error(CApiError { + msg: format!("Found memory, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_MEMORY; + let writer = import_export_value_out.func as *mut Memory; + *writer = memory.clone(); + } + Export::Table(table) => { + if tag != wasmer_import_export_kind::WASM_TABLE { + update_last_error(CApiError { + msg: format!("Found table, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_TABLE; + let writer = import_export_value_out.func as *mut Table; + *writer = table.clone(); + } + Export::Global(global) => { + if tag != wasmer_import_export_kind::WASM_GLOBAL { + update_last_error(CApiError { + msg: format!("Found global, expected {}", tag.to_str()), + }); + return wasmer_result_t::WASMER_ERROR; + } + import_out.tag = wasmer_import_export_kind::WASM_GLOBAL; + let writer = import_export_value_out.func as *mut Global; + *writer = global.clone(); + } + } + + import_out.value = *import_export_value; + import_out.module_name = namespace; + import_out.import_name = name; + + wasmer_result_t::WASMER_OK + } else { + update_last_error(CApiError { + msg: format!("Export {} {} not found", namespace_str, name_str), + }); + wasmer_result_t::WASMER_ERROR + } +} + /// Extends an existing import object with new imports #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/src/instance.rs b/lib/runtime-c-api/src/instance.rs index 69fa0131a..b39e52d7e 100644 --- a/lib/runtime-c-api/src/instance.rs +++ b/lib/runtime-c-api/src/instance.rs @@ -75,6 +75,7 @@ pub unsafe extern "C" fn wasmer_instantiate( let namespace = namespaces.entry(module_name).or_insert_with(Namespace::new); + // TODO check that tag is actually in bounds here let export = match import.tag { wasmer_import_export_kind::WASM_MEMORY => { let mem = import.value.memory as *mut Memory; diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 23caa54cc..dda77d7c4 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -10,10 +10,10 @@ * List of export/import kinds. */ enum wasmer_import_export_kind { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; typedef uint32_t wasmer_import_export_kind; @@ -469,6 +469,22 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec wasmer_import_t *imports, unsigned int imports_len); +/** + * Gets an entry from an ImportObject at the name and namespace. + * Stores an immutable reference to `name` and `namespace` in `import`. + * + * The caller owns all data involved. + * `import_export_value` will be written to based on `tag`, `import_export_value` must be + * initialized to point to the type specified by `tag`. Failure to do so may result + * in data corruption or undefined behavior. + */ +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index da8e39118..39bc12c69 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -8,10 +8,10 @@ /// List of export/import kinds. enum class wasmer_import_export_kind : uint32_t { - WASM_FUNCTION, - WASM_GLOBAL, - WASM_MEMORY, - WASM_TABLE, + WASM_FUNCTION = 0, + WASM_GLOBAL = 1, + WASM_MEMORY = 2, + WASM_TABLE = 3, }; enum class wasmer_result_t { @@ -371,6 +371,20 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec wasmer_import_t *imports, unsigned int imports_len); +/// Gets an entry from an ImportObject at the name and namespace. +/// Stores an immutable reference to `name` and `namespace` in `import`. +/// +/// The caller owns all data involved. +/// `import_export_value` will be written to based on `tag`, `import_export_value` must be +/// initialized to point to the type specified by `tag`. Failure to do so may result +/// in data corruption or undefined behavior. +wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, + wasmer_byte_array namespace_, + wasmer_byte_array name, + wasmer_import_t *import, + wasmer_import_export_value *import_export_value, + uint32_t tag); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new(); From 51f619a132f01b70eed80d81614433047ec16e21 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 10 Oct 2019 11:22:45 -0700 Subject: [PATCH 018/122] Change pointer that's not modified to be const in C API --- CHANGELOG.md | 1 + lib/runtime-c-api/src/import.rs | 2 +- lib/runtime-c-api/wasmer.h | 2 +- lib/runtime-c-api/wasmer.hh | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11365bb9..ce50507f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Blocks of changes will separated by version increments. Special thanks to @jdanford for their contributions! +- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object - [#850](https://github.com/wasmerio/wasmer/pull/850) New `WasiStateBuilder` API. small, add misc. breaking changes to existing API (for example, changing the preopen dirs arg on `wasi::generate_import_object` from `Vec` to `Vec`) - [#852](https://github.com/wasmerio/wasmer/pull/852) Make minor grammar/capitalization fixes to README.md - [#841](https://github.com/wasmerio/wasmer/pull/841) Slightly improve rustdoc documentation and small updates to outdated info in readme files diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index 52d196dd0..bc7232b50 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -276,7 +276,7 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( #[no_mangle] pub unsafe extern "C" fn wasmer_import_object_extend( import_object: *mut wasmer_import_object_t, - imports: *mut wasmer_import_t, + imports: *const wasmer_import_t, imports_len: c_uint, ) -> wasmer_result_t { let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index dda77d7c4..862f3580c 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -466,7 +466,7 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); * Extends an existing import object with new imports */ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object, - wasmer_import_t *imports, + const wasmer_import_t *imports, unsigned int imports_len); /** diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 39bc12c69..c7c796ae4 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -368,7 +368,7 @@ void wasmer_import_object_destroy(wasmer_import_object_t *import_object); /// Extends an existing import object with new imports wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_object, - wasmer_import_t *imports, + const wasmer_import_t *imports, unsigned int imports_len); /// Gets an entry from an ImportObject at the name and namespace. From bd8e8646565b6a0815bd77c5a46cd9c6e067cbbf Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 10 Oct 2019 16:07:56 -0700 Subject: [PATCH 019/122] Add functions import object to get import fns and free them --- lib/runtime-c-api/src/import.rs | 92 +++++++++++++++++++++++++++++++++ lib/runtime-c-api/wasmer.h | 12 +++++ lib/runtime-c-api/wasmer.hh | 8 +++ 3 files changed, 112 insertions(+) diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import.rs index bc7232b50..c39a7d121 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import.rs @@ -271,6 +271,98 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( } } +#[no_mangle] +/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function +pub unsafe extern "C" fn wasmer_import_object_get_functions( + import_object: *const wasmer_import_object_t, + imports: *mut wasmer_import_t, + imports_len: u32, +) -> i32 { + if import_object.is_null() || imports.is_null() { + update_last_error(CApiError { + msg: format!("import_object and imports must not be null"), + }); + return -1; + } + let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); + + let mut i = 0; + for (namespace, name, export) in import_object.clone_ref().into_iter() { + if i + 1 > imports_len { + return i as i32; + } + match export { + Export::Function { .. } => { + let ns = namespace.clone().into_bytes(); + let ns_bytes = wasmer_byte_array { + bytes: ns.as_ptr(), + bytes_len: ns.len() as u32, + }; + std::mem::forget(ns); + + let name = name.clone().into_bytes(); + let name_bytes = wasmer_byte_array { + bytes: name.as_ptr(), + bytes_len: name.len() as u32, + }; + std::mem::forget(name); + + let func = Box::new(export.clone()); + + let new_entry = wasmer_import_t { + module_name: ns_bytes, + import_name: name_bytes, + tag: wasmer_import_export_kind::WASM_FUNCTION, + value: wasmer_import_export_value { + func: Box::into_raw(func) as *mut _ as *const _, + }, + }; + *imports.add(i as usize) = new_entry; + i += 1; + } + _ => (), + } + } + + return i as i32; +} + +#[no_mangle] +/// Frees the memory acquired in `wasmer_import_object_get_functions` +pub unsafe extern "C" fn wasmer_import_object_imports_destroy( + imports: *mut wasmer_import_t, + imports_len: u32, +) { + // what's our null check policy here? + let imports: &[wasmer_import_t] = &*slice::from_raw_parts_mut(imports, imports_len as usize); + for import in imports { + let _namespace: Vec = Vec::from_raw_parts( + import.module_name.bytes as *mut u8, + import.module_name.bytes_len as usize, + import.module_name.bytes_len as usize, + ); + let _name: Vec = Vec::from_raw_parts( + import.import_name.bytes as *mut u8, + import.import_name.bytes_len as usize, + import.import_name.bytes_len as usize, + ); + match import.tag { + wasmer_import_export_kind::WASM_FUNCTION => { + let _: Box = Box::from_raw(import.value.func as *mut _); + } + wasmer_import_export_kind::WASM_GLOBAL => { + let _: Box = Box::from_raw(import.value.global as *mut _); + } + wasmer_import_export_kind::WASM_MEMORY => { + let _: Box = Box::from_raw(import.value.memory as *mut _); + } + wasmer_import_export_kind::WASM_TABLE => { + let _: Box = Box::from_raw(import.value.table as *mut _); + } + } + } +} + /// Extends an existing import object with new imports #[allow(clippy::cast_ptr_alignment)] #[no_mangle] diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 862f3580c..582a092c1 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -469,6 +469,13 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); +/** + * Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function + */ +int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, + wasmer_import_t *imports, + uint32_t imports_len); + /** * Gets an entry from an ImportObject at the name and namespace. * Stores an immutable reference to `name` and `namespace` in `import`. @@ -485,6 +492,11 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); +/** + * Frees the memory acquired in `wasmer_import_object_get_functions` + */ +void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index c7c796ae4..0dae80aa5 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -371,6 +371,11 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); +/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function +int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, + wasmer_import_t *imports, + uint32_t imports_len); + /// Gets an entry from an ImportObject at the name and namespace. /// Stores an immutable reference to `name` and `namespace` in `import`. /// @@ -385,6 +390,9 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); +/// Frees the memory acquired in `wasmer_import_object_get_functions` +void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new(); From 01c209fe96e3d3651b84ba8c63e5cd5d06d892a2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 11 Oct 2019 09:19:46 +0200 Subject: [PATCH 020/122] feat(runtime-c-api) Move the `wasi` module into its own file. --- .../src/{import.rs => import/mod.rs} | 104 +----------------- lib/runtime-c-api/src/import/wasi.rs | 101 +++++++++++++++++ 2 files changed, 102 insertions(+), 103 deletions(-) rename lib/runtime-c-api/src/{import.rs => import/mod.rs} (85%) create mode 100644 lib/runtime-c-api/src/import/wasi.rs diff --git a/lib/runtime-c-api/src/import.rs b/lib/runtime-c-api/src/import/mod.rs similarity index 85% rename from lib/runtime-c-api/src/import.rs rename to lib/runtime-c-api/src/import/mod.rs index c39a7d121..87b6b7447 100644 --- a/lib/runtime-c-api/src/import.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -52,109 +52,7 @@ pub unsafe extern "C" fn wasmer_import_object_new() -> *mut wasmer_import_object } #[cfg(feature = "wasi")] -mod wasi { - use super::*; - use crate::get_slice_checked; - use std::path::PathBuf; - - /// Opens a directory that's visible to the WASI module as `alias` but - /// is backed by the host file at `host_file_path` - #[repr(C)] - pub struct wasmer_wasi_map_dir_entry_t { - /// What the WASI module will see in its virtual root - pub alias: wasmer_byte_array, - /// The backing file that the WASI module will interact with via the alias - pub host_file_path: wasmer_byte_array, - } - - impl wasmer_wasi_map_dir_entry_t { - /// Converts the data into owned, Rust types - pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), std::str::Utf8Error> { - let alias = self.alias.as_str()?.to_owned(); - let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?); - - Ok((alias, host_path)) - } - } - - /// Creates a WASI import object. - /// - /// This function treats null pointers as empty collections. - /// For example, passing null for a string in `args`, will lead to a zero - /// length argument in that position. - #[no_mangle] - pub unsafe extern "C" fn wasmer_wasi_generate_import_object( - args: *const wasmer_byte_array, - args_len: c_uint, - envs: *const wasmer_byte_array, - envs_len: c_uint, - preopened_files: *const wasmer_byte_array, - preopened_files_len: c_uint, - mapped_dirs: *const wasmer_wasi_map_dir_entry_t, - mapped_dirs_len: c_uint, - ) -> *mut wasmer_import_object_t { - let arg_list = get_slice_checked(args, args_len as usize); - let env_list = get_slice_checked(envs, envs_len as usize); - let preopened_file_list = get_slice_checked(preopened_files, preopened_files_len as usize); - let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); - - wasmer_wasi_generate_import_object_inner( - arg_list, - env_list, - preopened_file_list, - mapped_dir_list, - ) - .unwrap_or(std::ptr::null_mut()) - } - - /// Inner function that wraps error handling - fn wasmer_wasi_generate_import_object_inner( - arg_list: &[wasmer_byte_array], - env_list: &[wasmer_byte_array], - preopened_file_list: &[wasmer_byte_array], - mapped_dir_list: &[wasmer_wasi_map_dir_entry_t], - ) -> Result<*mut wasmer_import_object_t, std::str::Utf8Error> { - let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect(); - let env_vec = env_list - .iter() - .map(|env_var| unsafe { env_var.as_vec() }) - .collect(); - let po_file_vec = preopened_file_list - .iter() - .map(|po_file| Ok(unsafe { PathBuf::from(po_file.as_str()?) }.to_owned())) - .collect::, _>>()?; - let mapped_dir_vec = mapped_dir_list - .iter() - .map(|entry| unsafe { entry.as_tuple() }) - .collect::, _>>()?; - - let import_object = Box::new(wasmer_wasi::generate_import_object( - arg_vec, - env_vec, - po_file_vec, - mapped_dir_vec, - )); - Ok(Box::into_raw(import_object) as *mut wasmer_import_object_t) - } - - /// Convenience function that creates a WASI import object with no arguments, - /// environment variables, preopened files, or mapped directories. - /// - /// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all - /// empty values. - #[no_mangle] - pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object( - ) -> *mut wasmer_import_object_t { - let import_object = Box::new(wasmer_wasi::generate_import_object( - vec![], - vec![], - vec![], - vec![], - )); - - Box::into_raw(import_object) as *mut wasmer_import_object_t - } -} +mod wasi; #[cfg(feature = "wasi")] pub use self::wasi::*; diff --git a/lib/runtime-c-api/src/import/wasi.rs b/lib/runtime-c-api/src/import/wasi.rs new file mode 100644 index 000000000..3df3c7f70 --- /dev/null +++ b/lib/runtime-c-api/src/import/wasi.rs @@ -0,0 +1,101 @@ +use super::*; +use crate::get_slice_checked; +use std::path::PathBuf; + +/// Opens a directory that's visible to the WASI module as `alias` but +/// is backed by the host file at `host_file_path` +#[repr(C)] +pub struct wasmer_wasi_map_dir_entry_t { + /// What the WASI module will see in its virtual root + pub alias: wasmer_byte_array, + /// The backing file that the WASI module will interact with via the alias + pub host_file_path: wasmer_byte_array, +} + +impl wasmer_wasi_map_dir_entry_t { + /// Converts the data into owned, Rust types + pub unsafe fn as_tuple(&self) -> Result<(String, PathBuf), std::str::Utf8Error> { + let alias = self.alias.as_str()?.to_owned(); + let host_path = std::path::PathBuf::from(self.host_file_path.as_str()?); + + Ok((alias, host_path)) + } +} + +/// Creates a WASI import object. +/// +/// This function treats null pointers as empty collections. +/// For example, passing null for a string in `args`, will lead to a zero +/// length argument in that position. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_generate_import_object( + args: *const wasmer_byte_array, + args_len: c_uint, + envs: *const wasmer_byte_array, + envs_len: c_uint, + preopened_files: *const wasmer_byte_array, + preopened_files_len: c_uint, + mapped_dirs: *const wasmer_wasi_map_dir_entry_t, + mapped_dirs_len: c_uint, +) -> *mut wasmer_import_object_t { + let arg_list = get_slice_checked(args, args_len as usize); + let env_list = get_slice_checked(envs, envs_len as usize); + let preopened_file_list = get_slice_checked(preopened_files, preopened_files_len as usize); + let mapped_dir_list = get_slice_checked(mapped_dirs, mapped_dirs_len as usize); + + wasmer_wasi_generate_import_object_inner( + arg_list, + env_list, + preopened_file_list, + mapped_dir_list, + ) + .unwrap_or(std::ptr::null_mut()) +} + +/// Inner function that wraps error handling +fn wasmer_wasi_generate_import_object_inner( + arg_list: &[wasmer_byte_array], + env_list: &[wasmer_byte_array], + preopened_file_list: &[wasmer_byte_array], + mapped_dir_list: &[wasmer_wasi_map_dir_entry_t], +) -> Result<*mut wasmer_import_object_t, std::str::Utf8Error> { + let arg_vec = arg_list.iter().map(|arg| unsafe { arg.as_vec() }).collect(); + let env_vec = env_list + .iter() + .map(|env_var| unsafe { env_var.as_vec() }) + .collect(); + let po_file_vec = preopened_file_list + .iter() + .map(|po_file| Ok(unsafe { PathBuf::from(po_file.as_str()?) }.to_owned())) + .collect::, _>>()?; + let mapped_dir_vec = mapped_dir_list + .iter() + .map(|entry| unsafe { entry.as_tuple() }) + .collect::, _>>()?; + + let import_object = Box::new(wasmer_wasi::generate_import_object( + arg_vec, + env_vec, + po_file_vec, + mapped_dir_vec, + )); + Ok(Box::into_raw(import_object) as *mut wasmer_import_object_t) +} + +/// Convenience function that creates a WASI import object with no arguments, +/// environment variables, preopened files, or mapped directories. +/// +/// This function is the same as calling [`wasmer_wasi_generate_import_object`] with all +/// empty values. +#[no_mangle] +pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wasmer_import_object_t +{ + let import_object = Box::new(wasmer_wasi::generate_import_object( + vec![], + vec![], + vec![], + vec![], + )); + + Box::into_raw(import_object) as *mut wasmer_import_object_t +} From c3ff8eb5401e99d807cd389d4690ef4765be8f54 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 11 Oct 2019 09:26:05 +0200 Subject: [PATCH 021/122] fix(runtime-c-api) Replace unsafe code by safe code. --- lib/runtime-c-api/src/export.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index 3112b6178..acc3d122e 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -112,11 +112,13 @@ impl std::convert::TryFrom for wasmer_import_export_kind { type Error = (); fn try_from(value: u32) -> Result { - if value > 3 { - Err(()) - } else { - Ok(unsafe { std::mem::transmute(value) }) - } + Ok(match value { + 0 => Self::WASM_FUNCTION, + 1 => Self::WASM_GLOBAL, + 2 => Self::WASM_MEMORY, + 3 => Self::WASM_TABLE, + _ => return Err(()), + }) } } From e9f476c93bcef881b97e98832a693cbcdc401312 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Sun, 13 Oct 2019 10:30:02 +0200 Subject: [PATCH 022/122] doc: add link to SO in C api example --- lib/runtime-c-api/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index c652948b8..99fc992f5 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -36,6 +36,7 @@ The C and C++ header files can be found in the source tree of this crate, respectively [`wasmer.h`][wasmer_h] and [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always up-to-date in this repository. +The runtime library needed to compile (so, dll, dylib) can be donwloaded in wasmer [release page](https://github.com/wasmerio/wasmer/releases). Here is a simple example to use the C API: From 5611bec3eb19c339b240fca0a7c3b37b4c823b9f Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Sun, 13 Oct 2019 21:52:10 -0700 Subject: [PATCH 023/122] Update README.md --- lib/runtime-c-api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/README.md b/lib/runtime-c-api/README.md index 99fc992f5..8ce84a130 100644 --- a/lib/runtime-c-api/README.md +++ b/lib/runtime-c-api/README.md @@ -36,7 +36,7 @@ The C and C++ header files can be found in the source tree of this crate, respectively [`wasmer.h`][wasmer_h] and [`wasmer.hh`][wasmer_hh]. They are automatically generated, and always up-to-date in this repository. -The runtime library needed to compile (so, dll, dylib) can be donwloaded in wasmer [release page](https://github.com/wasmerio/wasmer/releases). +The runtime shared library (so, dll, dylib) can also be downloaded in Wasmer [release page](https://github.com/wasmerio/wasmer/releases). Here is a simple example to use the C API: From 4e7ba405b8b0bef04a552d7d56044fae8b22b430 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2019 14:10:50 +0000 Subject: [PATCH 024/122] Bump structopt from 0.3.2 to 0.3.3 Bumps [structopt](https://github.com/TeXitoi/structopt) from 0.3.2 to 0.3.3. - [Release notes](https://github.com/TeXitoi/structopt/releases) - [Changelog](https://github.com/TeXitoi/structopt/blob/master/CHANGELOG.md) - [Commits](https://github.com/TeXitoi/structopt/compare/v0.3.2...v0.3.3) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c0d362ed..86c040659 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1199,16 +1199,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "structopt" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "structopt-derive" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1466,7 +1466,7 @@ dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-backend 0.8.0", @@ -1936,8 +1936,8 @@ dependencies = [ "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe8d3289b63ef2f196d89e7701f986583c0895e764b78f052a55b9b5d34d84a" -"checksum structopt-derive 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3add731f5b4fb85931d362a3c92deb1ad7113649a8d51701fb257673705f122" +"checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" +"checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" From 555d933057bb274b88c97bf3f607cfd1826b99b4 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 10 Oct 2019 22:20:10 -0700 Subject: [PATCH 025/122] Initial commit, reimplementation of F32Min. Fixes F32Min(negative_zero, zero) issue. Also removes some previously-fixed i32 and i64 exclusions from the tests. --- lib/singlepass-backend/src/codegen_x64.rs | 64 ++++++++++++++++++++++- lib/singlepass-backend/src/emitter_x64.rs | 8 ++- lib/spectests/tests/excludes.txt | 19 ------- 3 files changed, 70 insertions(+), 21 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7e3a9ed5f..7133a2789 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2822,7 +2822,69 @@ impl FunctionCodeGenerator for X64FunctionCode { a, &mut self.machine, &mut self.value_stack, - Assembler::emit_vminss, + |a, src1, src2, dst| { + let loc1 = Location::XMM(src1); + let loc2 = match src2 { + XMMOrMemory::XMM(x) => Location::XMM(x), + XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), + }; + // TODO: use temp_gpr (or at least check that src2 isn't + // XMMOrMemory that uses AX or DX. + a.emit_mov(Size::S32, loc1, Location::GPR(GPR::RAX)); + a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); + // TODO: we can skip this when dst is an XMM reg. + let tmp_xmm = if src1 == XMM::XMM0 { + if src2 == XMMOrMemory::XMM(XMM::XMM1) { + XMM::XMM2 + } else { + XMM::XMM1 + } + } else { + XMM::XMM0 + }; + match src2 { + XMMOrMemory::XMM(x) => { + a.emit_mov(Size::S64, Location::XMM(x), Location::XMM(tmp_xmm)) + } + XMMOrMemory::Memory(base, disp) => a.emit_mov( + Size::S64, + Location::Memory(base, disp), + Location::XMM(tmp_xmm), + ), + }; + a.emit_ucomiss(XMMOrMemory::XMM(src1), tmp_xmm); + let do_vminss = a.get_label(); + a.emit_jmp(Condition::NotEqual, do_vminss); + a.emit_jmp(Condition::ParityEven, do_vminss); + a.emit_cmp(Size::S32, Location::GPR(GPR::RAX), Location::GPR(GPR::RDX)); + a.emit_jmp(Condition::Equal, do_vminss); + static NEG_ZERO: u128 = 0x80000000; + match src2 { + XMMOrMemory::XMM(x) => { + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(GPR::RDX), + ); + a.emit_mov(Size::S64, Location::Memory(GPR::RDX, 0), Location::XMM(x)); + } + XMMOrMemory::Memory(base, disp) => { + // TODO: What if base == RDX? + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(GPR::RDX), + ); + a.emit_mov( + Size::S64, + Location::Memory(GPR::RDX, 0), + Location::Memory(base, disp), + ); + } + }; + a.emit_label(do_vminss); + a.emit_vminss(src1, src2, dst); + }, ), Operator::F32Eq => Self::emit_fp_cmpop_avx( a, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 2e747f7ec..d4030ce76 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -26,6 +26,8 @@ pub enum Condition { Equal, NotEqual, Signed, + ParityEven, + ParityOdd, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -36,7 +38,7 @@ pub enum Size { S64, } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[allow(dead_code)] pub enum XMMOrMemory { XMM(XMM), @@ -602,6 +604,8 @@ impl Emitter for Assembler { Condition::Equal => jmp_op!(je, self, label), Condition::NotEqual => jmp_op!(jne, self, label), Condition::Signed => jmp_op!(js, self, label), + Condition::ParityEven => jmp_op!(jp, self, label), + Condition::ParityOdd => jmp_op!(jnp, self, label), } } fn emit_jmp_location(&mut self, loc: Location) { @@ -625,6 +629,8 @@ impl Emitter for Assembler { Condition::Equal => trap_op!(je, self), Condition::NotEqual => trap_op!(jne, self), Condition::Signed => trap_op!(js, self), + Condition::ParityEven => trap_op!(jp, self), + Condition::ParityOdd => trap_op!(jnp, self), } } fn emit_set(&mut self, condition: Condition, dst: GPR) { diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index dee265684..dbc7677c5 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -465,7 +465,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E 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:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -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) singlepass:fail:f32.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) @@ -902,15 +901,6 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i32.wast:242 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:243 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") -singlepass:fail:i32.wast:244 # AssertReturn - result I32(15) ("0xf") does not match expected I32(16) ("0x10") -singlepass:fail:i32.wast:245 # AssertReturn - result I32(7) ("0x7") does not match expected I32(24) ("0x18") -singlepass:fail:i32.wast:246 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:247 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") -singlepass:fail:i32.wast:248 # AssertReturn - result I32(1) ("0x1") does not match expected I32(30) ("0x1e") -singlepass:fail:i32.wast:249 # AssertReturn - result I32(30) ("0x1e") does not match expected I32(1) ("0x1") -singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -920,15 +910,6 @@ singlepass:fail:i64.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i64.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i64.wast:242 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:243 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") -singlepass:fail:i64.wast:244 # AssertReturn - result I64(15) ("0xf") does not match expected I64(48) ("0x30") -singlepass:fail:i64.wast:245 # AssertReturn - result I64(7) ("0x7") does not match expected I64(56) ("0x38") -singlepass:fail:i64.wast:246 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:247 # AssertReturn - result I64(0) ("0x0") does not match expected I64(63) ("0x3f") -singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not match expected I64(62) ("0x3e") -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:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error From d6eba03a2f9e5eece1b16dfdcfb7af7f5d546254 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 10 Oct 2019 22:23:42 -0700 Subject: [PATCH 026/122] Remove loc1/loc2. That intended refactoring didn't work out. --- lib/singlepass-backend/src/codegen_x64.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7133a2789..8c3cf8234 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2823,15 +2823,20 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, |a, src1, src2, dst| { - let loc1 = Location::XMM(src1); - let loc2 = match src2 { - XMMOrMemory::XMM(x) => Location::XMM(x), - XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), - }; // TODO: use temp_gpr (or at least check that src2 isn't // XMMOrMemory that uses AX or DX. - a.emit_mov(Size::S32, loc1, Location::GPR(GPR::RAX)); - a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); + match src2 { + XMMOrMemory::XMM(x) => { + a.emit_mov(Size::S32, Location::XMM(x), Location::GPR(GPR::RDX)) + } + XMMOrMemory::Memory(base, disp) => a.emit_mov( + Size::S32, + Location::Memory(base, disp), + Location::GPR(GPR::RDX), + ), + }; + // TODO: we can skip this when dst is an XMM reg. let tmp_xmm = if src1 == XMM::XMM0 { if src2 == XMMOrMemory::XMM(XMM::XMM1) { From b75e5c0c7c9fcc68e75b1d7c65efafed042db594 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 11 Oct 2019 10:11:27 -0700 Subject: [PATCH 027/122] When we know RDX is unavailable, use RAX instead. Should be fine here. --- lib/singlepass-backend/src/codegen_x64.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 8c3cf8234..3df276fa6 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2874,15 +2874,15 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov(Size::S64, Location::Memory(GPR::RDX, 0), Location::XMM(x)); } XMMOrMemory::Memory(base, disp) => { - // TODO: What if base == RDX? + let neg_zero_base = if base == GPR::RDX { GPR::RAX } else { GPR::RDX }; a.emit_mov( Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(GPR::RDX), + Location::GPR(neg_zero_base), ); a.emit_mov( Size::S64, - Location::Memory(GPR::RDX, 0), + Location::Memory(neg_zero_base, 0), Location::Memory(base, disp), ); } From 0f712c90ab8c81a0fba8a6c0da4f059e6ca6d689 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 11 Oct 2019 10:53:39 -0700 Subject: [PATCH 028/122] Don't allocate another register when it's safe to reuse dst. --- lib/singlepass-backend/src/codegen_x64.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 3df276fa6..a1d426ccb 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2836,16 +2836,18 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::GPR(GPR::RDX), ), }; - - // TODO: we can skip this when dst is an XMM reg. - let tmp_xmm = if src1 == XMM::XMM0 { - if src2 == XMMOrMemory::XMM(XMM::XMM1) { - XMM::XMM2 - } else { - XMM::XMM1 - } + let tmp_xmm = if dst != src1 && XMMOrMemory::XMM(dst) != src2 { + dst } else { - XMM::XMM0 + if src1 == XMM::XMM0 { + if src2 == XMMOrMemory::XMM(XMM::XMM1) { + XMM::XMM2 + } else { + XMM::XMM1 + } + } else { + XMM::XMM0 + } }; match src2 { XMMOrMemory::XMM(x) => { From 8b937afc1fc095101b1987372fbb7812e6aa8b2b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 11 Oct 2019 11:25:16 -0700 Subject: [PATCH 029/122] Add comments to indicate the implemention we'd like to have, but can't right now. --- lib/singlepass-backend/src/codegen_x64.rs | 42 +++++++++++++---------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index a1d426ccb..d65369e73 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2823,30 +2823,34 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, |a, src1, src2, dst| { - // TODO: use temp_gpr (or at least check that src2 isn't - // XMMOrMemory that uses AX or DX. - a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); + // TODO: we don't have access to 'machine' here. + //let tmp1 = self.machine.acquire_temp_gpr().unwrap(); + //let tmp2 = self.machine.acquire_temp_gpr().unwrap(); + let tmp1 = GPR::RAX; + let tmp2 = GPR::RDX; + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmp1)); match src2 { XMMOrMemory::XMM(x) => { - a.emit_mov(Size::S32, Location::XMM(x), Location::GPR(GPR::RDX)) + a.emit_mov(Size::S32, Location::XMM(x), Location::GPR(tmp2)) + } + XMMOrMemory::Memory(base, disp) => { + a.emit_mov(Size::S32, Location::Memory(base, disp), Location::GPR(tmp2)) } - XMMOrMemory::Memory(base, disp) => a.emit_mov( - Size::S32, - Location::Memory(base, disp), - Location::GPR(GPR::RDX), - ), }; - let tmp_xmm = if dst != src1 && XMMOrMemory::XMM(dst) != src2 { - dst + let (tmp_xmm, _release_tmp_xmm) = if dst != src1 && XMMOrMemory::XMM(dst) != src2 + { + (dst, false) } else { + // TODO: we don't have access to 'machine' here. + //(self.machine.acquire_temp_xmm().unwrap(), true) if src1 == XMM::XMM0 { if src2 == XMMOrMemory::XMM(XMM::XMM1) { - XMM::XMM2 + (XMM::XMM2, false) } else { - XMM::XMM1 + (XMM::XMM1, false) } } else { - XMM::XMM0 + (XMM::XMM0, false) } }; match src2 { @@ -2863,7 +2867,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let do_vminss = a.get_label(); a.emit_jmp(Condition::NotEqual, do_vminss); a.emit_jmp(Condition::ParityEven, do_vminss); - a.emit_cmp(Size::S32, Location::GPR(GPR::RAX), Location::GPR(GPR::RDX)); + a.emit_cmp(Size::S32, Location::GPR(tmp1), Location::GPR(tmp2)); a.emit_jmp(Condition::Equal, do_vminss); static NEG_ZERO: u128 = 0x80000000; match src2 { @@ -2871,12 +2875,12 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov( Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(GPR::RDX), + Location::GPR(tmp2), ); - a.emit_mov(Size::S64, Location::Memory(GPR::RDX, 0), Location::XMM(x)); + a.emit_mov(Size::S64, Location::Memory(tmp2, 0), Location::XMM(x)); } XMMOrMemory::Memory(base, disp) => { - let neg_zero_base = if base == GPR::RDX { GPR::RAX } else { GPR::RDX }; + let neg_zero_base = if base == tmp2 { tmp1 } else { tmp2 }; a.emit_mov( Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), @@ -2891,6 +2895,8 @@ impl FunctionCodeGenerator for X64FunctionCode { }; a.emit_label(do_vminss); a.emit_vminss(src1, src2, dst); + // TODO: we don't have access to 'machine' here. + //if release_tmp_xmm { self.machine.release_temp_xmm(tmp_xmm) } }, ), Operator::F32Eq => Self::emit_fp_cmpop_avx( From 963148fdce577a1df60e1209fa51c5ae20cfcbf2 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 11 Oct 2019 17:51:29 -0700 Subject: [PATCH 030/122] Fix F32Min for all cases including NaNs. --- lib/singlepass-backend/src/codegen_x64.rs | 70 +++++++++++++++++++++++ lib/singlepass-backend/src/emitter_x64.rs | 32 +++++++++++ 2 files changed, 102 insertions(+) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index d65369e73..7f735384a 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2823,6 +2823,7 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, |a, src1, src2, dst| { + /* // TODO: we don't have access to 'machine' here. //let tmp1 = self.machine.acquire_temp_gpr().unwrap(); //let tmp2 = self.machine.acquire_temp_gpr().unwrap(); @@ -2897,6 +2898,75 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_vminss(src1, src2, dst); // TODO: we don't have access to 'machine' here. //if release_tmp_xmm { self.machine.release_temp_xmm(tmp_xmm) } +*/ + let tmp_xmm1 = /*if dst != src1 && XMMOrMemory::XMM(dst) != src2 + { + dst + } else { + // TODO: we don't have access to 'machine' here. + //(self.machine.acquire_temp_xmm().unwrap(), true) + if src1 == XMM::XMM0 { + if src2 == XMMOrMemory::XMM(XMM::XMM1) { + XMM::XMM2 + } else { + XMM::XMM1 + } + } else { + XMM::XMM0 + } + };*/ XMM::XMM6; + let tmp_xmm2 = XMM::XMM7; // TODO: pick value safely. + let tmp_xmm3 = XMM::XMM5; // TODO: pick value safely. + /* + let src2 = match src2 { + XMMOrMemory::XMM(x) => x, + XMMOrMemory::Memory(_, _) => panic!(), + }; + a.emit_vminss(src1, XMMOrMemory::XMM(src2), src2); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src1), tmp_xmm); + a.emit_vblendvps(src1, src2, XMMOrMemory::XMM(src1), tmp_xmm); + a.emit_vcmpordss(src1, XMMOrMemory::XMM(src1), src2); + let canonical_nan_base = GPR::RDX; + static CANONICAL_NAN: u128 = 0x7FC0_0000; + a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(canonical_nan_base)); + a.emit_mov(Size::S64, Location::Memory(canonical_nan_base, 0), Location::XMM(tmp_xmm)); + a.emit_vblendvps(src1, tmp_xmm, XMMOrMemory::XMM(src1), src2); + a.emit_mov(Size::S64, Location::XMM(src2), Location::XMM(dst)); + */ + static NEG_ZERO: u128 = 0x8000_0000; + static CANONICAL_NAN: u128 = 0x7FC0_0000; + let loc2 = match src2 { + XMMOrMemory::XMM(x) => Location::XMM(x), + XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), + }; + let spare_base = GPR::RDX; + //a.emit_ud2(); + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); + a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); + a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX)); + let src2 = match src2 { + XMMOrMemory::XMM(x) => x, + XMMOrMemory::Memory(_, _) => panic!(), + }; + a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + // load float -0.0 + a.emit_mov(Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), Location::GPR(spare_base)); + a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(tmp_xmm2)); + a.emit_label(label2); + a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(spare_base)); + a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(src2)); + a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(dst)); }, ), Operator::F32Eq => Self::emit_fp_cmpop_avx( diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index d4030ce76..599e908dd 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -107,6 +107,8 @@ pub trait Emitter { fn emit_cmovae_gpr_32(&mut self, src: GPR, dst: GPR); fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR); + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory); + fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vsubss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -138,6 +140,12 @@ pub trait Emitter { fn emit_vcmpgess(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vcmpgesd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpunordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpunordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + + fn emit_vcmpordss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vcmpordsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vsqrtss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vsqrtsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -166,6 +174,8 @@ pub trait Emitter { fn emit_vcvtsi2sd_32(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM); fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM); + fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM); + fn emit_test_gpr_64(&mut self, reg: GPR); fn emit_ud2(&mut self); @@ -951,6 +961,15 @@ impl Emitter for Assembler { dynasm!(self ; cmovae Rq(dst as u8), Rq(src as u8)); } + fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + match (src, dst) { + (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)), + (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), [Rq(base as u8) + disp]), + (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => dynasm!(self ; movaps [Rq(base as u8) + disp], Rx(src as u8)), + _ => panic!("singlepass can't emit VMOVAPS {:?} {:?}", src, dst), + }; + } + avx_fn!(vaddss, emit_vaddss); avx_fn!(vaddsd, emit_vaddsd); @@ -987,6 +1006,12 @@ impl Emitter for Assembler { avx_fn!(vcmpgess, emit_vcmpgess); avx_fn!(vcmpgesd, emit_vcmpgesd); + avx_fn!(vcmpunordss, emit_vcmpunordss); + avx_fn!(vcmpunordsd, emit_vcmpunordsd); + + avx_fn!(vcmpordss, emit_vcmpordss); + avx_fn!(vcmpordsd, emit_vcmpordsd); + avx_fn!(vsqrtss, emit_vsqrtss); avx_fn!(vsqrtsd, emit_vsqrtsd); @@ -1007,6 +1032,13 @@ impl Emitter for Assembler { avx_i2f_64_fn!(vcvtsi2ss, emit_vcvtsi2ss_64); avx_i2f_64_fn!(vcvtsi2sd, emit_vcvtsi2sd_64); + fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)), + XMMOrMemory::Memory(base, disp) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)), + } + } + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomiss Rx(dst as u8), Rx(x as u8)), From 4b89e018061d98b44720c8e6adcbc70bc1e101c9 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Sat, 12 Oct 2019 11:57:21 -0700 Subject: [PATCH 031/122] Remove commented-out code that I added so as to not lose its history in git. Apply trivial cleanups and reformat. Remove expected test failure entries that are fixed so far. --- lib/singlepass-backend/src/codegen_x64.rs | 140 ++++------------------ lib/singlepass-backend/src/emitter_x64.rs | 26 ++-- lib/spectests/tests/excludes.txt | 104 ---------------- 3 files changed, 40 insertions(+), 230 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7f735384a..09ccdf699 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2823,116 +2823,11 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.machine, &mut self.value_stack, |a, src1, src2, dst| { - /* - // TODO: we don't have access to 'machine' here. - //let tmp1 = self.machine.acquire_temp_gpr().unwrap(); - //let tmp2 = self.machine.acquire_temp_gpr().unwrap(); - let tmp1 = GPR::RAX; - let tmp2 = GPR::RDX; - a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmp1)); - match src2 { - XMMOrMemory::XMM(x) => { - a.emit_mov(Size::S32, Location::XMM(x), Location::GPR(tmp2)) - } - XMMOrMemory::Memory(base, disp) => { - a.emit_mov(Size::S32, Location::Memory(base, disp), Location::GPR(tmp2)) - } - }; - let (tmp_xmm, _release_tmp_xmm) = if dst != src1 && XMMOrMemory::XMM(dst) != src2 - { - (dst, false) - } else { - // TODO: we don't have access to 'machine' here. - //(self.machine.acquire_temp_xmm().unwrap(), true) - if src1 == XMM::XMM0 { - if src2 == XMMOrMemory::XMM(XMM::XMM1) { - (XMM::XMM2, false) - } else { - (XMM::XMM1, false) - } - } else { - (XMM::XMM0, false) - } - }; - match src2 { - XMMOrMemory::XMM(x) => { - a.emit_mov(Size::S64, Location::XMM(x), Location::XMM(tmp_xmm)) - } - XMMOrMemory::Memory(base, disp) => a.emit_mov( - Size::S64, - Location::Memory(base, disp), - Location::XMM(tmp_xmm), - ), - }; - a.emit_ucomiss(XMMOrMemory::XMM(src1), tmp_xmm); - let do_vminss = a.get_label(); - a.emit_jmp(Condition::NotEqual, do_vminss); - a.emit_jmp(Condition::ParityEven, do_vminss); - a.emit_cmp(Size::S32, Location::GPR(tmp1), Location::GPR(tmp2)); - a.emit_jmp(Condition::Equal, do_vminss); - static NEG_ZERO: u128 = 0x80000000; - match src2 { - XMMOrMemory::XMM(x) => { - a.emit_mov( - Size::S64, - Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(tmp2), - ); - a.emit_mov(Size::S64, Location::Memory(tmp2, 0), Location::XMM(x)); - } - XMMOrMemory::Memory(base, disp) => { - let neg_zero_base = if base == tmp2 { tmp1 } else { tmp2 }; - a.emit_mov( - Size::S64, - Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(neg_zero_base), - ); - a.emit_mov( - Size::S64, - Location::Memory(neg_zero_base, 0), - Location::Memory(base, disp), - ); - } - }; - a.emit_label(do_vminss); - a.emit_vminss(src1, src2, dst); - // TODO: we don't have access to 'machine' here. - //if release_tmp_xmm { self.machine.release_temp_xmm(tmp_xmm) } -*/ - let tmp_xmm1 = /*if dst != src1 && XMMOrMemory::XMM(dst) != src2 - { - dst - } else { - // TODO: we don't have access to 'machine' here. - //(self.machine.acquire_temp_xmm().unwrap(), true) - if src1 == XMM::XMM0 { - if src2 == XMMOrMemory::XMM(XMM::XMM1) { - XMM::XMM2 - } else { - XMM::XMM1 - } - } else { - XMM::XMM0 - } - };*/ XMM::XMM6; - let tmp_xmm2 = XMM::XMM7; // TODO: pick value safely. - let tmp_xmm3 = XMM::XMM5; // TODO: pick value safely. - /* - let src2 = match src2 { - XMMOrMemory::XMM(x) => x, - XMMOrMemory::Memory(_, _) => panic!(), - }; - a.emit_vminss(src1, XMMOrMemory::XMM(src2), src2); - a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src1), tmp_xmm); - a.emit_vblendvps(src1, src2, XMMOrMemory::XMM(src1), tmp_xmm); - a.emit_vcmpordss(src1, XMMOrMemory::XMM(src1), src2); - let canonical_nan_base = GPR::RDX; - static CANONICAL_NAN: u128 = 0x7FC0_0000; - a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(canonical_nan_base)); - a.emit_mov(Size::S64, Location::Memory(canonical_nan_base, 0), Location::XMM(tmp_xmm)); - a.emit_vblendvps(src1, tmp_xmm, XMMOrMemory::XMM(src1), src2); - a.emit_mov(Size::S64, Location::XMM(src2), Location::XMM(dst)); - */ + // TODO: pick values safely. + let tmp_xmm1 = XMM::XMM7; + let tmp_xmm2 = XMM::XMM6; + let tmp_xmm3 = XMM::XMM5; + static NEG_ZERO: u128 = 0x8000_0000; static CANONICAL_NAN: u128 = 0x7FC0_0000; let loc2 = match src2 { @@ -2940,7 +2835,6 @@ impl FunctionCodeGenerator for X64FunctionCode { XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), }; let spare_base = GPR::RDX; - //a.emit_ud2(); a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX)); @@ -2956,15 +2850,31 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_jmp(Condition::None, label2); a.emit_label(label1); // load float -0.0 - a.emit_mov(Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), Location::GPR(spare_base)); - a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(tmp_xmm2)); + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(spare_base), + ); + a.emit_mov( + Size::S64, + Location::Memory(spare_base, 0), + Location::XMM(tmp_xmm2), + ); a.emit_label(label2); a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); // load float canonical nan - a.emit_mov(Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(spare_base)); - a.emit_mov(Size::S64, Location::Memory(spare_base, 0), Location::XMM(src2)); + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(spare_base), + ); + a.emit_mov( + Size::S64, + Location::Memory(spare_base, 0), + Location::XMM(src2), + ); a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(dst)); }, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 599e908dd..c54a3a25a 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -26,8 +26,6 @@ pub enum Condition { Equal, NotEqual, Signed, - ParityEven, - ParityOdd, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -614,8 +612,6 @@ impl Emitter for Assembler { Condition::Equal => jmp_op!(je, self, label), Condition::NotEqual => jmp_op!(jne, self, label), Condition::Signed => jmp_op!(js, self, label), - Condition::ParityEven => jmp_op!(jp, self, label), - Condition::ParityOdd => jmp_op!(jnp, self, label), } } fn emit_jmp_location(&mut self, loc: Location) { @@ -639,8 +635,6 @@ impl Emitter for Assembler { Condition::Equal => trap_op!(je, self), Condition::NotEqual => trap_op!(jne, self), Condition::Signed => trap_op!(js, self), - Condition::ParityEven => trap_op!(jp, self), - Condition::ParityOdd => trap_op!(jnp, self), } } fn emit_set(&mut self, condition: Condition, dst: GPR) { @@ -963,9 +957,15 @@ impl Emitter for Assembler { fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { match (src, dst) { - (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)), - (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => dynasm!(self ; movaps Rx(dst as u8), [Rq(base as u8) + disp]), - (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => dynasm!(self ; movaps [Rq(base as u8) + disp], Rx(src as u8)), + (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movaps Rx(dst as u8), Rx(src as u8)) + } + (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movaps Rx(dst as u8), [Rq(base as u8) + disp]) + } + (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => { + dynasm!(self ; movaps [Rq(base as u8) + disp], Rx(src as u8)) + } _ => panic!("singlepass can't emit VMOVAPS {:?} {:?}", src, dst), }; } @@ -1034,8 +1034,12 @@ impl Emitter for Assembler { fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { match src2 { - XMMOrMemory::XMM(src2) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)), - XMMOrMemory::Memory(base, disp) => dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)), + XMMOrMemory::XMM(src2) => { + dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)) + } + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; vblendvps Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)) + } } } diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index dbc7677c5..ec0bed6d1 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -465,110 +465,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E 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:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -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) -singlepass:fail:f32.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1658 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1692 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1694 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1696 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1698 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1732 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1734 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1736 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1738 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1772 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1774 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1776 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1778 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1812 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1814 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1816 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1818 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1852 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1854 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1856 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1858 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1892 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1894 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1896 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1898 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1932 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1934 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1936 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1938 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:1939 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:1940 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:1941 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:1942 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:1943 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:1944 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:1945 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:1946 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:1947 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1948 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1949 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1950 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1951 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1952 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1953 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1954 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:1955 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1956 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1957 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1958 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1959 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1960 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1961 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1962 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:1963 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:1964 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:1965 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:1966 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:1967 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:1968 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:1969 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:1970 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:1971 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:1972 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:1973 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:1974 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:1975 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:1976 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:1977 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:1978 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:1979 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:1980 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:1981 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:1982 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:1983 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:1984 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:1985 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:1986 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:1987 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1988 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1989 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1990 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1991 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1992 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1993 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1994 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:1995 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:1996 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:1997 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:1998 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:1999 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2000 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2001 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2002 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2005 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2006 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2009 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2010 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2013 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2014 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2017 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2018 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f32.wast:2021 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") singlepass:fail:f32.wast:2052 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f32.wast:2054 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) From 765e1d3b9e1c1efc2259eadf3efeeeddd7b33912 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 13:44:45 -0700 Subject: [PATCH 032/122] Add XMM8--XMM15. These were added in x64. --- lib/runtime-core/src/state.rs | 8 ++++ lib/singlepass-backend/src/emitter_x64.rs | 48 +++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 7b8dcd2b1..1b11b1128 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -1023,6 +1023,14 @@ pub mod x64 { XMM5, XMM6, XMM7, + XMM8, + XMM9, + XMM10, + XMM11, + XMM12, + XMM13, + XMM14, + XMM15, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index c54a3a25a..b9bbe59bb 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -379,6 +379,14 @@ macro_rules! avx_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rx((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rx((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rx((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rx((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rx((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rx((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rx((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rx((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rx((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rx((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rx((x as u8))), }, XMMOrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, [Rq((base as u8)) + disp]), @@ -389,6 +397,14 @@ macro_rules! avx_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, [Rq((base as u8)) + disp]), }, } } @@ -408,6 +424,14 @@ macro_rules! avx_i2f_64_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rq((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rq((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rq((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rq((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rq((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rq((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rq((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rq((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rq((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rq((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rq((x as u8))), }, GPROrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, QWORD [Rq((base as u8)) + disp]), @@ -418,6 +442,14 @@ macro_rules! avx_i2f_64_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, QWORD [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, QWORD [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, QWORD [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, QWORD [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, QWORD [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, QWORD [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, QWORD [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, QWORD [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, QWORD [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, QWORD [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, QWORD [Rq((base as u8)) + disp]), }, } } @@ -437,6 +469,14 @@ macro_rules! avx_i2f_32_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, Rd((x as u8))), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, Rd((x as u8))), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, Rd((x as u8))), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, Rd((x as u8))), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, Rd((x as u8))), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, Rd((x as u8))), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, Rd((x as u8))), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, Rd((x as u8))), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, Rd((x as u8))), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, Rd((x as u8))), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, Rd((x as u8))), }, GPROrMemory::Memory(base, disp) => match src1 { XMM::XMM0 => dynasm!(self ; $ins Rx((dst as u8)), xmm0, DWORD [Rq((base as u8)) + disp]), @@ -447,6 +487,14 @@ macro_rules! avx_i2f_32_fn { XMM::XMM5 => dynasm!(self ; $ins Rx((dst as u8)), xmm5, DWORD [Rq((base as u8)) + disp]), XMM::XMM6 => dynasm!(self ; $ins Rx((dst as u8)), xmm6, DWORD [Rq((base as u8)) + disp]), XMM::XMM7 => dynasm!(self ; $ins Rx((dst as u8)), xmm7, DWORD [Rq((base as u8)) + disp]), + XMM::XMM8 => dynasm!(self ; $ins Rx((dst as u8)), xmm8, DWORD [Rq((base as u8)) + disp]), + XMM::XMM9 => dynasm!(self ; $ins Rx((dst as u8)), xmm9, DWORD [Rq((base as u8)) + disp]), + XMM::XMM10 => dynasm!(self ; $ins Rx((dst as u8)), xmm10, DWORD [Rq((base as u8)) + disp]), + XMM::XMM11 => dynasm!(self ; $ins Rx((dst as u8)), xmm11, DWORD [Rq((base as u8)) + disp]), + XMM::XMM12 => dynasm!(self ; $ins Rx((dst as u8)), xmm12, DWORD [Rq((base as u8)) + disp]), + XMM::XMM13 => dynasm!(self ; $ins Rx((dst as u8)), xmm13, DWORD [Rq((base as u8)) + disp]), + XMM::XMM14 => dynasm!(self ; $ins Rx((dst as u8)), xmm14, DWORD [Rq((base as u8)) + disp]), + XMM::XMM15 => dynasm!(self ; $ins Rx((dst as u8)), xmm15, DWORD [Rq((base as u8)) + disp]), }, } } From 336dab7fd97e3c7c925fd0461843f82d342a0784 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 13:45:42 -0700 Subject: [PATCH 033/122] Don't use utility functions in F32Min implementation. --- lib/singlepass-backend/src/codegen_x64.rs | 165 ++++++++++++++-------- 1 file changed, 105 insertions(+), 60 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 09ccdf699..7a46eb80c 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2818,67 +2818,112 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.value_stack, Assembler::emit_vmaxss, ), - Operator::F32Min => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - |a, src1, src2, dst| { - // TODO: pick values safely. - let tmp_xmm1 = XMM::XMM7; - let tmp_xmm2 = XMM::XMM6; - let tmp_xmm3 = XMM::XMM5; + Operator::F32Min => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); - static NEG_ZERO: u128 = 0x8000_0000; - static CANONICAL_NAN: u128 = 0x7FC0_0000; - let loc2 = match src2 { - XMMOrMemory::XMM(x) => Location::XMM(x), - XMMOrMemory::Memory(base, disp) => Location::Memory(base, disp), - }; - let spare_base = GPR::RDX; - a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); - a.emit_mov(Size::S32, loc2, Location::GPR(GPR::RDX)); - a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX)); - let src2 = match src2 { - XMMOrMemory::XMM(x) => x, - XMMOrMemory::Memory(_, _) => panic!(), - }; - a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); - let label1 = a.get_label(); - let label2 = a.get_label(); - a.emit_jmp(Condition::NotEqual, label1); - a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); - a.emit_jmp(Condition::None, label2); - a.emit_label(label1); - // load float -0.0 - a.emit_mov( - Size::S64, - Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(spare_base), - ); - a.emit_mov( - Size::S64, - Location::Memory(spare_base, 0), - Location::XMM(tmp_xmm2), - ); - a.emit_label(label2); - a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); - a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); - a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); - // load float canonical nan - a.emit_mov( - Size::S64, - Location::Imm64((&CANONICAL_NAN as *const u128) as u64), - Location::GPR(spare_base), - ); - a.emit_mov( - Size::S64, - Location::Memory(spare_base, 0), - Location::XMM(src2), - ); - a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); - a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(dst)); - }, - ), + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg)); + a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg)); + a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg)); + a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg)); + a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static NEG_ZERO: u128 = 0x8000_0000; + static CANONICAL_NAN: u128 = 0x7FC0_0000; + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); + a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(GPR::RDX)); + a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX)); + a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + // load float -0.0 + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(tmpg), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg, 0), + Location::XMM(tmp_xmm2), + ); + a.emit_label(label2); + a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg, 0), + Location::XMM(src2), + ); + a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + } Operator::F32Eq => Self::emit_fp_cmpop_avx( a, &mut self.machine, From 5cee23455d90b3bbfa6d3ffcd6d0ccbcbf93a8ce Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 13:51:03 -0700 Subject: [PATCH 034/122] Release the registers we acquire. Reformat. --- lib/singlepass-backend/src/codegen_x64.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7a46eb80c..3fcbdd6d5 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2908,11 +2908,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Imm64((&CANONICAL_NAN as *const u128) as u64), Location::GPR(tmpg), ); - a.emit_mov( - Size::S64, - Location::Memory(tmpg, 0), - Location::XMM(src2), - ); + a.emit_mov(Size::S64, Location::Memory(tmpg, 0), Location::XMM(src2)); a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { @@ -2923,6 +2919,10 @@ impl FunctionCodeGenerator for X64FunctionCode { } _ => unreachable!(), } + + self.machine.release_temp_gpr(tmpg); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); } Operator::F32Eq => Self::emit_fp_cmpop_avx( a, From b886a41a8535912e47406b9746c715ffd2d9b61c Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 13:53:30 -0700 Subject: [PATCH 035/122] Use temp_gprs instead of hard-coding RAX/RDX. --- lib/singlepass-backend/src/codegen_x64.rs | 36 ++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 3fcbdd6d5..31406cec1 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2832,7 +2832,8 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp1 = self.machine.acquire_temp_xmm().unwrap(); let tmp2 = self.machine.acquire_temp_xmm().unwrap(); - let tmpg = self.machine.acquire_temp_gpr().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); let src1 = match src1 { Location::XMM(x) => x, @@ -2841,13 +2842,13 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp1 } Location::Imm32(_) => { - a.emit_mov(Size::S32, src1, Location::GPR(tmpg)); - a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp1)); + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } Location::Imm64(_) => { - a.emit_mov(Size::S64, src1, Location::GPR(tmpg)); - a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp1)); + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); tmp1 } _ => unreachable!(), @@ -2859,13 +2860,13 @@ impl FunctionCodeGenerator for X64FunctionCode { tmp2 } Location::Imm32(_) => { - a.emit_mov(Size::S32, src2, Location::GPR(tmpg)); - a.emit_mov(Size::S32, Location::GPR(tmpg), Location::XMM(tmp2)); + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } Location::Imm64(_) => { - a.emit_mov(Size::S64, src2, Location::GPR(tmpg)); - a.emit_mov(Size::S64, Location::GPR(tmpg), Location::XMM(tmp2)); + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); tmp2 } _ => unreachable!(), @@ -2877,9 +2878,9 @@ impl FunctionCodeGenerator for X64FunctionCode { static NEG_ZERO: u128 = 0x8000_0000; static CANONICAL_NAN: u128 = 0x7FC0_0000; - a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(GPR::RAX)); - a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(GPR::RDX)); - a.emit_cmp(Size::S32, Location::GPR(GPR::RDX), Location::GPR(GPR::RAX)); + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S32, Location::GPR(tmpg2), Location::GPR(tmpg1)); a.emit_vminss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); let label1 = a.get_label(); let label2 = a.get_label(); @@ -2891,11 +2892,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov( Size::S64, Location::Imm64((&NEG_ZERO as *const u128) as u64), - Location::GPR(tmpg), + Location::GPR(tmpg1), ); a.emit_mov( Size::S64, - Location::Memory(tmpg, 0), + Location::Memory(tmpg1, 0), Location::XMM(tmp_xmm2), ); a.emit_label(label2); @@ -2906,9 +2907,9 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_mov( Size::S64, Location::Imm64((&CANONICAL_NAN as *const u128) as u64), - Location::GPR(tmpg), + Location::GPR(tmpg1), ); - a.emit_mov(Size::S64, Location::Memory(tmpg, 0), Location::XMM(src2)); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { @@ -2920,7 +2921,8 @@ impl FunctionCodeGenerator for X64FunctionCode { _ => unreachable!(), } - self.machine.release_temp_gpr(tmpg); + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); self.machine.release_temp_xmm(tmp2); self.machine.release_temp_xmm(tmp1); } From 06ffb00deb22c25d801be0c1b49b20f9a9617502 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 14:07:30 -0700 Subject: [PATCH 036/122] Reimplement F32Max. --- lib/singlepass-backend/src/codegen_x64.rs | 103 +++++++++++++++++++-- lib/singlepass-backend/src/emitter_x64.rs | 3 + lib/spectests/tests/excludes.txt | 105 ---------------------- 3 files changed, 100 insertions(+), 111 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 31406cec1..6967f9192 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2812,12 +2812,103 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.value_stack, Assembler::emit_vdivss, ), - Operator::F32Max => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vmaxss, - ), + Operator::F32Max => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static CANONICAL_NAN: u128 = 0x7FC0_0000; + a.emit_mov(Size::S32, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S32, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vmaxss(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovaps(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + a.emit_vxorps(tmp_xmm2, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm2); + a.emit_label(label2); + a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvps(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordss(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } Operator::F32Min => { let src2 = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index b9bbe59bb..db8cedaaa 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -106,6 +106,7 @@ pub trait Emitter { fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR); fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory); + fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -1018,6 +1019,8 @@ impl Emitter for Assembler { }; } + avx_fn!(vxorps, emit_vxorps); + avx_fn!(vaddss, emit_vaddss); avx_fn!(vaddsd, emit_vaddsd); diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index ec0bed6d1..1a256583d 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -465,111 +465,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E 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:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:f32.wast:2021 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") -singlepass:fail:f32.wast:2052 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2054 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2056 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2058 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2092 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2094 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2096 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2098 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2132 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2134 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2136 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2138 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2172 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2174 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2176 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2178 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2212 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2214 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2216 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2218 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2252 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2254 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2256 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2258 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2292 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2294 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2296 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2298 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2332 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2334 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2336 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2338 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2339 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:2340 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:2341 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:2342 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:2343 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.0) -singlepass:fail:f32.wast:2344 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.0) -singlepass:fail:f32.wast:2345 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.0) -singlepass:fail:f32.wast:2346 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.0) -singlepass:fail:f32.wast:2347 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2348 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2349 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2350 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2351 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2352 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2353 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2354 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000000000001) -singlepass:fail:f32.wast:2355 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2356 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2357 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2358 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2359 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2360 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2361 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2362 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.000000000000000000000000000000000000011754944) -singlepass:fail:f32.wast:2363 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:2364 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:2365 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:2366 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:2367 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-0.5) -singlepass:fail:f32.wast:2368 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-0.5) -singlepass:fail:f32.wast:2369 # "AssertReturnCanonicalNan" - value is not canonical nan F32(0.5) -singlepass:fail:f32.wast:2370 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(0.5) -singlepass:fail:f32.wast:2371 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:2372 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:2373 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:2374 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:2375 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-1.0) -singlepass:fail:f32.wast:2376 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-1.0) -singlepass:fail:f32.wast:2377 # "AssertReturnCanonicalNan" - value is not canonical nan F32(1.0) -singlepass:fail:f32.wast:2378 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(1.0) -singlepass:fail:f32.wast:2379 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:2380 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:2381 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:2382 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:2383 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-6.2831855) -singlepass:fail:f32.wast:2384 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-6.2831855) -singlepass:fail:f32.wast:2385 # "AssertReturnCanonicalNan" - value is not canonical nan F32(6.2831855) -singlepass:fail:f32.wast:2386 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(6.2831855) -singlepass:fail:f32.wast:2387 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2388 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2389 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2390 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2391 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2392 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2393 # "AssertReturnCanonicalNan" - value is not canonical nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2394 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(340282350000000000000000000000000000000.0) -singlepass:fail:f32.wast:2395 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2396 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2397 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2398 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2399 # "AssertReturnCanonicalNan" - value is not canonical nan F32(-inf) -singlepass:fail:f32.wast:2400 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(-inf) -singlepass:fail:f32.wast:2401 # "AssertReturnCanonicalNan" - value is not canonical nan F32(inf) -singlepass:fail:f32.wast:2402 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(inf) -singlepass:fail:f32.wast:2405 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2406 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2409 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2410 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2413 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2414 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2417 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) -singlepass:fail:f32.wast:2418 # "AssertReturnArithmeticNan" - value is not arithmetic nan F32(NaN) singlepass:fail:f64.wast:1620 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") singlepass:fail:f64.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) singlepass:fail:f64.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) From 26a4f073f085da2ee4bc82362ee96ebb2a9edcf1 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 14:15:18 -0700 Subject: [PATCH 037/122] Implement F64Min and F64Max. --- lib/singlepass-backend/src/codegen_x64.rs | 217 ++++++++++++++++++++-- lib/singlepass-backend/src/emitter_x64.rs | 30 +++ lib/spectests/tests/excludes.txt | 210 --------------------- 3 files changed, 235 insertions(+), 222 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 6967f9192..c2b9ae442 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3183,18 +3183,211 @@ impl FunctionCodeGenerator for X64FunctionCode { &mut self.value_stack, Assembler::emit_vdivsd, ), - Operator::F64Max => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vmaxsd, - ), - Operator::F64Min => Self::emit_fp_binop_avx( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_vminsd, - ), + Operator::F64Max => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static CANONICAL_NAN: u128 = 0x7FF8_0000_0000_0000; + a.emit_mov(Size::S64, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S64, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vmaxsd(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovapd(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + a.emit_vxorpd(tmp_xmm2, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm2); + a.emit_label(label2); + a.emit_vcmpeqsd(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvpd(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordsd(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovapd(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } + Operator::F64Min => { + let src2 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src1 = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let ret = self.machine.acquire_locations( + a, + &[(WpType::F64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let tmp1 = self.machine.acquire_temp_xmm().unwrap(); + let tmp2 = self.machine.acquire_temp_xmm().unwrap(); + let tmpg1 = self.machine.acquire_temp_gpr().unwrap(); + let tmpg2 = self.machine.acquire_temp_gpr().unwrap(); + + let src1 = match src1 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src1, Location::XMM(tmp1)); + tmp1 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src1, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp1)); + tmp1 + } + _ => unreachable!(), + }; + let src2 = match src2 { + Location::XMM(x) => x, + Location::GPR(_) | Location::Memory(_, _) => { + a.emit_mov(Size::S64, src2, Location::XMM(tmp2)); + tmp2 + } + Location::Imm32(_) => { + a.emit_mov(Size::S32, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S32, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + Location::Imm64(_) => { + a.emit_mov(Size::S64, src2, Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp2)); + tmp2 + } + _ => unreachable!(), + }; + + let tmp_xmm1 = XMM::XMM8; + let tmp_xmm2 = XMM::XMM9; + let tmp_xmm3 = XMM::XMM10; + + static NEG_ZERO: u128 = 0x8000_0000_0000_0000; + static CANONICAL_NAN: u128 = 0x7FF8_0000_0000_0000; + a.emit_mov(Size::S64, Location::XMM(src1), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::XMM(src2), Location::GPR(tmpg2)); + a.emit_cmp(Size::S64, Location::GPR(tmpg2), Location::GPR(tmpg1)); + a.emit_vminsd(src1, XMMOrMemory::XMM(src2), tmp_xmm1); + let label1 = a.get_label(); + let label2 = a.get_label(); + a.emit_jmp(Condition::NotEqual, label1); + a.emit_vmovapd(XMMOrMemory::XMM(tmp_xmm1), XMMOrMemory::XMM(tmp_xmm2)); + a.emit_jmp(Condition::None, label2); + a.emit_label(label1); + // load float -0.0 + a.emit_mov( + Size::S64, + Location::Imm64((&NEG_ZERO as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov( + Size::S64, + Location::Memory(tmpg1, 0), + Location::XMM(tmp_xmm2), + ); + a.emit_label(label2); + a.emit_vcmpeqsd(src1, XMMOrMemory::XMM(src2), tmp_xmm3); + a.emit_vblendvpd(tmp_xmm3, XMMOrMemory::XMM(tmp_xmm2), tmp_xmm1, tmp_xmm1); + a.emit_vcmpunordsd(src1, XMMOrMemory::XMM(src2), src1); + // load float canonical nan + a.emit_mov( + Size::S64, + Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::GPR(tmpg1), + ); + a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); + match ret { + Location::XMM(x) => { + a.emit_vmovaps(XMMOrMemory::XMM(src1), XMMOrMemory::XMM(x)); + } + Location::Memory(_, _) | Location::GPR(_) => { + a.emit_mov(Size::S64, Location::XMM(src1), ret); + } + _ => unreachable!(), + } + + self.machine.release_temp_gpr(tmpg2); + self.machine.release_temp_gpr(tmpg1); + self.machine.release_temp_xmm(tmp2); + self.machine.release_temp_xmm(tmp1); + } Operator::F64Eq => Self::emit_fp_cmpop_avx( a, &mut self.machine, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index db8cedaaa..e175350c3 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -106,7 +106,9 @@ pub trait Emitter { fn emit_cmovae_gpr_64(&mut self, src: GPR, dst: GPR); fn emit_vmovaps(&mut self, src: XMMOrMemory, dst: XMMOrMemory); + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory); fn emit_vxorps(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); + fn emit_vxorpd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddss(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); fn emit_vaddsd(&mut self, src1: XMM, src2: XMMOrMemory, dst: XMM); @@ -174,6 +176,7 @@ pub trait Emitter { fn emit_vcvtsi2sd_64(&mut self, src1: XMM, src2: GPROrMemory, dst: XMM); fn emit_vblendvps(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM); + fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM); fn emit_test_gpr_64(&mut self, reg: GPR); @@ -1019,7 +1022,23 @@ impl Emitter for Assembler { }; } + fn emit_vmovapd(&mut self, src: XMMOrMemory, dst: XMMOrMemory) { + match (src, dst) { + (XMMOrMemory::XMM(src), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movapd Rx(dst as u8), Rx(src as u8)) + } + (XMMOrMemory::Memory(base, disp), XMMOrMemory::XMM(dst)) => { + dynasm!(self ; movapd Rx(dst as u8), [Rq(base as u8) + disp]) + } + (XMMOrMemory::XMM(src), XMMOrMemory::Memory(base, disp)) => { + dynasm!(self ; movapd [Rq(base as u8) + disp], Rx(src as u8)) + } + _ => panic!("singlepass can't emit VMOVAPD {:?} {:?}", src, dst), + }; + } + avx_fn!(vxorps, emit_vxorps); + avx_fn!(vxorpd, emit_vxorpd); avx_fn!(vaddss, emit_vaddss); avx_fn!(vaddsd, emit_vaddsd); @@ -1094,6 +1113,17 @@ impl Emitter for Assembler { } } + fn emit_vblendvpd(&mut self, src1: XMM, src2: XMMOrMemory, mask: XMM, dst: XMM) { + match src2 { + XMMOrMemory::XMM(src2) => { + dynasm!(self ; vblendvpd Rx(dst as u8), Rx(mask as u8), Rx(src2 as u8), Rx(src1 as u8)) + } + XMMOrMemory::Memory(base, disp) => { + dynasm!(self ; vblendvpd Rx(dst as u8), Rx(mask as u8), [Rq(base as u8) + disp], Rx(src1 as u8)) + } + } + } + fn emit_ucomiss(&mut self, src: XMMOrMemory, dst: XMM) { match src { XMMOrMemory::XMM(x) => dynasm!(self ; ucomiss Rx(dst as u8), Rx(x as u8)), diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 1a256583d..75a297bd0 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -465,216 +465,6 @@ singlepass:fail:conversions.wast:240 # AssertTrap - expected trap, got Runtime:E 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:elem.wast:353 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:f64.wast:1620 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") -singlepass:fail:f64.wast:1652 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1654 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1656 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1658 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1692 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1694 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1696 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1698 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1732 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1734 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1736 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1738 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1772 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1774 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1776 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1778 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1812 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1814 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1816 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1818 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1852 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1854 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1856 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1858 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1892 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1894 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1896 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1898 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1932 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1934 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1936 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1938 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:1939 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:1940 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:1941 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:1942 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:1943 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:1944 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:1945 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:1946 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:1947 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1948 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1949 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1950 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1951 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1952 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1953 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1954 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:1955 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1956 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1957 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1958 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1959 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1960 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1961 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1962 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:1963 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:1964 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:1965 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:1966 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:1967 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:1968 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:1969 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:1970 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:1971 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:1972 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:1973 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:1974 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:1975 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:1976 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:1977 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:1978 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:1979 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1980 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1981 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:1982 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:1983 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1984 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:1985 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:1986 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:1987 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1988 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1989 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1990 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1991 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1992 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1993 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1994 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:1995 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:1996 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:1997 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:1998 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:1999 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2000 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2001 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2002 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2005 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2006 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2009 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2010 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2013 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2014 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2017 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2018 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2021 # AssertReturn - result F64(9223372036854775808) ("0x8000000000000000") does not match expected F64(0) ("0x0") -singlepass:fail:f64.wast:2052 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2054 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2056 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2058 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2092 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2094 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2096 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2098 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2132 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2134 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2136 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2138 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2172 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2174 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2176 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2178 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2212 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2214 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2216 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2218 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2252 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2254 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2256 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2258 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2292 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2294 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2296 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2298 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2332 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2334 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2336 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2338 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2339 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:2340 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:2341 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:2342 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:2343 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.0) -singlepass:fail:f64.wast:2344 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.0) -singlepass:fail:f64.wast:2345 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.0) -singlepass:fail:f64.wast:2346 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.0) -singlepass:fail:f64.wast:2347 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2348 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2349 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2350 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2351 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2352 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2353 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2354 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005) -singlepass:fail:f64.wast:2355 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2356 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2357 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2358 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2359 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2360 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2361 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2362 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022250738585072014) -singlepass:fail:f64.wast:2363 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:2364 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:2365 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:2366 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:2367 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-0.5) -singlepass:fail:f64.wast:2368 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-0.5) -singlepass:fail:f64.wast:2369 # "AssertReturnCanonicalNan" - value is not canonical nan F64(0.5) -singlepass:fail:f64.wast:2370 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(0.5) -singlepass:fail:f64.wast:2371 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:2372 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:2373 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:2374 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:2375 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-1.0) -singlepass:fail:f64.wast:2376 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-1.0) -singlepass:fail:f64.wast:2377 # "AssertReturnCanonicalNan" - value is not canonical nan F64(1.0) -singlepass:fail:f64.wast:2378 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(1.0) -singlepass:fail:f64.wast:2379 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2380 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2381 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:2382 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:2383 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2384 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-6.283185307179586) -singlepass:fail:f64.wast:2385 # "AssertReturnCanonicalNan" - value is not canonical nan F64(6.283185307179586) -singlepass:fail:f64.wast:2386 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(6.283185307179586) -singlepass:fail:f64.wast:2387 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2388 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2389 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2390 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2391 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2392 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2393 # "AssertReturnCanonicalNan" - value is not canonical nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2394 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0) -singlepass:fail:f64.wast:2395 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2396 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2397 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2398 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2399 # "AssertReturnCanonicalNan" - value is not canonical nan F64(-inf) -singlepass:fail:f64.wast:2400 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(-inf) -singlepass:fail:f64.wast:2401 # "AssertReturnCanonicalNan" - value is not canonical nan F64(inf) -singlepass:fail:f64.wast:2402 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(inf) -singlepass:fail:f64.wast:2405 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2406 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2409 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2410 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2413 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2414 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2417 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) -singlepass:fail:f64.wast:2418 # "AssertReturnArithmeticNan" - value is not arithmetic nan F64(NaN) singlepass:fail:func_ptrs.wast:78 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:func_ptrs.wast:79 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:func_ptrs.wast:80 # AssertTrap - expected trap, got Runtime:Error unknown error From feeb9cd8f9f7aa06607ce44c0806bc0074cd0da6 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 14 Oct 2019 15:02:51 -0700 Subject: [PATCH 038/122] These tests failed on mac on bors. Put them back. --- lib/spectests/tests/excludes.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 75a297bd0..17f5ff4af 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -482,6 +482,15 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:i32.wast:242 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") +singlepass:fail:i32.wast:243 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") +singlepass:fail:i32.wast:244 # AssertReturn - result I32(15) ("0xf") does not match expected I32(16) ("0x10") +singlepass:fail:i32.wast:245 # AssertReturn - result I32(7) ("0x7") does not match expected I32(24) ("0x18") +singlepass:fail:i32.wast:246 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") +singlepass:fail:i32.wast:247 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") +singlepass:fail:i32.wast:248 # AssertReturn - result I32(1) ("0x1") does not match expected I32(30) ("0x1e") +singlepass:fail:i32.wast:249 # AssertReturn - result I32(30) ("0x1e") does not match expected I32(1) ("0x1") +singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -491,6 +500,15 @@ singlepass:fail:i64.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i64.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error +singlepass:fail:i64.wast:242 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") +singlepass:fail:i64.wast:243 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") +singlepass:fail:i64.wast:244 # AssertReturn - result I64(15) ("0xf") does not match expected I64(48) ("0x30") +singlepass:fail:i64.wast:245 # AssertReturn - result I64(7) ("0x7") does not match expected I64(56) ("0x38") +singlepass:fail:i64.wast:246 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") +singlepass:fail:i64.wast:247 # AssertReturn - result I64(0) ("0x0") does not match expected I64(63) ("0x3f") +singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not match expected I64(62) ("0x3e") +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:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error From 169665db8c3157d875a466c8332ed25896ebb78e Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 11:03:55 -0700 Subject: [PATCH 039/122] Add extended system information for Mac. Enough to see CPUID flags. --- azure-pipelines.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c0c350d54..637b10099 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -60,6 +60,10 @@ jobs: cat /proc/meminfo displayName: System info - Extended (Linux) condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) + - bash: | + sysctl -a | grep machdep.cpu + displayName: System info - Extended (Mac) + condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - bash: make test displayName: Tests (*nix) condition: and(succeeded(), not(eq(variables['Agent.OS'], 'Windows_NT'))) From 761a5e843cde4db9a8cd85b5b89f93b35bc0e8f6 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 11:08:10 -0700 Subject: [PATCH 040/122] Indentation for syntax. --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 637b10099..db05b2d34 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -61,7 +61,7 @@ jobs: displayName: System info - Extended (Linux) condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - bash: | - sysctl -a | grep machdep.cpu + sysctl -a | grep machdep.cpu displayName: System info - Extended (Mac) condition: and(succeeded(), eq(variables['Agent.OS'], 'Darwin')) - bash: make test From cf3d2a830d3de845972953c729bbdb30f08f4e70 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 12:50:33 -0700 Subject: [PATCH 041/122] Reimplement I32Clz without relying on LZCNT. --- lib/singlepass-backend/src/codegen_x64.rs | 57 ++++++++++++++++++++--- lib/singlepass-backend/src/emitter_x64.rs | 10 ++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 7e3a9ed5f..10659e4b5 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2341,12 +2341,57 @@ impl FunctionCodeGenerator for X64FunctionCode { Condition::Equal, Location::Imm32(0), ), - Operator::I32Clz => Self::emit_xcnt_i32( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_lzcnt, - ), + Operator::I32Clz => { + let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmp)); + tmp + }, + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => { self.machine.acquire_temp_gpr().unwrap() }, + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsr(Size::S32, Location::GPR(src), Location::GPR(dst)); + a.emit_xor(Size::S32, Location::Imm32(31), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S32, Location::Imm32(32), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + }, + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + }, + _ => {} + }; + }, Operator::I32Ctz => Self::emit_xcnt_i32( a, &mut self.machine, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 2e747f7ec..361efa9b1 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -90,6 +90,7 @@ pub trait Emitter { fn emit_ror(&mut self, sz: Size, src: Location, dst: Location); fn emit_and(&mut self, sz: Size, src: Location, dst: Location); fn emit_or(&mut self, sz: Size, src: Location, dst: Location); + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location); fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location); @@ -753,6 +754,15 @@ impl Emitter for Assembler { panic!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst) }); } + + fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) { + binop_gpr_gpr!(bsr, self, sz, src, dst, { + binop_mem_gpr!(bsr, self, sz, src, dst, { + panic!("singlepass can't emit BSR {:?} {:?} {:?}", sz, src, dst) + }) + }); + } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(lzcnt, self, sz, src, dst, { binop_mem_gpr!(lzcnt, self, sz, src, dst, { From cafcfd3b50609c8486d1970b4792a58def9df4c1 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 13:07:44 -0700 Subject: [PATCH 042/122] cargo fmt --- lib/singlepass-backend/src/codegen_x64.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 10659e4b5..b2e4bca95 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2342,13 +2342,14 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::Imm32(0), ), Operator::I32Clz => { - let loc = get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); let src = match loc { Location::Imm32(_) | Location::Memory(_, _) => { let tmp = self.machine.acquire_temp_gpr().unwrap(); a.emit_mov(Size::S32, loc, Location::GPR(tmp)); tmp - }, + } Location::GPR(reg) => reg, _ => unreachable!(), }; @@ -2361,11 +2362,11 @@ impl FunctionCodeGenerator for X64FunctionCode { self.value_stack.push(ret); let dst = match ret { - Location::Memory(_, _) => { self.machine.acquire_temp_gpr().unwrap() }, + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), Location::GPR(reg) => reg, _ => unreachable!(), }; - + let zero_path = a.get_label(); let end = a.get_label(); @@ -2381,17 +2382,17 @@ impl FunctionCodeGenerator for X64FunctionCode { match loc { Location::Imm32(_) | Location::Memory(_, _) => { self.machine.release_temp_gpr(src); - }, + } _ => {} }; match ret { Location::Memory(_, _) => { a.emit_mov(Size::S32, Location::GPR(dst), ret); self.machine.release_temp_gpr(dst); - }, + } _ => {} }; - }, + } Operator::I32Ctz => Self::emit_xcnt_i32( a, &mut self.machine, From 3e854c4a3b9f4c1c237745bf2f708c065db46f22 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 13:21:07 -0700 Subject: [PATCH 043/122] Remove the exclusions for I32Clz. --- lib/spectests/tests/excludes.txt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index dee265684..07fed914d 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -902,14 +902,6 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i32.wast:242 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:243 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") -singlepass:fail:i32.wast:244 # AssertReturn - result I32(15) ("0xf") does not match expected I32(16) ("0x10") -singlepass:fail:i32.wast:245 # AssertReturn - result I32(7) ("0x7") does not match expected I32(24) ("0x18") -singlepass:fail:i32.wast:246 # AssertReturn - result I32(31) ("0x1f") does not match expected I32(0) ("0x0") -singlepass:fail:i32.wast:247 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") -singlepass:fail:i32.wast:248 # AssertReturn - result I32(1) ("0x1") does not match expected I32(30) ("0x1e") -singlepass:fail:i32.wast:249 # AssertReturn - result I32(30) ("0x1e") does not match expected I32(1) ("0x1") singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error From 99f7499a0589aa3115db7244359d1b60e9a74bf0 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 13:42:05 -0700 Subject: [PATCH 044/122] Reimplement I32Ctz, I64Clz and I64Ctz without LZCNT or TZCNT. --- lib/singlepass-backend/src/codegen_x64.rs | 172 +++++++++++++++++++--- lib/singlepass-backend/src/emitter_x64.rs | 9 ++ lib/spectests/tests/excludes.txt | 10 -- 3 files changed, 163 insertions(+), 28 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b2e4bca95..c2543b987 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -2393,12 +2393,57 @@ impl FunctionCodeGenerator for X64FunctionCode { _ => {} }; } - Operator::I32Ctz => Self::emit_xcnt_i32( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_tzcnt, - ), + Operator::I32Ctz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S32, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I32, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsf(Size::S32, Location::GPR(src), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S32, Location::Imm32(32), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S32, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } Operator::I32Popcnt => Self::emit_xcnt_i32( a, &mut self.machine, @@ -2678,18 +2723,109 @@ impl FunctionCodeGenerator for X64FunctionCode { Condition::Equal, Location::Imm64(0), ), - Operator::I64Clz => Self::emit_xcnt_i64( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_lzcnt, - ), - Operator::I64Ctz => Self::emit_xcnt_i64( - a, - &mut self.machine, - &mut self.value_stack, - Assembler::emit_tzcnt, - ), + Operator::I64Clz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsr(Size::S64, Location::GPR(src), Location::GPR(dst)); + a.emit_xor(Size::S64, Location::Imm32(63), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S64, Location::Imm32(64), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } + Operator::I64Ctz => { + let loc = + get_location_released(a, &mut self.machine, self.value_stack.pop().unwrap()); + let src = match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + let tmp = self.machine.acquire_temp_gpr().unwrap(); + a.emit_mov(Size::S64, loc, Location::GPR(tmp)); + tmp + } + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let ret = self.machine.acquire_locations( + a, + &[(WpType::I64, MachineValue::WasmStack(self.value_stack.len()))], + false, + )[0]; + self.value_stack.push(ret); + + let dst = match ret { + Location::Memory(_, _) => self.machine.acquire_temp_gpr().unwrap(), + Location::GPR(reg) => reg, + _ => unreachable!(), + }; + + let zero_path = a.get_label(); + let end = a.get_label(); + + a.emit_test_gpr_64(src); + a.emit_jmp(Condition::Equal, zero_path); + a.emit_bsf(Size::S64, Location::GPR(src), Location::GPR(dst)); + a.emit_jmp(Condition::None, end); + a.emit_label(zero_path); + a.emit_mov(Size::S64, Location::Imm32(64), Location::GPR(dst)); + a.emit_label(end); + + match loc { + Location::Imm64(_) | Location::Imm32(_) | Location::Memory(_, _) => { + self.machine.release_temp_gpr(src); + } + _ => {} + }; + match ret { + Location::Memory(_, _) => { + a.emit_mov(Size::S64, Location::GPR(dst), ret); + self.machine.release_temp_gpr(dst); + } + _ => {} + }; + } Operator::I64Popcnt => Self::emit_xcnt_i64( a, &mut self.machine, diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 361efa9b1..30414b921 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -91,6 +91,7 @@ pub trait Emitter { fn emit_and(&mut self, sz: Size, src: Location, dst: Location); fn emit_or(&mut self, sz: Size, src: Location, dst: Location); fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location); + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location); fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location); @@ -763,6 +764,14 @@ impl Emitter for Assembler { }); } + fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { + binop_gpr_gpr!(bsf, self, sz, src, dst, { + binop_mem_gpr!(bsf, self, sz, src, dst, { + panic!("singlepass can't emit BSF {:?} {:?} {:?}", sz, src, dst) + }) + }); + } + fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(lzcnt, self, sz, src, dst, { binop_mem_gpr!(lzcnt, self, sz, src, dst, { diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 07fed914d..bb1cabcfd 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -902,7 +902,6 @@ singlepass:fail:i32.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i32.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i32.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i32.wast:252 # AssertReturn - result I32(0) ("0x0") does not match expected I32(32) ("0x20") singlepass:fail:i64.wast:62 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:63 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:64 # AssertTrap - expected trap, got Runtime:Error unknown error @@ -912,15 +911,6 @@ singlepass:fail:i64.wast:99 # AssertTrap - expected trap, got Runtime:Error unkn singlepass:fail:i64.wast:100 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:120 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:i64.wast:121 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:i64.wast:242 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:243 # AssertReturn - result I64(0) ("0x0") does not match expected I64(64) ("0x40") -singlepass:fail:i64.wast:244 # AssertReturn - result I64(15) ("0xf") does not match expected I64(48) ("0x30") -singlepass:fail:i64.wast:245 # AssertReturn - result I64(7) ("0x7") does not match expected I64(56) ("0x38") -singlepass:fail:i64.wast:246 # AssertReturn - result I64(63) ("0x3f") does not match expected I64(0) ("0x0") -singlepass:fail:i64.wast:247 # AssertReturn - result I64(0) ("0x0") does not match expected I64(63) ("0x3f") -singlepass:fail:i64.wast:248 # AssertReturn - result I64(1) ("0x1") does not match expected I64(62) ("0x3e") -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:283 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:imports.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error From 4e5d559ab57087ce393a4a705d421174d565f8ff Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 13:44:18 -0700 Subject: [PATCH 045/122] Remove dead functions LZCNT and TZCNT. --- lib/singlepass-backend/src/emitter_x64.rs | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 30414b921..a7543688a 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -92,8 +92,6 @@ pub trait Emitter { fn emit_or(&mut self, sz: Size, src: Location, dst: Location); fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location); fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location); - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location); - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location); fn emit_movzx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location); fn emit_movsx(&mut self, sz_src: Size, src: Location, sz_dst: Size, dst: Location); @@ -755,7 +753,6 @@ impl Emitter for Assembler { panic!("singlepass can't emit OR {:?} {:?} {:?}", sz, src, dst) }); } - fn emit_bsr(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(bsr, self, sz, src, dst, { binop_mem_gpr!(bsr, self, sz, src, dst, { @@ -763,7 +760,6 @@ impl Emitter for Assembler { }) }); } - fn emit_bsf(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(bsf, self, sz, src, dst, { binop_mem_gpr!(bsf, self, sz, src, dst, { @@ -771,21 +767,6 @@ impl Emitter for Assembler { }) }); } - - fn emit_lzcnt(&mut self, sz: Size, src: Location, dst: Location) { - binop_gpr_gpr!(lzcnt, self, sz, src, dst, { - binop_mem_gpr!(lzcnt, self, sz, src, dst, { - panic!("singlepass can't emit LZCNT {:?} {:?} {:?}", sz, src, dst) - }) - }); - } - fn emit_tzcnt(&mut self, sz: Size, src: Location, dst: Location) { - binop_gpr_gpr!(tzcnt, self, sz, src, dst, { - binop_mem_gpr!(tzcnt, self, sz, src, dst, { - panic!("singlepass can't emit TZCNT {:?} {:?} {:?}", sz, src, dst) - }) - }); - } fn emit_popcnt(&mut self, sz: Size, src: Location, dst: Location) { binop_gpr_gpr!(popcnt, self, sz, src, dst, { binop_mem_gpr!(popcnt, self, sz, src, dst, { From 5ee311adab9aef6565acff5150db19b33139b7c2 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 15 Oct 2019 14:10:26 -0700 Subject: [PATCH 046/122] These were both calling i32.clz. They should be fixed. --- lib/spectests/tests/excludes.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index bb1cabcfd..6cd94753b 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -959,7 +959,6 @@ singlepass:fail:linking.wast:236 # AssertTrap - expected trap, got Runtime:Error singlepass:fail:linking.wast:248 # AssertTrap - expected trap, got Runtime:Error unknown error 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_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 @@ -967,7 +966,6 @@ singlepass:fail:memory_grow.wast:18 # AssertTrap - expected trap, got Runtime:Er singlepass:fail:memory_grow.wast:24 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:25 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_grow.wast:286 # AssertTrap - expected trap, got Runtime:Error unknown error -singlepass:fail:memory_grow.wast:299 # AssertReturn - result I32(0) ("0x0") does not match expected I32(31) ("0x1f") singlepass:fail:memory_trap.wast:23 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_trap.wast:24 # AssertTrap - expected trap, got Runtime:Error unknown error singlepass:fail:memory_trap.wast:25 # AssertTrap - expected trap, got Runtime:Error unknown error From 81be25d9703450044cfd072ed77ed8868e905849 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 16 Oct 2019 16:07:50 +0200 Subject: [PATCH 047/122] feat(runtime-core) Add documentation and make macros more readable. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a long time, the macros are easy to read, but not at first glance. I hope this PR will improve the situation: Same syntax used everywhere, more spaces… --- lib/runtime-core/src/typed_func.rs | 153 ++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 27 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 0014e13cd..74318747c 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -91,17 +91,35 @@ impl Wasm { /// This type, as part of the `Func` type signature, represents a function that is created /// by the host. pub struct Host(()); + impl Kind for Wasm {} impl Kind for Host {} +/// Represents a list of WebAssembly values. pub trait WasmTypeList { type CStruct; + type RetArray: AsMut<[u64]>; + + /// Construct `Self` based on an array of returned values. fn from_ret_array(array: Self::RetArray) -> Self; + + /// Generates an empty array that will hold the returned values of + /// the WebAssembly function. fn empty_ret_array() -> Self::RetArray; + + /// Transforms C values into Rust values. fn from_c_struct(c_struct: Self::CStruct) -> Self; + + /// Transforms Rust values into C values. fn into_c_struct(self) -> Self::CStruct; + + /// Get types of the current values. fn types() -> &'static [Type]; + + /// This method is used to distribute the values onto a function, + /// e.g. `(1, 2).call(func, …)`. This form is unlikely to be used + /// directly in the code, see the `Func:call` implementation. unsafe fn call( self, f: NonNull, @@ -112,6 +130,8 @@ pub trait WasmTypeList { Rets: WasmTypeList; } +/// Represents a function that can be converted to a `vm::Func` +/// (function pointer) that can be called within WebAssembly. pub trait ExternalFunction where Args: WasmTypeList, @@ -149,15 +169,7 @@ where } } -// pub fn Func<'a, Args, Rets, F>(f: F) -> Func<'a, Args, Rets, Unsafe> -// where -// Args: WasmTypeList, -// Rets: WasmTypeList, -// F: ExternalFunction -// { -// Func::new(f) -// } - +/// Represents a function that can be used by WebAssembly. pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, f: NonNull, @@ -215,9 +227,12 @@ where Rets: WasmTypeList, Inner: Kind, { + /// Returns the types of the function inputs. pub fn params(&self) -> &'static [Type] { Args::types() } + + /// Returns the types of the function outputs. pub fn returns(&self) -> &'static [Type] { Rets::types() } @@ -226,62 +241,83 @@ where impl WasmTypeList for Infallible { type CStruct = Infallible; type RetArray = [u64; 0]; + fn from_ret_array(_: Self::RetArray) -> Self { unreachable!() } + fn empty_ret_array() -> Self::RetArray { unreachable!() } + fn from_c_struct(_: Self::CStruct) -> Self { unreachable!() } + fn into_c_struct(self) -> Self::CStruct { unreachable!() } + fn types() -> &'static [Type] { &[] } + #[allow(non_snake_case)] - unsafe fn call( + unsafe fn call( self, _: NonNull, _: Wasm, _: *mut Ctx, - ) -> Result { + ) -> Result + where + Rets: WasmTypeList, + { unreachable!() } } -impl WasmTypeList for (A,) { +impl WasmTypeList for (A,) +where + A: WasmExternType, +{ type CStruct = S1; type RetArray = [u64; 1]; + fn from_ret_array(array: Self::RetArray) -> Self { (WasmExternType::from_native(NativeWasmType::from_binary( array[0], )),) } + fn empty_ret_array() -> Self::RetArray { [0u64] } + fn from_c_struct(c_struct: Self::CStruct) -> Self { let S1(a) = c_struct; (WasmExternType::from_native(a),) } + fn into_c_struct(self) -> Self::CStruct { #[allow(unused_parens, non_snake_case)] let (a,) = self; S1(WasmExternType::to_native(a)) } + fn types() -> &'static [Type] { &[A::Native::TYPE] } + #[allow(non_snake_case)] - unsafe fn call( + unsafe fn call( self, f: NonNull, wasm: Wasm, ctx: *mut Ctx, - ) -> Result { + ) -> Result + where + Rets: WasmTypeList, + { let (a,) = self; let args = [a.to_native().to_binary()]; let mut rets = Rets::empty_ret_array(); @@ -323,34 +359,57 @@ where macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { #[repr($repr)] - pub struct $struct_name <$( $x: WasmExternType ),*> ( $( <$x as WasmExternType>::Native ),* ); + pub struct $struct_name< $( $x ),* > ( $( <$x as WasmExternType>::Native ),* ) + where + $( $x: WasmExternType ),*; - impl< $( $x: WasmExternType, )* > WasmTypeList for ( $( $x ),* ) { + impl< $( $x ),* > WasmTypeList for ( $( $x ),* ) + where + $( $x: WasmExternType ),* + { type CStruct = $struct_name<$( $x ),*>; + type RetArray = [u64; count_idents!( $( $x ),* )]; + fn from_ret_array(array: Self::RetArray) -> Self { #[allow(non_snake_case)] let [ $( $x ),* ] = array; + ( $( WasmExternType::from_native(NativeWasmType::from_binary($x)) ),* ) } + fn empty_ret_array() -> Self::RetArray { [0; count_idents!( $( $x ),* )] } + fn from_c_struct(c_struct: Self::CStruct) -> Self { #[allow(non_snake_case)] let $struct_name ( $( $x ),* ) = c_struct; + ( $( WasmExternType::from_native($x) ),* ) } + fn into_c_struct(self) -> Self::CStruct { #[allow(unused_parens, non_snake_case)] let ( $( $x ),* ) = self; + $struct_name ( $( WasmExternType::to_native($x) ),* ) } + fn types() -> &'static [Type] { - &[$( $x::Native::TYPE, )*] + &[$( $x::Native::TYPE ),*] } + #[allow(non_snake_case)] - unsafe fn call(self, f: NonNull, wasm: Wasm, ctx: *mut Ctx) -> Result { + unsafe fn call( + self, + f: NonNull, + wasm: Wasm, + ctx: *mut Ctx, + ) -> Result + where + Rets: WasmTypeList + { #[allow(unused_parens)] let ( $( $x ),* ) = self; let args = [ $( $x.to_native().to_binary()),* ]; @@ -358,7 +417,16 @@ macro_rules! impl_traits { let mut trap = WasmTrapInfo::Unknown; let mut user_error = None; - if (wasm.invoke)(wasm.trampoline, ctx, f, args.as_ptr(), rets.as_mut().as_mut_ptr(), &mut trap, &mut user_error, wasm.invoke_env) { + if (wasm.invoke)( + wasm.trampoline, + ctx, + f, + args.as_ptr(), + rets.as_mut().as_mut_ptr(), + &mut trap, + &mut user_error, + wasm.invoke_env + ) { Ok(Rets::from_ret_array(rets)) } else { if let Some(data) = user_error { @@ -370,18 +438,36 @@ macro_rules! impl_traits { } } - impl< $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap> ExternalFunction<($( $x ),*), Rets> for FN { + impl< $( $x, )* Rets, Trap, FN > ExternalFunction<( $( $x ),* ), Rets> for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn(&mut Ctx $( , $x )*) -> Trap, + { #[allow(non_snake_case)] fn to_raw(&self) -> NonNull { if mem::size_of::() == 0 { /// This is required for the llvm backend to be able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] - extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, FN: Fn( &mut Ctx $( ,$x )* ) -> Trap>( ctx: &mut Ctx $( ,$x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct { + extern fn wrap<$( $x, )* Rets, Trap, FN>( + ctx: &mut Ctx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn(&mut Ctx $( , $x )*) -> Trap, + { let f: FN = unsafe { mem::transmute_copy(&()) }; - let err = match panic::catch_unwind(panic::AssertUnwindSafe(|| { - f( ctx $( ,WasmExternType::from_native($x) )* ).report() - })) { + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + f(ctx $( , WasmExternType::from_native($x) )* ).report() + } + ) + ) { Ok(Ok(returns)) => return returns.into_c_struct(), Ok(Err(err)) => { let b: Box<_> = err.into(); @@ -397,7 +483,12 @@ macro_rules! impl_traits { NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap() } else { - assert_eq!(mem::size_of::(), mem::size_of::(), "you cannot use a closure that captures state for `Func`."); + assert_eq!( + mem::size_of::(), + mem::size_of::(), + "you cannot use a closure that captures state for `Func`." + ); + NonNull::new(unsafe { ::std::mem::transmute_copy::<_, *mut vm::Func>(self) }).unwrap() @@ -405,14 +496,22 @@ macro_rules! impl_traits { } } - impl<'a, $( $x: WasmExternType, )* Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> + impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> where + $( $x: WasmExternType, )* Rets: WasmTypeList, { #[allow(non_snake_case)] pub fn call(&self, $( $x: $x, )* ) -> Result { #[allow(unused_parens)] - unsafe { <( $( $x ),* ) as WasmTypeList>::call(( $($x),* ), self.f, self.inner, self.ctx) } + unsafe { + <( $( $x ),* ) as WasmTypeList>::call( + ( $( $x ),* ), + self.f, + self.inner, + self.ctx + ) + } } } }; From f99d0360d208f02a3ae109af69ff9e6659d166dc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 16 Oct 2019 10:34:37 -0700 Subject: [PATCH 048/122] Add registers XMM8--15 to `from_dwarf_regnum` and `invoke_call_return_on_stack`. --- lib/runtime-core/src/state.rs | 39 +++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1b11b1128..386fe21b5 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -672,6 +672,37 @@ pub mod x64 { stack_offset -= 1; stack[stack_offset] = stack.as_ptr().offset(last_stack_offset as isize) as usize as u64; // rbp + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM15).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM14).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM13).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM12).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM11).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM10).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM9).to_index().0].unwrap_or(0); + + stack_offset -= 1; + stack[stack_offset] = + known_registers[X64Register::XMM(XMM::XMM8).to_index().0].unwrap_or(0); stack_offset -= 1; stack[stack_offset] = known_registers[X64Register::XMM(XMM::XMM7).to_index().0].unwrap_or(0); @@ -1074,6 +1105,14 @@ pub mod x64 { 22 => X64Register::XMM(XMM::XMM5), 23 => X64Register::XMM(XMM::XMM6), 24 => X64Register::XMM(XMM::XMM7), + 25 => X64Register::XMM(XMM::XMM8), + 26 => X64Register::XMM(XMM::XMM9), + 27 => X64Register::XMM(XMM::XMM10), + 28 => X64Register::XMM(XMM::XMM11), + 29 => X64Register::XMM(XMM::XMM12), + 30 => X64Register::XMM(XMM::XMM13), + 31 => X64Register::XMM(XMM::XMM14), + 32 => X64Register::XMM(XMM::XMM15), _ => return None, }) } From 2c5c1b1c2c4e21e05e2066f9d62b8da73da56a52 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 17 Oct 2019 11:55:01 -0700 Subject: [PATCH 049/122] For floating point operations, allow inputs to be arbitrary, including SNaNs. Instead of ensuring outputs are arithmetic NaNs on every function, we tag them as pending such a check, so that a sequence of computation can have a single canonicalization step at the end. There's an extra wriggle for SIMD. The Wasm type system only indicates them as V128, so it's possible that we might do computations as F32x4Add, I8x16Add, F64x2Add in a row with no other computations in between. Thus, most SIMD functions apply pending canonicalizations to their inputs, even integer SIMD operations. --- lib/llvm-backend/src/code.rs | 1530 +++++++++++++++++---------------- lib/llvm-backend/src/state.rs | 86 +- 2 files changed, 866 insertions(+), 750 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 9ccb0c990..fc4ac7184 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -31,7 +31,7 @@ use crate::backend::LLVMBackend; use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::{blocktype_to_type, type_to_type}; use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}; -use crate::state::{ControlFrame, IfElseState, State}; +use crate::state::{ControlFrame, ExtraInfo, IfElseState, State}; use crate::trampolines::generate_trampolines; fn func_sig_to_llvm( @@ -376,6 +376,138 @@ fn trap_if_zero( builder.position_at_end(&shouldnt_trap_block); } +fn v128_into_int_vec( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, + int_vec_ty: VectorType, +) -> VectorValue { + let value = match info { + ExtraInfo::None => value, + ExtraInfo::PendingF32NaN => { + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } + ExtraInfo::PendingF64NaN => { + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } + }; + builder + .build_bitcast(value, int_vec_ty, "") + .into_vector_value() +} + +fn v128_into_i8x16( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i8x16_ty) +} + +fn v128_into_i16x8( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i16x8_ty) +} + +fn v128_into_i32x4( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i32x4_ty) +} + +fn v128_into_i64x2( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + v128_into_int_vec(builder, intrinsics, value, info, intrinsics.i64x2_ty) +} + +// If the value is pending a 64-bit canonicalization, do it now. +// Return a f32x4 vector. +fn v128_into_f32x4( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + let value = if info == ExtraInfo::PendingF64NaN { + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else { + value + }; + builder + .build_bitcast(value, intrinsics.f32x4_ty, "") + .into_vector_value() +} + +// If the value is pending a 32-bit canonicalization, do it now. +// Return a f64x2 vector. +fn v128_into_f64x2( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> VectorValue { + let value = if info == ExtraInfo::PendingF32NaN { + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + canonicalize_nans(builder, intrinsics, value) + } else { + value + }; + builder + .build_bitcast(value, intrinsics.f64x2_ty, "") + .into_vector_value() +} + +fn apply_pending_canonicalization( + builder: &Builder, + intrinsics: &Intrinsics, + value: BasicValueEnum, + info: ExtraInfo, +) -> BasicValueEnum { + match info { + ExtraInfo::None => value, + ExtraInfo::PendingF32NaN => { + if value.get_type().is_vector_type() + || value.get_type() == intrinsics.i128_ty.as_basic_type_enum() + { + let ty = value.get_type(); + let value = builder.build_bitcast(value, intrinsics.f32x4_ty, ""); + let value = canonicalize_nans(builder, intrinsics, value); + builder.build_bitcast(value, ty, "") + } else { + canonicalize_nans(builder, intrinsics, value) + } + } + ExtraInfo::PendingF64NaN => { + if value.get_type().is_vector_type() + || value.get_type() == intrinsics.i128_ty.as_basic_type_enum() + { + let ty = value.get_type(); + let value = builder.build_bitcast(value, intrinsics.f64x2_ty, ""); + let value = canonicalize_nans(builder, intrinsics, value); + builder.build_bitcast(value, ty, "") + } else { + canonicalize_nans(builder, intrinsics, value) + } + } + } +} + // Replaces any NaN with the canonical QNaN, otherwise leaves the value alone. fn canonicalize_nans( builder: &Builder, @@ -538,7 +670,7 @@ fn emit_stack_map( params.extend_from_slice(&locals); value_semantics.extend((0..locals.len()).map(ValueSemantic::WasmLocal)); - params.extend_from_slice(&state.stack); + params.extend(state.stack.iter().map(|x| x.0)); value_semantics.extend((0..state.stack.len()).map(ValueSemantic::WasmStack)); // FIXME: Information needed for Abstract -> Runtime state transform is not fully preserved @@ -963,13 +1095,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { frame.phis().len() }; - let values = state.peekn(value_len)?; + let values = state.peekn_extra(value_len)?; + let values = values.iter().map(|(v, info)| { + apply_pending_canonicalization(builder, intrinsics, *v, *info) + }); // For each result of the block we're branching to, // pop a value off the value stack and load it into // the corresponding phi. - for (phi, value) in frame.phis().iter().zip(values.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); + for (phi, value) in frame.phis().iter().zip(values) { + phi.add_incoming(&[(&value, ¤t_block)]); } builder.build_unconditional_branch(frame.br_dest()); @@ -992,10 +1127,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { frame.phis().len() }; - let param_stack = state.peekn(value_len)?; + let param_stack = state.peekn_extra(value_len)?; + let param_stack = param_stack.iter().map(|(v, info)| { + apply_pending_canonicalization(builder, intrinsics, *v, *info) + }); - for (phi, value) in frame.phis().iter().zip(param_stack.iter()) { - phi.add_incoming(&[(value, ¤t_block)]); + for (phi, value) in frame.phis().iter().zip(param_stack) { + phi.add_incoming(&[(&value, ¤t_block)]); } let else_block = context.append_basic_block(&function, "else"); @@ -1022,7 +1160,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let default_frame = state.frame_at_depth(default_depth)?; let args = if default_frame.is_loop() { - &[] + Vec::new() } else { let res_len = default_frame.phis().len(); state.peekn(res_len)? @@ -1101,16 +1239,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::Else => { if state.reachable { let frame = state.frame_at_depth(0)?; - builder.build_unconditional_branch(frame.code_after()); let current_block = builder.get_insert_block().ok_or(BinaryReaderError { message: "not currently in a block", offset: -1isize as usize, })?; for phi in frame.phis().to_vec().iter().rev() { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = + apply_pending_canonicalization(builder, intrinsics, value, info); phi.add_incoming(&[(&value, ¤t_block)]) } + let frame = state.frame_at_depth(0)?; + builder.build_unconditional_branch(frame.code_after()); } let (if_else_block, if_else_state) = if let ControlFrame::IfElse { @@ -1138,12 +1279,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { })?; if state.reachable { - builder.build_unconditional_branch(frame.code_after()); - for phi in frame.phis().iter().rev() { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = + apply_pending_canonicalization(builder, intrinsics, value, info); phi.add_incoming(&[(&value, ¤t_block)]); } + + builder.build_unconditional_branch(frame.code_after()); } if let ControlFrame::IfElse { @@ -1197,10 +1340,10 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_unconditional_branch(frame.br_dest()); - let phis = frame.phis().to_vec(); - - for phi in phis.iter() { - let arg = state.pop1()?; + let frame = state.outermost_frame()?; + for phi in frame.phis().to_vec().iter() { + let (arg, info) = state.pop1_extra()?; + let arg = apply_pending_canonicalization(builder, intrinsics, arg, info); phi.add_incoming(&[(&arg, ¤t_block)]); } @@ -1209,7 +1352,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::Unreachable => { // Emit an unreachable instruction. - // If llvm cannot prove that this is never touched, + // If llvm cannot prove that this is never reached, // it will emit a `ud2` instruction on x86_64 arches. // Comment out this `if` block to allow spectests to pass. @@ -1340,7 +1483,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1349,10 +1492,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + // The spec is unclear, we interpret splat as preserving NaN + // payload bits. + state.push1_extra(res, i); } Operator::F64x2Splat => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = splat_vector( builder, intrinsics, @@ -1361,7 +1506,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { &state.var_name(), ); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + // The spec is unclear, we interpret splat as preserving NaN + // payload bits. + state.push1_extra(res, i); } // Operate on locals. @@ -1372,12 +1519,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::SetLocal { local_index } => { let pointer_value = locals[local_index as usize]; - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); builder.build_store(pointer_value, v); } Operator::TeeLocal { local_index } => { let pointer_value = locals[local_index as usize]; - let v = state.peek1()?; + let (v, i) = state.peek1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); builder.build_store(pointer_value, v); } @@ -1395,7 +1544,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } } Operator::SetGlobal { global_index } => { - let value = state.pop1()?; + let (value, info) = state.pop1_extra()?; + let value = apply_pending_canonicalization(builder, intrinsics, value, info); let index = GlobalIndex::new(global_index as usize); let global_cache = ctx.global_cache(index, intrinsics); match global_cache { @@ -1432,21 +1582,28 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let params: Vec<_> = std::iter::once(ctx.basic()) .chain( state - .peekn(func_sig.params().len())? + .peekn_extra(func_sig.params().len())? .iter() .enumerate() - .map(|(i, &v)| match func_sig.params()[i] { + .map(|(i, (v, info))| match func_sig.params()[i] { Type::F32 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i32_ty, &state.var_name(), ), Type::F64 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i64_ty, &state.var_name(), ), - _ => v, + Type::V128 => apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), + _ => *v, }), ) .collect(); @@ -1463,21 +1620,28 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum()) .chain( state - .peekn(func_sig.params().len())? + .peekn_extra(func_sig.params().len())? .iter() .enumerate() - .map(|(i, &v)| match func_sig.params()[i] { + .map(|(i, (v, info))| match func_sig.params()[i] { Type::F32 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i32_ty, &state.var_name(), ), Type::F64 => builder.build_bitcast( - v, + apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), intrinsics.i64_ty, &state.var_name(), ), - _ => v, + Type::V128 => apply_pending_canonicalization( + builder, intrinsics, *v, *info, + ), + _ => *v, }), ) .collect(); @@ -1682,16 +1846,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let wasmer_fn_sig = &info.signatures[sig_index]; let fn_ty = signatures[sig_index]; - let pushed_args = state.popn_save(wasmer_fn_sig.params().len())?; + let pushed_args = state.popn_save_extra(wasmer_fn_sig.params().len())?; let args: Vec<_> = std::iter::once(ctx_ptr) - .chain(pushed_args.into_iter().enumerate().map(|(i, v)| { + .chain(pushed_args.into_iter().enumerate().map(|(i, (v, info))| { match wasmer_fn_sig.params()[i] { - Type::F32 => { - builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()) - } - Type::F64 => { - builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()) + Type::F32 => builder.build_bitcast( + apply_pending_canonicalization(builder, intrinsics, v, info), + intrinsics.i32_ty, + &state.var_name(), + ), + Type::F64 => builder.build_bitcast( + apply_pending_canonicalization(builder, intrinsics, v, info), + intrinsics.i64_ty, + &state.var_name(), + ), + Type::V128 => { + apply_pending_canonicalization(builder, intrinsics, v, info) } _ => v, } @@ -1766,59 +1937,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Add => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_i64x2(builder, intrinsics, v2, i2); let res = builder.build_int_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I8x16AddSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.sadd_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1828,10 +1981,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8AddSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.sadd_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1841,10 +1993,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16AddSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.uadd_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1854,10 +2005,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8AddSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.uadd_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1873,62 +2023,41 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Sub => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_i64x2(builder, intrinsics, v2, i2); let res = builder.build_int_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I8x16SubSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.ssub_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1938,10 +2067,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8SubSaturateS => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.ssub_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1951,10 +2079,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16SubSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i8x16_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i8x16_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.usub_sat_i8x16, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1964,10 +2091,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8SubSaturateU => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder.build_bitcast(v1, intrinsics.i16x8_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.i16x8_ty, ""); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1).as_basic_value_enum(); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2).as_basic_value_enum(); let res = builder .build_call(intrinsics.usub_sat_i16x8, &[v1, v2], &state.var_name()) .try_as_basic_value() @@ -1983,40 +2109,25 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Mul => { - let (v1, v2) = state.pop2()?; - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); @@ -2094,25 +2205,34 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32And | Operator::I64And | Operator::V128And => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_and(v1, v2, &state.var_name()); state.push1(res); } Operator::I32Or | Operator::I64Or | Operator::V128Or => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_or(v1, v2, &state.var_name()); state.push1(res); } Operator::I32Xor | Operator::I64Xor | Operator::V128Xor => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = builder.build_xor(v1, v2, &state.var_name()); state.push1(res); } Operator::V128Bitselect => { - let (v1, v2, cond) = state.pop3()?; + let ((v1, i1), (v2, i2), (cond, cond_info)) = state.pop3_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); + let cond = apply_pending_canonicalization(builder, intrinsics, cond, cond_info); let v1 = builder .build_bitcast(v1, intrinsics.i1x128_ty, "") .into_vector_value(); @@ -2134,10 +2254,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2153,10 +2271,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2172,10 +2288,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2190,10 +2304,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2Shl => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2216,10 +2328,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2235,10 +2345,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2254,10 +2362,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2272,10 +2378,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2297,10 +2401,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(7, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i8_ty, ""); @@ -2316,10 +2418,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(15, false), ""); let v2 = builder.build_int_truncate(v2, intrinsics.i16_ty, ""); @@ -2335,10 +2435,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(31, false), ""); let v2 = splat_vector( @@ -2353,10 +2451,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ShrU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_and(v2, intrinsics.i32_ty.const_int(63, false), ""); let v2 = builder.build_int_z_extend(v2, intrinsics.i64_ty, ""); @@ -2520,125 +2616,117 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { * Floating-Point Arithmetic instructions. * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions ***************************/ - Operator::F32Add | Operator::F64Add => { + Operator::F32Add => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_add(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Add => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_add(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Add => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_add(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Sub | Operator::F64Sub => { + Operator::F32Sub => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_sub(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Sub => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_sub(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Sub => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Sub => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_sub(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Mul | Operator::F64Mul => { + Operator::F32Mul => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_mul(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Mul => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_mul(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Mul => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Mul => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_mul(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } - Operator::F32Div | Operator::F64Div => { + Operator::F32Div => { let (v1, v2) = state.pop2()?; - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let res = builder.build_float_div(v1, v2, &state.var_name()); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); + } + Operator::F64Div => { + let (v1, v2) = state.pop2()?; + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let res = builder.build_float_div(v1, v2, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Div => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_div(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64x2Div => { - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); - let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_div(v1, v2, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Sqrt => { let input = state.pop1()?; @@ -2647,7 +2735,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Sqrt => { let input = state.pop1()?; @@ -2656,24 +2744,32 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32x4Sqrt => { - let input = state.pop1()?.into_int_value(); - let float = builder.build_bitcast(input, intrinsics.f32x4_ty, "float"); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f32x4(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.sqrt_f32x4, &[float], &state.var_name()) + .build_call( + intrinsics.sqrt_f32x4, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); let bits = builder.build_bitcast(res, intrinsics.i128_ty, "bits"); - state.push1(bits); + state.push1_extra(bits, ExtraInfo::PendingF32NaN); } Operator::F64x2Sqrt => { - let input = state.pop1()?.into_int_value(); - let float = builder.build_bitcast(input, intrinsics.f64x2_ty, "float"); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f64x2(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.sqrt_f64x2, &[float], &state.var_name()) + .build_call( + intrinsics.sqrt_f64x2, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); @@ -2685,8 +2781,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -2724,6 +2826,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .into_float_value(); let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64Min => { @@ -2731,8 +2835,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -2770,18 +2880,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .into_float_value(); let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32x4Min => { // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, v1, @@ -2825,18 +2946,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64x2Min => { // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, v1, @@ -2880,15 +3012,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32Max => { - // This implements the same logic as LLVM's @llvm.maximum + // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -2925,15 +3065,23 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .into_float_value(); let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64Max => { - // This implements the same logic as LLVM's @llvm.maximum + // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -2970,17 +3118,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .into_float_value(); let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32x4Max => { // This implements the same logic as LLVM's @llvm.maximum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -3025,17 +3183,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F64x2Max => { // This implements the same logic as LLVM's @llvm.maximum // intrinsic would, but x86 lowering of that intrinsics // encounters a fatal error in LLVM 8 and LLVM 9. - let (v1, v2) = state.pop2()?; - let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); - let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let v1 = canonicalize_nans(builder, intrinsics, v1); - let v2 = canonicalize_nans(builder, intrinsics, v2); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); + + // To detect min(-0.0, 0.0), we check whether the integer + // representations are equal. There's one other case where that + // can happen: non-canonical NaNs. Here we unconditionally + // canonicalize the NaNs. Note that this is a different + // canonicalization from that which may be performed in the + // v128_into_f32x4 function. That may canonicalize as F64x2 if + // previous computations may have emitted F64x2 NaNs. + let v1 = canonicalize_nans(builder, intrinsics, v1.as_basic_value_enum()); + let v2 = canonicalize_nans(builder, intrinsics, v2.as_basic_value_enum()); let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); let v1_is_nan = builder.build_float_compare( FloatPredicate::UNO, @@ -3080,6 +3248,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let res = builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // Because inputs were canonicalized, we always produce + // canonical NaN outputs. No pending NaN cleanup. state.push1(res); } Operator::F32Ceil => { @@ -3089,7 +3259,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Ceil => { let input = state.pop1()?; @@ -3098,7 +3268,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Floor => { let input = state.pop1()?; @@ -3107,7 +3277,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64Floor => { let input = state.pop1()?; @@ -3116,123 +3286,179 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32Trunc => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.trunc_f32, &[input], &state.var_name()) + .build_call( + intrinsics.trunc_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F64Trunc => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.trunc_f64, &[input], &state.var_name()) + .build_call( + intrinsics.trunc_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F32Nearest => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.nearbyint_f32, &[input], &state.var_name()) + .build_call( + intrinsics.nearbyint_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F64Nearest => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; let res = builder - .build_call(intrinsics.nearbyint_f64, &[input], &state.var_name()) + .build_call( + intrinsics.nearbyint_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); - state.push1(res); + state.push1_extra(res, i); } Operator::F32Abs => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f32, &[input], &state.var_name()) + .build_call( + intrinsics.fabs_f32, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F64Abs => { - let input = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f64, &[input], &state.var_name()) + .build_call( + intrinsics.fabs_f64, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F64Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F32x4Abs => { - let v = state.pop1()?.into_int_value(); - let v = builder.build_bitcast(v, intrinsics.f32x4_ty, ""); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f32x4_ty, ""); + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder - .build_call(intrinsics.fabs_f32x4, &[v], &state.var_name()) + .build_call( + intrinsics.fabs_f32x4, + &[v.as_basic_value_enum()], + &state.var_name(), + ) .try_as_basic_value() .left() .unwrap(); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F64x2Abs => { - let v = state.pop1()?.into_int_value(); - let v = builder.build_bitcast(v, intrinsics.f64x2_ty, ""); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f64x2_ty, ""); + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let res = builder .build_call(intrinsics.fabs_f64x2, &[v], &state.var_name()) .try_as_basic_value() .left() .unwrap(); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Abs is fully defined. Do not + // adjust. state.push1(res); } Operator::F32x4Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f32x4_ty, ""); + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_vector_value(); let res = builder.build_float_neg(v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F32x4Neg is fully defined. Do not + // adjust. state.push1(res); } Operator::F64x2Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = builder.build_bitcast(v.into_int_value(), intrinsics.f64x2_ty, ""); + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_vector_value(); let res = builder.build_float_neg(v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); + // The exact NaN returned by F64x2Neg is fully defined. Do not + // adjust. state.push1(res); } Operator::F32Neg | Operator::F64Neg => { - let input = state.pop1()?.into_float_value(); - let res = builder.build_float_neg(input, &state.var_name()); + let (v, i) = state.pop1_extra()?; + let v = + apply_pending_canonicalization(builder, intrinsics, v, i).into_float_value(); + let res = builder.build_float_neg(v, &state.var_name()); + // The exact NaN returned by F32Neg and F64Neg are fully defined. + // Do not adjust. state.push1(res); } Operator::F32Copysign => { - let (mag, sgn) = state.pop2()?; + let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; + let mag = apply_pending_canonicalization(builder, intrinsics, mag, mag_info); + let sgn = apply_pending_canonicalization(builder, intrinsics, sgn, sgn_info); let res = builder .build_call(intrinsics.copysign_f32, &[mag, sgn], &state.var_name()) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Copysign is fully defined. + // Do not adjust. state.push1(res); } Operator::F64Copysign => { - let (msg, sgn) = state.pop2()?; + let ((mag, mag_info), (sgn, sgn_info)) = state.pop2_extra()?; + let mag = apply_pending_canonicalization(builder, intrinsics, mag, mag_info); + let sgn = apply_pending_canonicalization(builder, intrinsics, sgn, sgn_info); let res = builder - .build_call(intrinsics.copysign_f64, &[msg, sgn], &state.var_name()) + .build_call(intrinsics.copysign_f64, &[mag, sgn], &state.var_name()) .try_as_basic_value() .left() .unwrap(); + // The exact NaN returned by F32Copysign is fully defined. + // Do not adjust. state.push1(res); } @@ -3248,39 +3474,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3294,39 +3508,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3340,39 +3542,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3386,39 +3576,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3432,39 +3610,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3478,39 +3644,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4LeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::ULE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3524,39 +3678,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GtS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3570,39 +3712,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GtU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3616,39 +3746,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GeS => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::SGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3662,39 +3780,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); + let v2 = v128_into_i8x16(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i8x16_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); + let v2 = v128_into_i16x8(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i16x8_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4GeU => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_i32x4(builder, intrinsics, v2, i2); let res = builder.build_int_compare(IntPredicate::UGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3714,26 +3820,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Eq => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3748,26 +3846,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::UNE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Ne => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::UNE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3782,26 +3872,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Lt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Lt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3816,26 +3898,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Le => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Le => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OLE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3850,26 +3924,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Gt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Gt => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -3884,26 +3950,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Ge => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = v128_into_f32x4(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i32x4_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2Ge => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = builder - .build_bitcast(v2, intrinsics.f64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = v128_into_f64x2(builder, intrinsics, v2, i2); let res = builder.build_float_compare(FloatPredicate::OGE, v1, v2, ""); let res = builder.build_int_s_extend(res, intrinsics.i64x2_ty, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); @@ -4123,16 +4181,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32DemoteF64 => { - let v1 = state.pop1()?; - let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value(); - let res = builder.build_float_trunc(v1, intrinsics.f32_ty, &state.var_name()); - state.push1(res); + let v = state.pop1()?; + let v = v.into_float_value(); + let res = builder.build_float_trunc(v, intrinsics.f32_ty, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF32NaN); } Operator::F64PromoteF32 => { - let v1 = state.pop1()?; - let v1 = canonicalize_nans(builder, intrinsics, v1).into_float_value(); - let res = builder.build_float_ext(v1, intrinsics.f64_ty, &state.var_name()); - state.push1(res); + let v = state.pop1()?; + let v = v.into_float_value(); + let res = builder.build_float_ext(v, intrinsics.f64_ty, &state.var_name()); + state.push1_extra(res, ExtraInfo::PendingF64NaN); } Operator::F32ConvertSI32 | Operator::F32ConvertSI64 => { let v1 = state.pop1()?.into_int_value(); @@ -4199,12 +4257,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32ReinterpretF32 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let ret = builder.build_bitcast(v, intrinsics.i32_ty, &state.var_name()); state.push1(ret); } Operator::I64ReinterpretF64 => { - let v = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let ret = builder.build_bitcast(v, intrinsics.i64_ty, &state.var_name()); state.push1(ret); } @@ -4375,7 +4435,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_store(effective_address, value); } Operator::F32Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4387,10 +4448,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.f32_ptr_ty, 4, )?; - builder.build_store(effective_address, value); + builder.build_store(effective_address, v); } Operator::F64Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4402,10 +4464,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.f64_ptr_ty, 8, )?; - builder.build_store(effective_address, value); + builder.build_store(effective_address, v); } Operator::V128Store { ref memarg } => { - let value = state.pop1()?; + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i); let effective_address = resolve_memory_ptr( builder, intrinsics, @@ -4417,7 +4480,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { intrinsics.i128_ptr_ty, 16, )?; - builder.build_store(effective_address, value); + builder.build_store(effective_address, v); } Operator::I32Load8S { ref memarg } => { @@ -4664,43 +4727,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.build_store(effective_address, narrow_value); } Operator::I8x16Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I16x8Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I32x4Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i32x4(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::I64x2Neg => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i64x2(builder, intrinsics, v, i); let res = builder.build_int_sub(v.get_type().const_zero(), v, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::V128Not => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let res = builder.build_not(v, &state.var_name()); state.push1(res); } @@ -4708,7 +4764,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { | Operator::I16x8AnyTrue | Operator::I32x4AnyTrue | Operator::I64x2AnyTrue => { - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let res = builder.build_int_compare( IntPredicate::NE, v, @@ -4729,7 +4786,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::I64x2AllTrue => intrinsics.i64x2_ty, _ => unreachable!(), }; - let v = state.pop1()?.into_int_value(); + let (v, i) = state.pop1_extra()?; + let v = apply_pending_canonicalization(builder, intrinsics, v, i).into_int_value(); let lane_int_ty = context.custom_width_int_type(vec_ty.get_size()); let vec = builder.build_bitcast(v, vec_ty, "vec").into_vector_value(); let mask = @@ -4747,10 +4805,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ExtractLaneS { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4759,10 +4815,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I8x16ExtractLaneU { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i8x16_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i8x16(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4771,10 +4825,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ExtractLaneS { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4783,10 +4835,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ExtractLaneU { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i16x8_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i16x8(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder .build_extract_element(v, idx, &state.var_name()) @@ -4795,46 +4845,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i32x4(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::I64x2ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.i64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_i64x2(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::F32x4ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f32x4_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f32x4(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::F64x2ExtractLane { lane } => { - let v = state.pop1()?.into_int_value(); - let v = builder - .build_bitcast(v, intrinsics.f64x2_ty, "") - .into_vector_value(); + let (v, i) = state.pop1_extra()?; + let v = v128_into_f64x2(builder, intrinsics, v, i); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_extract_element(v, idx, &state.var_name()); state.push1(res); } Operator::I8x16ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i8x16_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i8x16(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_int_cast(v2, intrinsics.i8_ty, ""); let idx = intrinsics.i32_ty.const_int(lane.into(), false); @@ -4843,10 +4883,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I16x8ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i16x8_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i16x8(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let v2 = builder.build_int_cast(v2, intrinsics.i16_ty, ""); let idx = intrinsics.i32_ty.const_int(lane.into(), false); @@ -4855,10 +4893,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I32x4ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i32x4_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i32x4(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); @@ -4866,10 +4902,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::I64x2ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.i64x2_ty, "") - .into_vector_value(); + let ((v1, i1), (v2, _)) = state.pop2_extra()?; + let v1 = v128_into_i64x2(builder, intrinsics, v1, i1); let v2 = v2.into_int_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); @@ -4877,32 +4911,32 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f32x4_ty, "") - .into_vector_value(); - let v2 = v2.into_float_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f32x4(builder, intrinsics, v1, i1); + let v2 = + apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F64x2ReplaceLane { lane } => { - let (v1, v2) = state.pop2()?; - let v1 = builder - .build_bitcast(v1, intrinsics.f64x2_ty, "") - .into_vector_value(); - let v2 = v2.into_float_value(); + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = v128_into_f64x2(builder, intrinsics, v1, i1); + let v2 = + apply_pending_canonicalization(builder, intrinsics, v2, i2).into_float_value(); let idx = intrinsics.i32_ty.const_int(lane.into(), false); let res = builder.build_insert_element(v1, v2, idx, &state.var_name()); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::V8x16Swizzle => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); let v1 = builder .build_bitcast(v1, intrinsics.i8x16_ty, "") .into_vector_value(); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = builder .build_bitcast(v2, intrinsics.i8x16_ty, "") .into_vector_value(); @@ -4960,10 +4994,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::V8x16Shuffle { lanes } => { - let (v1, v2) = state.pop2()?; + let ((v1, i1), (v2, i2)) = state.pop2_extra()?; + let v1 = apply_pending_canonicalization(builder, intrinsics, v1, i1); let v1 = builder .build_bitcast(v1, intrinsics.i8x16_ty, "") .into_vector_value(); + let v2 = apply_pending_canonicalization(builder, intrinsics, v2, i2); let v2 = builder .build_bitcast(v2, intrinsics.i8x16_ty, "") .into_vector_value(); @@ -7179,15 +7215,21 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } fn finalize(&mut self) -> Result<(), CodegenError> { - let results = self.state.popn_save(self.func_sig.returns().len())?; + let results = self.state.popn_save_extra(self.func_sig.returns().len())?; match results.as_slice() { [] => { self.builder.as_ref().unwrap().build_return(None); } - [one_value] => { + [(one_value, one_value_info)] => { let builder = self.builder.as_ref().unwrap(); let intrinsics = self.intrinsics.as_ref().unwrap(); + let one_value = apply_pending_canonicalization( + builder, + intrinsics, + *one_value, + *one_value_info, + ); builder.build_return(Some(&builder.build_bitcast( one_value.as_basic_value_enum(), type_to_llvm_int_only(intrinsics, self.func_sig.returns()[0]), diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index 20f915ebc..aa6f7bbc5 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -67,9 +67,29 @@ impl ControlFrame { } } +#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] +pub enum ExtraInfo { + None, + + // This values is required to be arithmetic 32-bit NaN (or 32x4) by the WAsm + // machine, but which might not be in the LLVM value. The conversion to + // arithmetic NaN is pending. It is required for correctness. + PendingF32NaN, + + // This values is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm + // machine, but which might not be in the LLVM value. The conversion to + // arithmetic NaN is pending. It is required for correctness. + PendingF64NaN, +} +impl Default for ExtraInfo { + fn default() -> Self { + ExtraInfo::None + } +} + #[derive(Debug)] pub struct State { - pub stack: Vec, + pub stack: Vec<(BasicValueEnum, ExtraInfo)>, control_stack: Vec, value_counter: Cell, @@ -145,10 +165,18 @@ impl State { } pub fn push1(&mut self, value: T) { - self.stack.push(value.as_basic_value_enum()) + self.push1_extra(value, ExtraInfo::None); + } + + pub fn push1_extra(&mut self, value: T, info: ExtraInfo) { + self.stack.push((value.as_basic_value_enum(), info)); } pub fn pop1(&mut self) -> Result { + Ok(self.pop1_extra()?.0) + } + + pub fn pop1_extra(&mut self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { self.stack.pop().ok_or(BinaryReaderError { message: "invalid value stack", offset: -1isize as usize, @@ -161,6 +189,14 @@ impl State { Ok((v1, v2)) } + pub fn pop2_extra( + &mut self, + ) -> Result<((BasicValueEnum, ExtraInfo), (BasicValueEnum, ExtraInfo)), BinaryReaderError> { + let v2 = self.pop1_extra()?; + let v1 = self.pop1_extra()?; + Ok((v1, v2)) + } + pub fn pop3( &mut self, ) -> Result<(BasicValueEnum, BasicValueEnum, BasicValueEnum), BinaryReaderError> { @@ -170,7 +206,29 @@ impl State { Ok((v1, v2, v3)) } + pub fn pop3_extra( + &mut self, + ) -> Result< + ( + (BasicValueEnum, ExtraInfo), + (BasicValueEnum, ExtraInfo), + (BasicValueEnum, ExtraInfo), + ), + BinaryReaderError, + > { + let v3 = self.pop1_extra()?; + let v2 = self.pop1_extra()?; + let v1 = self.pop1_extra()?; + Ok((v1, v2, v3)) + } + + /* pub fn peek1(&self) -> Result { + Ok(self.peek1_extra()?.0) + } + */ + + pub fn peek1_extra(&self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { self.stack .get(self.stack.len() - 1) .ok_or(BinaryReaderError { @@ -180,7 +238,14 @@ impl State { .map(|v| *v) } - pub fn peekn(&self, n: usize) -> Result<&[BasicValueEnum], BinaryReaderError> { + pub fn peekn(&self, n: usize) -> Result, BinaryReaderError> { + Ok(self.peekn_extra(n)?.iter().map(|x| x.0).collect()) + } + + pub fn peekn_extra( + &self, + n: usize, + ) -> Result<&[(BasicValueEnum, ExtraInfo)], BinaryReaderError> { self.stack .get(self.stack.len() - n..) .ok_or(BinaryReaderError { @@ -188,9 +253,18 @@ impl State { offset: -1isize as usize, }) } - - pub fn popn_save(&mut self, n: usize) -> Result, BinaryReaderError> { - let v = self.peekn(n)?.to_vec(); + /* + pub fn popn_save(&mut self, n: usize) -> Result, BinaryReaderError> { + let v = self.peekn(n)?.to_vec(); + self.popn(n)?; + Ok(v) + } + */ + pub fn popn_save_extra( + &mut self, + n: usize, + ) -> Result, BinaryReaderError> { + let v = self.peekn_extra(n)?.to_vec(); self.popn(n)?; Ok(v) } From c0acd5be11547be4aa128db16e1cdce943ab488b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 17 Oct 2019 12:20:34 -0700 Subject: [PATCH 050/122] Show the full hex value of a float that fails assert returns arithmetic nan or assert returns canonical nan. --- lib/spectests/tests/spectest.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 62bfc7d53..587d576f8 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -445,8 +445,9 @@ mod tests { "AssertReturnCanonicalNan" ), message: format!( - "value is not canonical nan {:?}", - v + "value is not canonical nan {:?} ({:?})", + v, + value_to_hex(v.clone()), ), }, &test_key, @@ -512,8 +513,9 @@ mod tests { "AssertReturnArithmeticNan" ), message: format!( - "value is not arithmetic nan {:?}", - v + "value is not arithmetic nan {:?} ({:?})", + v, + value_to_hex(v.clone()), ), }, &test_key, @@ -945,6 +947,16 @@ mod tests { } } + fn value_to_hex(val: wasmer_runtime_core::types::Value) -> String { + match val { + wasmer_runtime_core::types::Value::I32(x) => format!("{:#x}", x), + wasmer_runtime_core::types::Value::I64(x) => format!("{:#x}", x), + wasmer_runtime_core::types::Value::F32(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime_core::types::Value::F64(x) => format!("{:#x}", x.to_bits()), + wasmer_runtime_core::types::Value::V128(x) => format!("{:#x}", x), + } + } + #[derive(Debug, Clone, Eq, PartialEq)] pub enum SpectestValue { I32(i32), From f101775380cff87a6f0e59e01b62249d2af03bf4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 17 Oct 2019 22:55:30 +0200 Subject: [PATCH 051/122] fix(cranelift-backend) Remove broken (and useless?) debug code. This debug code is broken (it doesn't compile). It can be assumed nobody uses it, and can be considered as dead code. As such, this PR removes it. --- lib/clif-backend/src/code.rs | 160 ------------------------------- lib/clif-backend/src/resolver.rs | 48 ++-------- 2 files changed, 7 insertions(+), 201 deletions(-) diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index b2ccc6652..f1d8489da 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -128,166 +128,6 @@ impl ModuleCodeGenerator .state .initialize(&builder.func.signature, exit_block); - #[cfg(feature = "debug")] - { - use cranelift_codegen::cursor::{Cursor, FuncCursor}; - use cranelift_codegen::ir::InstBuilder; - let entry_ebb = func.layout.entry_block().unwrap(); - let ebb = func.dfg.make_ebb(); - func.layout.insert_ebb(ebb, entry_ebb); - let mut pos = FuncCursor::new(&mut func).at_first_insertion_point(ebb); - let params = pos.func.dfg.ebb_params(entry_ebb).to_vec(); - - let new_ebb_params: Vec<_> = params - .iter() - .map(|¶m| { - pos.func - .dfg - .append_ebb_param(ebb, pos.func.dfg.value_type(param)) - }) - .collect(); - - let start_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("strtdbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let end_debug = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ir::AbiParam::special( - ir::types::I64, - ir::ArgumentPurpose::VMContext, - )], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("enddbug"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let i64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::I64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("i64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f32_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F32), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f32print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let f64_print = { - let signature = pos.func.import_signature(ir::Signature { - call_conv: self.target_config().default_call_conv, - params: vec![ - ir::AbiParam::special(ir::types::I64, ir::ArgumentPurpose::VMContext), - ir::AbiParam::new(ir::types::F64), - ], - returns: vec![], - }); - - let name = ir::ExternalName::testcase("f64print"); - - pos.func.import_function(ir::ExtFuncData { - name, - signature, - colocated: false, - }) - }; - - let vmctx = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - let func_index = pos.ins().iconst( - ir::types::I32, - func_index.index() as i64 + self.module.info.imported_functions.len() as i64, - ); - - pos.ins().call(start_debug, &[vmctx, func_index]); - - for param in new_ebb_params.iter().cloned() { - match pos.func.dfg.value_type(param) { - ir::types::I32 => pos.ins().call(i32_print, &[vmctx, param]), - ir::types::I64 => pos.ins().call(i64_print, &[vmctx, param]), - ir::types::F32 => pos.ins().call(f32_print, &[vmctx, param]), - ir::types::F64 => pos.ins().call(f64_print, &[vmctx, param]), - _ => unimplemented!(), - }; - } - - pos.ins().call(end_debug, &[vmctx]); - - pos.ins().jump(entry_ebb, new_ebb_params.as_slice()); - } - self.functions.push(func_env); Ok(self.functions.last_mut().unwrap()) } diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 7a868f35e..efc038d58 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -1,32 +1,31 @@ -use crate::{cache::BackendCache, trampoline::Trampolines}; use crate::{ + cache::BackendCache, libcalls, relocation::{ ExternalRelocation, LibCall, LocalRelocation, LocalTrapSink, Reloc, RelocSink, RelocationType, TrapSink, VmCall, VmCallKind, }, signal::HandlerData, + trampoline::Trampolines, }; -use rayon::prelude::*; - use byteorder::{ByteOrder, LittleEndian}; use cranelift_codegen::{ binemit::{Stackmap, StackmapSink}, ir, isa, Context, }; +use rayon::prelude::*; use std::{ mem, ptr::{write_unaligned, NonNull}, sync::Arc, }; - -use wasmer_runtime_core::cache::Error as CacheError; use wasmer_runtime_core::{ self, backend::{ sys::{Memory, Protect}, SigRegistry, }, + cache::Error as CacheError, error::{CompileError, CompileResult}, module::ModuleInfo, structures::{Map, SliceMap, TypedIndex}, @@ -250,17 +249,9 @@ impl FuncResolverBuilder { #[cfg(not(target_os = "windows"))] LibCall::Probestack => __rust_probestack as isize, }, - RelocationType::Intrinsic(ref name) => match name.as_str() { - "i32print" => i32_print as isize, - "i64print" => i64_print as isize, - "f32print" => f32_print as isize, - "f64print" => f64_print as isize, - "strtdbug" => start_debug as isize, - "enddbug" => end_debug as isize, - _ => Err(CompileError::InternalError { - msg: format!("unexpected intrinsic: {}", name), - })?, - }, + RelocationType::Intrinsic(ref name) => Err(CompileError::InternalError { + msg: format!("unexpected intrinsic: {}", name), + })?, RelocationType::VmCall(vmcall) => match vmcall { VmCall::Local(kind) => match kind { VmCallKind::StaticMemoryGrow | VmCallKind::SharedStaticMemoryGrow => { @@ -371,28 +362,3 @@ impl FuncResolver { fn round_up(n: usize, multiple: usize) -> usize { (n + multiple - 1) & !(multiple - 1) } - -extern "C" fn i32_print(_ctx: &mut vm::Ctx, n: i32) { - eprint!(" i32: {},", n); -} -extern "C" fn i64_print(_ctx: &mut vm::Ctx, n: i64) { - eprint!(" i64: {},", n); -} -extern "C" fn f32_print(_ctx: &mut vm::Ctx, n: f32) { - eprint!(" f32: {},", n); -} -extern "C" fn f64_print(_ctx: &mut vm::Ctx, n: f64) { - eprint!(" f64: {},", n); -} -extern "C" fn start_debug(ctx: &mut vm::Ctx, func_index: u32) { - if let Some(symbol_map) = unsafe { ctx.borrow_symbol_map() } { - if let Some(fn_name) = symbol_map.get(&func_index) { - eprint!("func ({} ({})), args: [", fn_name, func_index); - return; - } - } - eprint!("func ({}), args: [", func_index); -} -extern "C" fn end_debug(_ctx: &mut vm::Ctx) { - eprintln!(" ]"); -} From a257995f8d913f2d5a1d34246232ada508476fba Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 17 Oct 2019 23:53:53 +0200 Subject: [PATCH 052/122] fix(win-exception-handler) Remove `bindgen` and `regex` from cargo build deps. Those crates are not used. --- Cargo.lock | 148 --------------------------- lib/win-exception-handler/Cargo.toml | 4 +- 2 files changed, 1 insertion(+), 151 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86c040659..a80f3850e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,28 +53,6 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bindgen" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cexpr 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bitflags" version = "1.1.0" @@ -167,29 +145,11 @@ name = "cc" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cexpr" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "clang-sys" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "clap" version = "2.33.0" @@ -428,18 +388,6 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "env_logger" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "erased-serde" version = "0.3.9" @@ -571,14 +519,6 @@ name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "humantime" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "indexmap" version = "1.2.0" @@ -668,15 +608,6 @@ name = "libc" version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libloading" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "llvm-sys" version = "80.1.1" @@ -761,15 +692,6 @@ name = "nodrop" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "nom" -version = "4.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.2.8" @@ -846,11 +768,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "plain" version = "0.2.3" @@ -891,11 +808,6 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.3.15" @@ -1066,14 +978,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-hash" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc_version" version = "0.2.3" @@ -1177,11 +1081,6 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "smallvec" version = "0.6.10" @@ -1295,14 +1194,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "termcolor" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -1411,11 +1302,6 @@ name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "void" version = "1.0.2" @@ -1730,10 +1616,8 @@ dependencies = [ name = "wasmer-win-exception-handler" version = "0.8.0" dependencies = [ - "bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1743,14 +1627,6 @@ name = "wasmparser" version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "which" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1788,15 +1664,6 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wincolor" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" @@ -1805,7 +1672,6 @@ dependencies = [ "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bindgen 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ebd71393f1ec0509b553aa012b9b58e81dadbdff7130bd3b8cba576e69b32f75" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" @@ -1817,9 +1683,7 @@ dependencies = [ "checksum cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "926013f2860c46252efceabb19f4a6b308197505082c609025aa6706c011d427" "checksum cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" "checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" -"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 clang-sys 0.28.1 (registry+https://github.com/rust-lang/crates.io-index)" = "81de550971c976f176130da4b2978d3b524eaa0fd9ac31f3ceb5ae1231fb4853" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" @@ -1844,7 +1708,6 @@ dependencies = [ "checksum dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c408a211e7f5762829f5e46bdff0c14bc3b1517a21a4bb781c716bf88b0c68" "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" "checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" @@ -1862,7 +1725,6 @@ dependencies = [ "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" "checksum inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" @@ -1873,7 +1735,6 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" -"checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2110cd4daf9cd8e39dd3b933b1a2a2ac7315e91f7c92b3a20beab526c63b5978" "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -1884,20 +1745,17 @@ dependencies = [ "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" -"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f89ef58b3d32420dbd1a43d2f38ae92f6239ef12bb556ab09ca55445f5a67242" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" -"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" @@ -1918,7 +1776,6 @@ dependencies = [ "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" @@ -1932,7 +1789,6 @@ dependencies = [ "checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" "checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" "checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" @@ -1946,7 +1802,6 @@ dependencies = [ "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" @@ -1962,7 +1817,6 @@ dependencies = [ "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3c5c5c1286c6e578416982609f47594265f9d489f9b836157d403ad605a46693" "checksum wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af5d153dc96aad7dc13ab90835b892c69867948112d95299e522d370c4e13a08" @@ -1971,11 +1825,9 @@ dependencies = [ "checksum wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0cf2f552a9c1fda0555087170424bd8fedc63a079a97bb5638a4ef9b0d9656aa" "checksum wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0073b512e1af5948d34be7944b74c747bbe735ccff2e2f28c26ed4c90725de8e" "checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" -"checksum which 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "240a31163872f7e8e49f35b42b58485e35355b07eb009d9f3686733541339a69" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 12e5f6c0b..72426f2f4 100644 --- a/lib/win-exception-handler/Cargo.toml +++ b/lib/win-exception-handler/Cargo.toml @@ -13,6 +13,4 @@ winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwinde libc = "0.2.60" [build-dependencies] -cmake = "0.1" -bindgen = "0.51" -regex = "1.2" +cmake = "0.1" \ No newline at end of file From b180a2e14cb2cbf41a98f1d4af2de539fbfc2250 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 17 Oct 2019 15:37:35 -0700 Subject: [PATCH 053/122] Get aggressive about running cargo check over all packages with all features. Fixes the one issue uncovered. The capstone disassembling support in the LLVM backend was broken. Fixed by removing it. Instead, use the `--llvm-object-file` flag to get a finished object file to disassemble with any disassembler. --- Cargo.lock | 19 ------------------- Makefile | 32 +++++++++++++++++++++++++++++++- lib/llvm-backend/Cargo.toml | 2 -- lib/llvm-backend/src/backend.rs | 30 ------------------------------ 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86c040659..ed199b670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,22 +115,6 @@ dependencies = [ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "capstone" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "capstone-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo_toml" version = "0.6.4" @@ -1579,7 +1563,6 @@ name = "wasmer-llvm-backend" version = "0.8.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.45 (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)", @@ -1811,8 +1794,6 @@ dependencies = [ "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum capstone 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "031ba51c39151a1d6336ec859646153187204b0147c7b3f6fe2de636f1b8dbb3" -"checksum capstone-sys 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fae25eddcb80e24f98c35952c37a91ff7f8d0f60dbbdafb9763e8d5cc566b8d7" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" diff --git a/Makefile b/Makefile index 58b85dbb1..6ca9bd3a1 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,37 @@ check-bench-llvm: check-bench: check-bench-singlepass check-bench-llvm check: check-bench - cargo check --release --features backend-singlepass,backend-llvm,loader-kernel,debug + # TODO: We wanted `--workspace --exclude wasmer-runtime`, but for + # https://github.com/rust-lang/cargo/issues/6745 . + cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests + cargo check --release -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests + cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests --all-features + cargo check --release -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests --all-features + # wasmer-runtime doesn't work with all backends enabled at once. + # + # We test using manifest-path directly so as to disable the default. + # `--no-default-features` only disables the default features in the + # current package, not the package specified by `-p`. This is + # intentional. + # + # Test default features, test 'debug' feature only in non-release + # builds, test as many combined features as possible with each backend + # as default, and test a minimal set of features with only one backend + # at a time. + cargo check --manifest-path lib/runtime/Cargo.toml + cargo check --release --manifest-path lib/runtime/Cargo.toml + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-singlepass + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-singlepass + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-cranelift + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-cranelift + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-llvm + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-llvm + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=singlepass,default-backend-singlepass,debug + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=singlepass,default-backend-singlepass + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,default-backend-cranelift,debug + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,default-backend-cranelift + cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=llvm,default-backend-llvm,debug + cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=llvm,default-backend-llvm # Release release: diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 1cc15ec89..55bd7f399 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -11,7 +11,6 @@ wasmparser = "0.39.1" smallvec = "0.6" goblin = "0.0.24" libc = "0.2.60" -capstone = { version = "0.6", optional = true } byteorder = "1" [dependencies.inkwell] @@ -38,4 +37,3 @@ wabt = "0.9.1" [features] debug = ["wasmer-runtime-core/debug"] -disasm = ["capstone"] diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 682bd7278..0af4d2c4b 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -477,33 +477,3 @@ impl CacheGen for LLVMCache { Ok(([].as_ref().into(), memory)) } } - -#[cfg(feature = "disasm")] -unsafe fn disass_ptr(ptr: *const u8, size: usize, inst_count: usize) { - use capstone::arch::BuildsCapstone; - let mut cs = capstone::Capstone::new() // Call builder-pattern - .x86() // X86 architecture - .mode(capstone::arch::x86::ArchMode::Mode64) // 64-bit mode - .detail(true) // Generate extra instruction details - .build() - .expect("Failed to create Capstone object"); - - // Get disassembled instructions - let insns = cs - .disasm_count( - std::slice::from_raw_parts(ptr, size), - ptr as u64, - inst_count, - ) - .expect("Failed to disassemble"); - - println!("count = {}", insns.len()); - for insn in insns.iter() { - println!( - "0x{:x}: {:6} {}", - insn.address(), - insn.mnemonic().unwrap_or(""), - insn.op_str().unwrap_or("") - ); - } -} From 87d272e31e3cb33b0f9e0f757fbcc8ba960f8fbe Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 12:37:31 -0700 Subject: [PATCH 054/122] Initial implementation of AssertUninstantiable. Fixes linking.wast:387. --- lib/spectests/tests/excludes.txt | 3 --- lib/spectests/tests/spectest.rs | 42 +++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 6cd94753b..3da022b01 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -32,7 +32,6 @@ clif:fail:linking.wast:147 # AssertTrap - expected trap, got Runtime:Error "unkn clif:fail:linking.wast:149 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883037 - illegal instruction" clif:fail:linking.wast:185 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" clif:fail:linking.wast:187 # AssertTrap - expected trap, got Runtime:Error "unknown trap at 0x106883062 - illegal instruction" -clif:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") clif:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: `call_indirect` out-of-bounds # clif:skip:skip-stack-guard-page.wast:2 # Slow test @@ -269,7 +268,6 @@ llvm:fail:f32.wast:1621 # AssertReturn - result F32(0) ("0x0") does not match ex llvm:fail:f32.wast:2020 # AssertReturn - result F32(2147483648) ("0x80000000") does not match expected F32(0) ("0x0") llvm:fail:f64.wast:1621 # AssertReturn - result F64(0) ("0x0") does not match expected F64(9223372036854775808) ("0x8000000000000000") llvm:fail:f64.wast:2020 # AssertReturn - result F64(9223372036854775808) ("0x8000000000000000") does not match expected F64(0) ("0x0") -llvm:fail:linking.wast:387 # AssertReturn - result I32(0) ("0x0") does not match expected I32(104) ("0x68") llvm:fail:linking.wast:388 # AssertReturn - Call failed RuntimeError: WebAssembly trap occurred during runtime: incorrect `call_indirect` signature # LLVM Windows @@ -957,7 +955,6 @@ singlepass:fail:linking.wast:190 # AssertTrap - expected trap, got Runtime:Error 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: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: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 diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 587d576f8..19114ff67 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -720,10 +720,44 @@ mod tests { } } } - CommandKind::AssertUninstantiable { - module: _, - message: _, - } => println!("AssertUninstantiable not yet implmented "), + CommandKind::AssertUninstantiable { module, message: _ } => { + let spectest_import_object = get_spectest_import_object(®istered_modules); + let config = CompilerConfig { + features: Features { + simd: true, + threads: true, + }, + ..Default::default() + }; + let module = wasmer_runtime_core::compile_with_config( + &module.into_vec(), + &get_compiler(), + config, + ) + .expect("WASM can't be compiled"); + let result = panic::catch_unwind(AssertUnwindSafe(|| { + module + .instantiate(&spectest_import_object) + .expect("WASM can't be instantiated"); + })); + match result { + Err(_) => test_report.count_passed(), + Ok(_) => { + test_report.add_failure( + SpecFailure { + file: filename.to_string(), + line: line, + kind: format!("{}", "AssertUninstantiable"), + message: format!( + "instantiate successful, expected uninstantiable" + ), + }, + &test_key, + excludes, + ); + } + }; + } CommandKind::AssertExhaustion { action, message: _ } => { match action { Action::Invoke { From 675399909af7a1f2f73f330f659db1e53217ae5d Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 17 Oct 2019 18:38:11 -0700 Subject: [PATCH 055/122] Skip this test on windows + cranelift. It crashes the whole spectest runner. This exclusion is no worse than before where this test was silently ignored. --- lib/spectests/tests/excludes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 3da022b01..5432534f9 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -82,6 +82,7 @@ clif:fail:data.wast:227:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:258:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:273:windows # AssertUnlinkable - caught panic Any clif:fail:start.wast:92:windows # Module - caught panic Any +clif:fail:start.wast:98:windows clif:fail:align.wast:3:windows # Module - caught panic Any clif:fail:align.wast:4:windows # Module - caught panic Any From fbe2701a937d4cc932dcc8bfe32095fc863b12ea Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 17 Oct 2019 19:23:36 -0700 Subject: [PATCH 056/122] I meant 'skip' not 'fail'. --- lib/spectests/tests/excludes.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 5432534f9..a54b3df49 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -82,7 +82,7 @@ clif:fail:data.wast:227:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:258:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:273:windows # AssertUnlinkable - caught panic Any clif:fail:start.wast:92:windows # Module - caught panic Any -clif:fail:start.wast:98:windows +clif:skip:start.wast:98:windows clif:fail:align.wast:3:windows # Module - caught panic Any clif:fail:align.wast:4:windows # Module - caught panic Any From e559b54309dee9aafe454571c2c3dfe3bee1701c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Fri, 18 Oct 2019 11:09:58 +0200 Subject: [PATCH 057/122] fix(singlepass-backend) Use wasmparser from `runtime-core`. The `wasmer-runtime-core` crate re-exports the `wasmparser` crate. This patch updates the `singlepass-backend` crate to use `wasmparser` through the `wasmer-runtime-core` crate, which removes a direct dependency for this crate. --- Cargo.lock | 1 - lib/singlepass-backend/Cargo.toml | 1 - lib/singlepass-backend/src/codegen_x64.rs | 8 +++----- lib/singlepass-backend/src/machine.rs | 7 ++++--- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86c040659..da1d25c49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1680,7 +1680,6 @@ dependencies = [ "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 5243cc601..2e9abacc3 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -10,7 +10,6 @@ readme = "README.md" [dependencies] wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmparser = "0.39.1" dynasm = "0.3.2" dynasmrt = "0.3.1" lazy_static = "1.4" diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index c2543b987..3d0dd2fab 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -1,15 +1,13 @@ #![allow(clippy::forget_copy)] // Used by dynasm. #![warn(unused_imports)] -use crate::emitter_x64::*; -use crate::machine::*; -use crate::protect_unix; +use crate::{emitter_x64::*, machine::*, protect_unix}; use dynasmrt::{x64::Assembler, AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi}; use smallvec::SmallVec; -use std::ptr::NonNull; use std::{ any::Any, collections::{BTreeMap, HashMap}, + ptr::NonNull, sync::{Arc, RwLock}, }; use wasmer_runtime_core::{ @@ -33,8 +31,8 @@ use wasmer_runtime_core::{ TableIndex, Type, }, vm::{self, LocalGlobal, LocalTable, INTERNALS_SIZE}, + wasmparser::{MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}, }; -use wasmparser::{MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as WpTypeOrFuncType}; lazy_static! { /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. diff --git a/lib/singlepass-backend/src/machine.rs b/lib/singlepass-backend/src/machine.rs index 727b577d7..017ba1270 100644 --- a/lib/singlepass-backend/src/machine.rs +++ b/lib/singlepass-backend/src/machine.rs @@ -1,9 +1,10 @@ use crate::emitter_x64::*; use smallvec::SmallVec; use std::collections::HashSet; -use wasmer_runtime_core::state::x64::X64Register; -use wasmer_runtime_core::state::*; -use wasmparser::Type as WpType; +use wasmer_runtime_core::{ + state::{x64::X64Register, *}, + wasmparser::Type as WpType, +}; struct MachineStackOffset(usize); From dde31076a888340c5ab72816b65568406f07a6b8 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 18 Oct 2019 13:00:40 -0700 Subject: [PATCH 058/122] Grammer in comment. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6ca9bd3a1..8c5fdb80c 100644 --- a/Makefile +++ b/Makefile @@ -153,8 +153,8 @@ check-bench-llvm: check-bench: check-bench-singlepass check-bench-llvm check: check-bench - # TODO: We wanted `--workspace --exclude wasmer-runtime`, but for - # https://github.com/rust-lang/cargo/issues/6745 . + # TODO: We wanted `--workspace --exclude wasmer-runtime`, but can't due + # to https://github.com/rust-lang/cargo/issues/6745 . cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests cargo check --release -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests --all-features From 8424b61444bc634386a36b90fdaefd93c8c3617c Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 2 Aug 2019 14:03:19 -0700 Subject: [PATCH 059/122] Fix typo in comment. --- lib/runtime-core/src/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core/src/module.rs b/lib/runtime-core/src/module.rs index 6cc02343f..1bf914a46 100644 --- a/lib/runtime-core/src/module.rs +++ b/lib/runtime-core/src/module.rs @@ -29,7 +29,7 @@ pub struct ModuleInner { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ModuleInfo { - // This are strictly local and the typsystem ensures that. + // This are strictly local and the typesystem ensures that. pub memories: Map, pub globals: Map, pub tables: Map, From 961684a8e0b2959f0aa0bf2f64e89454005bc40e Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 21 Aug 2019 15:48:13 -0700 Subject: [PATCH 060/122] Adjust comment rulers. --- lib/runtime-core/src/vmcalls.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/runtime-core/src/vmcalls.rs b/lib/runtime-core/src/vmcalls.rs index 5205a0d69..33d473aa0 100644 --- a/lib/runtime-core/src/vmcalls.rs +++ b/lib/runtime-core/src/vmcalls.rs @@ -10,7 +10,7 @@ use crate::{ // +*****************************+ // | LOCAL MEMORIES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn local_static_memory_grow( ctx: &mut vm::Ctx, @@ -72,7 +72,7 @@ pub unsafe extern "C" fn local_dynamic_memory_size( // +*****************************+ // | IMPORTED MEMORIES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn imported_static_memory_grow( ctx: &mut vm::Ctx, @@ -140,7 +140,7 @@ pub unsafe extern "C" fn imported_dynamic_memory_size( // +*****************************+ // | LOCAL TABLES | -// +****************************+ +// +*****************************+ pub unsafe extern "C" fn local_table_grow( ctx: &mut vm::Ctx, From 10dddf99048873405c8934ab7d71a4cbe5f0d47b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 18 Oct 2019 16:34:45 -0700 Subject: [PATCH 061/122] Fix repeated typo in comment. --- lib/llvm-backend/src/code.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 9ccb0c990..7ce0459b9 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2682,7 +2682,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32Min => { // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); @@ -2728,7 +2728,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64Min => { // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); @@ -2774,7 +2774,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Min => { // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); @@ -2829,7 +2829,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Min => { // This implements the same logic as LLVM's @llvm.minimum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); @@ -2884,7 +2884,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32Max => { // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); @@ -2929,7 +2929,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64Max => { // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); @@ -2974,7 +2974,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32x4Max => { // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); @@ -3029,7 +3029,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F64x2Max => { // This implements the same logic as LLVM's @llvm.maximum - // intrinsic would, but x86 lowering of that intrinsics + // intrinsic would, but x86 lowering of that intrinsic // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); From 813f6414e02aac80c13276b00025739c3cb9f503 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 21 Oct 2019 11:16:51 -0700 Subject: [PATCH 062/122] Remove dead functions, don't leave them commented out. --- lib/llvm-backend/src/state.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs index aa6f7bbc5..0d46dc5c0 100644 --- a/lib/llvm-backend/src/state.rs +++ b/lib/llvm-backend/src/state.rs @@ -222,12 +222,6 @@ impl State { Ok((v1, v2, v3)) } - /* - pub fn peek1(&self) -> Result { - Ok(self.peek1_extra()?.0) - } - */ - pub fn peek1_extra(&self) -> Result<(BasicValueEnum, ExtraInfo), BinaryReaderError> { self.stack .get(self.stack.len() - 1) @@ -253,13 +247,7 @@ impl State { offset: -1isize as usize, }) } - /* - pub fn popn_save(&mut self, n: usize) -> Result, BinaryReaderError> { - let v = self.peekn(n)?.to_vec(); - self.popn(n)?; - Ok(v) - } - */ + pub fn popn_save_extra( &mut self, n: usize, From 33a2b361b046af6ae79a233d9d296f0994dac5c3 Mon Sep 17 00:00:00 2001 From: Syrus Date: Mon, 21 Oct 2019 12:09:10 -0700 Subject: [PATCH 063/122] Added JavaScript to the list of supported implementations --- README.md | 1 + docs/assets/languages/js.svg | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100755 docs/assets/languages/js.svg diff --git a/README.md b/README.md index e69fe2d1c..7e7f39cb1 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ Wasmer runtime can be used as a library embedded in different languages, so you | ![PHP logo](./docs/assets/languages/php.svg) | [**PHP**](https://github.com/wasmerio/php-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/php-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/php-ext-wasm?style=flat-square) | | ![Ruby logo](./docs/assets/languages/ruby.svg) | [**Ruby**](https://github.com/wasmerio/ruby-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/gem/v/wasmer?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/ruby-ext-wasm?style=flat-square) | | ![Postgres logo](./docs/assets/languages/postgres.svg) | [**Postgres**](https://github.com/wasmerio/postgres-ext-wasm) | Wasmer | actively developed | ![last release](https://img.shields.io/github/v/release/wasmerio/postgres-ext-wasm?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/postgres-ext-wasm?style=flat-square) | +| ![JS Logo](./docs/assets/languages/js.svg) | [**JavaScript**](https://github.com/wasmerio/wasmer-js) | Wasmer | actively developed | ![last release](https://img.shields.io/npm/v/@wasmer/wasi?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/wasmerio/wasmer-js?style=flat-square) | | ![C# logo](./docs/assets/languages/csharp.svg) | [**C#/.Net**](https://github.com/migueldeicaza/WasmerSharp) | [Miguel de Icaza](https://github.com/migueldeicaza) | actively developed | ![last release](https://img.shields.io/nuget/v/WasmerSharp?style=flat-square) | ![number of Github stars](https://img.shields.io/github/stars/migueldeicaza/WasmerSharp?style=flat-square) | | ![R logo](./docs/assets/languages/r.svg) | [**R**](https://github.com/dirkschumacher/wasmr) | [Dirk Schumacher](https://github.com/dirkschumacher) | actively developed | | ![number of Github stars](https://img.shields.io/github/stars/dirkschumacher/wasmr?style=flat-square) | | ![Swift logo](./docs/assets/languages/swift.svg) | [**Swift**](https://github.com/markmals/swift-ext-wasm) | [Mark Malström](https://github.com/markmals/) | passively maintained | | ![number of Github stars](https://img.shields.io/github/stars/markmals/swift-ext-wasm?style=flat-square) | diff --git a/docs/assets/languages/js.svg b/docs/assets/languages/js.svg new file mode 100755 index 000000000..6a186f383 --- /dev/null +++ b/docs/assets/languages/js.svg @@ -0,0 +1,8 @@ + + + + + + + + From b3e8202138af5e42add7647dbddb9cb1e433c11b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 21 Oct 2019 15:15:11 -0700 Subject: [PATCH 064/122] Clean up Makefile after talking with Nick --- Makefile | 57 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 8c5fdb80c..168428569 100644 --- a/Makefile +++ b/Makefile @@ -140,25 +140,27 @@ install: # Checks check-bench-singlepass: - cargo bench --all --no-run --no-default-features --features "backend-singlepass" \ + cargo check --benches --all --no-default-features --features "backend-singlepass" \ --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-kernel-loader check-bench-clif: - cargo bench --all --no-run --no-default-features --features "backend-cranelift" \ + cargo check --benches --all --no-default-features --features "backend-cranelift" \ --exclude wasmer-singlepass-backend --exclude wasmer-llvm-backend --exclude wasmer-kernel-loader \ --exclude wasmer-middleware-common-tests check-bench-llvm: - cargo bench --all --no-run --no-default-features --features "backend-llvm" \ + cargo check --benches --all --no-default-features --features "backend-llvm" \ --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-kernel-loader check-bench: check-bench-singlepass check-bench-llvm +# TODO: We wanted `--workspace --exclude wasmer-runtime`, but can't due +# to https://github.com/rust-lang/cargo/issues/6745 . +NOT_RUNTIME_CRATES = -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests +RUNTIME_CHECK = cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features check: check-bench - # TODO: We wanted `--workspace --exclude wasmer-runtime`, but can't due - # to https://github.com/rust-lang/cargo/issues/6745 . - cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests - cargo check --release -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests - cargo check -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests --all-features - cargo check --release -p wasmer-clif-backend -p wasmer-singlepass-backend -p wasmer-middleware-common -p wasmer-runtime-core -p wasmer-emscripten -p wasmer-llvm-backend -p wasmer-wasi -p wasmer-kernel-loader -p wasmer-dev-utils -p wasmer-wasi-tests -p wasmer-middleware-common-tests -p wasmer-emscripten-tests --all-features + cargo check $(NOT_RUNTIME_CRATES) + cargo check --release $(NOT_RUNTIME_CRATES) + cargo check --all-features $(NOT_RUNTIME_CRATES) + cargo check --release --all-features $(NOT_RUNTIME_CRATES) # wasmer-runtime doesn't work with all backends enabled at once. # # We test using manifest-path directly so as to disable the default. @@ -172,18 +174,31 @@ check: check-bench # at a time. cargo check --manifest-path lib/runtime/Cargo.toml cargo check --release --manifest-path lib/runtime/Cargo.toml - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-singlepass - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-singlepass - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-cranelift - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-cranelift - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,debug,llvm,singlepass,default-backend-llvm - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,cache,llvm,singlepass,default-backend-llvm - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=singlepass,default-backend-singlepass,debug - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=singlepass,default-backend-singlepass - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,default-backend-cranelift,debug - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=cranelift,default-backend-cranelift - cargo check --manifest-path lib/runtime/Cargo.toml --no-default-features --features=llvm,default-backend-llvm,debug - cargo check --release --manifest-path lib/runtime/Cargo.toml --no-default-features --features=llvm,default-backend-llvm + + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-singlepass + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-singlepass + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-cranelift + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-cranelift + $(RUNTIME_CHECK) \ + --features=cranelift,cache,debug,llvm,singlepass,default-backend-llvm + $(RUNTIME_CHECK) --release \ + --features=cranelift,cache,llvm,singlepass,default-backend-llvm + $(RUNTIME_CHECK) \ + --features=singlepass,default-backend-singlepass,debug + $(RUNTIME_CHECK) --release \ + --features=singlepass,default-backend-singlepass + $(RUNTIME_CHECK) \ + --features=cranelift,default-backend-cranelift,debug + $(RUNTIME_CHECK) --release \ + --features=cranelift,default-backend-cranelift + $(RUNTIME_CHECK) \ + --features=llvm,default-backend-llvm,debug + $(RUNTIME_CHECK) --release \ + --features=llvm,default-backend-llvm # Release release: From 88dc613385d0c5444a3e6b5b54c51ee582a3b424 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 21 Oct 2019 19:44:16 -0700 Subject: [PATCH 065/122] Save and restore the additional XMM registers in OSR too. --- lib/runtime-core/image-loading-linux-x86-64.s | 24 ++++++++++++ lib/runtime-core/image-loading-macos-x86-64.s | 24 ++++++++++++ lib/runtime-core/src/fault.rs | 37 ++++++++++++++++--- lib/runtime-core/src/state.rs | 4 +- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/lib/runtime-core/image-loading-linux-x86-64.s b/lib/runtime-core/image-loading-linux-x86-64.s index 859f010f8..c9d6edff2 100644 --- a/lib/runtime-core/image-loading-linux-x86-64.s +++ b/lib/runtime-core/image-loading-linux-x86-64.s @@ -41,6 +41,30 @@ add $8, %rsp movq (%rsp), %xmm7 add $8, %rsp +movq (%rsp), %xmm8 +add $8, %rsp + +movq (%rsp), %xmm9 +add $8, %rsp + +movq (%rsp), %xmm10 +add $8, %rsp + +movq (%rsp), %xmm11 +add $8, %rsp + +movq (%rsp), %xmm12 +add $8, %rsp + +movq (%rsp), %xmm13 +add $8, %rsp + +movq (%rsp), %xmm14 +add $8, %rsp + +movq (%rsp), %xmm15 +add $8, %rsp + popq %rbp popq %rax popq %rbx diff --git a/lib/runtime-core/image-loading-macos-x86-64.s b/lib/runtime-core/image-loading-macos-x86-64.s index ef6f94510..5e19f7b4a 100644 --- a/lib/runtime-core/image-loading-macos-x86-64.s +++ b/lib/runtime-core/image-loading-macos-x86-64.s @@ -41,6 +41,30 @@ add $8, %rsp movq (%rsp), %xmm7 add $8, %rsp +movq (%rsp), %xmm8 +add $8, %rsp + +movq (%rsp), %xmm9 +add $8, %rsp + +movq (%rsp), %xmm10 +add $8, %rsp + +movq (%rsp), %xmm11 +add $8, %rsp + +movq (%rsp), %xmm12 +add $8, %rsp + +movq (%rsp), %xmm13 +add $8, %rsp + +movq (%rsp), %xmm14 +add $8, %rsp + +movq (%rsp), %xmm15 +add $8, %rsp + popq %rbp popq %rax popq %rbx diff --git a/lib/runtime-core/src/fault.rs b/lib/runtime-core/src/fault.rs index a1a1f58c2..bc21052fa 100644 --- a/lib/runtime-core/src/fault.rs +++ b/lib/runtime-core/src/fault.rs @@ -207,7 +207,7 @@ pub fn allocate_and_run R>(size: usize, f: F) -> R { // NOTE: Keep this consistent with `image-loading-*.s`. stack[end_offset - 4 - 10] = &mut ctx as *mut Context as usize as u64; // rdi - const NUM_SAVED_REGISTERS: usize = 23; + const NUM_SAVED_REGISTERS: usize = 31; let stack_begin = stack .as_mut_ptr() .offset((end_offset - 4 - NUM_SAVED_REGISTERS) as isize); @@ -347,7 +347,7 @@ unsafe fn install_sighandler() { pub struct FaultInfo { pub faulting_addr: *const c_void, pub ip: *const c_void, - pub known_registers: [Option; 24], + pub known_registers: [Option; 32], } #[cfg(all(target_os = "linux", target_arch = "x86_64"))] @@ -378,7 +378,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let gregs = &(*ucontext).uc_mcontext.gregs; let fpregs = &*(*ucontext).uc_mcontext.fpregs; - let mut known_registers: [Option; 24] = [None; 24]; + let mut known_registers: [Option; 32] = [None; 32]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(gregs[REG_R15 as usize] as _); known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(gregs[REG_R14 as usize] as _); known_registers[X64Register::GPR(GPR::R13).to_index().0] = Some(gregs[REG_R13 as usize] as _); @@ -405,6 +405,14 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(read_xmm(&fpregs._xmm[5])); known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(read_xmm(&fpregs._xmm[6])); known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(read_xmm(&fpregs._xmm[7])); + known_registers[X64Register::XMM(XMM::XMM8).to_index().0] = Some(read_xmm(&fpregs._xmm[8])); + known_registers[X64Register::XMM(XMM::XMM9).to_index().0] = Some(read_xmm(&fpregs._xmm[9])); + known_registers[X64Register::XMM(XMM::XMM10).to_index().0] = Some(read_xmm(&fpregs._xmm[10])); + known_registers[X64Register::XMM(XMM::XMM11).to_index().0] = Some(read_xmm(&fpregs._xmm[11])); + known_registers[X64Register::XMM(XMM::XMM12).to_index().0] = Some(read_xmm(&fpregs._xmm[12])); + known_registers[X64Register::XMM(XMM::XMM13).to_index().0] = Some(read_xmm(&fpregs._xmm[13])); + known_registers[X64Register::XMM(XMM::XMM14).to_index().0] = Some(read_xmm(&fpregs._xmm[14])); + known_registers[X64Register::XMM(XMM::XMM15).to_index().0] = Some(read_xmm(&fpregs._xmm[15])); FaultInfo { faulting_addr: si_addr as usize as _, @@ -458,8 +466,17 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> } #[repr(C)] struct fpstate { - _unused: [u8; 168], - xmm: [[u64; 2]; 8], + _cwd: u16, + _swd: u16, + _ftw: u16, + _fop: u16, + _rip: u64, + _rdp: u64, + _mxcsr: u32, + _mxcr_mask: u32, + _st: [[u16; 8]; 8], + xmm: [[u64; 2]; 16], + _padding: [u32; 24], } #[allow(dead_code)] #[repr(C)] @@ -476,7 +493,7 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> let ss = &(*(*ucontext).uc_mcontext).ss; let fs = &(*(*ucontext).uc_mcontext).fs; - let mut known_registers: [Option; 24] = [None; 24]; + let mut known_registers: [Option; 32] = [None; 32]; known_registers[X64Register::GPR(GPR::R15).to_index().0] = Some(ss.r15); known_registers[X64Register::GPR(GPR::R14).to_index().0] = Some(ss.r14); @@ -504,6 +521,14 @@ pub unsafe fn get_fault_info(siginfo: *const c_void, ucontext: *const c_void) -> known_registers[X64Register::XMM(XMM::XMM5).to_index().0] = Some(fs.xmm[5][0]); known_registers[X64Register::XMM(XMM::XMM6).to_index().0] = Some(fs.xmm[6][0]); known_registers[X64Register::XMM(XMM::XMM7).to_index().0] = Some(fs.xmm[7][0]); + known_registers[X64Register::XMM(XMM::XMM8).to_index().0] = Some(fs.xmm[8][0]); + known_registers[X64Register::XMM(XMM::XMM9).to_index().0] = Some(fs.xmm[9][0]); + known_registers[X64Register::XMM(XMM::XMM10).to_index().0] = Some(fs.xmm[10][0]); + known_registers[X64Register::XMM(XMM::XMM11).to_index().0] = Some(fs.xmm[11][0]); + known_registers[X64Register::XMM(XMM::XMM12).to_index().0] = Some(fs.xmm[12][0]); + known_registers[X64Register::XMM(XMM::XMM13).to_index().0] = Some(fs.xmm[13][0]); + known_registers[X64Register::XMM(XMM::XMM14).to_index().0] = Some(fs.xmm[14][0]); + known_registers[X64Register::XMM(XMM::XMM15).to_index().0] = Some(fs.xmm[15][0]); FaultInfo { faulting_addr: si_addr, diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 386fe21b5..6025abe60 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -811,10 +811,10 @@ pub mod x64 { pub unsafe fn read_stack<'a, I: Iterator, F: Fn() -> I + 'a>( versions: F, mut stack: *const u64, - initially_known_registers: [Option; 24], + initially_known_registers: [Option; 32], mut initial_address: Option, ) -> ExecutionStateImage { - let mut known_registers: [Option; 24] = initially_known_registers; + let mut known_registers: [Option; 32] = initially_known_registers; let mut results: Vec = vec![]; let mut was_baseline = true; From 85ddbe38daa6c2d0ecb36069dc3207b2d8faff81 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 22 Oct 2019 18:16:36 +0000 Subject: [PATCH 066/122] Bump cc from 1.0.45 to 1.0.46 Bumps [cc](https://github.com/alexcrichton/cc-rs) from 1.0.45 to 1.0.46. - [Release notes](https://github.com/alexcrichton/cc-rs/releases) - [Commits](https://github.com/alexcrichton/cc-rs/compare/1.0.45...1.0.46) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cfd929f1..d8a040af1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -161,7 +161,7 @@ name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -597,7 +597,7 @@ name = "llvm-sys" version = "80.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -665,7 +665,7 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (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.62 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,7 +891,7 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1307,7 +1307,7 @@ name = "wabt-sys" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1449,7 +1449,7 @@ name = "wasmer-llvm-backend" version = "0.8.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1516,7 +1516,7 @@ version = "0.8.0" dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (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)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1662,7 +1662,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" -"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" From 3a87edc0c1d517b1b79fec076e61ad50557bf5bb Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 22 Oct 2019 16:36:05 -0700 Subject: [PATCH 067/122] Remove special casing of stdin, stdout, and stderr in WASI FS --- CHANGELOG.md | 1 + lib/wasi-tests/tests/wasitests/fd_close.rs | 18 ++ lib/wasi-tests/tests/wasitests/mod.rs | 1 + lib/wasi-tests/wasitests/fd_close.out | 2 + lib/wasi-tests/wasitests/fd_close.rs | 54 ++++++ lib/wasi-tests/wasitests/fd_close.wasm | Bin 0 -> 82928 bytes lib/wasi/src/state/mod.rs | 196 ++++++++++++++++++--- lib/wasi/src/state/types.rs | 4 + lib/wasi/src/syscalls/mod.rs | 79 ++++++++- 9 files changed, 324 insertions(+), 31 deletions(-) create mode 100644 lib/wasi-tests/tests/wasitests/fd_close.rs create mode 100644 lib/wasi-tests/wasitests/fd_close.out create mode 100644 lib/wasi-tests/wasitests/fd_close.rs create mode 100755 lib/wasi-tests/wasitests/fd_close.wasm diff --git a/CHANGELOG.md b/CHANGELOG.md index 49d90aaae..936238a6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on. - [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. ## 0.8.0 - 2019-10-02 diff --git a/lib/wasi-tests/tests/wasitests/fd_close.rs b/lib/wasi-tests/tests/wasitests/fd_close.rs new file mode 100644 index 000000000..8bff35789 --- /dev/null +++ b/lib/wasi-tests/tests/wasitests/fd_close.rs @@ -0,0 +1,18 @@ +// !!! THIS IS A GENERATED FILE !!! +// ANY MANUAL EDITS MAY BE OVERWRITTEN AT ANY TIME +// Files autogenerated with cargo build (build/wasitests.rs). + +#[test] +fn test_fd_close() { + assert_wasi_output!( + "../../wasitests/fd_close.wasm", + "fd_close", + vec![], + vec![( + ".".to_string(), + ::std::path::PathBuf::from("wasitests/test_fs/hamlet") + ),], + vec![], + "../../wasitests/fd_close.out" + ); +} diff --git a/lib/wasi-tests/tests/wasitests/mod.rs b/lib/wasi-tests/tests/wasitests/mod.rs index e469511fd..75a91d6f0 100644 --- a/lib/wasi-tests/tests/wasitests/mod.rs +++ b/lib/wasi-tests/tests/wasitests/mod.rs @@ -9,6 +9,7 @@ mod close_preopen_fd; mod create_dir; mod envvar; mod fd_allocate; +mod fd_close; mod fd_pread; mod fd_read; mod fd_sync; diff --git a/lib/wasi-tests/wasitests/fd_close.out b/lib/wasi-tests/wasitests/fd_close.out new file mode 100644 index 000000000..c42fc06c2 --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_close.out @@ -0,0 +1,2 @@ +Successfully closed stderr! +Successfully closed stdin! diff --git a/lib/wasi-tests/wasitests/fd_close.rs b/lib/wasi-tests/wasitests/fd_close.rs new file mode 100644 index 000000000..3d2104be6 --- /dev/null +++ b/lib/wasi-tests/wasitests/fd_close.rs @@ -0,0 +1,54 @@ +// Args: +// mapdir: .:wasitests/test_fs/hamlet + +use std::fs; +#[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 fd_close(fd: u32) -> u16; +} + +fn main() { + #[cfg(not(target_os = "wasi"))] + let mut base = PathBuf::from("wasitests/test_fs/hamlet"); + #[cfg(target_os = "wasi")] + let mut base = PathBuf::from("."); + + base.push("act3/scene3.txt"); + let file = fs::File::open(&base).expect("could not open file"); + + #[cfg(target_os = "wasi")] + { + let stdout_fd = std::io::stdout().as_raw_fd(); + let stderr_fd = std::io::stderr().as_raw_fd(); + let stdin_fd = std::io::stdin().as_raw_fd(); + + let result = unsafe { fd_close(stderr_fd) }; + if result == 0 { + println!("Successfully closed stderr!") + } else { + println!("Could not close stderr"); + } + let result = unsafe { fd_close(stdin_fd) }; + if result == 0 { + println!("Successfully closed stdin!") + } else { + println!("Could not close stdin"); + } + let result = unsafe { fd_close(stdout_fd) }; + if result == 0 { + println!("Successfully closed stdout!") + } else { + println!("Could not close stdout"); + } + } + #[cfg(not(target_os = "wasi"))] + { + println!("Successfully closed stderr!"); + println!("Successfully closed stdin!"); + } +} diff --git a/lib/wasi-tests/wasitests/fd_close.wasm b/lib/wasi-tests/wasitests/fd_close.wasm new file mode 100755 index 0000000000000000000000000000000000000000..a40a1bfda1eda6d84e0eedb1399d17925b4cca86 GIT binary patch literal 82928 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 z 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, /// for fds still open after the file has been deleted pub orphan_fds: HashMap, - - pub stdout: Box, - pub stderr: Box, - pub stdin: Box, } impl WasiFs { @@ -155,11 +165,11 @@ impl WasiFs { next_fd: Cell::new(3), inode_counter: Cell::new(1024), orphan_fds: HashMap::new(), - - stdin: Box::new(Stdin), - stdout: Box::new(Stdout), - stderr: Box::new(Stderr), }; + wasi_fs.create_stdin(); + wasi_fs.create_stdout(); + wasi_fs.create_stderr(); + // create virtual root let root_inode = { let all_rights = 0x1FFFFFFF; @@ -291,6 +301,67 @@ impl WasiFs { Ok(wasi_fs) } + /// Get the `WasiFile` object at stdout + pub fn stdout(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDOUT_FILENO) + } + /// Get the `WasiFile` object at stdout mutably + pub fn stdout_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDOUT_FILENO) + } + + /// Get the `WasiFile` object at stderr + pub fn stderr(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDERR_FILENO) + } + /// Get the `WasiFile` object at stderr mutably + pub fn stderr_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDERR_FILENO) + } + + /// Get the `WasiFile` object at stdin + pub fn stdin(&self) -> Result<&Option>, WasiFsError> { + self.std_dev_get(__WASI_STDIN_FILENO) + } + /// Get the `WasiFile` object at stdin mutably + pub fn stdin_mut(&mut self) -> Result<&mut Option>, WasiFsError> { + self.std_dev_get_mut(__WASI_STDIN_FILENO) + } + + /// Internal helper function to get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get(&self, fd: __wasi_fd_t) -> Result<&Option>, WasiFsError> { + if let Some(fd) = self.fd_map.get(&fd) { + if let Kind::File { ref handle, .. } = self.inodes[fd.inode].kind { + Ok(handle) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(WasiFsError::NoDevice) + } + } + /// Internal helper function to mutably get a standard device handle. + /// Expects one of `__WASI_STDIN_FILENO`, `__WASI_STDOUT_FILENO`, `__WASI_STDERR_FILENO`. + fn std_dev_get_mut( + &mut self, + fd: __wasi_fd_t, + ) -> Result<&mut Option>, WasiFsError> { + if let Some(fd) = self.fd_map.get_mut(&fd) { + if let Kind::File { ref mut handle, .. } = self.inodes[fd.inode].kind { + Ok(handle) + } else { + // Our public API should ensure that this is not possible + unreachable!("Non-file found in standard device location") + } + } else { + // this should only trigger if we made a mistake in this crate + Err(WasiFsError::NoDevice) + } + } + fn get_next_inode_index(&mut self) -> u64 { let next = self.inode_counter.get(); self.inode_counter.set(next + 1); @@ -358,21 +429,16 @@ impl WasiFs { fd: __wasi_fd_t, file: Box, ) -> Result>, WasiFsError> { + let mut ret = Some(file); match fd { __WASI_STDIN_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stdin, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stdin_mut()?, &mut ret); } __WASI_STDOUT_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stdout, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stdout_mut()?, &mut ret); } __WASI_STDERR_FILENO => { - let mut ret = file; - std::mem::swap(&mut self.stderr, &mut ret); - Ok(Some(ret)) + std::mem::swap(self.stderr_mut()?, &mut ret); } _ => { let base_fd = self.get_fd(fd).map_err(WasiFsError::from_wasi_err)?; @@ -380,14 +446,14 @@ impl WasiFs { match &mut self.inodes[base_inode].kind { Kind::File { ref mut handle, .. } => { - let mut ret = Some(file); std::mem::swap(handle, &mut ret); - Ok(ret) } _ => return Err(WasiFsError::NotAFile), } } } + + Ok(ret) } /// refresh size from filesystem @@ -733,6 +799,17 @@ impl WasiFs { } pub fn fdstat(&self, fd: __wasi_fd_t) -> Result<__wasi_fdstat_t, __wasi_errno_t> { + match fd { + __WASI_STDOUT_FILENO => { + return Ok(__wasi_fdstat_t { + fs_filetype: __WASI_FILETYPE_CHARACTER_DEVICE, + fs_flags: 0, + fs_rights_base: ALL_RIGHTS, + fs_rights_inheriting: ALL_RIGHTS, + }) + } + _ => (), + } let fd = self.get_fd(fd)?; debug!("fdstat: {:?}", fd); @@ -773,8 +850,18 @@ impl WasiFs { pub fn flush(&mut self, fd: __wasi_fd_t) -> Result<(), __wasi_errno_t> { match fd { __WASI_STDIN_FILENO => (), - __WASI_STDOUT_FILENO => self.stdout.flush().map_err(|_| __WASI_EIO)?, - __WASI_STDERR_FILENO => self.stderr.flush().map_err(|_| __WASI_EIO)?, + __WASI_STDOUT_FILENO => self + .stdout_mut() + .map_err(WasiFsError::into_wasi_err)? + .as_mut() + .and_then(|f| f.flush().ok()) + .ok_or(__WASI_EIO)?, + __WASI_STDERR_FILENO => self + .stderr_mut() + .map_err(WasiFsError::into_wasi_err)? + .as_mut() + .and_then(|f| f.flush().ok()) + .ok_or(__WASI_EIO)?, _ => { let fd = self.fd_map.get(&fd).ok_or(__WASI_EBADF)?; if fd.rights & __WASI_RIGHT_FD_DATASYNC == 0 { @@ -881,13 +968,78 @@ impl WasiFs { }; self.inodes.insert(InodeVal { - stat: stat, + stat, is_preopened: true, name: "/".to_string(), kind: root_kind, }) } + fn create_stdout(&mut self) { + self.create_std_dev_inner( + Box::new(Stdout), + "stdout", + __WASI_STDOUT_FILENO, + STDOUT_DEFAULT_RIGHTS, + __WASI_FDFLAG_APPEND, + ); + } + fn create_stdin(&mut self) { + self.create_std_dev_inner( + Box::new(Stdin), + "stdin", + __WASI_STDIN_FILENO, + STDIN_DEFAULT_RIGHTS, + 0, + ); + } + fn create_stderr(&mut self) { + self.create_std_dev_inner( + Box::new(Stderr), + "stderr", + __WASI_STDERR_FILENO, + STDERR_DEFAULT_RIGHTS, + __WASI_FDFLAG_APPEND, + ); + } + + fn create_std_dev_inner( + &mut self, + handle: Box, + name: &'static str, + raw_fd: __wasi_fd_t, + rights: __wasi_rights_t, + fd_flags: __wasi_fdflags_t, + ) { + let stat = __wasi_filestat_t { + st_filetype: __WASI_FILETYPE_CHARACTER_DEVICE, + st_ino: self.get_next_inode_index(), + ..__wasi_filestat_t::default() + }; + let kind = Kind::File { + handle: Some(handle), + path: "".into(), + }; + let inode = self.inodes.insert(InodeVal { + stat, + is_preopened: true, + name: name.to_string(), + kind, + }); + self.fd_map.insert( + raw_fd, + Fd { + rights, + rights_inheriting: 0, + flags: fd_flags, + // since we're not calling open on this, we don't need open flags + open_flags: 0, + offset: 0, + inode, + }, + ); + } + pub fn get_stat_for_kind(&self, kind: &Kind) -> Option<__wasi_filestat_t> { let md = match kind { Kind::File { handle, path } => match handle { diff --git a/lib/wasi/src/state/types.rs b/lib/wasi/src/state/types.rs index 2f97a5fe3..5eb55c670 100644 --- a/lib/wasi/src/state/types.rs +++ b/lib/wasi/src/state/types.rs @@ -49,6 +49,8 @@ pub enum WasiFsError { NotConnected, /// The requested file or directory could not be found EntityNotFound, + /// The requested device couldn't be accessed + NoDevice, /// Caller was not allowed to perform this operation PermissionDenied, /// The operation did not complete within the given amount of time @@ -80,6 +82,7 @@ impl WasiFsError { __WASI_EINTR => WasiFsError::Interrupted, __WASI_EINVAL => WasiFsError::InvalidInput, __WASI_ENOTCONN => WasiFsError::NotConnected, + __WASI_ENODEV => WasiFsError::NoDevice, __WASI_ENOENT => WasiFsError::EntityNotFound, __WASI_EPERM => WasiFsError::PermissionDenied, __WASI_ETIMEDOUT => WasiFsError::TimedOut, @@ -105,6 +108,7 @@ impl WasiFsError { WasiFsError::InvalidFd => __WASI_EBADF, WasiFsError::InvalidInput => __WASI_EINVAL, WasiFsError::IOError => __WASI_EIO, + WasiFsError::NoDevice => __WASI_ENODEV, WasiFsError::NotAFile => __WASI_EINVAL, WasiFsError::NotConnected => __WASI_ENOTCONN, WasiFsError::EntityNotFound => __WASI_ENOENT, diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 90dbfd458..37a6486c3 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -374,6 +374,7 @@ pub fn fd_allocate( /// If `fd` is invalid or not open pub fn fd_close(ctx: &mut Ctx, fd: __wasi_fd_t) -> __wasi_errno_t { debug!("wasi::fd_close"); + debug!("=> fd={}", fd); let state = get_wasi_state(ctx); let fd_entry = wasi_try!(state.fs.get_fd(fd)).clone(); @@ -662,7 +663,15 @@ pub fn fd_pread( let state = get_wasi_state(ctx); let bytes_read = match fd { - __WASI_STDIN_FILENO => wasi_try!(read_bytes(&mut state.fs.stdin, memory, iov_cells)), + __WASI_STDIN_FILENO => { + if let Some(ref mut stdin) = + wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(read_bytes(stdin, memory, iov_cells)) + } else { + return __WASI_EBADF; + } + } __WASI_STDOUT_FILENO => return __WASI_EINVAL, __WASI_STDERR_FILENO => return __WASI_EINVAL, _ => { @@ -802,8 +811,24 @@ pub fn fd_pwrite( let bytes_written = match fd { __WASI_STDIN_FILENO => return __WASI_EINVAL, - __WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)), - __WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)), + __WASI_STDOUT_FILENO => { + if let Some(ref mut stdout) = + wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stdout, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } + __WASI_STDERR_FILENO => { + if let Some(ref mut stderr) = + wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stderr, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } _ => { let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -872,7 +897,15 @@ pub fn fd_read( let state = get_wasi_state(ctx); let bytes_read = match fd { - __WASI_STDIN_FILENO => wasi_try!(read_bytes(&mut state.fs.stdin, memory, iovs_arr_cell)), + __WASI_STDIN_FILENO => { + if let Some(ref mut stdin) = + wasi_try!(state.fs.stdin_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(read_bytes(stdin, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } __WASI_STDOUT_FILENO | __WASI_STDERR_FILENO => return __WASI_EINVAL, _ => { let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -1211,8 +1244,24 @@ pub fn fd_write( let bytes_written = match fd { __WASI_STDIN_FILENO => return __WASI_EINVAL, - __WASI_STDOUT_FILENO => wasi_try!(write_bytes(&mut state.fs.stdout, memory, iovs_arr_cell)), - __WASI_STDERR_FILENO => wasi_try!(write_bytes(&mut state.fs.stderr, memory, iovs_arr_cell)), + __WASI_STDOUT_FILENO => { + if let Some(ref mut stdout) = + wasi_try!(state.fs.stdout_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stdout, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } + __WASI_STDERR_FILENO => { + if let Some(ref mut stderr) = + wasi_try!(state.fs.stderr_mut().map_err(WasiFsError::into_wasi_err)) + { + wasi_try!(write_bytes(stderr, memory, iovs_arr_cell)) + } else { + return __WASI_EBADF; + } + } _ => { let state = get_wasi_state(ctx); let fd_entry = wasi_try!(state.fs.fd_map.get_mut(&fd).ok_or(__WASI_EBADF)); @@ -2292,9 +2341,21 @@ pub fn 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(), + __WASI_STDERR_FILENO => wasi_try!( + wasi_try!(state.fs.stderr().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), + __WASI_STDIN_FILENO => wasi_try!( + wasi_try!(state.fs.stdin().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), + __WASI_STDOUT_FILENO => wasi_try!( + wasi_try!(state.fs.stdout().map_err(WasiFsError::into_wasi_err)).as_ref(), + __WASI_EBADF + ) + .as_ref(), _ => { let fd_entry = wasi_try!(state.fs.get_fd(fd)); let inode = fd_entry.inode; From 5353af79ad4918c3da94ebe4890c3e20898ed3ba Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 22 Oct 2019 17:29:19 -0700 Subject: [PATCH 068/122] Improve fd_close wasi test: explicitly close file --- lib/wasi-tests/wasitests/fd_close.out | 1 + lib/wasi-tests/wasitests/fd_close.rs | 9 +++++++++ lib/wasi-tests/wasitests/fd_close.wasm | Bin 82928 -> 83077 bytes 3 files changed, 10 insertions(+) diff --git a/lib/wasi-tests/wasitests/fd_close.out b/lib/wasi-tests/wasitests/fd_close.out index c42fc06c2..53c9c2727 100644 --- a/lib/wasi-tests/wasitests/fd_close.out +++ b/lib/wasi-tests/wasitests/fd_close.out @@ -1,2 +1,3 @@ +Successfully closed file! Successfully closed stderr! Successfully closed stdin! diff --git a/lib/wasi-tests/wasitests/fd_close.rs b/lib/wasi-tests/wasitests/fd_close.rs index 3d2104be6..e5cdaafd9 100644 --- a/lib/wasi-tests/wasitests/fd_close.rs +++ b/lib/wasi-tests/wasitests/fd_close.rs @@ -23,10 +23,18 @@ fn main() { #[cfg(target_os = "wasi")] { + let file_fd = file.as_raw_fd(); let stdout_fd = std::io::stdout().as_raw_fd(); let stderr_fd = std::io::stderr().as_raw_fd(); let stdin_fd = std::io::stdin().as_raw_fd(); + let result = unsafe { fd_close(file_fd) }; + if result == 0 { + println!("Successfully closed file!") + } else { + println!("Could not close file"); + } + let result = unsafe { fd_close(stderr_fd) }; if result == 0 { println!("Successfully closed stderr!") @@ -48,6 +56,7 @@ fn main() { } #[cfg(not(target_os = "wasi"))] { + println!("Successfully closed file!"); println!("Successfully closed stderr!"); println!("Successfully closed stdin!"); } diff --git a/lib/wasi-tests/wasitests/fd_close.wasm b/lib/wasi-tests/wasitests/fd_close.wasm index a40a1bfda1eda6d84e0eedb1399d17925b4cca86..5ace5206203c7385f622705c2503474978339113 100755 GIT binary patch delta 13792 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 delta 13827 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 z z{1DuDbb|1Pro`V5oy5$#`<)l0W1PaL>q^CUTe0J@sjvepjy*`f@yFkz-@4<|==aax zK25*Bew#(VSDiT0vw@MQf74{A6#HMnG55R0-uf#z`QJ%A^4$&eg=YFcCJn0ps*>KV z^JiXkw+N%70ol!TPenb=mM5S*xzm@ITvni^ZUF21x00nO@V@@XAWzM!^vnw^$aAjy z{^`7O3sCC}t)X6Jg2*V=s_OfH2dQmc9{SEG&ot!!6=zVJ;3l-bm+(yQph zIC`z6Q5IlAJyU;u7q>46{o5LTctxmN(RL~me!}*r9gxxmUJHZ zJ9KZ8WP^nlC(!r0KV00_`G))@%^=V4uStROfc(FbqFSR0hW{OSuf@C(cCo_f1`)Fnpe zF!%F8bnSMumRFJkiz+BJ+-dX~Xs8yapOjePCe}F< z%Q)_aVfCJ%H1`B!s0W^@SFf2vPyeHVSmPZpq(!ZsLF?)cWz{0%f*0DrFNPKg*NOwR z#>hxW6Z>n8$0I>^7PF(MD~vsna2vUnemFn-f+?`t*dGOdZnO*Z zFk)0lG6C2BU$z1>Fx-d7*c6?sQSODtPb#c6jzojYrl4X>Y5@rm_f44+p=?)FCC(Vy z0ur6~Kj4c{4k|`=3urAaD8}Fx;D=;mVhc!xTw_rS7#BVrR3%GMluEiLODTG2|9|}cxva_6iU0)H=BZM`#75q73fy1OFQKwr$qNs5g zo;c_Rp6dQ_umjpwku3hxGA2H#(ZnZC(K17@15Q^wKqBNbv{yOER%>Efifx=$+f1IRWOXz)n*^e9!ij;LQT+&;(>hoX$G zJ{U+k&h(MS4;Zicpm+5p9~=sUyNoY0pnt?yajFtc6no>0>`dtA=ozmn!cf~oobhBP zxL}xJWJ0fK2J>GzwLGD6L@eAo_#M(-gGVTAE6wSHGF~8}O^I?EoVoI=8hca3pcfAcS0Fc}K|6 z3kj@IH=X_^(7#ZhQM5+=cJ$nMoMVVXp|HATCm8FA&PY?0fz Date: Tue, 22 Oct 2019 23:14:42 -0700 Subject: [PATCH 069/122] Flip the default for 'track-state' from on to off. The flag is --track-state. --- src/bin/wasmer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/wasmer.rs b/src/bin/wasmer.rs index 4c51d9770..6195e60a6 100644 --- a/src/bin/wasmer.rs +++ b/src/bin/wasmer.rs @@ -177,8 +177,8 @@ struct Run { /// Whether or not state tracking should be disabled during compilation. /// State tracking is necessary for tier switching and backtracing. - #[structopt(long = "no-track-state")] - no_track_state: bool, + #[structopt(long = "track-state")] + track_state: bool, /// The command name is a string that will override the first argument passed /// to the wasm program. This is used in wapm to provide nicer output in @@ -419,7 +419,7 @@ fn execute_wasm(options: &Run) -> Result<(), String> { } } - let track_state = !options.no_track_state; + let track_state = options.track_state; #[cfg(feature = "loader-kernel")] let is_kernel_loader = if let Some(LoaderName::Kernel) = options.loader { From 92f0b1b2e323b817736e7d5560966440ecb345ce Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 22 Oct 2019 23:15:05 -0700 Subject: [PATCH 070/122] Thread whether state tracking is enabled into the LLVM backend. --- lib/llvm-backend/src/code.rs | 261 +++++++++++++++++++---------------- 1 file changed, 142 insertions(+), 119 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 7ce0459b9..f1ea2caa8 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -15,7 +15,7 @@ use std::cell::RefCell; use std::rc::Rc; use std::sync::{Arc, RwLock}; use wasmer_runtime_core::{ - backend::{Backend, CacheGen, Token}, + backend::{Backend, CacheGen, CompilerConfig, Token}, cache::{Artifact, Error as CacheError}, codegen::*, memory::MemoryType, @@ -676,6 +676,7 @@ pub struct LLVMModuleCodeGenerator { personality_func: FunctionValue, module: Module, stackmaps: Rc>, + track_state: bool, } pub struct LLVMFunctionCodeGenerator { @@ -693,6 +694,7 @@ pub struct LLVMFunctionCodeGenerator { stackmaps: Rc>, index: usize, opcode_offset: usize, + track_state: bool, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -768,27 +770,29 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let builder = self.builder.as_ref().unwrap(); let intrinsics = self.intrinsics.as_ref().unwrap(); - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &module_info, - &intrinsics, - &builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::FunctionHeader, - &self.locals, - &state, - self.ctx.as_mut().unwrap(), - ::std::usize::MAX, - ); - finalize_opcode_stack_map( - &intrinsics, - &builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::FunctionHeader, - ::std::usize::MAX, - ); + if self.track_state { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &module_info, + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + &self.locals, + &state, + self.ctx.as_mut().unwrap(), + ::std::usize::MAX, + ); + finalize_opcode_stack_map( + &intrinsics, + &builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::FunctionHeader, + ::std::usize::MAX, + ); + } } Ok(()) @@ -918,33 +922,35 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder.position_at_end(&loop_body); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Loop, - &self.locals, - state, - ctx, - offset, - ); - let signal_mem = ctx.signal_mem(); - let iv = builder - .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); - // Any 'store' can be made volatile. - iv.set_volatile(true).unwrap(); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Loop, - offset, - ); + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + &self.locals, + state, + ctx, + offset, + ); + let signal_mem = ctx.signal_mem(); + let iv = builder + .build_store(signal_mem, context.i8_type().const_int(0 as u64, false)); + // Any 'store' can be made volatile. + iv.set_volatile(true).unwrap(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Loop, + offset, + ); + } } state.push_loop(loop_body, loop_next, phis); @@ -1215,28 +1221,30 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { // Comment out this `if` block to allow spectests to pass. // TODO: fix this if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Trappable, - &self.locals, - state, - ctx, - offset, - ); - builder.build_call(intrinsics.trap, &[], "trap"); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Trappable, - offset, - ); + if self.track_state { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + &self.locals, + state, + ctx, + offset, + ); + builder.build_call(intrinsics.trap, &[], "trap"); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Trappable, + offset, + ); + } } builder.build_call( @@ -1495,32 +1503,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; state.popn(func_sig.params().len())?; - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - &self.locals, - state, - ctx, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ctx, + offset, + ) + } } let call_site = builder.build_call(func_ptr, ¶ms, &state.var_name()); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } } if let Some(basic_value) = call_site.try_as_basic_value().left() { @@ -1704,32 +1716,36 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { "typed_func_ptr", ); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - emit_stack_map( - &info, - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - &self.locals, - state, - ctx, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + emit_stack_map( + &info, + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + &self.locals, + state, + ctx, + offset, + ) + } } let call_site = builder.build_call(typed_func_ptr, &args, "indirect_call"); - if let Some(offset) = opcode_offset { - let mut stackmaps = self.stackmaps.borrow_mut(); - finalize_opcode_stack_map( - intrinsics, - builder, - self.index, - &mut *stackmaps, - StackmapEntryKind::Call, - offset, - ) + if self.track_state { + if let Some(offset) = opcode_offset { + let mut stackmaps = self.stackmaps.borrow_mut(); + finalize_opcode_stack_map( + intrinsics, + builder, + self.index, + &mut *stackmaps, + StackmapEntryKind::Call, + offset, + ) + } } match wasmer_fn_sig.returns() { @@ -7242,6 +7258,7 @@ impl ModuleCodeGenerator func_import_count: 0, personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), + track_state: false, } } @@ -7341,6 +7358,7 @@ impl ModuleCodeGenerator stackmaps: self.stackmaps.clone(), index: local_func_index, opcode_offset: 0, + track_state: self.track_state, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -7416,6 +7434,11 @@ impl ModuleCodeGenerator Ok((backend, Box::new(cache_gen))) } + fn feed_compiler_config(&mut self, config: &CompilerConfig) -> Result<(), CodegenError> { + self.track_state = config.track_state; + Ok(()) + } + fn feed_signatures(&mut self, signatures: Map) -> Result<(), CodegenError> { self.signatures = signatures .iter() From 6410da9c24fcf3ea9ef80c734bf197d0c5750c75 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 22 Oct 2019 23:35:16 -0700 Subject: [PATCH 071/122] Remove dead intrinsics. --- lib/llvm-backend/src/intrinsics.rs | 38 ------------------------------ 1 file changed, 38 deletions(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index afd3bf8ad..36c3b7081 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -49,16 +49,6 @@ pub struct Intrinsics { pub sqrt_f32x4: FunctionValue, pub sqrt_f64x2: FunctionValue, - pub minimum_f32: FunctionValue, - pub minimum_f64: FunctionValue, - pub minimum_f32x4: FunctionValue, - pub minimum_f64x2: FunctionValue, - - pub maximum_f32: FunctionValue, - pub maximum_f64: FunctionValue, - pub maximum_f32x4: FunctionValue, - pub maximum_f64x2: FunctionValue, - pub ceil_f32: FunctionValue, pub ceil_f64: FunctionValue, @@ -309,8 +299,6 @@ impl Intrinsics { let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false); let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false); - let ret_f32x4_take_f32x4_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic, f32x4_ty_basic], false); - let ret_f64x2_take_f64x2_f64x2 = f64x2_ty.fn_type(&[f64x2_ty_basic, f64x2_ty_basic], false); let ret_i32_take_ctx_i32_i32 = i32_ty.fn_type( &[ctx_ptr_ty.as_basic_type_enum(), i32_ty_basic, i32_ty_basic], @@ -335,32 +323,6 @@ impl Intrinsics { sqrt_f32x4: module.add_function("llvm.sqrt.v4f32", ret_f32x4_take_f32x4, None), sqrt_f64x2: module.add_function("llvm.sqrt.v2f64", ret_f64x2_take_f64x2, None), - minimum_f32: module.add_function("llvm.minnum.f32", ret_f32_take_f32_f32, None), - minimum_f64: module.add_function("llvm.minnum.f64", ret_f64_take_f64_f64, None), - minimum_f32x4: module.add_function( - "llvm.minnum.v4f32", - ret_f32x4_take_f32x4_f32x4, - None, - ), - minimum_f64x2: module.add_function( - "llvm.minnum.v2f64", - ret_f64x2_take_f64x2_f64x2, - None, - ), - - maximum_f32: module.add_function("llvm.maxnum.f32", ret_f32_take_f32_f32, None), - maximum_f64: module.add_function("llvm.maxnum.f64", ret_f64_take_f64_f64, None), - maximum_f32x4: module.add_function( - "llvm.maxnum.v4f32", - ret_f32x4_take_f32x4_f32x4, - None, - ), - maximum_f64x2: module.add_function( - "llvm.maxnum.v2f64", - ret_f64x2_take_f64x2_f64x2, - None, - ), - ceil_f32: module.add_function("llvm.ceil.f32", ret_f32_take_f32, None), ceil_f64: module.add_function("llvm.ceil.f64", ret_f64_take_f64, None), From efce780807db38e66ef1f3a09bdbd9b2733a78b4 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2019 17:45:10 +0000 Subject: [PATCH 072/122] Bump libc from 0.2.62 to 0.2.65 Bumps [libc](https://github.com/rust-lang/libc) from 0.2.62 to 0.2.65. - [Release notes](https://github.com/rust-lang/libc/releases) - [Commits](https://github.com/rust-lang/libc/compare/0.2.62...0.2.65) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8a040af1..291f229f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -34,7 +34,7 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -234,7 +234,7 @@ dependencies = [ "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -386,7 +386,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -396,7 +396,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -456,7 +456,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -520,7 +520,7 @@ dependencies = [ "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -589,7 +589,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -599,7 +599,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -630,7 +630,7 @@ name = "memchr" version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -638,7 +638,7 @@ name = "memmap" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -647,7 +647,7 @@ name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -667,7 +667,7 @@ dependencies = [ "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (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.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -689,7 +689,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -706,7 +706,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -745,7 +745,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -819,7 +819,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -870,7 +870,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1171,7 +1171,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1199,7 +1199,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1362,7 +1362,7 @@ dependencies = [ "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-native 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1407,7 +1407,7 @@ dependencies = [ name = "wasmer-dev-utils" version = "0.8.0" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1416,7 +1416,7 @@ version = "0.8.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", @@ -1440,7 +1440,7 @@ dependencies = [ name = "wasmer-kernel-loader" version = "0.1.0" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", ] @@ -1453,7 +1453,7 @@ dependencies = [ "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.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1505,7 +1505,7 @@ name = "wasmer-runtime-c-api" version = "0.8.0" dependencies = [ "cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime 0.8.0", "wasmer-runtime-core 0.8.0", ] @@ -1523,7 +1523,7 @@ dependencies = [ "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1545,7 +1545,7 @@ dependencies = [ "dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", @@ -1570,7 +1570,7 @@ dependencies = [ "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1599,7 +1599,7 @@ name = "wasmer-win-exception-handler" version = "0.8.0" dependencies = [ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.8.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1714,7 +1714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum llvm-sys 80.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2110cd4daf9cd8e39dd3b933b1a2a2ac7315e91f7c92b3a20beab526c63b5978" "checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" From 0818a0434bdc5c3510a5284c1cd15ed5b5cf1768 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2019 18:45:38 +0000 Subject: [PATCH 073/122] Bump indexmap from 1.2.0 to 1.3.0 Bumps [indexmap](https://github.com/bluss/indexmap) from 1.2.0 to 1.3.0. - [Release notes](https://github.com/bluss/indexmap/releases) - [Commits](https://github.com/bluss/indexmap/compare/1.2.0...1.3.0) Signed-off-by: dependabot-preview[bot] --- Cargo.lock | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 291f229f1..2d433bca9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -505,9 +505,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "indexmap" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1521,7 +1522,7 @@ dependencies = [ "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1705,7 +1706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum goblin 0.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" +"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" "checksum inkwell 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" From 82f258b88850b2ddc829906d405b4faa7c72bff8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 23 Oct 2019 13:40:35 -0700 Subject: [PATCH 074/122] Prepare for 0.9.0 release --- CHANGELOG.md | 9 +++++---- Cargo.toml | 2 +- lib/clif-backend/Cargo.toml | 6 +++--- lib/dev-utils/Cargo.toml | 2 +- lib/emscripten-tests/Cargo.toml | 14 +++++++------- lib/emscripten/Cargo.toml | 4 ++-- lib/llvm-backend/Cargo.toml | 4 ++-- lib/middleware-common-tests/Cargo.toml | 12 ++++++------ lib/middleware-common/Cargo.toml | 4 ++-- lib/runtime-c-api/Cargo.toml | 6 +++--- lib/runtime-core/Cargo.toml | 2 +- lib/runtime/Cargo.toml | 8 ++++---- lib/singlepass-backend/Cargo.toml | 4 ++-- lib/spectests/Cargo.toml | 10 +++++----- lib/wasi-tests/Cargo.toml | 16 ++++++++-------- lib/wasi/Cargo.toml | 4 ++-- lib/win-exception-handler/Cargo.toml | 6 +++--- scripts/update_version_numbers.sh | 4 ++-- src/installer/wasmer.iss | 2 +- 19 files changed, 60 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4a7498a9..b92188fba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ # Changelog -All PRs to the Wasmer repository must add to this file. - -Blocks of changes will separated by version increments. - ## **[Unreleased]** +## 0.9.0 - 2019-10-23 + +Special thanks to @alocquet for their contributions! + +- [#898](https://github.com/wasmerio/wasmer/pull/898) State tracking is now disabled by default in the LLVM backend. It can be enabled with `--track-state`. - [#861](https://github.com/wasmerio/wasmer/pull/861) Add descriptions to `unimplemented!` macro in various places - [#897](https://github.com/wasmerio/wasmer/pull/897) Removes special casing of stdin, stdout, and stderr in WASI. Closing these files now works. Removes `stdin`, `stdout`, and `stderr` from `WasiFS`, replaced by the methods `stdout`, `stdout_mut`, and so on. - [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. diff --git a/Cargo.toml b/Cargo.toml index 4d619059e..5c183b235 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" repository = "https://github.com/wasmerio/wasmer" diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index c940b1b6e..22af9de03 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-clif-backend" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime Cranelift compiler backend" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,7 +9,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } cranelift-native = "0.44.0" cranelift-codegen = "0.44.0" cranelift-entity = "0.44.0" @@ -35,7 +35,7 @@ version = "0.0.7" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["errhandlingapi", "minwindef", "minwinbase", "winnt"] } -wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.8.0" } +wasmer-win-exception-handler = { path = "../win-exception-handler", version = "0.9.0" } [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/dev-utils/Cargo.toml b/lib/dev-utils/Cargo.toml index bb6957b3a..3bb7c6f4f 100644 --- a/lib/dev-utils/Cargo.toml +++ b/lib/dev-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-dev-utils" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime core library" license = "MIT" authors = ["The Wasmer Engineering Team "] diff --git a/lib/emscripten-tests/Cargo.toml b/lib/emscripten-tests/Cargo.toml index 53bf8d2c2..8f2725f57 100644 --- a/lib/emscripten-tests/Cargo.toml +++ b/lib/emscripten-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten-tests" -version = "0.8.0" +version = "0.9.0" description = "Tests for our Emscripten implementation" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,15 +9,15 @@ publish = false build = "build/mod.rs" [dependencies] -wasmer-emscripten = { path = "../emscripten", version = "0.8.0" } -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-emscripten = { path = "../emscripten", version = "0.9.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [dev-dependencies] wabt = "0.9.1" -wasmer-dev-utils = { path = "../dev-utils", version = "0.8.0"} +wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} [build-dependencies] glob = "0.3" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index e55fb221a..d6fff3fbc 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-emscripten" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime emscripten implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -12,7 +12,7 @@ byteorder = "1.3" lazy_static = "1.4" libc = "0.2.60" time = "0.1" -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } [target.'cfg(windows)'.dependencies] rand = "0.7" diff --git a/lib/llvm-backend/Cargo.toml b/lib/llvm-backend/Cargo.toml index 55bd7f399..4cd3e2479 100644 --- a/lib/llvm-backend/Cargo.toml +++ b/lib/llvm-backend/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "wasmer-llvm-backend" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } wasmparser = "0.39.1" smallvec = "0.6" goblin = "0.0.24" diff --git a/lib/middleware-common-tests/Cargo.toml b/lib/middleware-common-tests/Cargo.toml index 48a5c68bd..e27bb4a9c 100644 --- a/lib/middleware-common-tests/Cargo.toml +++ b/lib/middleware-common-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common-tests" -version = "0.8.0" +version = "0.9.0" authors = ["The Wasmer Engineering Team "] edition = "2018" repository = "https://github.com/wasmerio/wasmer" @@ -8,11 +8,11 @@ license = "MIT" publish = false [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-middleware-common = { path = "../middleware-common", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-middleware-common = { path = "../middleware-common", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [features] clif = [] diff --git a/lib/middleware-common/Cargo.toml b/lib/middleware-common/Cargo.toml index 0da56b81d..3d4def870 100644 --- a/lib/middleware-common/Cargo.toml +++ b/lib/middleware-common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-middleware-common" -version = "0.8.0" +version = "0.9.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime common middlewares" license = "MIT" @@ -8,4 +8,4 @@ authors = ["The Wasmer Engineering Team "] edition = "2018" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 5b9bc2634..30df2aed8 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-c-api" -version = "0.8.0" +version = "0.9.0" description = "Wasmer C API library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,12 +17,12 @@ libc = "0.2.60" [dependencies.wasmer-runtime] default-features = false path = "../runtime" -version = "0.8.0" +version = "0.9.0" [dependencies.wasmer-runtime-core] default-features = false path = "../runtime-core" -version = "0.8.0" +version = "0.9.0" [features] default = ["cranelift-backend"] diff --git a/lib/runtime-core/Cargo.toml b/lib/runtime-core/Cargo.toml index 7fd9e32e8..7e8e80c5f 100644 --- a/lib/runtime-core/Cargo.toml +++ b/lib/runtime-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime core library" license = "MIT" authors = ["The Wasmer Engineering Team "] diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 2e42055c2..d2bcb83a7 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,17 +9,17 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } lazy_static = "1.4" memmap = "0.7" [dependencies.wasmer-runtime-core] path = "../runtime-core" -version = "0.8.0" +version = "0.9.0" [dependencies.wasmer-clif-backend] path = "../clif-backend" -version = "0.8.0" +version = "0.9.0" optional = true [dev-dependencies] diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 2e9abacc3..7abd4a158 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-singlepass-backend" -version = "0.8.0" +version = "0.9.0" repository = "https://github.com/wasmerio/wasmer" description = "Wasmer runtime single pass compiler backend" license = "MIT" @@ -9,7 +9,7 @@ edition = "2018" readme = "README.md" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } dynasm = "0.3.2" dynasmrt = "0.3.1" lazy_static = "1.4" diff --git a/lib/spectests/Cargo.toml b/lib/spectests/Cargo.toml index 6f62ab098..88df56329 100644 --- a/lib/spectests/Cargo.toml +++ b/lib/spectests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-spectests" -version = "0.8.0" +version = "0.9.0" description = "Wasmer spectests library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,10 +9,10 @@ edition = "2018" [dependencies] glob = "0.3" -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } [build-dependencies] wabt = "0.9.1" diff --git a/lib/wasi-tests/Cargo.toml b/lib/wasi-tests/Cargo.toml index 580f0303d..96626f6cf 100644 --- a/lib/wasi-tests/Cargo.toml +++ b/lib/wasi-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi-tests" -version = "0.8.0" +version = "0.9.0" description = "Tests for our WASI implementation" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -9,20 +9,20 @@ publish = false build = "build/mod.rs" [dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } -wasmer-runtime = { path = "../runtime", version = "0.8.0" } -wasmer-wasi = { path = "../wasi", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } +wasmer-runtime = { path = "../runtime", version = "0.9.0" } +wasmer-wasi = { path = "../wasi", version = "0.9.0" } # hack to get tests to work -wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8.0", optional = true } -wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8.0", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9.0", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9.0", optional = true } [build-dependencies] glob = "0.3" [dev-dependencies] -wasmer-clif-backend = { path = "../clif-backend", version = "0.8.0" } -wasmer-dev-utils = { path = "../dev-utils", version = "0.8.0"} +wasmer-clif-backend = { path = "../clif-backend", version = "0.9.0" } +wasmer-dev-utils = { path = "../dev-utils", version = "0.9.0"} [features] clif = [] diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index 067894dde..afbba97a3 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-wasi" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime WASI implementation library" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -17,7 +17,7 @@ rand = "0.7" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } [target.'cfg(windows)'.dependencies] winapi = "0.3" diff --git a/lib/win-exception-handler/Cargo.toml b/lib/win-exception-handler/Cargo.toml index 72426f2f4..b3281c511 100644 --- a/lib/win-exception-handler/Cargo.toml +++ b/lib/win-exception-handler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-win-exception-handler" -version = "0.8.0" +version = "0.9.0" description = "Wasmer runtime exception handling for Windows" license = "MIT" authors = ["The Wasmer Engineering Team "] @@ -8,9 +8,9 @@ repository = "https://github.com/wasmerio/wasmer" edition = "2018" [target.'cfg(windows)'.dependencies] -wasmer-runtime-core = { path = "../runtime-core", version = "0.8.0" } +wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } winapi = { version = "0.3.8", features = ["winbase", "errhandlingapi", "minwindef", "minwinbase", "winnt"] } libc = "0.2.60" [build-dependencies] -cmake = "0.1" \ No newline at end of file +cmake = "0.1" diff --git a/scripts/update_version_numbers.sh b/scripts/update_version_numbers.sh index 21b28a916..d93bdefb4 100755 --- a/scripts/update_version_numbers.sh +++ b/scripts/update_version_numbers.sh @@ -1,5 +1,5 @@ -PREVIOUS_VERSION='0.7.0' -NEXT_VERSION='0.8.0' +PREVIOUS_VERSION='0.8.0' +NEXT_VERSION='0.9.0' # quick hack fd Cargo.toml --exec sed -i '' "s/version = \"$PREVIOUS_VERSION\"/version = \"$NEXT_VERSION\"/" diff --git a/src/installer/wasmer.iss b/src/installer/wasmer.iss index a5a24951a..cce60f984 100644 --- a/src/installer/wasmer.iss +++ b/src/installer/wasmer.iss @@ -1,6 +1,6 @@ [Setup] AppName=Wasmer -AppVersion=0.8.0 +AppVersion=0.9.0 DefaultDirName={pf}\Wasmer DefaultGroupName=Wasmer Compression=lzma2 From bc64b4ce6c1a67397f58e85ed102b8077b65a09b Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 23 Oct 2019 16:04:29 -0700 Subject: [PATCH 075/122] Set target triple and datalayout when creating the LLVM module. --- lib/llvm-backend/src/backend.rs | 25 ++----------------------- lib/llvm-backend/src/code.rs | 31 ++++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 0af4d2c4b..f7847f063 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -4,8 +4,7 @@ use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}; use inkwell::{ memory_buffer::MemoryBuffer, module::Module, - targets::{CodeModel, FileType, InitializationConfig, RelocMode, Target, TargetMachine}, - OptimizationLevel, + targets::{FileType, TargetMachine}, }; use libc::c_char; use std::{ @@ -172,28 +171,8 @@ impl LLVMBackend { _intrinsics: Intrinsics, _stackmaps: &StackmapRegistry, _module_info: &ModuleInfo, + target_machine: &TargetMachine, ) -> (Self, LLVMCache) { - Target::initialize_x86(&InitializationConfig { - asm_parser: true, - asm_printer: true, - base: true, - disassembler: true, - info: true, - machine_code: true, - }); - let triple = TargetMachine::get_default_triple().to_string(); - let target = Target::from_triple(&triple).unwrap(); - let target_machine = target - .create_target_machine( - &triple, - &TargetMachine::get_host_cpu_name().to_string(), - &TargetMachine::get_host_cpu_features().to_string(), - OptimizationLevel::Aggressive, - RelocMode::Static, - CodeModel::Large, - ) - .unwrap(); - let memory_buffer = target_machine .write_to_memory_buffer(&module, FileType::Object) .unwrap(); diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index f1ea2caa8..9d928428b 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -3,12 +3,13 @@ use inkwell::{ context::Context, module::{Linkage, Module}, passes::PassManager, + targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, types::{BasicType, BasicTypeEnum, FunctionType, PointerType, VectorType}, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PhiValue, PointerValue, VectorValue, }, - AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, + AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; use smallvec::SmallVec; use std::cell::RefCell; @@ -677,6 +678,7 @@ pub struct LLVMModuleCodeGenerator { module: Module, stackmaps: Rc>, track_state: bool, + target_machine: TargetMachine, } pub struct LLVMFunctionCodeGenerator { @@ -7234,6 +7236,31 @@ impl ModuleCodeGenerator fn new() -> LLVMModuleCodeGenerator { let context = Context::create(); let module = context.create_module("module"); + + Target::initialize_x86(&InitializationConfig { + asm_parser: true, + asm_printer: true, + base: true, + disassembler: true, + info: true, + machine_code: true, + }); + let triple = TargetMachine::get_default_triple().to_string(); + let target = Target::from_triple(&triple).unwrap(); + let target_machine = target + .create_target_machine( + &triple, + &TargetMachine::get_host_cpu_name().to_string(), + &TargetMachine::get_host_cpu_features().to_string(), + OptimizationLevel::Aggressive, + RelocMode::Static, + CodeModel::Large, + ) + .unwrap(); + + module.set_target(&target); + module.set_data_layout(&target_machine.get_target_data().get_data_layout()); + let builder = context.create_builder(); let intrinsics = Intrinsics::declare(&module, &context); @@ -7259,6 +7286,7 @@ impl ModuleCodeGenerator personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), track_state: false, + target_machine: target_machine, } } @@ -7430,6 +7458,7 @@ impl ModuleCodeGenerator self.intrinsics.take().unwrap(), &*stackmaps, module_info, + &self.target_machine, ); Ok((backend, Box::new(cache_gen))) } From 894c5084f3db8a74f8b4a16f7692fa9acafb8319 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 23 Oct 2019 19:21:12 -0700 Subject: [PATCH 076/122] Insert allocas as a contiguous block at the top of the entry block. This minimizes the chance we accidentally get categorized as having a dynamic alloca. --- lib/llvm-backend/src/code.rs | 46 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index f1ea2caa8..2a904a2f9 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -682,6 +682,7 @@ pub struct LLVMModuleCodeGenerator { pub struct LLVMFunctionCodeGenerator { context: Option, builder: Option, + alloca_builder: Option, intrinsics: Option, state: State, function: FunctionValue, @@ -706,12 +707,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Ok(()) } - fn feed_local(&mut self, ty: WpType, n: usize) -> Result<(), CodegenError> { + fn feed_local(&mut self, ty: WpType, count: usize) -> Result<(), CodegenError> { let param_len = self.num_params; - let mut local_idx = 0; - // let (count, ty) = local?; - let count = n; let wasmer_ty = type_to_type(ty)?; let intrinsics = self.intrinsics.as_ref().unwrap(); @@ -726,14 +724,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { }; let builder = self.builder.as_ref().unwrap(); + let alloca_builder = self.alloca_builder.as_ref().unwrap(); - for _ in 0..count { - let alloca = builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); - + for local_idx in 0..count { + let alloca = + alloca_builder.build_alloca(ty, &format!("local{}", param_len + local_idx)); builder.build_store(alloca, default_value); - + if local_idx == 0 { + alloca_builder.position_before( + &alloca + .as_instruction() + .unwrap() + .get_next_instruction() + .unwrap(), + ); + } self.locals.push(alloca); - local_idx += 1; } Ok(()) } @@ -7301,6 +7307,8 @@ impl ModuleCodeGenerator let mut state = State::new(); let entry_block = context.append_basic_block(&function, "entry"); + let alloca_builder = context.create_builder(); + alloca_builder.position_at_end(&entry_block); let return_block = context.append_basic_block(&function, "return"); builder.position_at_end(&return_block); @@ -7322,20 +7330,23 @@ impl ModuleCodeGenerator .skip(1) .enumerate() .map(|(index, param)| { - //let ty = param.get_type(); let real_ty = func_sig.params()[index]; let real_ty_llvm = type_to_llvm(&intrinsics, real_ty); - - let alloca = builder.build_alloca(real_ty_llvm, &format!("local{}", index)); - - //if real_ty_llvm != ty { + let alloca = + alloca_builder.build_alloca(real_ty_llvm, &format!("local{}", index)); builder.build_store( alloca, builder.build_bitcast(param, real_ty_llvm, &state.var_name()), ); - /*} else { - builder.build_store(alloca, param); - }*/ + if index == 0 { + alloca_builder.position_before( + &alloca + .as_instruction() + .unwrap() + .get_next_instruction() + .unwrap(), + ); + } alloca }), ); @@ -7347,6 +7358,7 @@ impl ModuleCodeGenerator state, context: Some(context), builder: Some(builder), + alloca_builder: Some(alloca_builder), intrinsics: Some(intrinsics), function, func_sig: func_sig, From 80cfeb590e33e5a031d6eddd6f6a65ab83cf9082 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 24 Oct 2019 11:50:43 -0700 Subject: [PATCH 077/122] Clean up comments add headers too --- lib/runtime-c-api/src/import/mod.rs | 6 ++++-- lib/runtime-c-api/wasmer.h | 3 +++ lib/runtime-c-api/wasmer.hh | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index 87b6b7447..3ef5a487c 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -100,7 +100,7 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( }; if import.is_null() || import_export_value.is_null() { update_last_error(CApiError { - msg: "pointer to import and import_export_value must not be null".to_string(), + msg: "pointers to import and import_export_value must not be null".to_string(), }); return wasmer_result_t::WASMER_ERROR; } @@ -227,11 +227,13 @@ pub unsafe extern "C" fn wasmer_import_object_get_functions( #[no_mangle] /// Frees the memory acquired in `wasmer_import_object_get_functions` +/// +/// This function does not free the memory in `wasmer_import_object_t`; +/// it only frees memory allocated while querying a `wasmer_import_object_t`. pub unsafe extern "C" fn wasmer_import_object_imports_destroy( imports: *mut wasmer_import_t, imports_len: u32, ) { - // what's our null check policy here? let imports: &[wasmer_import_t] = &*slice::from_raw_parts_mut(imports, imports_len as usize); for import in imports { let _namespace: Vec = Vec::from_raw_parts( diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 582a092c1..57338a5bc 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -494,6 +494,9 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im /** * Frees the memory acquired in `wasmer_import_object_get_functions` + * + * This function does not free the memory in `wasmer_import_object_t`; + * it only frees memory allocated while querying a `wasmer_import_object_t`. */ void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 0dae80aa5..521c6fa6c 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -391,6 +391,9 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im uint32_t tag); /// Frees the memory acquired in `wasmer_import_object_get_functions` +/// +/// This function does not free the memory in `wasmer_import_object_t`; +/// it only frees memory allocated while querying a `wasmer_import_object_t`. void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); /// Creates a new empty import object. From 9c715619272c03e76942c2926e6625ce03499955 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 24 Oct 2019 15:15:53 -0700 Subject: [PATCH 078/122] Rewrite resolve_memory_ptr to use GEPs as much as possible. ptr_to_int and int_to_ptr are not treated the same as type-safe pointer operations. LLVM intentionally performs fewer optimizations to code using the former as compared with the latter. We don't need that in our code, standard pointer optimizations are safe for us. --- lib/llvm-backend/src/code.rs | 131 +++++++++++++++++------------------ 1 file changed, 64 insertions(+), 67 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index f1ea2caa8..63c7d9f6f 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -426,17 +426,9 @@ fn resolve_memory_ptr( ptr_ty: PointerType, value_size: usize, ) -> Result { - // Ignore alignment hint for the time being. - let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false); - let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false); - let var_offset_i32 = state.pop1()?.into_int_value(); - let var_offset = - builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name()); - let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name()); - let end_offset = builder.build_int_add(effective_offset, value_size_v, &state.var_name()); + // Look up the memory base (as pointer) and bounds (as unsigned integer). let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); - - let mem_base_int = match memory_cache { + let (mem_base, mem_bound) = match memory_cache { MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds, @@ -445,66 +437,71 @@ fn resolve_memory_ptr( .build_load(ptr_to_base_ptr, "base") .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); - - let base_as_int = builder.build_ptr_to_int(base, intrinsics.i64_ty, "base_as_int"); - - let base_in_bounds_1 = builder.build_int_compare( - IntPredicate::ULE, - end_offset, - bounds, - "base_in_bounds_1", - ); - let base_in_bounds_2 = builder.build_int_compare( - IntPredicate::ULT, - effective_offset, - end_offset, - "base_in_bounds_2", - ); - let base_in_bounds = - builder.build_and(base_in_bounds_1, base_in_bounds_2, "base_in_bounds"); - - let base_in_bounds = builder - .build_call( - intrinsics.expect_i1, - &[ - base_in_bounds.as_basic_value_enum(), - intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), - ], - "base_in_bounds_expect", - ) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); - - let in_bounds_continue_block = - context.append_basic_block(function, "in_bounds_continue_block"); - let not_in_bounds_block = context.append_basic_block(function, "not_in_bounds_block"); - builder.build_conditional_branch( - base_in_bounds, - &in_bounds_continue_block, - ¬_in_bounds_block, - ); - builder.position_at_end(¬_in_bounds_block); - builder.build_call( - intrinsics.throw_trap, - &[intrinsics.trap_memory_oob], - "throw", - ); - builder.build_unreachable(); - builder.position_at_end(&in_bounds_continue_block); - - base_as_int + (base, bounds) } - MemoryCache::Static { - base_ptr, - bounds: _, - } => builder.build_ptr_to_int(base_ptr, intrinsics.i64_ty, "base_as_int"), + MemoryCache::Static { base_ptr, bounds } => (base_ptr, bounds), }; + let mem_base = builder + .build_bitcast(mem_base, intrinsics.i8_ptr_ty, &state.var_name()) + .into_pointer_value(); - let effective_address_int = - builder.build_int_add(mem_base_int, effective_offset, &state.var_name()); - Ok(builder.build_int_to_ptr(effective_address_int, ptr_ty, &state.var_name())) + // Compute the offset over the memory_base. + let imm_offset = intrinsics.i64_ty.const_int(memarg.offset as u64, false); + let var_offset_i32 = state.pop1()?.into_int_value(); + let var_offset = + builder.build_int_z_extend(var_offset_i32, intrinsics.i64_ty, &state.var_name()); + let effective_offset = builder.build_int_add(var_offset, imm_offset, &state.var_name()); + + if let MemoryCache::Dynamic { .. } = memory_cache { + // If the memory is dynamic, do a bounds check. For static we rely on + // the size being a multiple of the page size and hitting a reserved + // but unreadable memory. + let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false); + let load_offset_end = + builder.build_int_add(effective_offset, value_size_v, &state.var_name()); + + let ptr_in_bounds = builder.build_int_compare( + IntPredicate::ULE, + load_offset_end, + mem_bound, + &state.var_name(), + ); + let ptr_in_bounds = builder + .build_call( + intrinsics.expect_i1, + &[ + ptr_in_bounds.as_basic_value_enum(), + intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), + ], + "ptr_in_bounds_expect", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + + let in_bounds_continue_block = + context.append_basic_block(function, "in_bounds_continue_block"); + let not_in_bounds_block = context.append_basic_block(function, "not_in_bounds_block"); + builder.build_conditional_branch( + ptr_in_bounds, + &in_bounds_continue_block, + ¬_in_bounds_block, + ); + builder.position_at_end(¬_in_bounds_block); + builder.build_call( + intrinsics.throw_trap, + &[intrinsics.trap_memory_oob], + "throw", + ); + builder.build_unreachable(); + builder.position_at_end(&in_bounds_continue_block); + } + + let ptr = unsafe { builder.build_gep(mem_base, &[effective_offset], &state.var_name()) }; + Ok(builder + .build_bitcast(ptr, ptr_ty, &state.var_name()) + .into_pointer_value()) } fn emit_stack_map( From f3d4fde7ef7ac672bb93a45b65631eba122e2211 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 24 Oct 2019 15:21:19 -0700 Subject: [PATCH 079/122] Run `cargo update` to pick up new commit to wasmerio/inkwell llvm8-0 branch. --- Cargo.lock | 331 ++++++++++++++++++++++++++--------------------------- 1 file changed, 165 insertions(+), 166 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d433bca9..582e608d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,10 +23,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -40,22 +40,22 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" -version = "1.1.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -64,7 +64,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -86,11 +86,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -115,10 +114,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -131,7 +130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -141,7 +140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -153,7 +152,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -186,8 +185,8 @@ dependencies = [ "cranelift-codegen-meta 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen-shared 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -243,7 +242,7 @@ dependencies = [ "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -272,8 +271,8 @@ name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -293,7 +292,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -305,7 +304,7 @@ dependencies = [ "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -319,7 +318,7 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -339,7 +338,7 @@ name = "dynasm" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -360,7 +359,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -401,21 +400,21 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -438,7 +437,7 @@ name = "generational-arena" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -455,7 +454,7 @@ name = "getrandom" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -465,7 +464,7 @@ name = "ghost" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -508,16 +507,16 @@ name = "indexmap" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#8f480124663b812ee76cd4370f3ee170135b9d0e" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +528,7 @@ dependencies = [ [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#8f480124663b812ee76cd4370f3ee170135b9d0e" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -542,7 +541,7 @@ name = "inventory" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -552,7 +551,7 @@ name = "inventory-impl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -562,7 +561,7 @@ name = "itertools" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -618,7 +617,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -665,16 +664,16 @@ name = "nix" version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -682,7 +681,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -717,8 +716,8 @@ version = "0.1.0" dependencies = [ "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", ] [[package]] @@ -744,7 +743,7 @@ name = "parking_lot_core" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -764,7 +763,7 @@ version = "0.1.0" [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -772,7 +771,7 @@ name = "proc-macro-error" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -787,7 +786,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -811,7 +810,7 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -831,7 +830,7 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -891,7 +890,7 @@ name = "raw-cpuid" version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -902,7 +901,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -973,7 +972,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1051,18 +1050,18 @@ name = "serde_derive" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1097,7 +1096,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1127,7 +1126,7 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1142,13 +1141,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1161,9 +1160,9 @@ name = "target-lexicon" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1171,7 +1170,7 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1211,7 +1210,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1252,7 +1251,7 @@ name = "typetag-impl" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1299,7 +1298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1330,7 +1329,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "wasmer" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1340,24 +1339,24 @@ dependencies = [ "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-emscripten 0.8.0", - "wasmer-emscripten-tests 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-emscripten 0.9.0", + "wasmer-emscripten-tests 0.9.0", "wasmer-kernel-loader 0.1.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-middleware-common 0.8.0", - "wasmer-middleware-common-tests 0.8.0", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", - "wasmer-wasi 0.8.0", - "wasmer-wasi-tests 0.8.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-middleware-common 0.9.0", + "wasmer-middleware-common-tests 0.9.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", + "wasmer-wasi 0.9.0", + "wasmer-wasi-tests 0.9.0", ] [[package]] name = "wasmer-clif-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1373,9 +1372,9 @@ dependencies = [ "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", - "wasmer-win-exception-handler 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", + "wasmer-win-exception-handler 0.9.0", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1397,44 +1396,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "cranelift-entity 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-dev-utils" -version = "0.8.0" +version = "0.9.0" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-emscripten" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-emscripten-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-emscripten 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-emscripten 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] @@ -1442,12 +1441,12 @@ name = "wasmer-kernel-loader" version = "0.1.0" dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-llvm-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1461,61 +1460,61 @@ dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-runtime-core 0.9.0", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-middleware-common" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-middleware-common-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-middleware-common 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-middleware-common 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-runtime" -version = "0.8.0" +version = "0.9.0" dependencies = [ "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-runtime-c-api" -version = "0.8.0" +version = "0.9.0" dependencies = [ "cbindgen 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-runtime-core" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", "digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1534,13 +1533,13 @@ dependencies = [ "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-singlepass-backend" -version = "0.8.0" +version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1549,26 +1548,26 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", ] [[package]] name = "wasmer-spectests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", ] [[package]] name = "wasmer-wasi" -version = "0.8.0" +version = "0.9.0" dependencies = [ - "bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1577,37 +1576,37 @@ dependencies = [ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmer-wasi-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-clif-backend 0.8.0", - "wasmer-dev-utils 0.8.0", - "wasmer-llvm-backend 0.8.0", - "wasmer-runtime 0.8.0", - "wasmer-runtime-core 0.8.0", - "wasmer-singlepass-backend 0.8.0", - "wasmer-wasi 0.8.0", + "wasmer-clif-backend 0.9.0", + "wasmer-dev-utils 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", + "wasmer-wasi 0.9.0", ] [[package]] name = "wasmer-win-exception-handler" -version = "0.8.0" +version = "0.9.0" dependencies = [ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasmer-runtime-core 0.8.0", + "wasmer-runtime-core 0.9.0", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasmparser" -version = "0.39.1" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1651,20 +1650,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum bincode 1.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9f04a5e50dc80b3d5d35320889053637d15011aed5e66b66b37ae798c65da6f7" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ab639324e3ee8774d296864fbc0dbbb256cf1a41c490b94cba90c082915f92" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9daec6140ab4dcd38c3dd57e580b59a621172a526ac79f1527af760a55afeafd" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" @@ -1683,17 +1682,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37519ccdfd73a75821cac9319d4fce15a81b9fcf75f951df5b9988aa3a0af87d" "checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" -"checksum ctor 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5b6b2f4752cc29efbfd03474c532ce8f916f2d44ec5bb8c21f93bc76e5365528" +"checksum ctor 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" "checksum digest 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" "checksum dynasm 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f36d49ab6f8ecc642d2c6ee10fda04ba68003ef0277300866745cdde160e6b40" "checksum dynasmrt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c408a211e7f5762829f5e46bdff0c14bc3b1517a21a4bb781c716bf88b0c68" -"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7798e7da2d4cb0d6d6fc467e8d6b5bf247e9e989f786dde1732d79899c32bb10" "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" @@ -1725,7 +1724,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" "checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b2e0b4f3320ed72aaedb9a5ac838690a8047c7b275da22711fddff4f8a14229" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" @@ -1733,10 +1732,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "aeccfe4d5d8ea175d5f0e4a2ad0637e0f4121d63bd99d356fb1f39ab2e7c6097" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" @@ -1758,7 +1757,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" @@ -1769,7 +1768,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d733da87e79faaac25616e33d26299a41143fd4cd42746cbb0e91d8feea243fd" "checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" "checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" @@ -1779,7 +1778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7975cb2c6f37d77b190bc5004a2bb015971464756fde9514651a525ada2a741a" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" @@ -1805,7 +1804,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" "checksum wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0cf2f552a9c1fda0555087170424bd8fedc63a079a97bb5638a4ef9b0d9656aa" "checksum wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0073b512e1af5948d34be7944b74c747bbe735ccff2e2f28c26ed4c90725de8e" -"checksum wasmparser 0.39.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a026c1436af49d5537c7561c7474f81f7a754e36445fe52e6e88795a9747291c" +"checksum wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e5083b449454f7de0b15f131eee17de54b5a71dcb9adcf11df2b2f78fad0cd82" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" From a52246bb9dd451cb196b440ff0fa9f60104998d4 Mon Sep 17 00:00:00 2001 From: Maxwell Anderson Date: Thu, 24 Oct 2019 21:54:30 -0400 Subject: [PATCH 080/122] fix README grammar --- lib/runtime/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/runtime/README.md b/lib/runtime/README.md index 769e4cdb6..ce18500bf 100644 --- a/lib/runtime/README.md +++ b/lib/runtime/README.md @@ -94,8 +94,8 @@ fn main() -> error::Result<()> { ## Additional Notes -The `wasmer-runtime` crate is build to support multiple compiler -backends. We support have a [Cranelift] backend in the +The `wasmer-runtime` crate is built to support multiple compiler +backends. We support having a [Cranelift] backend in the [`wasmer-clif-backend`] crate, a [LLVM] backend in the [`wasmer-llvm-backend`] crate, and the [Singlepass] backend in the [`wasmer-singlepass-backend`] crate. Currently, the Cranelift backend From dae99497ee0af642866fd6e5579dd7e8c29d0adf Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 25 Oct 2019 13:15:32 -0700 Subject: [PATCH 081/122] Add changelog entry. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b92188fba..4331aa7f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## **[Unreleased]** +- [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. + ## 0.9.0 - 2019-10-23 Special thanks to @alocquet for their contributions! From 2a532b8ce5cc3be69f62fb66916ee57fb03faa2b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 25 Oct 2019 14:24:22 -0700 Subject: [PATCH 082/122] Add tests for C API import_object and WASI updates --- Makefile | 2 + lib/runtime-c-api/src/import/mod.rs | 34 ++- lib/runtime-c-api/tests/CMakeLists.txt | 10 + lib/runtime-c-api/tests/assets/README.md | 3 + .../tests/assets/extended_wasi.rs | 31 +++ .../tests/assets/extended_wasi.wasm | Bin 0 -> 77757 bytes lib/runtime-c-api/tests/test-exports.c | 2 +- lib/runtime-c-api/tests/test-import-object | Bin 0 -> 14932 bytes lib/runtime-c-api/tests/test-import-object.c | 172 ++++++++++++ .../tests/test-wasi-import-object | Bin 0 -> 19508 bytes .../tests/test-wasi-import-object.c | 258 ++++++++++++++++++ lib/runtime-c-api/wasmer.h | 10 +- lib/runtime-c-api/wasmer.hh | 8 +- 13 files changed, 524 insertions(+), 6 deletions(-) create mode 100644 lib/runtime-c-api/tests/assets/README.md create mode 100644 lib/runtime-c-api/tests/assets/extended_wasi.rs create mode 100755 lib/runtime-c-api/tests/assets/extended_wasi.wasm create mode 100755 lib/runtime-c-api/tests/test-import-object create mode 100644 lib/runtime-c-api/tests/test-import-object.c create mode 100755 lib/runtime-c-api/tests/test-wasi-import-object create mode 100644 lib/runtime-c-api/tests/test-wasi-import-object.c diff --git a/Makefile b/Makefile index 58b85dbb1..0f3560e67 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,8 @@ capi: test-capi: capi cargo test -p wasmer-runtime-c-api --release +capi-test: test-capi + test-rest: cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index 3ef5a487c..ad0470af6 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -170,7 +170,35 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( } #[no_mangle] -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function +/// Get the number of functions that an import object contains. +/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. +/// This function returns -1 on error. +pub unsafe extern "C" fn wasmer_import_object_get_num_functions( + import_object: *const wasmer_import_object_t, +) -> i32 { + if import_object.is_null() { + update_last_error(CApiError { + msg: "import_object must not be null".to_owned(), + }); + return -1; + } + let import_object: &ImportObject = &*(import_object as *const ImportObject); + import_object + .clone_ref() + .into_iter() + .filter(|(_, _, e)| { + if let Export::Function { .. } = e { + true + } else { + false + } + }) + .count() as i32 +} + +#[no_mangle] +/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. +/// This function return -1 on error. pub unsafe extern "C" fn wasmer_import_object_get_functions( import_object: *const wasmer_import_object_t, imports: *mut wasmer_import_t, @@ -178,11 +206,11 @@ pub unsafe extern "C" fn wasmer_import_object_get_functions( ) -> i32 { if import_object.is_null() || imports.is_null() { update_last_error(CApiError { - msg: format!("import_object and imports must not be null"), + msg: "import_object and imports must not be null".to_owned(), }); return -1; } - let import_object: &mut ImportObject = &mut *(import_object as *mut ImportObject); + let import_object: &ImportObject = &*(import_object as *const ImportObject); let mut i = 0; for (namespace, name, export) in import_object.clone_ref().into_iter() { diff --git a/lib/runtime-c-api/tests/CMakeLists.txt b/lib/runtime-c-api/tests/CMakeLists.txt index 7db3cbcb0..d8f206c49 100644 --- a/lib/runtime-c-api/tests/CMakeLists.txt +++ b/lib/runtime-c-api/tests/CMakeLists.txt @@ -6,6 +6,8 @@ add_executable(test-exports test-exports.c) add_executable(test-globals test-globals.c) add_executable(test-import-function test-import-function.c) add_executable(test-imports test-imports.c) +add_executable(test-import-object test-import-object.c) +add_executable(test-wasi-import-object test-wasi-import-object.c) add_executable(test-instantiate test-instantiate.c) add_executable(test-memory test-memory.c) add_executable(test-module test-module.c) @@ -58,6 +60,14 @@ target_link_libraries(test-imports general ${WASMER_LIB}) target_compile_options(test-imports PRIVATE ${COMPILER_OPTIONS}) add_test(test-imports test-imports) +target_link_libraries(test-import-object general ${WASMER_LIB}) +target_compile_options(test-import-object PRIVATE ${COMPILER_OPTIONS}) +add_test(test-import-object test-import-object) + +target_link_libraries(test-wasi-import-object general ${WASMER_LIB}) +target_compile_options(test-wasi-import-object PRIVATE ${COMPILER_OPTIONS}) +add_test(test-wasi-import-object test-wasi-import-object) + target_link_libraries(test-instantiate general ${WASMER_LIB}) target_compile_options(test-instantiate PRIVATE ${COMPILER_OPTIONS}) add_test(test-instantiate test-instantiate) diff --git a/lib/runtime-c-api/tests/assets/README.md b/lib/runtime-c-api/tests/assets/README.md new file mode 100644 index 000000000..52e92c052 --- /dev/null +++ b/lib/runtime-c-api/tests/assets/README.md @@ -0,0 +1,3 @@ +These are used in tests in the parent directory. + +To keep the generated wasm small, use `wasm-opt` and `wasm-strip` from wabt-tools (can be installed via wapm). Addtionally, consider passing the `-C opt-level=z` flag to `rustc` to optimize for size. diff --git a/lib/runtime-c-api/tests/assets/extended_wasi.rs b/lib/runtime-c-api/tests/assets/extended_wasi.rs new file mode 100644 index 000000000..31c659f8e --- /dev/null +++ b/lib/runtime-c-api/tests/assets/extended_wasi.rs @@ -0,0 +1,31 @@ +extern "C" { + fn host_print(ptr: u32, len: u32); +} + +fn main() { + let args = std::env::args().collect::>(); + + println!("Found {} args on program {}", args.len(), args[0]); + + let env_vars = std::env::vars() + .map(|(arg, val)| format!("{}={}", arg, val)) + .collect::>(); + let env_var_list = env_vars.join(", "); + + println!("Found {} env vars: {}", env_vars.len(), env_var_list); + + let dirs_in_root = std::fs::read_dir("/") + .unwrap() + .map(|e| e.map(|inner| format!("{:?}", inner))) + .collect::, _>>() + .unwrap(); + + println!( + "Found {} pre opened dirs: {}", + dirs_in_root.len(), + dirs_in_root.join(", ") + ); + + const HOST_STR: &str = "This string came from a WASI module"; + unsafe { host_print(HOST_STR.as_ptr() as u32, HOST_STR.len() as u32) }; +} diff --git a/lib/runtime-c-api/tests/assets/extended_wasi.wasm b/lib/runtime-c-api/tests/assets/extended_wasi.wasm new file mode 100755 index 0000000000000000000000000000000000000000..b8eedd722160b2f70e0b4215d5e71f44ab5cc207 GIT binary patch literal 77757 zcmd?Se}E=eS?61)s@@;n_4Z6n7@(OMNWCwkbYzAM3Ypn}rq3*yWC$_H<=$moy&*`1 zbVJDeFvPu(?vMcj1QIkzlqiD)iJGuMvl`bREoL>YxSQ3e(TylQR%v)8b&d=vOzt3|{B^ModZAg+Nd?-BS6#LVAy?VXDB{7$#D+q9xG z>WZ~C?nGEhzmU$%y#AsCmt6QGmmWBH(JNka@wy*=<%O5+znF)E7ryG^gGsvj^%Evu zzw(m(7hZbNYcEdvtMhEQ_|nTS+5fsrFFbI`zrXmvTD25Sjx}0XchUY=9XNT>zP+|` z8MREm`gI2m(&0-kJ(zS>ccV{Nf9N%@J8*H*JMqQq_g`}G;$&*|i)l*izxbk8GO%QN z^{c7NE;{(?3txBH#g`_<@o)CO?uRbC_=-yoCSmoP8LIo?SB@c>y*s@wO}eKfr*yj^ zf5OIIFFdgm_^;FLgbx3ml7^6^Icc448q%pWSx7c?pOP(wxV*fQ6iZ3`lLoIdxOaPD(|^xwZX{f=`!9QOQdxHY^fYgDb(JRj0^!%gYFT%gQBW(QXu<3^M-`yOp3Rf;IhwpgxrnvXj-~YbwqVK&a zyzqjTeBTdzF#KOH{qgXV;r-#fp9=rxUE#WLeRy~HvGB705N;38`)K&3@ZD#=VE$ik zdewgm|2=HFF?}$6I{dHj=i#rzrsr?^a(E;xr<>lFUX{Kny*mBL^rzD4ul{3pUHX|c z^4o=&oS7tgQ+`4}cZQj~r~;)%VI~xXnn6OOsJJdnUv~ z%m!K0gE3bdXQcLWpyqg=*n4HB?Zlf)$V`jmY+hEO%+8)ki}*W9`5PfAEZuTg)7C7* z%e~=&HEeBqE7lty-+r=a1Rc88R;TxaP34mr4C9UE!q#McVZ$6}3D)qxOH;UU71UuM z1>{CyAuiF|DlG0BWmUdc5LMT5s>p7u(%Y^ab#_NQn6`8w7e7^K$11$YjO1E^4OtWtrGN%ku|- ztecd7$mL%LSob`zS$bivDGRDD3{zFdd{Q0rkWN&Ww$<5tRrRYOWWuv*ag=RMeC7oS z0J2!60ss(R7^PL%3p}&kS1m6umpilBDvSLEer6Xc5bofJT*`Ug=22d*t1{-m8rNNa z6k>Aj3=lC?9CZW+@|HW*Q6X2=i2=0ORq$>mF#Nm*CH)2PvGPe&8THu)|Lb38$FHU1 zE6KN@=Y!Wofc5ot{*=T(Av9w6kYG{#D-ld~fs%w!!X&3Js8DYffrZklYyoszU&K2Y zPI*7z_~$guL1ZRzM>~nBBbQ?@$hkZ0OcO`5!D~i&geC`<-nKiva?}%I0`!ckbE@8| zyED?Nnc!-n>V3F;j!mQ{C-ce8%MIj!G{6L<J1i#G^S#+qweCcqr0-|E)2VLF|J%y4-9+-;O&*xP``YlD%|Gv&JDYIVmxzV5(?iuNT3!L+pL1be;#WSH(XXRllRnvtH3B3>>Ue9Iy z!ghNUt17;2RbHwfx2hD-%2_U!D@#K0qu%m7Y@1r4ch7bNz=$6~P>iA6Vny0<=jG3k zbC@zcfTD~+0>lOzAmun${%+V56K5e*dRn@1XNq(HH-&y7&M(r(9c>>|T22M32CjK| zHGQtq)3Uz6n0j~D`KZ-Yxv?l-;VcKyM$fZ(`obvt@E9(GJ>vTm90<*;l;Mjh(l(W* zIlbXdY!Q;%Xp=^Jr=<|KrPyfc;+I3(TS{x1aQJKmy?D(i^Zi3`9Ii5?vN*Re?3}C< zv(|~+x>GmO;bG%~%}U!T*r9dQ#Ga<8>Zsp6hnXFtvCV)1$-^rmT5^{Vp*MdK<$Yo9=R< zJcCJP98AY^QW+(VpX2!~*V`lls6J&lUPvsM!ShiDpQU!X*{{u(B94EkXQW$(GX?rt%g6} zPEQ)|Nt#Jd^$HoNRuF$8vl=%TuHBW{ym|(PS&QWxRA*&6QQWm4D1mj1+FDa>)y`~( z@*pa8$u&(Hf)`i6t<&>xZaUqmV6Ale>5Pn8=)vGM8VVKdP>*v_BMERY?{20yJ-5ratwJF__wKbb5{ks;*`(QD!9~i7*gDyU@4T-U0{fJM$J1t(wP|dWAsVSyd zeazvg74|%A2=E`Ne_~tWS`^-7V#h=hb>*hsPE&cgReZhpX*>rmac&Q0-2!%D)&IkF zSym`l!(ab++{; zN1=QY+_;`U?^o0EJx$AXkEC?ZuWsFHvtDyo_io%Hb#1enxdO3{Vs3rp7ZAE0$31yG zy-k6>yszJ-qL_<&%uL>;eBhc*uW*dN)6y4=IucCG@EPf?YJt+74}%*|;=V;k19c7P zKdAx;T`d3?@7oc6n|3(<7eT(iHCS2w&_lv{E~j&0N{ z79|AGomAf!R5_YV_A)M*ZZ9JBh!r{4a)`7myMr@|1E|>Dy4_*7LY6s_%7yqK#mYZp z;K%ULIoYj1cCJNf;Aq3H(@H&_OXr5UC@SM0oI$*-d@~$F)Rx6m+PRq1u*XXp#PZrI z2pAEfQJLaW^>$`-39BY%vM=)TnE-}VoIpwK?WkmTeouM@s*F|S)o>4-@1Q-6`ev^2 zVH@^g-47tP)PLr8Fl={YJ1Y|8Jfl`1d7=*TAN zx+2u96>(SLA-1ifV2trZeSE9*@!~r{Il4(ssqE=_GfApRKz&KC#^;+O3|ge%Tm<^Z@}BWtNwcfQ_h&2{Whs5F%jtdz{QmfCUc2&xs2TdtAKatiqKb96})mD;_fob0e zNKHd1dz)$;F&Ng^Bumz_Vs|KqAZKXUjl z9%MZu+5P3We(JBUdfRyWf5NpMAR?j(+45Z+`FlK6K57;=XP= zJ;pgX4VNO7$CY=jBHPpGp3(G{b(|@B-5N+h_Lj(BNwb^Bn={i z;}55~%r6cL5P=uZ0a3W@81{A91{5<%dFAD@gBG~VabY%@w{7@TbD@;|U0Gl2XSiZ6 zrZioCE}$PQFW;R&&d|HsH&4{IQKAf)+)ZdB)ErZo;!@SwmL#LDd0XLokOL?$1*vkt z4?{E;n+oDGRl%yWJqhuweZ^=%iBtEDregQtelJW-pT?b)Y?`d1(^Mg&O)j;$Du|C# zMKw@ac*s;7SRKc3$pUJ;r+f0Hn9z6Yaowz!nTn?zWQ@m>ec%Vh_ZOoizMh)n)8t8$ z6yGx=DeG|P7##3POQ9&n5aJQG1|z>N<%LZ}KA6_*^v<4{qT&7-=@w>#F+blgI1J-m zKPe%{^eBBBmpd$hiHZX`8hiL9nAtu<)y$GyF?+l0ZVPvnP*$qy+vHd&3U~}Z4<%X% z(NGuHJ&i@OB&_jYsE*F^;I`ekf|u`24xvYUiB*D4F~A3t z@*yp8kdp%NoV5xR!VFIjL@{tZ_ER?SGmSXcwSHHt}6p>)j@Kc69; z&0%#6l>@56*N*%@mkW|mK)oCK0y^p}!xv;w=HCXjF|)uC;aw9CZ{`yJ`_7&LmA5AwBv3%L zT_c*DOP?>H%k{d<^#|GpbZf7bjzF}bTA%e z5Lz}XKNCA2y?(w|=ZW8RKc7{!Sry2r<-}1P~&qi(dLClHFN6Ch1q@ zMUfc)ruVV9Hgi1_Unm;cYEE^sC%4GJ{taoCce=g))O0bJS+~C2fLE9vg?P`;tR!)! zd}lh?;0ZSzCZVr{(i09Tp;Q6_M@7E$eiAk)VVx%&Rl<5D%y_~dwmAl#@HVKa4Y`D**fqx5cSHjXt z%9mltzzWj9gYTxkw7gcD7CQGA^eEM8un>=NU;Y(MNOv5RZwqH8r^e+Ut23Os5btj? zNM*A;?_{A>8Kh%Z3-Ma+siFMmfZ!v;R-roA3Nb&>@}74`FI7c|AJFK!)*D_*^DDik zwpsdk3z?{O6CDHB>kKy;T*yp@JKGG@YK@B!$c;!lGw}j6_6IgrK|BmPJlZWTlXIiuNtdh`SBDvIn9(}4Nu%lk}TjjRggyC85=4Xww(o|;({ zd6=3cLByDrP-UIRmS1aUb*I-zh7)wJXD1XT`B0;Gy{EbPhk(}8(CHUKG2t9R)sk~$ z{Q5m<@ysLwMtPZ9Ot3Y1el!(awbFw%M8xg6wb;acv6;c;EIWoV)CS^Idq z|IDN-aK!HAZ2~$d34_by`hD?;a^x|S44W(jGLh$$%i}T2aC{YBCsj0!bYd>#qL8XH z?S8U4Z<0Qox({o|noNtKU=IJ(q;Z#vL!SpzBzb$%cjKWpJHR3wBQm&zq2yoNs|3S0 zoe*SL?N#c#dr6iEy^|bHjfSgG{8LTEKsT)BsWtu}N2Hq5E0}ybA2lw48ZEm&GMR)` z;&*WiDy^-fix^ou`m-NjN#>H|j6?&3O8$W7(~@MTJ+p%FUnZYF(LTgMv%HU@v->8k zMdJxTcv>Iox9LpR?zG0u8*C8_IW$@pDS29S%Q=UIm?^gY9EA!vx?^Y))8TrKNiOjO z6Vb*b<2ttqZ!{GG#^ft#jQjLt=6T5!Ln*{KY$cM4m=lVdjRRW)NFb9zLOmOIk?xm& zs=n5%lK=lg?DPM{5&K`V-jo5GwXN@waM{v~~qbg%5t6pYw4Vx%!;ytD611UEud+(lw~?~O<8#n z?|;h*Y7)8NFZW-ASeBpi(dey%M8=WwZ(LicniV2R5#v%ukj?4?^TqQCYn1X4RRav~|#ud2;lz>UX`@j6cNB^QLH-bh~&|YR3l#Vil zo+oq1D;t4(6L}y-W274Ss?sx)r`t%9@_&YrRy0VHoh%ZplJYNuhB1qmipv&gbwh^t zi>_m8jr}v zFf%y^V;4YGA{ni}30_L!N;8gnpH}7pInb zBJ&t9i*aFL8^Pt-yl@mqz75LcJqQ!;^a&s0nCFguPVW(aR}K$0Whi)cX(24m!c{vfSX@dhr|3a?nb7*_43w)RfkRTQHT4!%Pc!1g?LtDM-8)JYOO((u zfq5;JY;PfM{u~Ltf!fqclKdC(&YS3Bf(iN&XzB;Z-Gbe;Py-&-(zjt?d?q$PFeawX zSYryW3{%Sg6U3rhbmF+t|C)U6;}{>CT{&LNmz2dV5>Ke(LaX>xJ#d%OMUWOnP|7=t z9wbRaP!9~xxwgx{LUlmnn64ZK9fwryU*~lzTdf1Zsl~&SM3$=@*tBo>_|tG@bsaGW z81WhjT`X(77CsEpO^Kk)jU=qGeyaoj7%YRFMg%6pW+*huH>&`-ZMmb$Hy2EtIg{kx zyc(Q2}gv8)Djqcg=!t3eaOr#I84j2d4hM)U5Il zZfvyzW?t&nz*RhvmOPEps?^H8uwILQJXVvyKv^!d+)f5nnblOBn`l@VU_@*`rsS;$ z4#cqoQGe(v{~K8sPix1L)MKIH@j#xyK*Szeg1`sxv2@bZZ@|m6a@!ccsiXw(e>59- z9UN?x4LoBB6E^VRL>rixHVQR1usjH>s_;4|Y~UHUfdx30$hZ)g1&v}7UZ|%&ZbOF% z4Ahi6OEt~9UmMS@J?;IQFqj81Ek;(8m7)O))2jKpmg$Tyv$)#WwvinXKu_G)I)hyI zt}Rxed8Kc-w-Ck zDvkY%n+o0|13Kcac8z4MYlPSmt;jx3*T|z2ITJW`jfgkmR}01C>6P2H|B}5@JaG*g zpaN;>K@_(-m{cHx8lZv+XPhFHu1^UmHV$I&m4zxe8_!N%0jbwcjW;0)TsR^2$j7}m z4i!M*CtXi{UyfenBDA)?jkS-uVsV){XGEF$L&<<@&P-;scsD?yL$X@!8We6FtOoPv zC@(lk3=We+S1>1FDQ2|8o3xY(ufZ^(z=8&Q?$$>DLjNV z)$dWDbK%gV-Hh$QqL9kwLDj>%u?KK?8bW~ zrqhsz%rrFcjJ}7*tF>hsMFquEopC|=f;Hl} zRR)de;+HBR*%a^7df-#z-CWd_QU?J4$UM-NN4l;Pgc#K4kgTg@lj* z1qbM^4u8{a9sZ_U4}Sxb7UEYZR=!S1%fLrQg6OI>-ZRh53Iuph!6O!+bUJk?e-4y_ z`42gV2#C5G417T*oGg@CboFh3_=J@=#BN%g&n$nMbsutbt`vZ zO~rJX_m2g)mYmx1<7?8NHm7pRkPrBgJ+(PzT9WKm-Znf!%URu$tmE zp#OF(#b9?vGUYQ$_N!hk*Gc%vg8^GWI zg7C;9Mj=VDglw+{b?*Kd1woiggL!w2T)>5MFn#TgLYqnusUjQ*M5egAg=9OZYM&Cq z-WZpP!pwwJK2f6%!owtYWxGl`L#o3CWozfAipbRvaf`*ES5g%^2qk4;jgOAx<*t!- z50k-$sKl{B5Fc(tpicmlVti0hezvi+UgH#-5pTn?PG|?F%wST0q(8u%%0I-UFQUQV zCA;CBfPYIo#HC@4>;n^{7J$q#1hx6mx2m}>f(q>c6eResvrcN;|Y602<(J8@aWzCs8jxD;@WbcN)0*mNh3@hfmRuE zPr8kv2zrxf*T%fGXGW`=$Zcl4@m3>&WFcy@ZCf%+AK-xLF~khqHk#U9y``EuG@K&5 z#+E|xvJ5p~*goCW-Hzr?JyyqofI2?E=pDa;B$y1lIVuu}n-)%Rr#%l|g*G}+FdjAN zsqFg3ohu&iZeInBovW(AFUb}GC0_F`=lj|_ZQvGlGMYLXN5ird0`5c|U7#eiM+j6? z-vc8CLDU&JVk(A8sIq$I0j&SL3bh63_;dr4BCtXvrsKD6UTIc|O_#Zg=hJ+Z*w)YP zn0y9F-xqVozF@F$-c6+TcOG?ylaUzM6m0IGRT!^y%gDmwDuPsDLEoIs@VjGzW z8)uakwVO7It;S=FP3zXHZhj+A2W|91A9ai9D1c`v90i9v=)6T+DuqKX4oKs zuhVO64dQ#93jJocg51)z(BLAIi~vn_T8=1q@qUc+46Kq1QDzXr$s5Ehq=FeO6V$Zq!Yw zYZfVka;OoMo|%Bn*|F%sNV=oZyyw(m$eDqdU;rit&&4?VT7@F>+U4@iwWWz%#w{i2 z$DuJV_bp)Ve-YMMGYK>IkMdkIFY$-?z~r;U-{kWr+lQJx;SYu;C(M0tl54e zaeRD=%>YoGj8DlXnHP(t8WI_%pO*v%ok_3_#@wy3)g>oEA8}?7#8`aRa5)Wp6?3y* zDdi7y*Iwq~1r8-asuEn#QR?j&Xz#xIB)gbl3GhkzPG+tZW+}E-Wb%;k+WNDNSGN<+ zXA7rsgHOGHELkQ%$mb)hP+ih(RTm=uZ7HG^G#J#OfAZtY!Q8gb2+1p(g}6W>>R28_ zi~9NNR&W!=C)t*sRxQ;?*8bD@;KxLkhIDmk=_yFjPY~%xZ6(^{h9Z8{pEmGR7V-W5 zbP7*sPuGoet}EhKueWk~M?}Ukf12TGP{hyjM6_u9eNTNNsXTqcpD;28#Pi-Ze%CMJ zjpL_Y5wG&6CzF#X-+%D&4tOFM_ly2C#S=jmpY^9{o^X5pzCWowyhR`9sbFa9=jK%-QfHmN1;w5dX!n!wse$&V&V(}dgddy2oy z)Ag+^#i=L*3FBqW$ytK^TPTly*tDesayFT#Z{#P;l=VR#WplucUZNJ7fM(T9YJNWK zM_Yad(@^UWpjp)~%o0NI5Um24O!4Ypjfm?97HoF#lWNS#8HR+*8EF8sO-gGf#BmJnb|d)OjYi$x(;p?ez!y9L zvNS4(GTcEufC;$xHBn8XcTjliKFi|MQ1*%9w^~E=`T-oW*IcPH`6@1VQu&&QUM3_d z?C|T6l{K+30ukHsf)LYWLJ(r(f8By`uv!pKL5MEFXOi8&d)?1}@S}IW`M=$|ROF-< zPvWHkr5+GafQcVZ!Dm^5K;MkI_*#mm#`bZrUY$eI7I_ChDF35WQ`cFz6KR@~Dm?}D z)%{SlpiXbApy}!@hj5Pz2XkO95d>b5fEuZUO3-Ec9=iwubg_1Yfau3(xoL; zFe`MZ)5Eu?SK998QGa*9bF=$R%V9SHc6&0nc{H{AH{Z0J9;#4vw=*~Ulnw|WCOEeRrQPHVs# z?zRuR*nHAFNCA8q`>(|L7Z&?z%DGn4$%8Yif&TkcXzD>Ylcs&ME}I6JL$# zua2^+-kD2?9o5R6qBJ2y5;kIObWTh9$RjSvkSe{|P!-k*8C45pADJ;=G7L&TPaZZo zx@?;nW5b*I5=^=t&7vRO_kk50kMV9U=K1Qz!}yu^%&>tFVHlsqoi@*y*U(^2K%hGU zw+I@nEiE;@hUxql+u)HcC{h7khAvurP-Q(`QnzkWlh25UeztA$1J>kp)jgdiKcYQ? z)96>wB@&qM;TigG;Fs2A-dKQbc8BqM+h|proGG$j7HQMSwe`4K3zc<7Xn5>gY>acW z0~NYxWQ$gcij^?iI_r+Mj8+rK)~pE<=3282ls5Arfg?0t9MIk^Ql_JMi+MNgM1ZU* zxI;BT4jU#_2zedLhx|8Vq4;uIJ9Z(1`nbK?H=r}iNR%dmKnAg7>6>Ff>;b)nrwf#H zo^xtkaGJ=|&l$S@1ZTos7r|DsL|*I}^*0Yg)n}Y3o(Ifrz&~p3vHv&wg;=mz_39XpfH!Y=IlS#%mYJ=1$IsAqCL*-UVjE-Vy5ceR^_cuA}o*D zK4htAS3HuRM)%O|qlVP0;VL75yTVT+-leXv-^PzNMD^wo5eYpw?$pFCTCQVf6k`J(b+T(!!@P`E@oy`r=5~%cP?sTG_PEx6zW!+fE63a zh42H-wqd{fzS~_Q$4o=*n`~x!G!t*v7BEPH%H(e~&n!UH25w-hfC_wl&g!qd6DqSX zaUZtW2ju}mtHx@vpyRcbBetJt`nVtzMLv#ko!daVMhh0(v!UBo4u$J#yGAoI-HuQS zG%`7cH|eF1tZU;#erV6)^s#~UC_u+*g^6uiW1R~*3hx_&R6S*ap`_ecBS%Yp6JUoxR?f(wTnhF8?MC%dt-m> zguRhr-`#j&O@66Wnd-9!Dq$-0W84k;>XLlt z(G{UB(Hh1cxGbVv)Q)4^O2AZDFKwSyvBdWth8#TauCscLG1bb=?9#RK2r1O-386NrZ71hKV)~Do7#-A7L2R+l1GI z+gpf_kP*9iXTn6qhuepmzyUMVvHLm}y^k@oq7>2gnEX*&Ph9jizb8aDx%)DEl--xm zB%Q4{beho9Mr!Z0DYs&rHn02$DH@GKw_UV53T=MOHlQ)`5GhPV7Y8IlEU8 zE6;dra|f6s#Zkh^Emj9q4G?2?4U|C6lbsCdUOS|ZaRjY@N)CxOpo}^W)bOd@5&MT7 zAF|>=O)ANj*D7r-(?nT3w=xbgu4Np%JbWMJU0@mBB4={(J|C?EOb^C8E)&omXa)_E z?P3GI=-cn&{ay+X>ds?e>sKme$b!lrkNAVRsMzL5ar28>sF@sWLSJ*cWq{0lTsrPY zHB}-AISD}tiDYl6Zr5278mOm=q0+VTJwc0*3KDw!ZApahP(Ns^{E3$9O+*DthgBZi zSZ08zWh;mBn7Zr2Rq7Y>*o62Pu<9PM7WQ@Y$OG~Og2(I>haYLT8}8{L0PxuzSH)=H%5YtX`k5^1V>ZE!DVZQLy^P=IscWy<|GD7>!0@kvdOBD_R2k4Jbh zL60K5r0kp!vGw%|FCA;v3NKb`!Td?#rAhrpg_qXIC9l^OK2*E|5-F|=>G)X}7@ilnGvR}_!^%a) z6Kf;*D{P5`Tw>Fr`0|j*a+gRI7J!(24i?Eg{Ds>c*ea%yb1_GXe0FAmX)OqfyDrv#{7RYReqcrpyQ_P^Eip9|$+HF*AE-15m*|@rL)94q?ib>>c=T z`2o18XxXF8YA;`SJR4zz?yAMY!PN>+aN$h7H2*D=s7YptU(*Q>XF-QvS`w~R6=Aw< z$<$wFFZdd`kqj_!t?mfjYNFW7dw+yuQs04YU>6@LqcT*kX29ZfoG@VTOB{hlJ&noQN zyq*Qb#y+V|129NFJ0>ur@1rE22TByptvvR5Vp?!T`?^O{hoWl?W^T&;f|@o~xC&VJ zjEt^Ck>e5$-(<{EF%%Jmp4;w(AgS3d6CxpFE(-j#=n(IEtJGE~#ka;VKN!pw{#ooWB*9Fp8J zHR&^RRQ^gxH4#doWc;0*!H5lZw5%_DrrI1t#GEV~#bPbrC;%}|?k!wSQS8YOJW>BF z1c^HfMU>qkODIgdwR~pVxK)xi5nES>cIkQHcT|JAgSF>T!xC#)TU9nSU{4Dq@6bj> znlTQA?@QA;Y|bum5@L;6&##y)#Ws4xK0PZx1hf2L4eXj~gU*tdSRk`xg`y11+b2pH z*T0n)H*kWA2LZSz1JpOU;D!Wymwc?V?O3;bBV)C1A3aT@=%1%<`Fd``x9G4HNG?An zq!S9D_-IPc-z=soeEt{$!c=sN5@zZ(9+tp1vLb+gO=ZY{!@c;)akQ!nDrUemWnaT`W~&-m_WiEfxr^iviG6F#x(Auf54JK!8<8tEOKt_4?pg zcJrxU{H)?rvQn5OF2|dK;u3HFoV5?!b!RS6>TeLRZQf%+D_%X({1_D?_bfofBnX^Y zJPXhX(hj<&gI=jQA(4%M(1e&k_;q$w>On11j`RC&VZ<8qDlR?P(9_HpuWtkazC;t0 z96VM2phO+e;09bu(VBG3&Uhl))!W|rD7DpGWvAaOAcn^pu zD57y_E4Ch?baM~WwR@YlB6wRxg<|3Q(&DTR1@7|#yYj_Ct5148UyV?X=ab{6o0Vf1cX&{KuFWw~ z$Km7aU?B(u@q;}8i(IinpQN~>c3#wagh+|iHc^ut6JU>~PePIGRh7~OhNe&q#Y=DH z%B%Zo6%<9M4RqEOhW98ilPxd_GmWKrmO}vB z@#HWw#{Koc3?SDqGt3rEig~OWpX+fxz8^wA@u`=uM0wNs%9JOGz%ay_23({{YRp4A z-&lqL2*Nmwy-+NEl6>`kA_;sHW@VMl_6$@GI-m?zo3%I64ts-k48GgG_|LVu%_6Dm zCih<@^j8bsG2<*yyH=?{+$8?>CqDG0?imU5vilI$IG+q{ln~|@IF}r;kj_7*?IkLI z*r^!qO{f7pV0oqPZQWn5dF|x(!(zYY!wM@Qe`kJK~tiSdM2y(Tq|ChOj ziIcSELh;bgP)vt@t4q=o#a1|O`>2-Uzv9PQ!-OW@TuTXmGjZbgogF{aMUn{BN!T#{ zqekK#Clay!41?VcGNh4BA?ZtR#p;83J4U+vEw~IkKq@Y5Ng>no(eyRHI=a8U)7&;+ z4ImxOMZUH2ii%vPWo*g>pH17OnX+Z94-Im;)%eCp_eGHI+FjzTT zohvA#x=qxw^GU2_fT2W-P)-4q(W)@A;iSm1NA-s8Xb)1&;&;}ov_M5Q37Woa1E>HQ zG8Z?6PMdGAuHn(vnz?((v}MHcupn_J|1-XJC^60E=_lKxDT!biV&=+NM;;N3B8@?) zparmud$9}o0oYhn2eQ`tid$q4kd+qKs8c%*f0t*vjI=jSX;Itt9m6oBNaPgLY%>M4 z3z?sp*oZdPq~&pn%?BemaU60~P?MEtg$zYRv}z&V@LtVlQrxm54CsbTqRXR%f9^4Q1s!}qM? z@)0(2^PKM^jwHdmQ>6!KV|kgAeMnCCjl%v#N``}R{pE@a?JZnxBO|DU&#d%_7KwNL z&t`0nYck?{FA2cLMz&uGp0gVmFEbmwpE_}K>0^jTaqWb(QURrcX0R^Cpd`$)5g#9!V^c-raOgs}zQ@^k0o3Fyq4ez!lnjY2@ zo!N(IG`&P1XrhI>EN2;V;kLfAN?(slQKSKlf;#-{uayNcAp>Dh%3#Q6VxVPBmqxR{ znqmyvx%I6Z-KyD6W_rZvx0t96YV2rBs_AbDU{^JbK3pS`6mPBW;gSUTqL%%{k*dJn zP@K0S*#@fiWi7EBCqQteg{%P@4kgSK`Tz7)e5eHcK*#!!QW2%>{^H$6$;CD zI`(XKrdeh6mJlZTBgQ&6FBkb7@{Pc<~M>GHAPOP=uHx@jz?Mv_KbPOiRmUATinXVxRtcH zg_Qwj!3W@z!YyhZ;}&U#TS>ud!zS=d6BaZ8VH)FWaLd$VaYt)bgSPX9p923BjF`F! z#9~-`he8$b%TbF4HZx7+;fvesz6p{`2DZlE52&fTVZe~m1)6$62TzAW@Igu;8rtsK=Id@|d~sb%-lPTGD@cgxF-(MEVA3DrP)&}IAL z{lD->ztB0LK0ZvcS9ni*x4g`@T(JZjXFMGRkPUy4r^QhZ5hj2>G2Tsn!Ix9Q<6ZSV z7{%t^s(-%rMxM8S=1F*Kc(pxAkc~6_b`n(Ple`!vnW0lMV!A~p=J4mR0+tW8gm1I1 zMWUFLcjGmd_DSdm+qgA8wJ!S(q)v^WBDtB^OvVRNn~iC<8RvYM?$=Dg*-xxu(`}iJ zO}C*BM?O4aII^W=bk!bI%Gb4|Ku_=~F*IkJ(qf!tIYaBh&?Yz^nC$GX<|k4?fMU(i zo-jB?y`#r~wCNyApw=)b&fxTuFYKX}bV%8b975fR(O7d!d-j9fHTuwFAR9ajIqX;tO$bTlT0ldKO95k-@eCj&}x;4gXY(1S{8*3ay zAftc;f=V&w7Lf#;MO-&E1kXTtb%B;2EYT=kqvzN?HHBQoccMF^+FL1SacuE+-PJUz zJol5w<}U+jU325=in-ffafKp{AqLxE2A1W<78kt&K*ZiY^@caxakRfUQ8&I!7>vn{ z&M4s!Z&AAs(HP)XyW(U9kO}r=Xg(+PPC=WBD(&wR?w>E!RipUABSUxaTD zVb~QcooYd1orcGhx%C;dhyI#`qP*m?VCgY! zkV1f5!pvd=3P<1=QgzraEUqDlW3+ji02Hs38N&-+!6+Q7(2@-y6`mup!1g*bnj4*( zk8C@tfy|V|K(#L(3aFBx*=|N4XU~=eGj_X^#x8X>#%}jpW9-%}t+9B){l*GcZ!t1+ zdW+17GJs_$F7j&zFmM1Q?tPK|YWjQEze)Pk%cZenPJ_RoL2dDloU*Q&6HV|HzMAnteLOQ)h457>A+#;L&RjvvOkEUc?RDacE?S>TNjhpJ z&!^5xBNr(RcAJgE>|3gprA~6Y7_@2?VNbVom`y#WreHXm(cnzK!U~egRdXuKYAsGM zBl0zR6G#bhNo|11e+4{^JLsKucboZSppl-|=#13~paB5zLV-&$K+yZFVo+=9mquzV zpazzMr|O|AV5JD64Sr$@z)LPSYXH8M&NFe1#Z&JZX5mJYt|gkt5 zS37ua^$5&Gy7;*1k|ADR1xh=q|!9XoH8;k9kA;fOSH4GtRVa$}OVM?Ig+7Jp- zcm!+~G&PYEhLFXQm?31d@2?v}sKI){p!QX8Bm)ye2e}}(tfRSc09mCqz(HitT=<#J z+aJP$6z2pOP>;^J8b6~>RMPJR?rCrRmvnzrAVIPyuE_g{g>Fi?Q`z0sL2R3$g zr8v950e5yO1lF8gV5gj2z=G9B=RxC17-kJXXu+6P$C;L~0gA!~I4)6sFq`Ry4WMfp z8{pUhZSpWSpoWxd%my^W&IT;9*nEN~k~WAh(&o|^l=Xz+CQ=pGG=r}p?T(YSF%?!& z^-h^pRCHY%WR_|LsZd0%tVZlsJ&LrBDufn=`%ELnPPEa@oiJgeXR^^vzu?FUXFC35 zsEHI;Gp>SznlMGT(a8g93LA}UklBdMh?qg^b%UBXY0O3+5rJbH-P<6^t)jBy#mu&!cnG`{mY6TgVqpFn{_#kzP zh@q-JEw12Fgy91-p=X+^FY)10mlB!8H`E^bD{!Rp&3hX-B)Jbx?Vf!Yn|Lta!IGDt zQHy1vz~qLB3Rt1E(LLp*62hPxwo*nqrfu(q2Wc*hyUG#R**nv%KWtE|s(e-r#Fh3Q zT%R(*)?&U3GEs_SuHvpF(JYX0fXGMlwRY{mNlm}C#peLllxV_eW9Z(O43&eKH^FAw zhy^{!^mXOLBnlI*^C&Z<67tWp8MyS-C20wK_DpkJd;D~Eh=?^AVjvwa*l^X?iwU-0 zL$G711rHw^%xl30z?ci?9tJ+1jC)X>xCg`c@2uHCQ56N^3Bjg514}%7Ff)Xrz4qan zjF&>!uya^RUduP;<^qXNg?o-*6EOHh6FvFIJg56)i`E_~eTb{|5$gf9%2tddDIF(Z zG_HAYF`R(MPU3_igV}DiHVwBse$KUaV0xig>Dqc>iyzEo?dm!QkBKQt5WPFJOmidl zz!WK~YfVLJTvyu{u#Wx<>ufaWbHX|sl8xr^Vx8+zoiQHCBcoj~-)wa2sB;AMJu13& zB&;3_-Kb|xbkiWjCe}o^Mp&(ZXDv*}G(9MD0HdDpdw}vj8<3R zV`AV5s0(e>YEYsq7UN~?!TwbjGp6)Kag<7r@p zx-qCSdP@tn`DgM5vO|-~U6bPTB@Aj9U_U|3VysE!k~b8VCS~N*7*r}iY^iurt%S(B z5gTa5CCtRcWri?R9+@y)v_4|G56I6G`0h2hoC2Cw$c_v|7|{SiLWS)zsa372vbC00 zRbIqfnK1jIzqUY0mF}X4I%S)?8L82jgP2Y+C@-e3pcEGpMk2(h66l8^y+-yWBV$oF z*O6cN@q}KN@}UP7i|8$}y;>MDHNftTqe>iZPrxNHJ1Veaws7DSKi3b1;T&~^IFGA* zY>HXnZm?is`@)GYl5;BeURyk%N*&FDTUhRwbdr5e-lJS*w%8%Tj4-QxIPeJ(; z@H+sXjrQhN+qan`lc36JufR4T```e%%$9jMS}&4J2-@ovZ~$WV-PnzB^e zfv#c;Lg=J5j4W@EmQX`Rdcg@xp;i_B(1gw6v$N?#m`cjn9NP4W+{oFlrq0Loy1z7 zGNpz?_t^S&yh+p%D$vJ}JUasL&XBwKoq>H~m8BzBr3IDA zKeN98vFX>^s3pl{vWl4m&`nN#LN;s0B!Z9)iEuJSn)W7&K6dOr{?@`nWl^ z7BVsPHIZqRe*E~6X{{+9PaErTZXRo1Tm4v?idK2V@#L}1uwRX&!2*uHc6kA7~jk}T0-@p&jNp~Z4tPU6~e z+PE8GiE=kOa9fIIQ|_d8Obb1F3#&Bkm@;U`IG5ySG-asP6Jnk>q}*p=srcu>=G3N*)!8bzxaSQ(r{WO`XYH0ds%XhRfck0NlnBCND&W=hz?5O ztB*L%&|w-G5-EurR?E=ZzB8egN_;F3J~394?8pZip?cwiW)`&-RMwG^3i(96;$>t+ zM7p`_h$Knp#kiiH0U6vwL}Y4xiyCMFo&{q?%c=E49`P8lYG||Lf)mj%UcpFOC6Xq_ z(ijXyu!?WAD<4wNT;;YkM^!4JOb4ikK4}h8hAtuK9xPrl2I-neAqC}V84t{qo2yX- z0HPED@(>NzEWNl+i8yMMSnM9Uqbcq$6i-$~eWNi`{?&!@u2A$yFFDug=G<(Cb~=_n zze1<*Y|FMt%N2a}O$rb4>A)~y|56FS(FIN)R^a=vh)csR6F#l+P4T%HR)#dF{k zTeB&yM3F)1GIIpWUJfIQv78Lp38!X`o6;CoP&~CzKt2FWD+N^(JVR3`xlA;nZzaogmj4)$J$BfL{oQy(3ID`c|X3@5pbaZy7j$av*n6T2KY^E!o`6LSKnh)7k~tkQ(B>w!b8DWT4SM(QbYJt(lxn7$ zN7Sc~;mG)jSfP3PFRU%YYR&C%R{zC_@v@nHeuHcwk1dp*gBd#3hTMTR;TWc@Z1x2a3ef0bugT zSO59-3;W{oRc|_U1+oUX+9wleKsCd?R@cb58W)H z(C4!QYv%xDLS#Wst1V3pT$c_^LO?PJHkfEg*1X20Wdij|QCnmvexeAR?>}!SfgG?o zaAfjh{UsAAr`;(UIK%)|+ICL|3KJ~m$rc(bYm7BxoDylq?^B8ZPD|n~W5>&2A|_r2 zPp5OV05ptL84%SN@A7A8Kp{Bodk9y@VYJV9A}H<-iJS^YtaQR4?b9{%Nm$UA3yn;5 z+>fn-sSNA3kg7C4f8W*#Q1xDztoIgsNkR<;yW>0%xVS{1a_X~k$|*N3$!%8Cz8P)> z%VpeX+*-?_Mp@Bh7j8{dXJ8n0Y$K5BV84$f*&7!WEF3d^bs>+hSs=i5I2~)XmPiAk zsQd(YVUb$E zW>H(fhBXlI;N4I^;hyoeoVSnaCyCDs^~(lkl32q5haT^6W;L9C)8|#g;T6MeUacC= z>QbwQGg)f&a85a4I7az-d|f>p=6P~B+{0Rg47m4vosUExo?f2PQ9CSrfwPN%B0%-Nt4(Xm_02LfDhWo7*`>x?@UF z>~z;XGm&3{yWW|JT%+9e>ywDKCsSu8`feg=(`P2re#ckf43@-p)+f1bPiFLid&{@( z%w(P4tv@qa557zgy87A>^@&8OR=&|*izm>0%^Em^wT8&!YegJGrJZr0AfL4KYQ`aR zNFvw0`H{F&56lJq6mw=rN?J(345?2qtj7>mD@gdvaE${Xv~_=DPvy*4BI6*9D` zV5&|>28uyTrn}{7y7r=uMv@I=C7dB!3Cko+#ML2;KQ9$Ha?tOx_!L!bIarQX;zqxq z3F!&@84l7EgR7YU2z-X6xqD?(6$SErad!X6RvE-hrHi=iNbyZ%YG-z#xob`alP1`t zakQc2)5|rMQ$-2_ajOa;_G_WDFj0c4>=Q4x>Ip)#s-+wI*tn9KX(c3$=nCiMKyX3`Q)o;}lCg-&qBTx7&|qwg zYc^+R{3%i}T2aC{YBCsj0!%=m`}>AD=uQjYhq zGYfL$b0bPbMloXy3?OOzHcA$K@C%uPbFyvkA00k*UtID2rGz}HCaX(Gr*eSPYcyk0 z-x}D&Alx+jemCSQyk8i0Ah*q;Y*)n*lSitkaV@rpOWHKguB2i%f>{gk-jA+On%5kG z!qtukdy0A=;@wAAR4Eq46F8%RV`JcGnAN|$;-BL9QtAgC)Cajp{laCzg)f5O_8oPg zL#d1IV&SbwM4G+HKh{O@^NC5O^UWV^S}2En?VREv-q7Pd-uX)_2p+aC{c%WKx3@Jl zeWC;MMN(5UAj=gt6md;O2;Iiy$ID^a@yW?L0g9)_I+I$+n8BS295y{3WJ7kyQ8M6S z+Y-cx6`wEBGItzkIk;dA&`K6@URDiSJNZ@I$IqSt4)Wqjy=Vw8WmA$4wy=%=>W>|6 zaU+0^-$hkKdfx*C%D-XscKA|bWmr9G-=;n(Uh62qgk+!uAdnvcRC40pQl9~saZ-^E zLL-MxX&~+*F8@bK32DrvZ>2~EB4{<#V$kO-!M`J`*~6;;GrDqF+nOVwxpWw&YF3bo zpE#)R;CXAQx5kkrzv8W>-kRX+t?5q9%mI4(Uh&AblWTvKv8%x!NW)Tgr5_y>7$BQ0 z_ymG3CG)K<7oeBE+@MpVbT|=D6;I=H;lS!D(@8d9!_KVY5@`B=Z!{}(Pq2HOqq(;k z&AE)mj!dj6Sd(gKtEFW|rtKpjq9(|Isum94p|(WhHm7NM8(_Jki@UdiQh`ECNj&!X zyr~_tiO*551qNzjWo|9hY}AWqI4b}4rQPZxJ*WMms`#VQaoH*L1y1p1w(z6 zd8x{_CHRA(uY4XK7dwLFQ%i6ldnAthxo2TWf=}3vI8A$mhY(e?Z#0PAgXlR@T1Hv? zG$&8-k(VVF!0Q@vuc3!9Q4NG3(Wuuzh=~f1a_z*Vk_-+`T+Fz5)fr~)rd1(eTGyhW z)Kd;3K#nE*Xqq~xgvYzldvxxGcSo)`DqttEL{=dtR!uER6~y+y>LT)_QIou|sU<8A z1KjQ&c{Kn4AtV(afCs;b&;Ukpp0B3?LDegn#Hj3frFSfU#yA zptm{d2-+khut{9gG+{^9pb%XSV5Ar64j{7a2$-kyQU**zkcMUG#}8f_md-&{J}52! znZ7`#q#UNrh&`X7sbv$6qPUpWWiPi3y{=(0u3i9FEdUGQv#MskaW+xqB<2?%>bvwh zhHo;5nZPK;^Pw$>nZ6L#taFfI5Ld~W4KTvuupgIGdHhMIF>Se~Rh!?B>ns<5!l$d) z7YdB{o)sA5De_+7qh-Hb)zv`VEr!QeLIsdW=Hv)CzWl^aGab72`{MoA{rU9sxw)jUN;V3K8o}XHtA>#2?pR1LUv)po9iGMm!WtiAiUwb!O8|HCKR=nx&by zg}zriho!R#Bh`J%vg?e&$x~~}sijmMy2n9pc7nadDCBmo{bx-IaCjWcef7Ogo_!8E z?_^Xu5hxe;e-WL^n-hU_t7F_=W{El*=*4!YLuk+C-3~-5g^gYFcywI%32mBq^Imz} zqgENz`k}iXtM!++t$ROoEUx!MNMeY&t6GT>#T1-gPY~j3TCep zy_iz&#Wv2`hbp9C7AsrV2(zSFIFFd8o%}#=x+>b8D8mV!4W~r27N?ZveK#v%hDeB? ztr~3I16o~%2PZLA(^0BA##DrhQ79)I5$g)BYN!GoXm9K`it4im^-O(nVlt1P*uR)S zrlWqpyW`XOU^AUUZRYEwIQ8mwR(*cAwzDeLqn_34KUU9bycdPYzBeah<+&*ni@9jz?UFg9cV&pl;czZ{zEr0 z6t)~T32?h?c^mzzh$iytLUsg+@a^DQ$25JV*LN?@;7NXz>CRD*l zedrn1od}osTBbK++(EoUCEE_ld?A6=MVz>Fl;djv=}9_@fVGYyN$|%>E~vji1dD-6 z#HIC6%7tMN=D{|Th;h?h{xzH47$$wDkO{AlW>AAZ(WuT@2b@!T=Me84e$OX)jaZQf zoPSRrm@@nHBxlvhm9FpaO%{(2e|!b{VJT0>i3-g@id?qA59p}8;=+3wD^>-WC##@{ z1b|Lh18qv?x^-+Y;~t`b;0;L^s9NpRO6}4?% z;p46Ms(o+L)!wr|$%ceT^dZ&wfnLN^psZL&w{QXRkxT&eG6%7-GmYP1$N0H|^VX7d z$_|b@dN8W{iu|mBY<-pPpg1~5O5CE#3sN#0V2Z|y@~GjR1UI)juDGU%90o`y!%vj3 zsj8>=6ycy{)OMyCV2QBWl53o1=}|ZZu8jFYd{EP#z!iMj?VQRgFJ6V`4gTOdJ-|_p zBl4JOM>hk4u|tp;h%!@j!AwEHkM|<*%>pxG!xoor0Sv4-X@2ryeG^0Ri>WuXO!N!t z3ut4Aqsp}oR%&yMQK$6GSnU(sZi~UVm^rA_my}^8&=yn8x3h3uq&Q3{y+ca%pYWW; z>AikJvQz>1LCgutLII#}%ZRcxUd1fRvk~H9m}kVkP+h!>NtG;?Z>eK-Puj}PZ%QLz zj@pzBO&^y-`KO}A_U>yz{!muNZ3f#%_r%MdyudI&B9z!aalhJstkt~-q?pgQuV}e9#4cY zIUd3$jT+R1T`4z(y}V8@*&n>>F25R@GXq;4)Z0zg4Ft)I)U=-PCz??|6>_Pd3WS)(MhHqJ5yV+HQ0oNNbAy(gFrAe z#gX$EfEBWBHog~D@~M4)d*4o=_)+{g>6Zy?;-Zw-T%aTdW=R$&muU0z9G z43H7Sp6JRxE^HmRMjepsJ+V!xqUaQ7CQn8Y?ZhWDuVvMhCuvHT5@$sxavJ*=e?ts8 zk+ynTs#BnKt%lgQr=@d4_A5wT-f?Dft`d^r3<-ms@X`+7eb07rnU9;SRfM;N_Ra=#?6Mpq?Q8MzNeeI^{s5$9HH{s9|U+u51l^Mkrbz#Zc6OX-A)d zLorQ?m#@Ym;nsvBX>0wxgH-ZIj?D+n1E^&)q1HBG1-6Cx;J9;TAw}nk$D|p{8>cVJ zGWm=`i0wTsuC9?6{TQi)T58RL+oB$1svEo@oD5!2k~?y7if#N$gLW<-p$yJ$XaAwo>^KJZ_UXV&xB>w*cE`w2O8Dbb2_y8` zX;2GZj9%MEX|PomkQ^@+Yn6mpMmwh4a!fP3oDZS0odwhdBqG+n%q^Y#iW)vGyI$TR zuW}EsSae0f*2)Q90Zx0^>q!2onr!3b?i=Tt$G=Al3o0`@W_U7#=i1KGfh1k>!)z{a#(1Kg04ft%}UaIf*g!M(-{2Y2&gHMo`9fScK5tnvYYJD`fX zWC`L>M7No0!kjzHm#J9%RUW3;CWy*}aAiDNB-e6gM&Py1CKBBCj`Gc;DO^z42NM>8 z0dL9{%7oXOh0kgZ_Z4z{)Rid&Akm5)z(P5>MAfa~lzPZp9KfQ9Dd}QhD)+kR2h@uV zTK5)(_xS=Rz%WL8B8Sy9QaQ`Z=}&y)i=cq|Nm%yA=0W5Fmdc5#<;oK(=Y&&wqvf?} zDP+P=L=4PcI@%i~uH)NpxaHpD05L|OA4}dAk4JaSGHhPb@dKnChnt3vU=1EK8d0Uf z#D>TX3=B@8Yp?B22R%#0Y%ITO71cIRl zZ|%GHxfq7Z)QncY_-YSi6C-H; zq#>{&iZO75C~eYpg*tKa!^mXQa!%Q3nl2NOHG445{>W%5F1?Tq8eRa(|6g~mSYQDi zWrk8ksKXx@*QIGj=Y+&M8?0jI<@C5y+QnN1lDmr{2^{9ML)riZE5jvb&r}C-R9$#> z9)C}2Xues%s~zJrDQCp1dLXFkrv{uVrg~0N&K(5w_%J=~$C>kH5)Fa`dOMR&{3kmi zXAOB@Jd79Ajxj{oX!MMoH;2Oo9CawzPel%QmR4VA+^aIJOl0~RIsPV`Lxzvz#hu8< zxr!PvOY-gt94SJ;M%_8tsO?O8My&#Gw3F2;jDsChU9Sck8h;Wyt9F@mRQe}x};?WT=7r0!t^$WAb+ z{y6$64NJvv^iAvbPlJCd1P=usOvCyh_T`!yYPESG(DZ-_K>>dUqm=U!Hw;{p+bv?> ze1c5=W`eS%V941w3$z&Dc-02UN40trzxoK%)GqsID+UgVA4MqB?#u$EkX z@l(ENA~Z?y2)xETv{YuH?YVp+5{?XZS+TzwoBt`rx8vLKrQ7)Lam^ISn0c z>cCMFzt}v)BTWTOomqUaNwPX|Cfx45JJPe>#T9!5Q{-}rM^-%@n|xxt+2!$J_RK+% z_x}mqDflYU?m+rk`)+&7)$BPbJ`ykxTEL|9cH5UCk;Kowg9y9NzH{4N?%#h4_wS$G zyPtawD^2#rpE)+YhlfvnmKW>x?$?W-|D_*Uh^Hz0@4cJ5g47wccKuh*S%}wtr8v)w z<&XaMN)n$Q|4Emh3-PD#;d*0M{&;HUvt?QSP0~(_f1t~U()drm#q~d>WGUV*9}dQ- z9A0w0V}B<9Z+l+?9#?hWd*So1oihj z=ibqbY+7hv``Uc(+E?eEef#hKbMI7ZmZ%nhOJFL zUo{5UNePgMNgTEKvox3oFaz&hyvrXEalw}%Tzt@CP>FIOCB)gZu3MwDv*BIFO|xkv zR~0Z4^~w=+NXe!ltJ6O(|A8SFb7@d!ax0**!=*{mFhU-uf&ZGqq?CILj8-0?8!rG= zM-@=EHMCBS>K*5(lK-E=QFVu-Zm0;-7>V~@9FEGjw!l+?nmnlID`BbQrBFt))G{ga zST0M|6-ym2CqF{WcgWOi3WF`oMk}4Jk~Ilf(o%@okVV4&?XpNY8<$1m+=0s?u~Mg* z$F1%>@pcEctvCwe{isL3Ho(AOi*n#OVIN?Mo zEly~X1X;%>;k+&_PM8EunVgwpc_KS6HvB+1WF_z|eADIAlA^jms)B;6S=NTuTJm?Z6( z=g~A#BsLcwbw25^hyM!YX%2sjp%&7vV*BBD)GxG$-{l)amPcC50T!P0E(<>e;?F!H ziRa7WumYD;(?f6&>eYlQ03uhiTE`fx(S$n-^dpC;!~5rftKR)*db`c*j!2=k*nsTq z2HPCFrC*WlqvEjYfGoZ=E5e*#vn%v3U2!EfO=iF6W&_3{5FNof;;USoe@`F`mK~(N*p_RLp_1o#!`44sk6Z&$+~FJQqb$}-HS8W_hYn0qa}?2Bi930FF5@qrM0 zZJ*vs1Q5ud11yrvVM$QH=!I6|!*_{*yZ8rN-XcnD%!Un<+NrU}`C%>t)CtLeJy@AQ zPEj6hU|fJsjvi!Bn9>6zqd-c?%osaQoFT;kG2sg0^gnRlSf6%W{ibm)s4%HGNiq)_ zVY3mXAy^)e!a*VuLex1IlPE5TX)s!imBcWm=MH8ALJ^!euS1GNwq~Kn@XwqGn$=_k zAb@?4o`5X&KvH3}Ln6$bmXujq-Xv+puxrLo7P1`R3NS_~&7sqp^;tp&L}?uAB06i< z?TX|w0jHlqqc9$ckYYpV=Ow&AN_;Li2smB33#Kedk{ei)t4p#eQ6mo- z;WsG&@ruga>1^nPm6q@i0O8J@{0@Ks9TgXmn-BX}Ve^-v18{xvb%hhE?!&72(z>Bv zc$BLH!niz$Oo~#D+0tJ|;(=!K@>K$a|25tr01nV^DD?oUmW5XgfTr?2hT_)(;1R-9 zq*ky~O;jB&Kv_(bZ2e=M_kWZ~p#g%5&ifbM$N=vDPWdrOhdkjiPw4;BYX+z5_GwM? zsw2=~GITI5qTFqY?pt3J+eu`qX;=d~crBWyl@S;lD+}an0xWmcl}BJD;~VPMagnUS z*`%!X$2f^_x$}M@-R;Zo_UC-D$)2Jz?DplpKlc%{i%lEa|297*(rg{mPMz+I%MF~kfxJ1zmG-D(eZ z)29w67S1#yj*8VD7!k1uWe)3vTI_?jLkeu{8_b{Qi{R(Pxb^V0{HnE7Ce-0A4}LG_ z)NDDFfTJeB=LCCdwMXmXKMOR7r<=>rZRzP|pFBdQ+;u$D3~M09C(k*PL~*E?1&;*K zS%5|4TH}vo;-{Q#CYRu8EPOj31&T(G6+Hcjs9}8U5oujTW5U$_#W7LVaLPc6U||ef ziV|wB;9^W8|3*92f}6(aQp|A9T7xEypS9*5qoizfe1<~Srko;Mb9zuB&&Tbda8Mi` zVYXMoJ0KSPA}MCjpB#;ZQRg z`;aP10$?c=(R=u=G@1ZVhFWL{WIxtjr(xe8*46aFN)?un%N+W3Kr1i2*AkGYMuNmQ z!pjV+2C!YEZqn@{Ki0xwUtSHaUE`~+&{>=~CpAo*ONQJF%I>^mg4aHv1ptw8;DUgM zV;J%PH9VTM^x#*w=vT*&VO~)a;>l$^!VFq7Y5XMwV-?Hdk7;AB~s>qAk}X44M~n#BA+Pw;%5l?`vqY{p}YYDA&N?Y#Ua8_0VH(t z5VTZgK){S@EFV5;0poy<2Lm&K2}1qDmSJV_;WGilgqv1bVjj>nkMKc}tt?UUVFQp0 zM>~K{Cs}DWYyc`7b^!T?vEQsbf*l^W0ZcSigP>Fv>Hn48j{a|kDvVhZS`QzlCRgau z=?a>^{M;dQ6w{AK9l!2pfmuTa#-`1J{)I=L&!1)K7HBCwBfYb+S8x}Xv?sfU{UhYU zhTJRAFS$qVYc{M>W>)Nx#|cazFW7szJPT2P4}uCeA2h27JT$o-k}48W;qY<1e8-G_O=yj$ ztpmyebh9x#jO&vr613(^>b1Xe3 zj2BM`hZ@91FV}+~c80AP7EjBQk$N%D(|~vtow#P+6`^-MO5$~tJ;}Cy@efCZ#Y0y` z`aOoIDGmuPFRh=FLlQ{jK{)G|tOSXG{?wQ89R5e?O^3At1O_MNtoK!`vcPr6-2%`` zt1)0@1;KC80<{WO5CEz;jTHoog=KN9Ao@frh<-XNh|>2|%NC3w*Lyy$^9$#y|6_b# zrwrv^MXvv_p)B;kiY=+Xco;5Pt$WS2HQFDU+BJYq{3Q7Ny&wm8XU9E@d?z;10=N}} zi9EB58KC4bPv~B)*pfh_m)ueAo+ELohu>G4Ymxn zH8gb$#yafQj^^gUj*gaiOItJ6^h4G+;t7k5Xz%Wz5cn_Fr*g@-X-3n#G91ZBI<+eu z9X5m4p_~u-HzTY$-Nk8I@4()?v{HT`Jtk6^=QgAQzLc~vyLZZX}9d( zq3q8(ywxdL zoET_?#ZvUK6ya2apG2n&i^p)*g!n?l7vbg(aP4bxe;mAAjPjf>>k{|bKk<|CWw;4D zZoCf9#d}OTRYFMi+OgA;I~xF|$er+e6}@{Gb0m#<9vu;eO4>NYC@J^eL>x=*OgV$i$7JPP*Co&hEC&ft(~}pxbD8d2f>$9D3>-<8Pf)tNrTK|m&mlidXbVF!FH(j zK53^@*~Bo$mCAvLg292Evt9Q&ksQfMNW!+E?s!xCQn{hHIRK`+2kQ!kY`V0}-VgZ8 z45U-YFh>$2fYvyecSi1bbT8xvZh)J}EzH;sFeD``Vu|>`0Y^b7G1#IMv}9*X;)AFk z#}tPXnGEa1?IbYG85A2HBop0~NXCU|!J3l(@ovSvB@;`BJK$38bGx{xsyz0KQ6EA$yq!Is0~}0QCxXgy=wd zmsY}!BUa#EiF+`W9;UpOR*+LtZWZ!Z<6eWiuCA_VIGNF8tR8z32X-mEIWriRJaZ!k zPTX~5Kt%wtUx0p=PsmL!;G~oUv-?se*rC0jG@zJ9ccC2%_r#7<$(YSvzkohTGe3)k zC$BkG)=)%ap}B3lwY{hBTx;7V${pwJ*u1%S^M*qGlv95T+6Bg-5+8O)GnAS3CQ`W! z8MRH|P9-v6gn%oz?`Kd~?tzl;NJ}!KnZ8(RcsP};k7oOT9NE6a@CXLn6;kwvw1af^ z)bWC*f~r=pGS_X{+#|YC#^sG`@w^T46mXWFQ*blTCwY*99NM*e*c(EVeS2+>->HuHGuA3rQHY zK82M5@$WS2>dY%kcBC*{MezF)$w39Db>(WlQChL+M5KuuQ?0`7@L=QEqc?NJ4rs1-cOFlB2GLM3WjWfuoC%S6udD#CH_L ztDe;07V_lYaR$7T4E-Xo)a~TITXNZ6#eUZT;GM@_GT)tKwB6*hmQo&iB!BIe{B*^Q|m#~02_)s7vdQxOkL~z1IStTzhinPxjFi8T2q4%7w(ZP&lC0C#w zYG8kYo08b6R3l>#4c5g{sXYmsWFrG&Si4xb^}hZu*8@YWgHEWd2~dO~HuTX5QK)~^ zsXq=kgOCk?Bwz-P{!EDrZ;OHS{sCs5r?+p%0alh|v6Cq-jddlaY>NF$mB*wq@+eG1!2J)wX@)y zXrsVYI)l`@c+H%=ZiTjH*@h{rnj*p3zV(}W+A4b|P1n2Tu3XwW|Lo;+Jmy)8aj<6U zw3@nb`|410!;E^XtfT78wT<1KUSnbHqKYN+TKuy%p0R)=RP@4lvkP2;ii4T4!8XCM z#k$lmbqhH&p$t1x1Wnu6I*6RqxNQNr#%5--qhcK59T8G&DG1J-qZBd8R#68N#@5P> z$A%MbV%Yi7LXJbf#Cn2;5{Sk5v>rjaODU~SuBy}xvZEs$hp7}MX%3NM>|WU21PBAA zdc~qR4Q1UJ$Yn-F5j8O(X28q_O>$^xyc7*@sWem`Ku0cFkiAh+N%|Sv-XqqgQ<=>2 zI7AzWIYUrQQ9l}Ao=T#UoS|x3KuuAzl&eUS-l!O-B7j7Y5o`h0$xat7T|vDlEi8$Q z*qF*>O_-N*Nhr0@O1UGXUzC=WW*`)ylZu4st>5D8r@IBtuqnr=YK1LOIf!z9$9Jfg zn%8)AyS*O@0(VKSXwQB-#*Kjx>~!QV6%_RxHArDO4_GRUU2bOzc(HACcpwE!sa!!I zPHIGMzEpP$g|=h!hoi|+X?c^~%4s?aj5*1XjFS?K)urm9I|@WBr8Jyt4E!?g@=ICB zU5NE8TmUyw=$l)dVO3&xaSsLHievvJ{wpOf6$6bC+h|B|5Ga;{%qTZ&t0NMd5D=j? z#G!c=?LCNo%!XlAtj{HtLPtb`_&a2CEfp#`dKRG^GY62tNrE3WQ29MBU zjioIDisDoN6@XNNHB3@*VE-p_scaM^GiF1F$F{)cpV*xmfdDMM2uNBBW7$Ar2<*rv z_GDlVNyHLFO-w>kd!#BHhB!n1a0zb1xi3X{8SXw|o%jZ{f;TWV+viH-nMBE;r6$V}jny~2Y z0YCxdKtT~#1(71eIcNic7(z(PfolQ&w_2iaMLU%HpFl{B(X~XoV|LRY0DyRrPt%K= zCuWyeUgVkqnCXV1lSxcLKHI#>saw3Z#a=TtJ$E6}w7n`yLeCo4MtLR7?P!l)or@6G zAY6%%I>mJ8JRF;B(^)JCSLrOMcUG+;jDIpBzJNNE5xZX2g~CzQ31;*_bY_N(ur;Q(I#Pw_$avyodaowtz})YR16)Y8=2)YjDA)X^MiZfI_7 zZfb6BZfS09ZfkCD?r4d$G_*9fG_^Fhw6wIgw6(OibhJiV8(JG%n_8P&TUuLN+gjUO zJK7>`4Q-8WO>NC>Ep4rBZEfvs9qp0!hW5txruOFcmiE^6w)Xb+jt&g51KoF^=?+xu zKoYzXn5Sz=y&TVba1Y@&d3`FlEC`qEr_3wOD{F(b%Yqk+VdS~Ih|G!ns5mW!_z3PR z@J+L)08}l-FjdTMUY@Ujh)KDM%xwM*w zO+{|$c%w?_#@V7-6kmep;(U@+qOV(?WWvNPJi6EG^XYzHAW&8noD-T^KBZ#vq>4%- ztWTbNM%gsabngsprasF*N1N-JKh4ya8q2ihp*l}QZ_pY&N3^eMUo##G{7!q%`+MU9 zeXQ(}{i8SD^v98%7u@)nTj$LEKa(mqo%7!Nb@gj5xwP+3|NihzH{W*qSHJQ26VE*R zgTMUS<8O`$qiXWvhUT`;6{~vBzVz_T$o$shPdxjVFTQmAO}wHzN#=I0=vm);_GNMV z@NIX0@dq!yR8h6Kr*~)EzUj8FqVO|6c;on+Cya`!9!Q}1gNMKQepOyc<_t2yIEZ?Eu>lgZ`hNhQIDW6h)xi9FO<-5?o z)Vn^o%qTZJdP8WLG0PXy^A96yzIBeVT+aqp>XrIRe|uo5_t03?j6i+Wa@`D9SLQ!s z9J*s>XzF#J^VWM;__awh%JPp!vgP^LW|e#MW8VB@-Ua1%KO6jEBz*WLy{+uvB~$X> z3FM!Pv=~8OdtiN_+?Nf_(=ReEEX!X#V@_~d*~UQr2H!*XmrpkuzGNKy=|X?G*PH)J z)xqKL{@NwJbBz2=M*h3{Y`wBV_;7B`V`u5T3FlE-nsGYbGB~VaXuldKV}c^$?U)Kzzz3*?dy*oeYrgS<@^8Y z`DE&{nooIkY=mui>g)1{=IRZVbBqOL^Sn#F>x@ZD@?Y~UFcuiKf##4Wf9t`vvT4CU z{>~0P7AT8M!_N)O_IkS7jZNNqBj_*lcbSWf^0HRF(>u#=l>4{#wl!5W`Rf9~gA3>9 z57q{jy?}jH2*WdEWp$%X9vqK&JC5G0&Ft|Qg>pkPpqZiwoj1GTQmoev#lYv9;e5K;x z{06AoK^Y%z0&6~c6etuYX>JSGvejv2P^bT^;I2nE0!5$ z0AgSMuB%@|TF9F%zt9gPG1@Ws+Q7W?_UR3J{(mn)+wS(6MPCr5%z9cWKx1Pt)j9>Zl2k@;G^*kRg zLF>jBkUkA{?sNM6;J_Ql#_%dl(-$$?3PwG$JdVi->un}Z%`<^HGUI*u z*C(u-UP7in{~P*7j|%G^M(cI4E}+!Fh^(aNS^Ox<j_~O%YzL72#6DGD7R~P?q7`UxlUS{_ktcHnNk1`6e6oQ@gB%eJP;xl|$gB}BA zL3|{mViHy;Tm=>Dj44y6LC2UebJlFR2Xomnjy279da40TEjVi-(-sNqombF|1_Qfw z%@6ssWGTLW!za%&VZFcy@A5hv1cQ3bh#qNZ6xMZrjmL6Mb1|FY842qlrs*wk!&~3y zW1tN?OgT$fcl-!(pUHwAe1?ay?MMB|6HE}-@=rhi;9}BIXO|qH7&{I9u5<-MHFgEtvzmcOup%W~LwsD<6v)_9i ztxc9SO8yAzJ3mIwq>@Cyt|5&8#SU)oZ$}?zQWB)+4&%4{3`3*>l-g)M2lDUZDZMamkPM z7@F5tRN}wqqyJ+LyVy#Q27%-M(>&uPwWmD4n+Xu5E$`#kkAg(OA P)_uo8SU8%8LYXMEu&j*TlbN*j`)l|L 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 literal 0 HcmV?d00001 diff --git a/lib/runtime-c-api/tests/test-import-object.c b/lib/runtime-c-api/tests/test-import-object.c new file mode 100644 index 000000000..640f16640 --- /dev/null +++ b/lib/runtime-c-api/tests/test-import-object.c @@ -0,0 +1,172 @@ +#include +#include "../wasmer.h" +#include +#include +#include + +bool static print_str_called = false; + +// Host function that will be imported into the Web Assembly Instance +void print_str(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + print_str_called = true; + const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `print_str` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) print_str, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + const char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = (const uint8_t *) module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + const char *import_name = "_print_str"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = (const uint8_t *) import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + const char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + const char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = (const uint8_t *) import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + const char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = (const uint8_t *) import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + // Define an empty import object + wasmer_import_object_t *import_object = wasmer_import_object_new(); + // Create our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + int imports_len = sizeof(imports) / sizeof(imports[0]); + // Add our imports to the import object + wasmer_import_object_extend(import_object, imports, imports_len); + + // Read the wasm file bytes + FILE *file = fopen("assets/hello_wasm.wasm", "r"); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + // Compile the WebAssembly module + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(compile_result == WASMER_OK); + + // Instantiatoe the module with our import_object + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object); + printf("Instantiate result: %d\n", instantiate_result); + if (instantiate_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(instantiate_result == WASMER_OK); + + // Call the exported "hello_wasm" function of our instance + wasmer_value_t params[] = {}; + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + wasmer_result_t call_result = wasmer_instance_call(instance, "_hello_wasm", params, 0, results, 1); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_OK); + assert(print_str_called); + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + wasmer_import_object_destroy(import_object); + wasmer_module_destroy(module); + + return 0; +} diff --git a/lib/runtime-c-api/tests/test-wasi-import-object b/lib/runtime-c-api/tests/test-wasi-import-object new file mode 100755 index 0000000000000000000000000000000000000000..70e24d17d8b27c47e5810e79983e2fe5e4b8779d GIT binary patch literal 19508 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 literal 0 HcmV?d00001 diff --git a/lib/runtime-c-api/tests/test-wasi-import-object.c b/lib/runtime-c-api/tests/test-wasi-import-object.c new file mode 100644 index 000000000..cf4a145d5 --- /dev/null +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -0,0 +1,258 @@ +#include +#include "../wasmer.h" +#include +#include +#include + +bool static host_print_called = false; + +// Host function that will be imported into the Web Assembly Instance +void host_print(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) +{ + host_print_called = true; + const wasmer_memory_t *memory = wasmer_instance_context_memory(ctx, 0); + uint32_t mem_len = wasmer_memory_length(memory); + uint8_t *mem_bytes = wasmer_memory_data(memory); + printf("%.*s", len, mem_bytes + ptr); +} + +// Use the last_error API to retrieve error messages +void print_wasmer_error() +{ + int error_len = wasmer_last_error_length(); + printf("Error len: `%d`\n", error_len); + char *error_str = malloc(error_len); + wasmer_last_error_message(error_str, error_len); + printf("Error str: `%s`\n", error_str); +} + +// helper function to print byte array to stdout +void print_byte_array(wasmer_byte_array *arr) { + for (int i = 0; i < arr->bytes_len; ++i) { + putchar(arr->bytes[i]); + } +} + +int main() +{ + // Create a new func to hold the parameter and signature + // of our `host_print` host function + wasmer_value_tag params_sig[] = {WASM_I32, WASM_I32}; + wasmer_value_tag returns_sig[] = {}; + wasmer_import_func_t *func = wasmer_import_func_new((void (*)(void *)) host_print, params_sig, 2, returns_sig, 0); + + // Create module name for our imports + // represented in bytes for UTF-8 compatability + const char *module_name = "env"; + wasmer_byte_array module_name_bytes; + module_name_bytes.bytes = (const uint8_t *) module_name; + module_name_bytes.bytes_len = strlen(module_name); + + // Define a function import + const char *import_name = "host_print"; + wasmer_byte_array import_name_bytes; + import_name_bytes.bytes = (const uint8_t *) import_name; + import_name_bytes.bytes_len = strlen(import_name); + wasmer_import_t func_import; + func_import.module_name = module_name_bytes; + func_import.import_name = import_name_bytes; + func_import.tag = WASM_FUNCTION; + func_import.value.func = func; + + // Define a memory import + const char *import_memory_name = "memory"; + wasmer_byte_array import_memory_name_bytes; + import_memory_name_bytes.bytes = (const uint8_t *) import_memory_name; + import_memory_name_bytes.bytes_len = strlen(import_memory_name); + wasmer_import_t memory_import; + memory_import.module_name = module_name_bytes; + memory_import.import_name = import_memory_name_bytes; + memory_import.tag = WASM_MEMORY; + wasmer_memory_t *memory = NULL; + wasmer_limits_t descriptor; + descriptor.min = 256; + wasmer_limit_option_t max; + max.has_some = true; + max.some = 256; + descriptor.max = max; + wasmer_result_t memory_result = wasmer_memory_new(&memory, descriptor); + if (memory_result != WASMER_OK) + { + print_wasmer_error(); + } + memory_import.value.memory = memory; + + // Define a global import + const char *import_global_name = "__memory_base"; + wasmer_byte_array import_global_name_bytes; + import_global_name_bytes.bytes = (const uint8_t *) import_global_name; + import_global_name_bytes.bytes_len = strlen(import_global_name); + wasmer_import_t global_import; + global_import.module_name = module_name_bytes; + global_import.import_name = import_global_name_bytes; + global_import.tag = WASM_GLOBAL; + wasmer_value_t val; + val.tag = WASM_I32; + val.value.I32 = 1024; + wasmer_global_t *global = wasmer_global_new(val, false); + global_import.value.global = global; + + // Define a table import + const char *import_table_name = "table"; + wasmer_byte_array import_table_name_bytes; + import_table_name_bytes.bytes = (const uint8_t *) import_table_name; + import_table_name_bytes.bytes_len = strlen(import_table_name); + wasmer_import_t table_import; + table_import.module_name = module_name_bytes; + table_import.import_name = import_table_name_bytes; + table_import.tag = WASM_TABLE; + wasmer_table_t *table = NULL; + wasmer_limits_t table_descriptor; + table_descriptor.min = 256; + wasmer_limit_option_t table_max; + table_max.has_some = true; + table_max.some = 256; + table_descriptor.max = table_max; + wasmer_result_t table_result = wasmer_table_new(&table, table_descriptor); + if (table_result != WASMER_OK) + { + print_wasmer_error(); + } + table_import.value.table = table; + + + // Create arbitrary arguments for our program + + // Set up data for our WASI import object + // + // Environment variables and program arguments are processed by the WASI + // program. They will not have any effects unless the program includes + // logic to process them. + const char *wasi_prog_name = "wasi_test_program"; + const char *wasi_first_arg = "--help"; + wasmer_byte_array args[] = { + { .bytes = (const uint8_t *) wasi_prog_name, + .bytes_len = strlen(wasi_prog_name) }, + { .bytes = (const uint8_t *) wasi_first_arg, + .bytes_len = strlen(wasi_first_arg) } + }; + int wasi_argc = sizeof(args) / sizeof(args[0]); + + // Create arbitrary environment variables for our program; + const char *wasi_color_env = "COLOR=TRUE"; + const char *wasi_app_should_log = "APP_SHOULD_LOG=FALSE"; + wasmer_byte_array envs[] = { + { .bytes = (const uint8_t *) wasi_color_env, + .bytes_len = strlen(wasi_color_env) }, + { .bytes = (const uint8_t *) wasi_app_should_log, + .bytes_len = strlen(wasi_app_should_log) } + }; + int wasi_env_len = sizeof(args) / sizeof(args[0]); + + // Open the host's current directory under a different name. + // WARNING: this gives the WASI module limited access to your host's file system, + // use caution when granting these permissions to untrusted Wasm modules. + const char *wasi_map_dir_alias = "the_host_current_dir"; + const char *wasi_map_dir_host_path = "."; + wasmer_wasi_map_dir_entry_t mapped_dirs[] = { + { .alias = + { .bytes = (const uint8_t *) wasi_map_dir_alias, + .bytes_len = strlen(wasi_map_dir_alias) }, + .host_file_path = + { .bytes = (const uint8_t *) wasi_map_dir_host_path, + .bytes_len = strlen(wasi_map_dir_host_path) } } + }; + int mapped_dir_len = sizeof(mapped_dirs) / sizeof(mapped_dirs[0]); + + // Create the WASI import object + wasmer_import_object_t *import_object = + wasmer_wasi_generate_import_object(args, wasi_argc, + envs, wasi_env_len, + NULL, 0, + mapped_dirs, mapped_dir_len); + + // Create our imports + wasmer_import_t imports[] = {func_import, global_import, memory_import, table_import}; + int imports_len = sizeof(imports) / sizeof(imports[0]); + // Add our imports to the import object + wasmer_import_object_extend(import_object, imports, imports_len); + + // Read the wasm file bytes + FILE *file = fopen("assets/extended_wasi.wasm", "r"); + assert(file); + fseek(file, 0, SEEK_END); + long len = ftell(file); + uint8_t *bytes = malloc(len); + fseek(file, 0, SEEK_SET); + fread(bytes, 1, len, file); + fclose(file); + + wasmer_module_t *module = NULL; + // Compile the WebAssembly module + wasmer_result_t compile_result = wasmer_compile(&module, bytes, len); + printf("Compile result: %d\n", compile_result); + if (compile_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(compile_result == WASMER_OK); + + // Instantiatoe the module with our import_object + wasmer_instance_t *instance = NULL; + wasmer_result_t instantiate_result = wasmer_module_import_instantiate(&instance, module, import_object); + printf("Instantiate result: %d\n", instantiate_result); + if (instantiate_result != WASMER_OK) + { + print_wasmer_error(); + } + assert(instantiate_result == WASMER_OK); + + // Call the exported "hello_wasm" function of our instance + wasmer_value_t params[] = {}; + wasmer_value_t result_one; + wasmer_value_t results[] = {result_one}; + // _start runs before main for WASI programs + wasmer_result_t call_result = wasmer_instance_call(instance, "_start", params, 0, results, 1); + printf("Call result: %d\n", call_result); + assert(call_result == WASMER_OK); + assert(host_print_called); + + int32_t num_functions = wasmer_import_object_get_num_functions(import_object); + if (num_functions == -1) { + print_wasmer_error(); + return -1; + } + wasmer_import_t *func_array = malloc(sizeof(wasmer_import_t) * num_functions); + assert(func_array); + + int32_t num_returned = wasmer_import_object_get_functions(import_object, func_array, num_functions); + if (num_functions == -1) { + print_wasmer_error(); + return -1; + } + assert(num_functions == num_returned); + + printf("Found %d functions in import object:\n", num_returned); + for (int i = 0; i < num_returned; ++i) { + print_byte_array(&func_array[i].module_name); + putchar(' '); + print_byte_array(&func_array[i].import_name); + putchar('\n'); + assert(func_array[i].tag == WASM_FUNCTION); + assert(func_array[i].value.func); + } + + // Use *_destroy methods to cleanup as specified in the header documentation + wasmer_import_object_imports_destroy(func_array, num_returned); + free(func_array); + wasmer_import_func_destroy(func); + wasmer_global_destroy(global); + wasmer_memory_destroy(memory); + wasmer_table_destroy(table); + wasmer_instance_destroy(instance); + wasmer_import_object_destroy(import_object); + wasmer_module_destroy(module); + + return 0; +} + diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 57338a5bc..8bb9fb254 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -470,7 +470,8 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec unsigned int imports_len); /** - * Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function + * Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. + * This function return -1 on error. */ int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, wasmer_import_t *imports, @@ -492,6 +493,13 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); +/** + * Get the number of functions that an import object contains. + * The result of this is useful as an argument to `wasmer_import_object_get_functions`. + * This function returns -1 on error. + */ +int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); + /** * Frees the memory acquired in `wasmer_import_object_get_functions` * diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 521c6fa6c..21426f278 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -371,7 +371,8 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function +/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. +/// This function return -1 on error. int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, wasmer_import_t *imports, uint32_t imports_len); @@ -390,6 +391,11 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); +/// Get the number of functions that an import object contains. +/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. +/// This function returns -1 on error. +int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); + /// Frees the memory acquired in `wasmer_import_object_get_functions` /// /// This function does not free the memory in `wasmer_import_object_t`; From aa82df7bc526c9453c14802cfee1b56777269d2a Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 25 Oct 2019 14:42:39 -0700 Subject: [PATCH 083/122] Fix github merge move entry in changelog due to release --- CHANGELOG.md | 2 +- lib/runtime-c-api/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef174e902..b4b97be02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## **[Unreleased]** - [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. +- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object ## 0.9.0 - 2019-10-23 @@ -17,7 +18,6 @@ Special thanks to @alocquet for their contributions! Special thanks to @jdanford for their contributions! -- [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object - [#850](https://github.com/wasmerio/wasmer/pull/850) New `WasiStateBuilder` API. small, add misc. breaking changes to existing API (for example, changing the preopen dirs arg on `wasi::generate_import_object` from `Vec` to `Vec`) - [#852](https://github.com/wasmerio/wasmer/pull/852) Make minor grammar/capitalization fixes to README.md - [#841](https://github.com/wasmerio/wasmer/pull/841) Slightly improve rustdoc documentation and small updates to outdated info in readme files diff --git a/lib/runtime-c-api/Cargo.toml b/lib/runtime-c-api/Cargo.toml index 216975bd6..8d5dbb614 100644 --- a/lib/runtime-c-api/Cargo.toml +++ b/lib/runtime-c-api/Cargo.toml @@ -27,7 +27,7 @@ version = "0.9.0" [dependencies.wasmer-wasi] default-features = false path = "../wasi" -version = "0.8.0" +version = "0.9.0" optional = true [features] From b67f2c9f189b88c3596ad8cd2ced29ae4ea56358 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Mon, 28 Oct 2019 18:33:15 +0300 Subject: [PATCH 084/122] use getrandom instead of rand --- Cargo.lock | 12 ++++++------ lib/emscripten/Cargo.toml | 2 +- lib/emscripten/src/syscalls/windows.rs | 4 ++-- lib/wasi/Cargo.toml | 2 +- lib/wasi/src/syscalls/mod.rs | 12 ++++++------ lib/wasi/src/syscalls/types.rs | 1 + 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 582e608d2..68b864931 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,7 +451,7 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -818,7 +818,7 @@ name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -852,7 +852,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1415,9 +1415,9 @@ name = "wasmer-emscripten" version = "0.9.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.9.0", ] @@ -1570,9 +1570,9 @@ dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1698,7 +1698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "921c3803adaeb9f9639de5149d9f0f9f4b79f00c423915b701db2e02ed80b9ce" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" diff --git a/lib/emscripten/Cargo.toml b/lib/emscripten/Cargo.toml index d6fff3fbc..f51ee1a72 100644 --- a/lib/emscripten/Cargo.toml +++ b/lib/emscripten/Cargo.toml @@ -15,7 +15,7 @@ time = "0.1" wasmer-runtime-core = { path = "../runtime-core", version = "0.9.0" } [target.'cfg(windows)'.dependencies] -rand = "0.7" +getrandom = "0.1" [features] debug = ["wasmer-runtime-core/debug"] diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index 3c1f32dac..0e01aa1dc 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -2,7 +2,6 @@ use crate::utils::{copy_cstr_into_wasm, get_cstr_path}; use crate::varargs::VarArgs; use libc::mkdir; use libc::open; -use rand::Rng; use std::env; use std::ffi::CString; use std::fs::File; @@ -39,7 +38,8 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { let ptr = tmp_dir_c_str.as_ptr() as *const i8; let mut urandom_file = File::create(tmp_dir).unwrap(); // create some random bytes and put them into the file - let random_bytes = rand::thread_rng().gen::<[u8; 32]>(); + let mut random_bytes = [0u8; 32]; + getrandom::getrandom(random_bytes).unwrap(); let _ = urandom_file.write_all(&random_bytes).unwrap(); // put the file path string into wasm memory let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) }; diff --git a/lib/wasi/Cargo.toml b/lib/wasi/Cargo.toml index afbba97a3..e73b57ea4 100644 --- a/lib/wasi/Cargo.toml +++ b/lib/wasi/Cargo.toml @@ -13,7 +13,7 @@ byteorder = "1.3" generational-arena = { version = "0.2", features = ["serde"] } libc = "0.2.60" log = "0.4" -rand = "0.7" +getrandom = "0.1" time = "0.1" typetag = "0.1" serde = { version = "1", features = ["derive"] } diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 37a6486c3..90128bd34 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -15,7 +15,6 @@ use crate::{ }, ExitCode, }; -use rand::{thread_rng, Rng}; use std::borrow::Borrow; use std::cell::Cell; use std::convert::{Infallible, TryInto}; @@ -2453,17 +2452,18 @@ pub fn proc_raise(ctx: &mut Ctx, sig: __wasi_signal_t) -> __wasi_errno_t { /// The number of bytes that will be written pub fn random_get(ctx: &mut Ctx, buf: WasmPtr, buf_len: u32) -> __wasi_errno_t { debug!("wasi::random_get buf_len: {}", buf_len); - let mut rng = thread_rng(); let memory = ctx.memory(0); let buf = wasi_try!(buf.deref(memory, 0, buf_len)); - unsafe { + let res = unsafe { let u8_buffer = &mut *(buf as *const [_] as *mut [_] as *mut [u8]); - thread_rng().fill(u8_buffer); + getrandom::getrandom(u8_buffer) + }; + match res { + Ok(()) => __WASI_ESUCCESS, + Err(_) => __WASI_ERNGFAILURE, } - - __WASI_ESUCCESS } /// ### `sched_yield()` diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index d2aaa0554..26d9be448 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -147,6 +147,7 @@ pub const __WASI_ETIMEDOUT: u16 = 73; pub const __WASI_ETXTBSY: u16 = 74; pub const __WASI_EXDEV: u16 = 75; pub const __WASI_ENOTCAPABLE: u16 = 76; +pub const __WASI_ERNGFAILURE: u16 = 77; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] From 8e6f4c448b764271f4fdd9a19edd29ce9eb1ca2c Mon Sep 17 00:00:00 2001 From: newpavlov Date: Mon, 28 Oct 2019 18:37:14 +0300 Subject: [PATCH 085/122] reuse __WASI_EIO error code --- lib/wasi/src/syscalls/mod.rs | 2 +- lib/wasi/src/syscalls/types.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/wasi/src/syscalls/mod.rs b/lib/wasi/src/syscalls/mod.rs index 90128bd34..585469035 100644 --- a/lib/wasi/src/syscalls/mod.rs +++ b/lib/wasi/src/syscalls/mod.rs @@ -2462,7 +2462,7 @@ pub fn random_get(ctx: &mut Ctx, buf: WasmPtr, buf_len: u32) -> __was }; match res { Ok(()) => __WASI_ESUCCESS, - Err(_) => __WASI_ERNGFAILURE, + Err(_) => __WASI_EIO, } } diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index 26d9be448..d2aaa0554 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -147,7 +147,6 @@ pub const __WASI_ETIMEDOUT: u16 = 73; pub const __WASI_ETXTBSY: u16 = 74; pub const __WASI_EXDEV: u16 = 75; pub const __WASI_ENOTCAPABLE: u16 = 76; -pub const __WASI_ERNGFAILURE: u16 = 77; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] From 56475594e9fd3c8c48e1553f227edeeba6e9ff88 Mon Sep 17 00:00:00 2001 From: Artyom Pavlov Date: Mon, 28 Oct 2019 17:57:29 +0000 Subject: [PATCH 086/122] compilation error fix --- lib/emscripten/src/syscalls/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/emscripten/src/syscalls/windows.rs b/lib/emscripten/src/syscalls/windows.rs index 0e01aa1dc..b5ed6cc83 100644 --- a/lib/emscripten/src/syscalls/windows.rs +++ b/lib/emscripten/src/syscalls/windows.rs @@ -39,7 +39,7 @@ pub fn ___syscall5(ctx: &mut Ctx, which: c_int, mut varargs: VarArgs) -> c_int { let mut urandom_file = File::create(tmp_dir).unwrap(); // create some random bytes and put them into the file let mut random_bytes = [0u8; 32]; - getrandom::getrandom(random_bytes).unwrap(); + getrandom::getrandom(&mut random_bytes).unwrap(); let _ = urandom_file.write_all(&random_bytes).unwrap(); // put the file path string into wasm memory let urandom_file_offset = unsafe { copy_cstr_into_wasm(ctx, ptr) }; From 9224db6d1e72c5abdd32ea017ba26122e5313f63 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 28 Oct 2019 15:53:26 -0700 Subject: [PATCH 087/122] Don't emit bounds checks when the offset is less than the minimum memory size. --- Cargo.lock | 120 ++++++++++++++--------------- lib/llvm-backend/src/code.rs | 113 +++++++++++++++++---------- lib/llvm-backend/src/intrinsics.rs | 62 +++++++++------ 3 files changed, 170 insertions(+), 125 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68b864931..ce4f98c87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,7 +50,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -76,7 +76,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -97,8 +97,8 @@ name = "cargo_toml" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -116,11 +116,11 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -188,7 +188,7 @@ dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -231,7 +231,7 @@ dependencies = [ "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -240,8 +240,8 @@ dependencies = [ "rand_xoshiro 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -254,7 +254,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -305,7 +305,7 @@ dependencies = [ "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -322,7 +322,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -376,7 +376,7 @@ name = "erased-serde" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -413,7 +413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -438,7 +438,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -466,7 +466,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -508,13 +508,13 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#5ae21b51d9dd20a63e4431b06e3beb7a42d6ceb8" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -528,7 +528,7 @@ dependencies = [ [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#5ae21b51d9dd20a63e4431b06e3beb7a42d6ceb8" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -553,12 +553,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itertools" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -748,7 +748,7 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -773,7 +773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1022,10 +1022,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1034,7 +1034,7 @@ version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1042,17 +1042,17 @@ name = "serde_bytes" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1062,12 +1062,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "smallvec" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1098,7 +1098,7 @@ dependencies = [ "proc-macro-error 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1123,7 +1123,7 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1146,7 +1146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1209,7 +1209,7 @@ name = "tinytemplate" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1218,15 +1218,15 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1242,7 +1242,7 @@ dependencies = [ "erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1253,7 +1253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1296,8 +1296,8 @@ name = "wabt" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "wabt-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1335,7 +1335,7 @@ dependencies = [ "errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1365,10 +1365,10 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-frontend 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-fork-wasm 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1385,7 +1385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cranelift-codegen 0.44.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "target-lexicon 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1458,7 +1458,7 @@ dependencies = [ "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.9.0", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1528,11 +1528,11 @@ dependencies = [ "page_size 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "wasmparser 0.39.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1547,7 +1547,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.9.0", ] @@ -1573,7 +1573,7 @@ dependencies = [ "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.9.0", @@ -1710,7 +1710,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum inkwell_internal_macros 0.1.0 (git+https://github.com/wasmerio/inkwell?branch=llvm8-0)" = "" "checksum inventory 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f4cece20baea71d9f3435e7bbe9adf4765f091c5fe404975f844006964a71299" "checksum inventory-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2869bf972e998977b1cb87e60df70341d48e48dca0823f534feb91ea44adaf9" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" +"checksum itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87fa75c9dea7b07be3138c49abbb83fd4bea199b5cdc76f9804458edc5da0d6e" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" @@ -1764,19 +1764,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scroll_derive 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4b39bd9b0b087684013a792c59e3e07a46a01d2322518d8a1104641a0b1be0" "checksum serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "d733da87e79faaac25616e33d26299a41143fd4cd42746cbb0e91d8feea243fd" "checksum serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "45af0182ff64abaeea290235eb67da3825a576c5d53e642c4d5b652e12e6effc" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" +"checksum serde_derive 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)" = "ca13fc1a832f793322228923fbb3aba9f3f44444898f835d31ad1b74fa0a2bf8" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum smallvec 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cefaa50e76a6f10b86f36e640eb1739eafbd4084865067778463913e43a77ff3" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum structopt 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4f66a4c0ddf7aee4677995697366de0749b0139057342eccbb609b12d0affc" "checksum structopt-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8fe0c13e476b4e21ff7f5c4ace3818b6d7bdc16897c31c73862471bc1663acae" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum syn 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7bedb3320d0f3035594b0b723c8a28d7d336a3eda3881db79e61d676fb644c" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" @@ -1787,7 +1787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tinytemplate 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4574b75faccaacddb9b284faecdf0b544b80b6b294f3d062d325c5726a209c20" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724" +"checksum toml 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c04dffffeac90885436d23c692517bb5b8b3f8863e4afc15023628d067d667b7" "checksum typenum 1.11.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" "checksum typetag 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebb2c484029d695fb68a06d80e1536c68d491b3e0cf874c66abed255e831cfe" "checksum typetag-impl 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b63fd4799e4d0ec5cf0b055ebb8e2c3a657bbf76a84f6edc77ca60780e000204" diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index bd13e0ea2..4fdd7caab 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -561,18 +561,25 @@ fn resolve_memory_ptr( ) -> Result { // Look up the memory base (as pointer) and bounds (as unsigned integer). let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); - let (mem_base, mem_bound) = match memory_cache { + let (mem_base, mem_bound, minimum, _maximum) = match memory_cache { MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds, + minimum, + maximum, } => { let base = builder .build_load(ptr_to_base_ptr, "base") .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); - (base, bounds) + (base, bounds, minimum, maximum) } - MemoryCache::Static { base_ptr, bounds } => (base_ptr, bounds), + MemoryCache::Static { + base_ptr, + bounds, + minimum, + maximum, + } => (base_ptr, bounds, minimum, maximum), }; let mem_base = builder .build_bitcast(mem_base, intrinsics.i8_ptr_ty, &state.var_name()) @@ -587,48 +594,72 @@ fn resolve_memory_ptr( if let MemoryCache::Dynamic { .. } = memory_cache { // If the memory is dynamic, do a bounds check. For static we rely on - // the size being a multiple of the page size and hitting a reserved - // but unreadable memory. + // the size being a multiple of the page size and hitting a guard page. let value_size_v = intrinsics.i64_ty.const_int(value_size as u64, false); - let load_offset_end = - builder.build_int_add(effective_offset, value_size_v, &state.var_name()); + let ptr_in_bounds = if effective_offset.is_const() { + let load_offset_end = effective_offset.const_add(value_size_v); + let ptr_in_bounds = load_offset_end.const_int_compare( + IntPredicate::ULE, + intrinsics.i64_ty.const_int(minimum.bytes().0 as u64, false), + ); + if ptr_in_bounds.is_constant_int() { + Some(ptr_in_bounds) + } else { + None + } + } else { + None + } + .unwrap_or_else(|| { + let load_offset_end = + builder.build_int_add(effective_offset, value_size_v, &state.var_name()); - let ptr_in_bounds = builder.build_int_compare( - IntPredicate::ULE, - load_offset_end, - mem_bound, - &state.var_name(), - ); - let ptr_in_bounds = builder - .build_call( - intrinsics.expect_i1, - &[ - ptr_in_bounds.as_basic_value_enum(), - intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), - ], - "ptr_in_bounds_expect", + builder.build_int_compare( + IntPredicate::ULE, + load_offset_end, + mem_bound, + &state.var_name(), ) - .try_as_basic_value() - .left() - .unwrap() - .into_int_value(); + }); + if !ptr_in_bounds.is_constant_int() + || ptr_in_bounds.get_zero_extended_constant().unwrap() != 1 + { + // LLVM may have folded this into 'i1 true' in which case we know + // the pointer is in bounds. LLVM may also have folded it into a + // constant expression, not known to be either true or false yet. + // If it's false, unknown-but-constant, or not-a-constant, emit a + // runtime bounds check. LLVM may yet succeed at optimizing it away. + let ptr_in_bounds = builder + .build_call( + intrinsics.expect_i1, + &[ + ptr_in_bounds.as_basic_value_enum(), + intrinsics.i1_ty.const_int(1, false).as_basic_value_enum(), + ], + "ptr_in_bounds_expect", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); - let in_bounds_continue_block = - context.append_basic_block(function, "in_bounds_continue_block"); - let not_in_bounds_block = context.append_basic_block(function, "not_in_bounds_block"); - builder.build_conditional_branch( - ptr_in_bounds, - &in_bounds_continue_block, - ¬_in_bounds_block, - ); - builder.position_at_end(¬_in_bounds_block); - builder.build_call( - intrinsics.throw_trap, - &[intrinsics.trap_memory_oob], - "throw", - ); - builder.build_unreachable(); - builder.position_at_end(&in_bounds_continue_block); + let in_bounds_continue_block = + context.append_basic_block(function, "in_bounds_continue_block"); + let not_in_bounds_block = context.append_basic_block(function, "not_in_bounds_block"); + builder.build_conditional_branch( + ptr_in_bounds, + &in_bounds_continue_block, + ¬_in_bounds_block, + ); + builder.position_at_end(¬_in_bounds_block); + builder.build_call( + intrinsics.throw_trap, + &[intrinsics.trap_memory_oob], + "throw", + ); + builder.build_unreachable(); + builder.position_at_end(&in_bounds_continue_block); + } } let ptr = unsafe { builder.build_gep(mem_base, &[effective_offset], &state.var_name()) }; diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 36c3b7081..9fb668f1a 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -21,6 +21,7 @@ use wasmer_runtime_core::{ GlobalIndex, ImportedFuncIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, }, + units::Pages, vm::{Ctx, INTERNALS_SIZE}, }; @@ -559,11 +560,15 @@ pub enum MemoryCache { Dynamic { ptr_to_base_ptr: PointerValue, ptr_to_bounds: PointerValue, + minimum: Pages, + maximum: Option, }, /// The memory is always in the same place. Static { base_ptr: PointerValue, bounds: IntValue, + minimum: Pages, + maximum: Option, }, } @@ -662,30 +667,35 @@ impl<'a> CtxType<'a> { ); *cached_memories.entry(index).or_insert_with(|| { - let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) { - LocalOrImport::Local(local_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_memories()), - "memory_array_ptr_ptr", - ) - }, - local_mem_index.index() as u64, - info.memories[local_mem_index].memory_type(), - ), - LocalOrImport::Import(import_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_imported_memories()), - "memory_array_ptr_ptr", - ) - }, - import_mem_index.index() as u64, - info.imported_memories[import_mem_index].1.memory_type(), - ), - }; + let (memory_array_ptr_ptr, index, memory_type, minimum, maximum) = + match index.local_or_import(info) { + LocalOrImport::Local(local_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_memories()), + "memory_array_ptr_ptr", + ) + }, + local_mem_index.index() as u64, + info.memories[local_mem_index].memory_type(), + info.memories[local_mem_index].minimum, + info.memories[local_mem_index].maximum, + ), + LocalOrImport::Import(import_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_imported_memories()), + "memory_array_ptr_ptr", + ) + }, + import_mem_index.index() as u64, + info.imported_memories[import_mem_index].1.memory_type(), + info.imported_memories[import_mem_index].1.minimum, + info.imported_memories[import_mem_index].1.maximum, + ), + }; let memory_array_ptr = cache_builder .build_load(memory_array_ptr_ptr, "memory_array_ptr") @@ -713,6 +723,8 @@ impl<'a> CtxType<'a> { MemoryType::Dynamic => MemoryCache::Dynamic { ptr_to_base_ptr, ptr_to_bounds, + minimum, + maximum, }, MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static { base_ptr: cache_builder @@ -721,6 +733,8 @@ impl<'a> CtxType<'a> { bounds: cache_builder .build_load(ptr_to_bounds, "bounds") .into_int_value(), + minimum, + maximum, }, } }) From a104d08c048a695603ce4fe8cef0fbc86b609ea0 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 29 Oct 2019 14:55:14 -0700 Subject: [PATCH 088/122] Update ImportObject C API to use iterators --- lib/runtime-c-api/src/import/mod.rs | 197 ++++++++++++------ .../tests/test-wasi-import-object | Bin 19508 -> 15612 bytes .../tests/test-wasi-import-object.c | 34 ++- lib/runtime-c-api/wasmer.h | 56 +++-- lib/runtime-c-api/wasmer.hh | 44 ++-- 5 files changed, 208 insertions(+), 123 deletions(-) diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index ad0470af6..a38645dd1 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -13,7 +13,7 @@ use std::{convert::TryFrom, ffi::c_void, ptr, slice, sync::Arc}; use wasmer_runtime::{Global, Memory, Module, Table}; use wasmer_runtime_core::{ export::{Context, Export, FuncPointer}, - import::ImportObject, + import::{ImportObject, ImportObjectIterator}, module::ImportName, types::{FuncSig, Type}, }; @@ -41,6 +41,10 @@ pub struct wasmer_import_descriptor_t; #[derive(Clone)] pub struct wasmer_import_descriptors_t; +#[repr(C)] +#[derive(Clone)] +pub struct wasmer_import_object_iter_t; + /// Creates a new empty import object. /// See also `wasmer_import_object_append` #[allow(clippy::cast_ptr_alignment)] @@ -58,12 +62,11 @@ mod wasi; pub use self::wasi::*; /// Gets an entry from an ImportObject at the name and namespace. -/// Stores an immutable reference to `name` and `namespace` in `import`. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. /// /// The caller owns all data involved. -/// `import_export_value` will be written to based on `tag`, `import_export_value` must be -/// initialized to point to the type specified by `tag`. Failure to do so may result -/// in data corruption or undefined behavior. +/// `import_export_value` will be written to based on `tag`. #[no_mangle] pub unsafe extern "C" fn wasmer_import_object_get_import( import_object: *const wasmer_import_object_t, @@ -169,95 +172,157 @@ pub unsafe extern "C" fn wasmer_import_object_get_import( } } +/// private wrapper data type used for casting +#[repr(C)] +struct WasmerImportObjectIterator( + std::iter::Peekable::Item>>>, +); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` #[no_mangle] -/// Get the number of functions that an import object contains. -/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. -/// This function returns -1 on error. -pub unsafe extern "C" fn wasmer_import_object_get_num_functions( +pub unsafe extern "C" fn wasmer_import_object_iterate_functions( import_object: *const wasmer_import_object_t, -) -> i32 { +) -> *mut wasmer_import_object_iter_t { if import_object.is_null() { update_last_error(CApiError { msg: "import_object must not be null".to_owned(), }); - return -1; + return std::ptr::null_mut(); } let import_object: &ImportObject = &*(import_object as *const ImportObject); - import_object - .clone_ref() - .into_iter() - .filter(|(_, _, e)| { - if let Export::Function { .. } = e { - true - } else { - false - } - }) - .count() as i32 + let iter_inner = Box::new(import_object.clone_ref().into_iter().filter(|(_, _, e)| { + if let Export::Function { .. } = e { + true + } else { + false + } + })) as Box::Item>>; + let iterator = Box::new(WasmerImportObjectIterator(iter_inner.peekable())); + + Box::into_raw(iterator) as *mut wasmer_import_object_iter_t } +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. #[no_mangle] -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. -/// This function return -1 on error. -pub unsafe extern "C" fn wasmer_import_object_get_functions( - import_object: *const wasmer_import_object_t, - imports: *mut wasmer_import_t, - imports_len: u32, -) -> i32 { - if import_object.is_null() || imports.is_null() { +pub unsafe extern "C" fn wasmer_import_object_iter_next( + import_object_iter: *mut wasmer_import_object_iter_t, + import: *mut wasmer_import_t, +) -> wasmer_result_t { + if import_object_iter.is_null() || import.is_null() { update_last_error(CApiError { - msg: "import_object and imports must not be null".to_owned(), + msg: "import_object_iter and import must not be null".to_owned(), }); - return -1; + return wasmer_result_t::WASMER_ERROR; } - let import_object: &ImportObject = &*(import_object as *const ImportObject); - let mut i = 0; - for (namespace, name, export) in import_object.clone_ref().into_iter() { - if i + 1 > imports_len { - return i as i32; - } + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + let out = &mut *import; + // TODO: the copying here can be optimized away, we just need to use a different type of + // iterator internally + if let Some((namespace, name, export)) = iter.0.next() { + let ns = { + let mut n = namespace.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let ns_bytes = wasmer_byte_array { + bytes: ns.as_ptr(), + bytes_len: ns.len() as u32, + }; + + let name = { + let mut n = name.clone(); + n.shrink_to_fit(); + n.into_bytes() + }; + let name_bytes = wasmer_byte_array { + bytes: name.as_ptr(), + bytes_len: name.len() as u32, + }; + + out.module_name = ns_bytes; + out.import_name = name_bytes; + + std::mem::forget(ns); + std::mem::forget(name); + match export { Export::Function { .. } => { - let ns = namespace.clone().into_bytes(); - let ns_bytes = wasmer_byte_array { - bytes: ns.as_ptr(), - bytes_len: ns.len() as u32, - }; - std::mem::forget(ns); - - let name = name.clone().into_bytes(); - let name_bytes = wasmer_byte_array { - bytes: name.as_ptr(), - bytes_len: name.len() as u32, - }; - std::mem::forget(name); - let func = Box::new(export.clone()); - let new_entry = wasmer_import_t { - module_name: ns_bytes, - import_name: name_bytes, - tag: wasmer_import_export_kind::WASM_FUNCTION, - value: wasmer_import_export_value { - func: Box::into_raw(func) as *mut _ as *const _, - }, + out.tag = wasmer_import_export_kind::WASM_FUNCTION; + out.value = wasmer_import_export_value { + func: Box::into_raw(func) as *mut _ as *const _, }; - *imports.add(i as usize) = new_entry; - i += 1; } - _ => (), - } - } + Export::Global(global) => { + let glbl = Box::new(global.clone()); - return i as i32; + out.tag = wasmer_import_export_kind::WASM_GLOBAL; + out.value = wasmer_import_export_value { + global: Box::into_raw(glbl) as *mut _ as *const _, + }; + } + Export::Memory(memory) => { + let mem = Box::new(memory.clone()); + + out.tag = wasmer_import_export_kind::WASM_MEMORY; + out.value = wasmer_import_export_value { + memory: Box::into_raw(mem) as *mut _ as *const _, + }; + } + Export::Table(table) => { + let tbl = Box::new(table.clone()); + + out.tag = wasmer_import_export_kind::WASM_TABLE; + out.value = wasmer_import_export_value { + memory: Box::into_raw(tbl) as *mut _ as *const _, + }; + } + } + + wasmer_result_t::WASMER_OK + } else { + wasmer_result_t::WASMER_ERROR + } } +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data #[no_mangle] -/// Frees the memory acquired in `wasmer_import_object_get_functions` +pub unsafe extern "C" fn wasmer_import_object_iter_at_end( + import_object_iter: *mut wasmer_import_object_iter_t, +) -> bool { + if import_object_iter.is_null() { + update_last_error(CApiError { + msg: "import_object_iter must not be null".to_owned(), + }); + return true; + } + let iter = &mut *(import_object_iter as *mut WasmerImportObjectIterator); + + iter.0.peek().is_none() +} + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +#[no_mangle] +pub unsafe extern "C" fn wasmer_import_object_iter_destroy( + import_object_iter: *mut wasmer_import_object_iter_t, +) { + let _ = Box::from_raw(import_object_iter as *mut WasmerImportObjectIterator); +} + +/// Frees the memory allocated in `wasmer_import_object_iter_next` /// /// This function does not free the memory in `wasmer_import_object_t`; /// it only frees memory allocated while querying a `wasmer_import_object_t`. +#[no_mangle] pub unsafe extern "C" fn wasmer_import_object_imports_destroy( imports: *mut wasmer_import_t, imports_len: u32, diff --git a/lib/runtime-c-api/tests/test-wasi-import-object b/lib/runtime-c-api/tests/test-wasi-import-object index 70e24d17d8b27c47e5810e79983e2fe5e4b8779d..912bc8c0d7c62e00ceb3a3dabe9d541f58305382 100755 GIT binary patch delta 4052 zcmZu!ZBSI#89sa2)dg7=M3IkOc9E}DAt)2ATG8c8F9aJhF$tqa*udIFVHaUZu%j-O zY~pp@6g-kTY0}^i4HHeJqhtuG=_NlzULkYZhD8k z&-1+JIq!Mzx#!$_Iel0&v9nuBu#!g)YtI|YW-pE-L<8|Fv1;SuxSl(!XFp6;qha3T zVJa=utezcCQ^S4O1CDSS-3#Gvvl>nj)Nr?%Uem0ed%~iItJNq$EzsM#G-?-8uo{*n zp0`@*HepQ`kLr1lfR38vfHUA{qnCxeN#kU1{r@p8pysG4qn($W9ATUZ85hy!s71P( z45+B5IE@ZPEl6G*Q5|SJCg^uj)>R;|Ks_Ljv&Q8h>{>!P9w(#)A~+k#@C$=R->Maa zjL>Ja7R^GO1zq@Oggo8zR3h!y+Ts)czB@7d#budq|8>(FX_{}+=q>GXq1s4Ob$^&G zLjoLd0sP`w!c(_(&*~4FlX4A-P^cK#eP8-et~3xLO64+0S$2Ss%D-T|!a$46^J4Wz zY(GChz`A6|`rQih? z2o5pm9RQFiEaqbAT$!|f6pCZ1r1CMCG^BF-RO^k4{*Nb86ot)SP&bPW?H^%<==3r4 zqxmLb$xJ#v-(*Xi>NIrGe;ORT&n0yp`qe&T(KJ8PBwU?Ap8)vd4BD8vpomo*V3kz` z)T#r$STz)X0-#*_1gcc)*JhOk-ojv+v^h&Je>sC*%{2S^ARtN?VG@uH;U0q3ahOGM zb#w!h$8``5_*t}TWHBsoF*w+Pvo2j11HI@0>prxeRjtUyDeL`6YbRPMShbM0lX|k| z&13_4bTpV{vf@DUATb!DfgdeQaVkNv>x!q9Rp?aN-6 z-+=r{XqNm9&^a)OXQ=QMxPP!o&Ct>n!k9+#*U@{~1*u=dvlME-%fL_pzTpqC!~;>( zo@2AEWVtr5TzH0D>1wW*;ep&0!WiV*OuKUmQa7r(YSdi+1Q;H}Twe?H)10E*GY}~L z03X0|Idqo%t5{k*L)xRz3MGCd(4yS=g*9*?#+Ttuf%E$wo93m*85nk8-cK>hT3ChS zK*)Ywub%egruaOnvsrakq4P6z>L;BrtKBf39E1SO-C}j@rC^lvASC%Wz`$U_2KiZt zJg)R>jDE;R##cb;yb0D8L5H37nSefBAvpUKjq%XA&bvzIZH@8$b7Fm1?0QJ1uHzcs zx8Tw-28NrEbodTdw;d9*>kxw>mUi=h73EJ>Y&wWz27?$CyUxXn(pAY{4a3PR&;mP_ z$R4nCg{y3xbcm7A|yaS^@5bLjsUEjeaRe^u123#Ca!+Ny_oUdUVT9)CY*3cEQ zVJ>4Yjmt^)#j5@o)i0v|-{?O&{}BHM=S9J0Do&is(Zytdt4?``zB z+pLXlYh!bZr`2oqys*t#?_C)~XwPGFW~f2BryyyP9w}H9haaHueZziAD*dcrbx)nv zr{$lNaU7F5&gYoNaT!ND$4ZVHIBwzS;@HY@7sppP5|jGD7o(z&%;AA_jy8^k99MB% z%dwi{Mve^}-5fhO?&WxZk9zGWw>I#snfy{KHET3Q?3 z-mR!wP_=vOU5-|i9ja_Q^{suThCWx4s2Qar#VPTPUT15q!&~cgH=u0{gIWyIEhQ=R z<6=V`bGV%yY>Zpjo`fNX*IB!Daxr07nQkvJX~J}0Nsi_|Jy~KAIt6;SWNvJe)BQ`Y z3oZLFU^R6M3HI8T9Bs`oG+d0Qb!TmZ!|OoDVVYlR*7VUQN=+;Je`<3(UqaWw^cGJ; zdy})a!P(|*^{`nPqJ5<{%?Q0zYDyiQ=JYyV03%N^MwQZq)K>O$VZcP4WtN;iGyDtF znGUD1bXe!?7%;WeRRcQ)`#LU~keUqoZdrQax}vAr*j zJ}7(9@q3V<;PIm#M(rWEW6(Nz$oHmD@G&3C5290oh+SLI3~& delta 4180 zcmZu!4Nw&48QwkaT$#>QH};}k1@MXo}Pz0=FK zZr7`rPaL#yWF~2%t&L0&OGqyPwP?~Nf-_c{I2pCpS!PUn(L_P1*Z2K)0l8-9ZlC9Q zzxR8;XTSZv-MjIYv+ZoFV6-#S5Bs5G%i|y4q*WTthiRc*^%j777T19SYW)p`hncRv5$)~C%6Nv_;G3t8~7ZG#BWTIU$X$nh>gaYZLHX=jAWx?2o zif5Cah;)-f_Q6cl2aQKA8H=zMI%I=UfKYAnSOGc+ZfzwD(*RMteiM8ASM=#wUdryx*<;GWC<3dE};gh02;nQZ(pN^8Q$~h-=T@7=79YyTA#6_72;Fc5jj0yu%wT@vpp;Q7XNgfbF=^e_q=}4_E zDb4^DIN^LJBMoawt1fx1ndXd(?s3jv^e;WbK+`F>{hV{pxKMge5|Im~K`0W0Bmr{YLD)niKW} zFY%`#4%Y+aA8|srbvzUjJ}d6QOXY+%6UcSKc~0OB*x-+Yv-EBpb`M~L6KRiLoMle* zV|t0mW0q0s!8C#IpyO(;>4>Da7IFzuLvANI zF)JyO4s>D$3Cv2h;y}`eSjk^h7LAbS1Q7Vs*syvA8Jm@vk|8&wQ_yY$=sgGSrMnv9 zNHi@9YS2i)3$rKiC$Zlhj0k))&ZihakgjWpCoxI&o`$q1rlq`vS$n7YL2^5WwrI#; z;^NH1$XlRU;H#js*o|j!_*=Mtut{Hp7GD5ktiZRDMM+Cjp5VOs^TsG>UxvKi0kn8d zO&XGHwvDvbdRhz5P-~%F>nv<>UjSoJ>j3G4T3h5=6>_bw0D1?pmRU`rO+||?LZJA4 zdm~uN>_5~0aeOtfxn~?Vwt3Nm7;hg6=-zYQbT*5o$&$~-O zdmU``-o|0xgu2wZ;s@3?78Bdhixff4Ede^++`qq_W^Nu75vjM8JSOW8dnT>)bIw7| z_jt-lx$I=K?Bqx21Pw?j6Hdf#tO2vV3EJRBJP!?*cpJnZ4d&`KxFaIf%4mKY+)CIR zbTXWN%=BuXW+7X zzror|ptdse&pMwl?rXNe9X;>8AM)OYJ9?jU4othDDRNnpTy{5>y^m$D!D)o?&@-Im ziSqTq*1+o>8NfG=NEeJe&(czQjWiJsN zq9Le{Z6$`;U&eneuz-xu-r%_ggNz)3ol>pFb#wq(7P5WFUP9K4 z%#ExLSsSt{Wap5*f@~OB8L|h+)*v(Djx9v?9I|X=95NfSt;o{geut_LB2B>HX=E|T z{)&u22A9B$JcNm@#_c_F57`oAw~-Yf8%DMk*=NXb4o5B`t3cL^tQJ`(vR@#38`*wf zi$~r-dIW>7BYO+keq`?<`z5k|WKCUubAZj+>aKH^S2i|QwlH<>+H#al+w1FgT8oOT z7-)1gxf|JJoN~_RVCkB{3{=+>)WgU+%du7JlLP`9CbH zJU8G{;SMo(6$~o)SV48B+^$p5q~KfymngVQL5G4bD7aq1pD1`QL$3EwM%WI@Krsp? zD43?8O~Gsh3l&_WV3~riC|IRnor28@?o;r9f=4LA|BDVK@COCYD)^y-mleE=vLDW{()YLmsRiJX!IvZM0 zRm*Cps|i&DsD{Svbxm7QHKTGjIjbuhyB^vjS?xAg)6{w(aoK5!7@4+8u-_mtW~Y#+ zS@G;J>CH}MZ<6cT3t5Rg&9zj_+f_zK`L4>HwXR0=T;JGIUgz3{-8#rnj+s44{*z;4JBcYbm3*BOr)#R*QsbIP z=_4=YE+#Fx1uAa=>CUw*3>LuOw852d>L`R2M-Oj7Lq!=d7i>ozJWaSP@;Emwd*UzV zTxin6^0cPOtH!42LFF$f?oMoPFq0SZeqMPTBq(@7$OrDVXZ0V$bXS=EAWUBf(|;p# zmYwjNf|BwFn&B7<(~rWm7W_P$pBbjtgz1Vfy?eTjXAVveFmIFM<(8MPghlU$=_r`u zXKkc~X?vJnPi`%L2Osbb_%+95lCPHkjuhq}jezw|uIA?xW5Gb!itH;$GXCF+Bz*<; Ku01Q8+5Z6}_`S3M diff --git a/lib/runtime-c-api/tests/test-wasi-import-object.c b/lib/runtime-c-api/tests/test-wasi-import-object.c index cf4a145d5..e3f530d2d 100644 --- a/lib/runtime-c-api/tests/test-wasi-import-object.c +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -217,34 +217,26 @@ int main() assert(call_result == WASMER_OK); assert(host_print_called); - int32_t num_functions = wasmer_import_object_get_num_functions(import_object); - if (num_functions == -1) { - print_wasmer_error(); - return -1; - } - wasmer_import_t *func_array = malloc(sizeof(wasmer_import_t) * num_functions); - assert(func_array); + wasmer_import_object_iter_t *func_iter = wasmer_import_object_iterate_functions(import_object); - int32_t num_returned = wasmer_import_object_get_functions(import_object, func_array, num_functions); - if (num_functions == -1) { - print_wasmer_error(); - return -1; - } - assert(num_functions == num_returned); + puts("Functions in import object:"); + while ( !wasmer_import_object_iter_at_end(func_iter) ) { + wasmer_import_t import; + wasmer_result_t result = wasmer_import_object_iter_next(func_iter, &import); + assert(result == WASMER_OK); - printf("Found %d functions in import object:\n", num_returned); - for (int i = 0; i < num_returned; ++i) { - print_byte_array(&func_array[i].module_name); + print_byte_array(&import.module_name); putchar(' '); - print_byte_array(&func_array[i].import_name); + print_byte_array(&import.import_name); putchar('\n'); - assert(func_array[i].tag == WASM_FUNCTION); - assert(func_array[i].value.func); + + assert(import.tag == WASM_FUNCTION); + assert(import.value.func); + wasmer_import_object_imports_destroy(&import, 1); } + wasmer_import_object_iter_destroy(func_iter); // Use *_destroy methods to cleanup as specified in the header documentation - wasmer_import_object_imports_destroy(func_array, num_returned); - free(func_array); wasmer_import_func_destroy(func); wasmer_global_destroy(global); wasmer_memory_destroy(memory); diff --git a/lib/runtime-c-api/wasmer.h b/lib/runtime-c-api/wasmer.h index 8bb9fb254..eb9dab50d 100644 --- a/lib/runtime-c-api/wasmer.h +++ b/lib/runtime-c-api/wasmer.h @@ -138,6 +138,10 @@ typedef struct { typedef struct { +} wasmer_import_object_iter_t; + +typedef struct { + } wasmer_instance_t; typedef struct { @@ -469,22 +473,13 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); -/** - * Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. - * This function return -1 on error. - */ -int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, - wasmer_import_t *imports, - uint32_t imports_len); - /** * Gets an entry from an ImportObject at the name and namespace. - * Stores an immutable reference to `name` and `namespace` in `import`. + * Stores `name`, `namespace`, and `import_export_value` in `import`. + * Thus these must remain valid for the lifetime of `import`. * * The caller owns all data involved. - * `import_export_value` will be written to based on `tag`, `import_export_value` must be - * initialized to point to the type specified by `tag`. Failure to do so may result - * in data corruption or undefined behavior. + * `import_export_value` will be written to based on `tag`. */ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, wasmer_byte_array namespace_, @@ -494,20 +489,41 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im uint32_t tag); /** - * Get the number of functions that an import object contains. - * The result of this is useful as an argument to `wasmer_import_object_get_functions`. - * This function returns -1 on error. - */ -int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); - -/** - * Frees the memory acquired in `wasmer_import_object_get_functions` + * Frees the memory allocated in `wasmer_import_object_iter_next` * * This function does not free the memory in `wasmer_import_object_t`; * it only frees memory allocated while querying a `wasmer_import_object_t`. */ void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); +/** + * Returns true if further calls to `wasmer_import_object_iter_next` will + * not return any new data + */ +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/** + * Frees the memory allocated by `wasmer_import_object_iterate_functions` + */ +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/** + * Writes the next value to `import`. `WASMER_ERROR` is returned if there + * was an error or there's nothing left to return. + * + * To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. + * To check if the iterator is done, use `wasmer_import_object_iter_at_end`. + */ +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/** + * Create an iterator over the functions in the import object. + * Get the next import with `wasmer_import_object_iter_next` + * Free the iterator with `wasmer_import_object_iter_destroy` + */ +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /** * Creates a new empty import object. * See also `wasmer_import_object_append` diff --git a/lib/runtime-c-api/wasmer.hh b/lib/runtime-c-api/wasmer.hh index 21426f278..04a095c48 100644 --- a/lib/runtime-c-api/wasmer.hh +++ b/lib/runtime-c-api/wasmer.hh @@ -120,6 +120,10 @@ struct wasmer_import_t { wasmer_import_export_value value; }; +struct wasmer_import_object_iter_t { + +}; + struct wasmer_instance_t { }; @@ -371,19 +375,12 @@ wasmer_result_t wasmer_import_object_extend(wasmer_import_object_t *import_objec const wasmer_import_t *imports, unsigned int imports_len); -/// Call `wasmer_import_object_imports_destroy` to free the memory allocated by this function. -/// This function return -1 on error. -int32_t wasmer_import_object_get_functions(const wasmer_import_object_t *import_object, - wasmer_import_t *imports, - uint32_t imports_len); - /// Gets an entry from an ImportObject at the name and namespace. -/// Stores an immutable reference to `name` and `namespace` in `import`. +/// Stores `name`, `namespace`, and `import_export_value` in `import`. +/// Thus these must remain valid for the lifetime of `import`. /// /// The caller owns all data involved. -/// `import_export_value` will be written to based on `tag`, `import_export_value` must be -/// initialized to point to the type specified by `tag`. Failure to do so may result -/// in data corruption or undefined behavior. +/// `import_export_value` will be written to based on `tag`. wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *import_object, wasmer_byte_array namespace_, wasmer_byte_array name, @@ -391,17 +388,32 @@ wasmer_result_t wasmer_import_object_get_import(const wasmer_import_object_t *im wasmer_import_export_value *import_export_value, uint32_t tag); -/// Get the number of functions that an import object contains. -/// The result of this is useful as an argument to `wasmer_import_object_get_functions`. -/// This function returns -1 on error. -int32_t wasmer_import_object_get_num_functions(const wasmer_import_object_t *import_object); - -/// Frees the memory acquired in `wasmer_import_object_get_functions` +/// Frees the memory allocated in `wasmer_import_object_iter_next` /// /// This function does not free the memory in `wasmer_import_object_t`; /// it only frees memory allocated while querying a `wasmer_import_object_t`. void wasmer_import_object_imports_destroy(wasmer_import_t *imports, uint32_t imports_len); +/// Returns true if further calls to `wasmer_import_object_iter_next` will +/// not return any new data +bool wasmer_import_object_iter_at_end(wasmer_import_object_iter_t *import_object_iter); + +/// Frees the memory allocated by `wasmer_import_object_iterate_functions` +void wasmer_import_object_iter_destroy(wasmer_import_object_iter_t *import_object_iter); + +/// Writes the next value to `import`. `WASMER_ERROR` is returned if there +/// was an error or there's nothing left to return. +/// +/// To free the memory allocated here, pass the import to `wasmer_import_object_imports_destroy`. +/// To check if the iterator is done, use `wasmer_import_object_iter_at_end`. +wasmer_result_t wasmer_import_object_iter_next(wasmer_import_object_iter_t *import_object_iter, + wasmer_import_t *import); + +/// Create an iterator over the functions in the import object. +/// Get the next import with `wasmer_import_object_iter_next` +/// Free the iterator with `wasmer_import_object_iter_destroy` +wasmer_import_object_iter_t *wasmer_import_object_iterate_functions(const wasmer_import_object_t *import_object); + /// Creates a new empty import object. /// See also `wasmer_import_object_append` wasmer_import_object_t *wasmer_import_object_new(); From bc9b92c323cd7dae46843ef0d0f5f54f60ecaa52 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 29 Oct 2019 15:18:45 -0700 Subject: [PATCH 089/122] Add null checks to new destructors in C API --- lib/runtime-c-api/src/import/mod.rs | 7 ++++++- lib/runtime-c-api/tests/.gitignore | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/src/import/mod.rs b/lib/runtime-c-api/src/import/mod.rs index a38645dd1..5b44eb2b5 100644 --- a/lib/runtime-c-api/src/import/mod.rs +++ b/lib/runtime-c-api/src/import/mod.rs @@ -315,7 +315,9 @@ pub unsafe extern "C" fn wasmer_import_object_iter_at_end( pub unsafe extern "C" fn wasmer_import_object_iter_destroy( import_object_iter: *mut wasmer_import_object_iter_t, ) { - let _ = Box::from_raw(import_object_iter as *mut WasmerImportObjectIterator); + if !import_object_iter.is_null() { + let _ = Box::from_raw(import_object_iter as *mut WasmerImportObjectIterator); + } } /// Frees the memory allocated in `wasmer_import_object_iter_next` @@ -327,6 +329,9 @@ pub unsafe extern "C" fn wasmer_import_object_imports_destroy( imports: *mut wasmer_import_t, imports_len: u32, ) { + if imports.is_null() { + return; + } let imports: &[wasmer_import_t] = &*slice::from_raw_parts_mut(imports, imports_len as usize); for import in imports { let _namespace: Vec = Vec::from_raw_parts( diff --git a/lib/runtime-c-api/tests/.gitignore b/lib/runtime-c-api/tests/.gitignore index 26a85acee..b64fa610c 100644 --- a/lib/runtime-c-api/tests/.gitignore +++ b/lib/runtime-c-api/tests/.gitignore @@ -25,3 +25,5 @@ test-tables test-validate test-context test-module-import-instantiate +test-wasi-import-object + From ae07620818bf4a65b764ab4092ca6ecca57eac09 Mon Sep 17 00:00:00 2001 From: nlewycky Date: Tue, 29 Oct 2019 15:28:59 -0700 Subject: [PATCH 090/122] Use printf portably. PRId64 is defined to the right printf format string to print a int64_t on the current system. --- lib/runtime-c-api/tests/test-exports.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/runtime-c-api/tests/test-exports.c b/lib/runtime-c-api/tests/test-exports.c index 3af813d0e..e245414be 100644 --- a/lib/runtime-c-api/tests/test-exports.c +++ b/lib/runtime-c-api/tests/test-exports.c @@ -1,3 +1,4 @@ +#include #include #include "../wasmer.h" #include @@ -242,7 +243,7 @@ int main() wasmer_result_t call_result = wasmer_export_func_call(exported_function, inputs, inputs_arity, outputs, outputs_arity); - printf("Result: %lld\n", outputs[0].value.I64); + printf("Result: %" PRId64 "\n", outputs[0].value.I64); assert(outputs[0].value.I64 == 7); assert(call_result == WASMER_OK); From 44f026adfb44bc152c7ee2a386eee5a7d8bdc6b5 Mon Sep 17 00:00:00 2001 From: nlewycky Date: Tue, 29 Oct 2019 15:30:59 -0700 Subject: [PATCH 091/122] Move the linkage before the type. Though both orders work, this is customary. --- lib/runtime-c-api/tests/test-wasi-import-object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-c-api/tests/test-wasi-import-object.c b/lib/runtime-c-api/tests/test-wasi-import-object.c index e3f530d2d..bd1478dc1 100644 --- a/lib/runtime-c-api/tests/test-wasi-import-object.c +++ b/lib/runtime-c-api/tests/test-wasi-import-object.c @@ -4,7 +4,7 @@ #include #include -bool static host_print_called = false; +static bool host_print_called = false; // Host function that will be imported into the Web Assembly Instance void host_print(const wasmer_instance_context_t *ctx, int32_t ptr, int32_t len) From 1e4fa78e11ef00e80315bfb4230b3c11c71335ee Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 29 Oct 2019 15:52:42 -0700 Subject: [PATCH 092/122] Fix bug in getting a Memory from export in C API --- lib/runtime-c-api/src/export.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/runtime-c-api/src/export.rs b/lib/runtime-c-api/src/export.rs index d6dfa5d97..e10f36e13 100644 --- a/lib/runtime-c-api/src/export.rs +++ b/lib/runtime-c-api/src/export.rs @@ -13,7 +13,7 @@ use crate::{ }; use libc::{c_int, c_uint}; use std::{ptr, slice}; -use wasmer_runtime::{Instance, Memory, Module, Value}; +use wasmer_runtime::{Instance, Module, Value}; use wasmer_runtime_core::{export::Export, module::ExportIndex}; /// Intermediate representation of an `Export` instance that is @@ -355,7 +355,8 @@ pub unsafe extern "C" fn wasmer_export_to_memory( let export = &named_export.export; if let Export::Memory(exported_memory) = export { - *memory = exported_memory as *const Memory as *mut wasmer_memory_t; + let mem = Box::new(exported_memory.clone()); + *memory = Box::into_raw(mem) as *mut wasmer_memory_t; wasmer_result_t::WASMER_OK } else { update_last_error(CApiError { From 7fd20e33556690f0f01380890e1e422e4d5bda96 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Tue, 29 Oct 2019 12:14:14 -0700 Subject: [PATCH 093/122] NFC: Fold variable into initializer. --- lib/llvm-backend/src/code.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index bd13e0ea2..0a8df9084 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -7316,15 +7316,13 @@ impl ModuleCodeGenerator Some(Linkage::External), ); - let signatures = Map::new(); - LLVMModuleCodeGenerator { context: Some(context), builder: Some(builder), intrinsics: Some(intrinsics), module, functions: vec![], - signatures, + signatures: Map::new(), signatures_raw: Map::new(), function_signatures: None, func_import_count: 0, From edb6cbefcadbec18b043b7689592cb81875536c4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 13:01:31 +0100 Subject: [PATCH 094/122] fix(runtime-core) Share the definition of `Trampoline` across all the backends. This patch updates all the backends to use the definition of `Trampoline` as defined in the `wasmer_runtime_core::typed_func` module. That way, there is no copy of that type, and as such, it is easier to avoid regression (a simple `cargo check` does the job). This patch also formats the `use` statements in the updated files. --- lib/clif-backend/src/signal/mod.rs | 12 ++--- lib/clif-backend/src/signal/windows.rs | 44 +++++++++++-------- lib/clif-backend/src/trampoline.rs | 10 ++--- lib/llvm-backend/src/backend.rs | 17 +++---- lib/llvm-backend/src/code.rs | 23 +++++----- lib/runtime-core/src/typed_func.rs | 23 ++++++---- lib/singlepass-backend/src/codegen_x64.rs | 42 ++++++++---------- .../src/exception_handling.rs | 6 ++- 8 files changed, 91 insertions(+), 86 deletions(-) diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 3facce2ad..116da3f56 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -1,12 +1,14 @@ -use crate::relocation::{TrapData, TrapSink}; -use crate::resolver::FuncResolver; -use crate::trampoline::Trampolines; +use crate::{ + relocation::{TrapData, TrapSink}, + resolver::FuncResolver, + trampoline::Trampolines, +}; use libc::c_void; use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc}; use wasmer_runtime_core::{ backend::RunnableModule, module::ModuleInfo, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, }; @@ -59,7 +61,7 @@ impl RunnableModule for Caller { fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { unsafe extern "C" fn invoke( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), + trampoline: Trampoline, ctx: *mut vm::Ctx, func: NonNull, args: *const u64, diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index 52dc3e966..363119c6e 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -1,24 +1,30 @@ -use crate::relocation::{TrapCode, TrapData}; -use crate::signal::{CallProtError, HandlerData}; -use crate::trampoline::Trampoline; -use std::cell::Cell; -use std::ffi::c_void; -use std::ptr::{self, NonNull}; -use wasmer_runtime_core::typed_func::WasmTrapInfo; -use wasmer_runtime_core::vm::Ctx; -use wasmer_runtime_core::vm::Func; +use crate::{ + relocation::{TrapCode, TrapData}, + signal::{CallProtError, HandlerData}, +}; +use std::{ + cell::Cell, + ffi::c_void, + ptr::{self, NonNull}, +}; +use wasmer_runtime_core::{ + typed_func::{Trampoline, WasmTrapInfo}, + vm::{Ctx, Func}, +}; use wasmer_win_exception_handler::CallProtectedData; pub use wasmer_win_exception_handler::_call_protected; -use winapi::shared::minwindef::DWORD; -use winapi::um::minwinbase::{ - EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, - EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO, - EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, - EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, - EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, - EXCEPTION_INVALID_HANDLE, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_POSSIBLE_DEADLOCK, EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, - EXCEPTION_STACK_OVERFLOW, +use winapi::{ + shared::minwindef::DWORD, + um::minwinbase::{ + EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, + EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, + EXCEPTION_FLT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT, + EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK, + EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, EXCEPTION_ILLEGAL_INSTRUCTION, + EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_INVALID_HANDLE, + EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, EXCEPTION_POSSIBLE_DEADLOCK, + EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, EXCEPTION_STACK_OVERFLOW, + }, }; thread_local! { diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index f9c7245e9..fcd1ff83d 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -1,18 +1,16 @@ -use crate::cache::TrampolineCache; -use crate::resolver::NoopStackmapSink; +use crate::{cache::TrampolineCache, resolver::NoopStackmapSink}; use cranelift_codegen::{ binemit::{NullTrapSink, Reloc, RelocSink}, cursor::{Cursor, FuncCursor}, ir::{self, InstBuilder}, isa, Context, }; -use std::collections::HashMap; -use std::{iter, mem, ptr::NonNull}; +use std::{collections::HashMap, iter, mem}; use wasmer_runtime_core::{ backend::sys::{Memory, Protect}, module::{ExportIndex, ModuleInfo}, + typed_func::Trampoline, types::{FuncSig, SigIndex, Type}, - vm, }; struct NullRelocSink {} @@ -28,8 +26,6 @@ impl RelocSink for NullRelocSink { fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {} } -pub type Trampoline = unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64); - pub struct Trampolines { memory: Memory, offsets: HashMap, diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index f7847f063..e878c3feb 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -1,6 +1,8 @@ use super::stackmap::StackmapRegistry; -use crate::intrinsics::Intrinsics; -use crate::structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}; +use crate::{ + intrinsics::Intrinsics, + structs::{Callbacks, LLVMModule, LLVMResult, MemProtect}, +}; use inkwell::{ memory_buffer::MemoryBuffer, module::Module, @@ -27,7 +29,7 @@ use wasmer_runtime_core::{ module::ModuleInfo, state::ModuleStateMap, structures::TypedIndex, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, vmcalls, }; @@ -57,7 +59,7 @@ extern "C" { #[allow(improper_ctypes)] fn invoke_trampoline( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), + trampoline: Trampoline, vmctx_ptr: *mut vm::Ctx, func_ptr: NonNull, params: *const u64, @@ -387,12 +389,7 @@ impl RunnableModule for LLVMBackend { } fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { - let trampoline: unsafe extern "C" fn( - *mut vm::Ctx, - NonNull, - *const u64, - *mut u64, - ) = unsafe { + let trampoline: Trampoline = unsafe { let name = if cfg!(target_os = "macos") { format!("_trmp{}", sig_index.index()) } else { diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index bd13e0ea2..9aade0f27 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1,3 +1,11 @@ +use crate::{ + backend::LLVMBackend, + intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}, + read_info::{blocktype_to_type, type_to_type}, + stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}, + state::{ControlFrame, ExtraInfo, IfElseState, State}, + trampolines::generate_trampolines, +}; use inkwell::{ builder::Builder, context::Context, @@ -12,9 +20,11 @@ use inkwell::{ AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; use smallvec::SmallVec; -use std::cell::RefCell; -use std::rc::Rc; -use std::sync::{Arc, RwLock}; +use std::{ + cell::RefCell, + rc::Rc, + sync::{Arc, RwLock}, +}; use wasmer_runtime_core::{ backend::{Backend, CacheGen, CompilerConfig, Token}, cache::{Artifact, Error as CacheError}, @@ -28,13 +38,6 @@ use wasmer_runtime_core::{ }; use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; -use crate::backend::LLVMBackend; -use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; -use crate::read_info::{blocktype_to_type, type_to_type}; -use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}; -use crate::state::{ControlFrame, ExtraInfo, IfElseState, State}; -use crate::trampolines::generate_trampolines; - fn func_sig_to_llvm( context: &Context, intrinsics: &Intrinsics, diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 74318747c..54eb4e7a4 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -52,16 +52,21 @@ impl fmt::Display for WasmTrapInfo { /// of the `Func` struct. pub trait Kind {} -pub type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); +pub type Trampoline = unsafe extern "C" fn( + vmctx: *mut Ctx, + func: NonNull, + args: *const u64, + rets: *mut u64, +); pub type Invoke = unsafe extern "C" fn( - Trampoline, - *mut Ctx, - NonNull, - *const u64, - *mut u64, - *mut WasmTrapInfo, - *mut Option>, - Option>, + trampoline: Trampoline, + vmctx: *mut Ctx, + func: NonNull, + args: *const u64, + rets: *mut u64, + trap_info: *mut WasmTrapInfo, + user_error: *mut Option>, + extra: Option>, ) -> bool; /// TODO(lachlan): Naming TBD. diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index e3c9cca52..f4411a74c 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -7,8 +7,12 @@ use smallvec::SmallVec; use std::{ any::Any, collections::{BTreeMap, HashMap}, + ffi::c_void, + iter, mem, ptr::NonNull, + slice, sync::{Arc, RwLock}, + usize, }; use wasmer_runtime_core::{ backend::{ @@ -25,7 +29,7 @@ use wasmer_runtime_core::{ ModuleStateMap, OffsetInfo, SuspendOffset, WasmAbstractValue, }, structures::{Map, TypedIndex}, - typed_func::Wasm, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{ FuncIndex, FuncSig, GlobalIndex, LocalFuncIndex, LocalOrImport, MemoryIndex, SigIndex, TableIndex, Type, @@ -116,8 +120,8 @@ lazy_static! { ; ret ); let buf = assembler.finalize().unwrap(); - let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; - ::std::mem::forget(buf); + let ret = unsafe { mem::transmute(buf.ptr(offset)) }; + mem::forget(buf); ret }; } @@ -225,7 +229,7 @@ impl RunnableModule for X64ExecutionContext { 14: 41 ff e3 jmpq *%r11 */ #[repr(packed)] - struct Trampoline { + struct LocalTrampoline { movabsq_rax: [u8; 2], addr_rax: u64, movabsq_r11: [u8; 2], @@ -236,7 +240,7 @@ impl RunnableModule for X64ExecutionContext { self.code.make_writable(); let trampoline = &mut *(self.function_pointers[self.func_import_count + idx].0 - as *const Trampoline as *mut Trampoline); + as *const LocalTrampoline as *mut LocalTrampoline); trampoline.movabsq_rax[0] = 0x48; trampoline.movabsq_rax[1] = 0xb8; trampoline.addr_rax = target_address as u64; @@ -253,16 +257,8 @@ impl RunnableModule for X64ExecutionContext { } fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { - use std::ffi::c_void; - use wasmer_runtime_core::typed_func::WasmTrapInfo; - unsafe extern "C" fn invoke( - _trampoline: unsafe extern "C" fn( - *mut vm::Ctx, - NonNull, - *const u64, - *mut u64, - ), + _trampoline: Trampoline, ctx: *mut vm::Ctx, func: NonNull, args: *const u64, @@ -273,12 +269,10 @@ impl RunnableModule for X64ExecutionContext { ) -> bool { let rm: &Box = &(&*(*ctx).module).runnable_module; let execution_context = - ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); + mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); - let args = std::slice::from_raw_parts( - args, - num_params_plus_one.unwrap().as_ptr() as usize - 1, - ); + let args = + slice::from_raw_parts(args, num_params_plus_one.unwrap().as_ptr() as usize - 1); let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect(); let ret = match protect_unix::call_protected( || { @@ -1735,7 +1729,7 @@ impl X64FunctionCode { control_stack: &mut [ControlFrame], ) -> usize { if !m.track_state { - return ::std::usize::MAX; + return usize::MAX; } let last_frame = control_stack.last_mut().unwrap(); let mut diff = m.state.diff(&last_frame.state); @@ -1851,7 +1845,7 @@ impl FunctionCodeGenerator for X64FunctionCode { Location::GPR(GPR::RAX), ); - assert_eq!(self.machine.state.wasm_inst_offset, ::std::usize::MAX); + assert_eq!(self.machine.state.wasm_inst_offset, usize::MAX); Ok(()) } @@ -4721,7 +4715,7 @@ impl FunctionCodeGenerator for X64FunctionCode { |a| { a.emit_call_location(Location::GPR(GPR::RAX)); }, - ::std::iter::once(Location::Imm32(memory_index.index() as u32)), + iter::once(Location::Imm32(memory_index.index() as u32)), None, ); let ret = self.machine.acquire_locations( @@ -4760,8 +4754,8 @@ impl FunctionCodeGenerator for X64FunctionCode { |a| { a.emit_call_location(Location::GPR(GPR::RAX)); }, - ::std::iter::once(Location::Imm32(memory_index.index() as u32)) - .chain(::std::iter::once(param_pages)), + iter::once(Location::Imm32(memory_index.index() as u32)) + .chain(iter::once(param_pages)), None, ); diff --git a/lib/win-exception-handler/src/exception_handling.rs b/lib/win-exception-handler/src/exception_handling.rs index c448392b0..712214c8b 100644 --- a/lib/win-exception-handler/src/exception_handling.rs +++ b/lib/win-exception-handler/src/exception_handling.rs @@ -1,7 +1,9 @@ use std::ptr::NonNull; -use wasmer_runtime_core::vm::{Ctx, Func}; +use wasmer_runtime_core::{ + typed_func::Trampoline, + vm::{Ctx, Func}, +}; -type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); type CallProtectedResult = Result<(), CallProtectedData>; #[repr(C)] From bdc1ab34125a52404379aae5d81d0ea505f93039 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 13:28:01 +0100 Subject: [PATCH 095/122] feat(runtime-core-tests) Introduce the new `wasmer-runtime-core-tests` crate. This non-publishable new crate contains a test suite for the `wasmer-runtime-core` crate. So far, the test suite is rather small, but it aims to be extended in a close future. --- Cargo.lock | 11 +++ Cargo.toml | 1 + Makefile | 22 ++++- lib/runtime-core-tests/Cargo.toml | 21 +++++ lib/runtime-core-tests/src/lib.rs | 21 +++++ lib/runtime-core-tests/tests/imports.rs | 112 ++++++++++++++++++++++++ 6 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 lib/runtime-core-tests/Cargo.toml create mode 100644 lib/runtime-core-tests/src/lib.rs create mode 100644 lib/runtime-core-tests/tests/imports.rs diff --git a/Cargo.lock b/Cargo.lock index 917724f89..d15d45dd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1538,6 +1538,17 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmer-runtime-core-tests" +version = "0.8.0" +dependencies = [ + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-clif-backend 0.9.0", + "wasmer-llvm-backend 0.9.0", + "wasmer-runtime-core 0.9.0", + "wasmer-singlepass-backend 0.9.0", +] + [[package]] name = "wasmer-singlepass-backend" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 5c183b235..2a47f943d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "lib/singlepass-backend", "lib/runtime", "lib/runtime-core", + "lib/runtime-core-tests", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", diff --git a/Makefile b/Makefile index 145759993..a01c6689e 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ generate: generate-spectests generate-emtests generate-wasitests # Spectests spectests-singlepass: - cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture + cargo +nightly test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture spectests-cranelift: cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture @@ -88,13 +88,16 @@ wasitests: wasitests-unit wasitests-singlepass wasitests-cranelift wasitests-llv # Backends singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasitests-singlepass - cargo test -p wasmer-singlepass-backend --release + cargo +nightly test -p wasmer-singlepass-backend --release + cargo +nightly test -p wasmer-runtime-core-tests --release --no-default-features --features backend-singlepass cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift cargo test -p wasmer-clif-backend --release + cargo test -p wasmer-runtime-core-tests --release llvm: spectests-llvm emtests-llvm wasitests-llvm cargo test -p wasmer-llvm-backend --release + cargo test -p wasmer-runtime-core-tests --release --no-default-features --features backend-llvm # All tests @@ -108,7 +111,20 @@ test-capi: capi capi-test: test-capi test-rest: - cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests + cargo test --release \ + --all \ + --exclude wasmer-runtime-c-api \ + --exclude wasmer-emscripten \ + --exclude wasmer-spectests \ + --exclude wasmer-wasi \ + --exclude wasmer-middleware-common \ + --exclude wasmer-middleware-common-tests \ + --exclude wasmer-singlepass-backend \ + --exclude wasmer-clif-backend \ + --exclude wasmer-llvm-backend \ + --exclude wasmer-wasi-tests \ + --exclude wasmer-emscripten-tests \ + --exclude wasmer-runtime-core-tests circleci-clean: @if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi; diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml new file mode 100644 index 000000000..2c1b3daa1 --- /dev/null +++ b/lib/runtime-core-tests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wasmer-runtime-core-tests" +version = "0.8.0" +description = "Tests for the Wasmer runtime core crate" +license = "MIT" +authors = ["The Wasmer Engineering Team "] +edition = "2018" +publish = false + +[dependencies] +wabt = "0.9.1" +wasmer-runtime-core = { path = "../runtime-core", version = "0.9" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.9", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.9", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.9", optional = true } + +[features] +default = ["backend-cranelift"] +backend-cranelift = ["wasmer-clif-backend"] +backend-singlepass = ["wasmer-singlepass-backend"] +backend-llvm = ["wasmer-llvm-backend"] \ No newline at end of file diff --git a/lib/runtime-core-tests/src/lib.rs b/lib/runtime-core-tests/src/lib.rs new file mode 100644 index 000000000..96f7e6265 --- /dev/null +++ b/lib/runtime-core-tests/src/lib.rs @@ -0,0 +1,21 @@ +pub use wabt::wat2wasm; +use wasmer_runtime_core::backend::Compiler; + +#[cfg(feature = "backend-cranelift")] +pub fn get_compiler() -> impl Compiler { + use wasmer_clif_backend::CraneliftCompiler; + + CraneliftCompiler::new() +} + +#[cfg(feature = "backend-singlepass")] +pub fn get_compiler() -> impl Compiler { + use wasmer_singlepass_backend::SinglePassCompiler; + SinglePassCompiler::new() +} + +#[cfg(feature = "backend-llvm")] +pub fn get_compiler() -> impl Compiler { + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() +} diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs new file mode 100644 index 000000000..85bec1eb7 --- /dev/null +++ b/lib/runtime-core-tests/tests/imports.rs @@ -0,0 +1,112 @@ +use wasmer_runtime_core::{ + compile_with, error::RuntimeError, imports, memory::Memory, typed_func::Func, + types::MemoryDescriptor, units::Pages, vm, +}; +use wasmer_runtime_core_tests::{get_compiler, wat2wasm}; + +#[test] +fn imported_functions_forms() { + const MODULE: &str = r#" +(module + (type $type (func (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) + (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) + (func (export "function_fn_with_vmctx") (type $type) + get_local 0 + call $callback_fn_with_vmctx) + (func (export "function_fn_trap_with_vmctx") (type $type) + get_local 0 + call $callback_fn_trap_with_vmctx)) +"#; + + let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); + let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); + let memory_descriptor = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap(); + let memory = Memory::new(memory_descriptor).unwrap(); + + const SHIFT: i32 = 10; + memory.view()[0].set(SHIFT); + + let import_object = imports! { + "env" => { + "memory" => memory.clone(), + "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), + }, + }; + let instance = module.instantiate(&import_object).unwrap(); + + macro_rules! call_and_assert { + ($function:ident, $expected_value:expr) => { + let $function: Func = instance.func(stringify!($function)).unwrap(); + + let result = $function.call(1); + + match (result, $expected_value) { + (Ok(value), expected_value) => assert_eq!( + Ok(value), + expected_value, + concat!("Expected right when calling `", stringify!($function), "`.") + ), + ( + Err(RuntimeError::Error { data }), + Err(RuntimeError::Error { + data: expected_data, + }), + ) => { + if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::<&str>(), + expected_data.downcast_ref::<&str>(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::(), + expected_data.downcast_ref::(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else { + assert!(false, "Unexpected error, cannot compare it.") + } + } + (result, expected_value) => assert!( + false, + format!( + "Unexpected assertion for `{}`: left = `{:?}`, right = `{:?}`.", + stringify!($function), + result, + expected_value + ) + ), + } + }; + } + + call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!( + function_fn_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("baz {}", 2 + SHIFT)) + }) + ); +} + +fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) +} + +fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Err(format!("baz {}", shift + n + 1)) +} From 12a05ca2800a921d9b16bbb7a10a6a4d2be61ad7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 15:00:31 +0100 Subject: [PATCH 096/122] chore(makefile) Remove the `+nightly` flag. --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index a01c6689e..e8d11bed0 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ generate: generate-spectests generate-emtests generate-wasitests # Spectests spectests-singlepass: - cargo +nightly test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture + cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture spectests-cranelift: cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture @@ -88,8 +88,8 @@ wasitests: wasitests-unit wasitests-singlepass wasitests-cranelift wasitests-llv # Backends singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasitests-singlepass - cargo +nightly test -p wasmer-singlepass-backend --release - cargo +nightly test -p wasmer-runtime-core-tests --release --no-default-features --features backend-singlepass + cargo test -p wasmer-singlepass-backend --release + cargo test -p wasmer-runtime-core-tests --release --no-default-features --features backend-singlepass cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift cargo test -p wasmer-clif-backend --release From 4e83e1b8e0baefc4916cd9bfc875852c2c43aa85 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 17:59:07 +0100 Subject: [PATCH 097/122] chore(runtime-core-tests) Update crate version. --- lib/runtime-core-tests/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml index 2c1b3daa1..d2db29f2b 100644 --- a/lib/runtime-core-tests/Cargo.toml +++ b/lib/runtime-core-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-runtime-core-tests" -version = "0.8.0" +version = "0.9.0" description = "Tests for the Wasmer runtime core crate" license = "MIT" authors = ["The Wasmer Engineering Team "] From f77d9bfe3247dbbd70a7579bcfbd0f1535dc9677 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 30 Oct 2019 10:29:51 -0700 Subject: [PATCH 098/122] Initial implementation of TBAA for the LLVM backend. --- Cargo.lock | 4 +- lib/llvm-backend/src/code.rs | 473 +++++++++++++++++++++++++++++++++-- 2 files changed, 460 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 917724f89..1c0527cdb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -514,7 +514,7 @@ dependencies = [ [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#10d180807ce6e621ae13d74001bf5677b0e1f179" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -528,7 +528,7 @@ dependencies = [ [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#57e192cdccd6cde6ee5ee0a7e0b280490126d5c6" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#10d180807ce6e621ae13d74001bf5677b0e1f179" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 0a8df9084..b5d7dd57b 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -6,8 +6,8 @@ use inkwell::{ targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, types::{BasicType, BasicTypeEnum, FunctionType, PointerType, VectorType}, values::{ - BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PhiValue, PointerValue, - VectorValue, + BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, MetadataValue, PhiValue, + PointerValue, VectorValue, }, AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; @@ -558,6 +558,8 @@ fn resolve_memory_ptr( memarg: &MemoryImmediate, ptr_ty: PointerType, value_size: usize, + context_field_ptr_to_base_tbaa: MetadataValue, + context_field_ptr_to_bounds_tbaa: MetadataValue, ) -> Result { // Look up the memory base (as pointer) and bounds (as unsigned integer). let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); @@ -570,6 +572,14 @@ fn resolve_memory_ptr( .build_load(ptr_to_base_ptr, "base") .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); + let tbaa_kind = context.get_kind_id("tbaa"); + base.as_instruction_value() + .unwrap() + .set_metadata(context_field_ptr_to_base_tbaa, tbaa_kind); + bounds + .as_instruction_value() + .unwrap() + .set_metadata(context_field_ptr_to_bounds_tbaa, tbaa_kind); (base, bounds) } MemoryCache::Static { base_ptr, bounds } => (base_ptr, bounds), @@ -808,6 +818,11 @@ pub struct LLVMModuleCodeGenerator { stackmaps: Rc>, track_state: bool, target_machine: TargetMachine, + memory_tbaa: MetadataValue, + locals_tbaa: MetadataValue, + globals_tbaa: MetadataValue, + context_field_ptr_to_base_tbaa: MetadataValue, + context_field_ptr_to_bounds_tbaa: MetadataValue, } pub struct LLVMFunctionCodeGenerator { @@ -827,6 +842,11 @@ pub struct LLVMFunctionCodeGenerator { index: usize, opcode_offset: usize, track_state: bool, + memory_tbaa: MetadataValue, + locals_tbaa: MetadataValue, + globals_tbaa: MetadataValue, + context_field_ptr_to_base_tbaa: MetadataValue, + context_field_ptr_to_bounds_tbaa: MetadataValue, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -1528,19 +1548,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::GetLocal { local_index } => { let pointer_value = locals[local_index as usize]; let v = builder.build_load(pointer_value, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + v.as_instruction_value() + .unwrap() + .set_metadata(self.locals_tbaa, tbaa_kind); state.push1(v); } Operator::SetLocal { local_index } => { let pointer_value = locals[local_index as usize]; let (v, i) = state.pop1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); - builder.build_store(pointer_value, v); + let store = builder.build_store(pointer_value, v); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.locals_tbaa, tbaa_kind); } Operator::TeeLocal { local_index } => { let pointer_value = locals[local_index as usize]; let (v, i) = state.peek1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); - builder.build_store(pointer_value, v); + let store = builder.build_store(pointer_value, v); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.locals_tbaa, tbaa_kind); } Operator::GetGlobal { global_index } => { @@ -1552,6 +1580,11 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } GlobalCache::Mut { ptr_to_value } => { let value = builder.build_load(ptr_to_value, "global_value"); + let tbaa_kind = context.get_kind_id("tbaa"); + value + .as_instruction_value() + .unwrap() + .set_metadata(self.locals_tbaa, tbaa_kind); state.push1(value); } } @@ -1563,7 +1596,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let global_cache = ctx.global_cache(index, intrinsics); match global_cache { GlobalCache::Mut { ptr_to_value } => { - builder.build_store(ptr_to_value, value); + let store = builder.build_store(ptr_to_value, value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.globals_tbaa, tbaa_kind); } GlobalCache::Const { value: _ } => { return Err(CodegenError { @@ -4360,8 +4395,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load { ref memarg } => { @@ -4375,8 +4417,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::F32Load { ref memarg } => { @@ -4390,8 +4439,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.f32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::F64Load { ref memarg } => { @@ -4405,8 +4461,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.f64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::V128Load { ref memarg } => { @@ -4420,8 +4483,15 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i128_ptr_ty, 16, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } @@ -4437,8 +4507,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I64Store { ref memarg } => { let value = state.pop1()?; @@ -4452,8 +4526,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; - builder.build_store(effective_address, value); + let store = builder.build_store(effective_address, value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::F32Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4468,8 +4546,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.f32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; - builder.build_store(effective_address, v); + let store = builder.build_store(effective_address, v); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::F64Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4484,8 +4566,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.f64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; - builder.build_store(effective_address, v); + let store = builder.build_store(effective_address, v); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::V128Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4500,10 +4586,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i128_ptr_ty, 16, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; - builder.build_store(effective_address, v); + let store = builder.build_store(effective_address, v); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } - Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, @@ -4515,12 +4604,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I32Load16S { ref memarg } => { @@ -4534,12 +4630,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load8S { ref memarg } => { @@ -4553,12 +4656,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load16S { ref memarg } => { @@ -4572,12 +4682,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load32S { ref memarg } => { @@ -4591,12 +4708,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } @@ -4611,12 +4735,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I32Load16U { ref memarg } => { @@ -4630,12 +4761,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load8U { ref memarg } => { @@ -4649,12 +4787,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load16U { ref memarg } => { @@ -4668,12 +4813,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load32U { ref memarg } => { @@ -4687,12 +4839,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); + let tbaa_kind = context.get_kind_id("tbaa"); + result + .as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } @@ -4708,10 +4867,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4725,10 +4888,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4742,10 +4909,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); - builder.build_store(effective_address, narrow_value); + let store = builder.build_store(effective_address, narrow_value); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I8x16Neg => { let (v, i) = state.pop1_extra()?; @@ -5046,8 +5217,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let elem = builder.build_load(effective_address, "").into_int_value(); + let tbaa_kind = context.get_kind_id("tbaa"); + elem.as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); let res = splat_vector( builder, intrinsics, @@ -5069,8 +5246,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let elem = builder.build_load(effective_address, "").into_int_value(); + let tbaa_kind = context.get_kind_id("tbaa"); + elem.as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); let res = splat_vector( builder, intrinsics, @@ -5092,8 +5275,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let elem = builder.build_load(effective_address, "").into_int_value(); + let tbaa_kind = context.get_kind_id("tbaa"); + elem.as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); let res = splat_vector( builder, intrinsics, @@ -5115,8 +5304,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; let elem = builder.build_load(effective_address, "").into_int_value(); + let tbaa_kind = context.get_kind_id("tbaa"); + elem.as_instruction_value() + .unwrap() + .set_metadata(self.memory_tbaa, tbaa_kind); let res = splat_vector( builder, intrinsics, @@ -5147,6 +5342,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5161,6 +5358,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64AtomicLoad { ref memarg } => { @@ -5174,6 +5373,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5188,6 +5389,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(8).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I32AtomicLoad8U { ref memarg } => { @@ -5201,6 +5404,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5217,6 +5422,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -5232,6 +5439,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5248,6 +5457,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -5263,6 +5474,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5279,6 +5492,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5294,6 +5509,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5310,6 +5527,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5325,6 +5544,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5341,6 +5562,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + load.set_metadata(self.memory_tbaa, tbaa_kind); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5357,6 +5580,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5371,6 +5596,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I64AtomicStore { ref memarg } => { let value = state.pop1()?; @@ -5384,6 +5611,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5398,6 +5627,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I32AtomicStore8 { ref memarg } | Operator::I64AtomicStore8 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5411,6 +5642,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5427,6 +5660,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I32AtomicStore16 { ref memarg } | Operator::I64AtomicStore16 { ref memarg } => { @@ -5441,6 +5676,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5457,6 +5694,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I64AtomicStore32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5470,6 +5709,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5486,6 +5727,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); + let tbaa_kind = context.get_kind_id("tbaa"); + store.set_metadata(self.memory_tbaa, tbaa_kind); } Operator::I32AtomicRmw8UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5499,6 +5742,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5533,6 +5778,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5567,6 +5814,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5598,6 +5847,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5632,6 +5883,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5666,6 +5919,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5700,6 +5955,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5731,6 +5988,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5765,6 +6024,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5799,6 +6060,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5830,6 +6093,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5864,6 +6129,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5898,6 +6165,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5932,6 +6201,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5963,6 +6234,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5997,6 +6270,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6031,6 +6306,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6062,6 +6339,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6096,6 +6375,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6130,6 +6411,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6164,6 +6447,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6195,6 +6480,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6229,6 +6516,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6263,6 +6552,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6295,6 +6586,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6329,6 +6622,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6363,6 +6658,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6397,6 +6694,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6428,6 +6727,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6462,6 +6763,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6496,6 +6799,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6527,6 +6832,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6561,6 +6868,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6595,6 +6904,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6629,6 +6940,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6660,6 +6973,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6694,6 +7009,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6728,6 +7045,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6759,6 +7078,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6793,6 +7114,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6827,6 +7150,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6861,6 +7186,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6893,6 +7220,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6935,6 +7264,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6977,6 +7308,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7011,6 +7344,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i8_ptr_ty, 1, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7053,6 +7388,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i16_ptr_ty, 2, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7095,6 +7432,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i32_ptr_ty, 4, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7137,6 +7476,8 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { memarg, intrinsics.i64_ptr_ty, 8, + self.context_field_ptr_to_base_tbaa, + self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7316,6 +7657,97 @@ impl ModuleCodeGenerator Some(Linkage::External), ); + module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); + let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; + let memory = context.metadata_string("memory"); + module.add_global_metadata( + "memory", + &MetadataValue::create_node(&[memory.into(), tbaa_root.into()]), + ); + let memory_tbaa = module.get_global_metadata("memory")[0]; + module.add_global_metadata( + "memory_memop", + &MetadataValue::create_node(&[ + memory_tbaa.into(), + memory_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let memory_tbaa = module.get_global_metadata("memory_memop")[0]; + + let locals = context.metadata_string("locals"); + module.add_global_metadata( + "locals", + &MetadataValue::create_node(&[locals.into(), tbaa_root.into()]), + ); + let locals_tbaa = module.get_global_metadata("locals")[0]; + module.add_global_metadata( + "locals_memop", + &MetadataValue::create_node(&[ + locals_tbaa.into(), + locals_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let locals_tbaa = module.get_global_metadata("locals_memop")[0]; + + let globals = context.metadata_string("globals"); + module.add_global_metadata( + "globals", + &MetadataValue::create_node(&[globals.into(), tbaa_root.into()]), + ); + let globals_tbaa = module.get_global_metadata("globals")[0]; + module.add_global_metadata( + "globals_memop", + &MetadataValue::create_node(&[ + globals_tbaa.into(), + globals_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let globals_tbaa = module.get_global_metadata("globals_memop")[0]; + + let context_field_ptr_to_base_tbaa = + context.metadata_string("context_field_ptr_to_base_tbaa"); + module.add_global_metadata( + "context_field_ptr_to_base_tbaa", + &MetadataValue::create_node(&[context_field_ptr_to_base_tbaa.into(), tbaa_root.into()]), + ); + let context_field_ptr_to_base_tbaa = + module.get_global_metadata("context_field_ptr_to_base_tbaa")[0]; + module.add_global_metadata( + "context_field_ptr_to_base_tbaa_memop", + &MetadataValue::create_node(&[ + context_field_ptr_to_base_tbaa.into(), + context_field_ptr_to_base_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let context_field_ptr_to_base_tbaa = + module.get_global_metadata("context_field_ptr_to_base_tbaa_memop")[0]; + + let context_field_ptr_to_bounds_tbaa = + context.metadata_string("context_field_ptr_to_bounds_tbaa"); + module.add_global_metadata( + "context_field_ptr_to_bounds_tbaa", + &MetadataValue::create_node(&[ + context_field_ptr_to_bounds_tbaa.into(), + tbaa_root.into(), + ]), + ); + let context_field_ptr_to_bounds_tbaa = + module.get_global_metadata("context_field_ptr_to_bounds_tbaa")[0]; + module.add_global_metadata( + "context_field_ptr_to_bounds_tbaa_memop", + &MetadataValue::create_node(&[ + context_field_ptr_to_bounds_tbaa.into(), + context_field_ptr_to_bounds_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let context_field_ptr_to_bounds_tbaa = + module.get_global_metadata("context_field_ptr_to_bounds_tbaa_memop")[0]; + LLVMModuleCodeGenerator { context: Some(context), builder: Some(builder), @@ -7329,7 +7761,12 @@ impl ModuleCodeGenerator personality_func, stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), track_state: false, - target_machine: target_machine, + target_machine, + memory_tbaa, + locals_tbaa, + globals_tbaa, + context_field_ptr_to_base_tbaa, + context_field_ptr_to_bounds_tbaa, } } @@ -7436,6 +7873,11 @@ impl ModuleCodeGenerator index: local_func_index, opcode_offset: 0, track_state: self.track_state, + memory_tbaa: self.memory_tbaa, + locals_tbaa: self.locals_tbaa, + globals_tbaa: self.globals_tbaa, + context_field_ptr_to_base_tbaa: self.context_field_ptr_to_base_tbaa, + context_field_ptr_to_bounds_tbaa: self.context_field_ptr_to_bounds_tbaa, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) @@ -7485,6 +7927,7 @@ impl ModuleCodeGenerator pass_manager.add_scalar_repl_aggregates_pass(); pass_manager.add_instruction_combining_pass(); pass_manager.add_cfg_simplification_pass(); + pass_manager.add_type_based_alias_analysis_pass(); pass_manager.add_gvn_pass(); pass_manager.add_jump_threading_pass(); pass_manager.add_correlated_value_propagation_pass(); From 77e01f01bd147004c36e46f1716bc5ca28fc51cf Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 13:59:27 +0100 Subject: [PATCH 099/122] chore(runtime-core) Use `vm::Ctx` to access it. Just to be consistent with the rest of the code. --- lib/runtime-core/src/typed_func.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 74318747c..4bcd6804a 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -3,7 +3,7 @@ use crate::{ export::{Context, Export, FuncPointer}, import::IsExport, types::{FuncSig, NativeWasmType, Type, WasmExternType}, - vm::{self, Ctx}, + vm, }; use std::{ any::Any, @@ -52,10 +52,10 @@ impl fmt::Display for WasmTrapInfo { /// of the `Func` struct. pub trait Kind {} -pub type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); +pub type Trampoline = unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64); pub type Invoke = unsafe extern "C" fn( Trampoline, - *mut Ctx, + *mut vm::Ctx, NonNull, *const u64, *mut u64, @@ -173,7 +173,7 @@ where pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, f: NonNull, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, _phantom: PhantomData<(&'a (), Args, Rets)>, } @@ -188,7 +188,7 @@ where pub(crate) unsafe fn from_raw_parts( inner: Wasm, f: NonNull, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Func<'a, Args, Rets, Wasm> { Func { inner, @@ -267,7 +267,7 @@ impl WasmTypeList for Infallible { self, _: NonNull, _: Wasm, - _: *mut Ctx, + _: *mut vm::Ctx, ) -> Result where Rets: WasmTypeList, @@ -313,7 +313,7 @@ where self, f: NonNull, wasm: Wasm, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Result where Rets: WasmTypeList, @@ -405,7 +405,7 @@ macro_rules! impl_traits { self, f: NonNull, wasm: Wasm, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Result where Rets: WasmTypeList @@ -443,7 +443,7 @@ macro_rules! impl_traits { $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut Ctx $( , $x )*) -> Trap, + FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap, { #[allow(non_snake_case)] fn to_raw(&self) -> NonNull { @@ -451,13 +451,13 @@ macro_rules! impl_traits { /// This is required for the llvm backend to be able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] extern fn wrap<$( $x, )* Rets, Trap, FN>( - ctx: &mut Ctx $( , $x: <$x as WasmExternType>::Native )* + ctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut Ctx $( , $x )*) -> Trap, + FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap, { let f: FN = unsafe { mem::transmute_copy(&()) }; @@ -564,7 +564,7 @@ mod tests { use super::*; #[test] fn test_call() { - fn foo(_ctx: &mut Ctx, a: i32, b: i32) -> (i32, i32) { + fn foo(_ctx: &mut vm::Ctx, a: i32, b: i32) -> (i32, i32) { (a, b) } @@ -575,7 +575,7 @@ mod tests { fn test_imports() { use crate::{func, imports}; - fn foo(_ctx: &mut Ctx, a: i32) -> i32 { + fn foo(_ctx: &mut vm::Ctx, a: i32) -> i32 { a } From bd9d4d9cc8a17e25f7ef0ed699eaf7873e73ff56 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 13:59:59 +0100 Subject: [PATCH 100/122] test(runtime-core) Add tests for the `Func` structure. --- lib/runtime-core/src/typed_func.rs | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 4bcd6804a..fab028f30 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -562,6 +562,44 @@ where #[cfg(test)] mod tests { use super::*; + + macro_rules! test_func_arity_n { + ($test_name:ident, $($x:ident),*) => { + #[test] + fn $test_name() { + use crate::vm; + + fn with_vmctx(_: &mut vm::Ctx, $($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + + let _func = Func::new(with_vmctx); + } + } + } + + #[test] + fn test_func_arity_0() { + fn foo(_: &mut vm::Ctx) -> i32 { + 0 + } + + let _ = Func::new(foo); + } + + test_func_arity_n!(test_func_arity_1, a); + test_func_arity_n!(test_func_arity_2, a, b); + test_func_arity_n!(test_func_arity_3, a, b, c); + test_func_arity_n!(test_func_arity_4, a, b, c, d); + test_func_arity_n!(test_func_arity_5, a, b, c, d, e); + test_func_arity_n!(test_func_arity_6, a, b, c, d, e, f); + test_func_arity_n!(test_func_arity_7, a, b, c, d, e, f, g); + test_func_arity_n!(test_func_arity_8, a, b, c, d, e, f, g, h); + test_func_arity_n!(test_func_arity_9, a, b, c, d, e, f, g, h, i); + test_func_arity_n!(test_func_arity_10, a, b, c, d, e, f, g, h, i, j); + test_func_arity_n!(test_func_arity_11, a, b, c, d, e, f, g, h, i, j, k); + test_func_arity_n!(test_func_arity_12, a, b, c, d, e, f, g, h, i, j, k, l); + #[test] fn test_call() { fn foo(_ctx: &mut vm::Ctx, a: i32, b: i32) -> (i32, i32) { From 95e1b85c5669573e00dda8795cf8c776c107f6b7 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 14:46:22 +0100 Subject: [PATCH 101/122] feat(runtime-core) Allow host functions without an explicit `vm::Ctx` argument. This patch allows host functions to get a signature without an explicit `vm::Ctx` argument. It is for Rust only. The C API receives a function pointer and has no clue whether a `vm::Ctx` argument is present or not, so it assumes it is always declared. From the backend point of view, the pointer to `vm::Ctx` is always inserted in the stack, but it is not used by the function when the argument is absent. --- lib/runtime-core/src/typed_func.rs | 90 ++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index fab028f30..c9c0b332b 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -124,16 +124,27 @@ pub trait WasmTypeList { self, f: NonNull, wasm: Wasm, - ctx: *mut Ctx, + ctx: *mut vm::Ctx, ) -> Result where Rets: WasmTypeList; } +/// Empty trait to specify the kind of `ExternalFunction`: With or +/// without a `vm::Ctx` argument. +pub trait ExternalFunctionKind {} + +pub struct ExplicitVmCtx {} +pub struct ImplicitVmCtx {} + +impl ExternalFunctionKind for ExplicitVmCtx {} +impl ExternalFunctionKind for ImplicitVmCtx {} + /// Represents a function that can be converted to a `vm::Func` /// (function pointer) that can be called within WebAssembly. -pub trait ExternalFunction +pub trait ExternalFunction where + Kind: ExternalFunctionKind, Args: WasmTypeList, Rets: WasmTypeList, { @@ -208,9 +219,10 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - pub fn new(f: F) -> Func<'a, Args, Rets, Host> + pub fn new(f: F) -> Func<'a, Args, Rets, Host> where - F: ExternalFunction, + Kind: ExternalFunctionKind, + F: ExternalFunction, { Func { inner: Host(()), @@ -438,7 +450,7 @@ macro_rules! impl_traits { } } - impl< $( $x, )* Rets, Trap, FN > ExternalFunction<( $( $x ),* ), Rets> for FN + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN where $( $x: WasmExternType, )* Rets: WasmTypeList, @@ -451,20 +463,20 @@ macro_rules! impl_traits { /// This is required for the llvm backend to be able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] extern fn wrap<$( $x, )* Rets, Trap, FN>( - ctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut vm::Ctx $( , $x )*) -> Trap, + FN: Fn(&mut vm::Ctx, $( $x, )*) -> Trap, { let f: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( panic::AssertUnwindSafe( || { - f(ctx $( , WasmExternType::from_native($x) )* ).report() + f(vmctx $( , WasmExternType::from_native($x) )* ).report() } ) ) { @@ -477,7 +489,7 @@ macro_rules! impl_traits { }; unsafe { - (&*ctx.module).runnable_module.do_early_trap(err) + (&*vmctx.module).runnable_module.do_early_trap(err) } } @@ -490,7 +502,65 @@ macro_rules! impl_traits { ); NonNull::new(unsafe { - ::std::mem::transmute_copy::<_, *mut vm::Func>(self) + mem::transmute_copy::<_, *mut vm::Func>(self) + }).unwrap() + } + } + } + + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x, )*) -> Trap, + { + #[allow(non_snake_case)] + fn to_raw(&self) -> NonNull { + if mem::size_of::() == 0 { + /// This is required for the llvm backend to be able to unwind through this function. + #[cfg_attr(nightly, unwind(allowed))] + extern fn wrap<$( $x, )* Rets, Trap, FN>( + vmctx: &mut vm::Ctx $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn($( $x, )*) -> Trap, + { + let f: FN = unsafe { mem::transmute_copy(&()) }; + + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + f($( WasmExternType::from_native($x), )* ).report() + } + ) + ) { + Ok(Ok(returns)) => return returns.into_c_struct(), + Ok(Err(err)) => { + let b: Box<_> = err.into(); + b as Box + }, + Err(err) => err, + }; + + unsafe { + (&*vmctx.module).runnable_module.do_early_trap(err) + } + } + + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap() + } else { + assert_eq!( + mem::size_of::(), + mem::size_of::(), + "you cannot use a closure that captures state for `Func`." + ); + + NonNull::new(unsafe { + mem::transmute_copy::<_, *mut vm::Func>(self) }).unwrap() } } From 7eef49be127f7259fbbb124652752165bac58c8c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 14:58:57 +0100 Subject: [PATCH 102/122] test(runtime-core) Test host functions without a `vm::Ctx` argument. --- lib/runtime-core-tests/tests/imports.rs | 25 +++++++++++++++++++++++++ lib/runtime-core/src/typed_func.rs | 10 ++++++++++ 2 files changed, 35 insertions(+) diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs index 85bec1eb7..69b9040cd 100644 --- a/lib/runtime-core-tests/tests/imports.rs +++ b/lib/runtime-core-tests/tests/imports.rs @@ -10,11 +10,19 @@ fn imported_functions_forms() { (module (type $type (func (param i32) (result i32))) (import "env" "memory" (memory 1 1)) + (import "env" "callback_fn" (func $callback_fn (type $type))) (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) + (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) + (func (export "function_fn") (type $type) + get_local 0 + call $callback_fn) (func (export "function_fn_with_vmctx") (type $type) get_local 0 call $callback_fn_with_vmctx) + (func (export "function_fn_trap") (type $type) + get_local 0 + call $callback_fn_trap) (func (export "function_fn_trap_with_vmctx") (type $type) get_local 0 call $callback_fn_trap_with_vmctx)) @@ -31,7 +39,9 @@ fn imported_functions_forms() { let import_object = imports! { "env" => { "memory" => memory.clone(), + "callback_fn" => Func::new(callback_fn), "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + "callback_fn_trap" => Func::new(callback_fn_trap), "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), }, }; @@ -88,7 +98,14 @@ fn imported_functions_forms() { }; } + call_and_assert!(function_fn, Ok(2)); call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!( + function_fn_trap, + Err(RuntimeError::Error { + data: Box::new(format!("foo {}", 1)) + }) + ); call_and_assert!( function_fn_trap_with_vmctx, Err(RuntimeError::Error { @@ -97,6 +114,10 @@ fn imported_functions_forms() { ); } +fn callback_fn(n: i32) -> Result { + Ok(n + 1) +} + fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { let memory = vmctx.memory(0); let shift: i32 = memory.view()[0].get(); @@ -104,6 +125,10 @@ fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { Ok(shift + n + 1) } +fn callback_fn_trap(n: i32) -> Result { + Err(format!("foo {}", n)) +} + fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { let memory = vmctx.memory(0); let shift: i32 = memory.view()[0].get(); diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index c9c0b332b..66c68845e 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -643,7 +643,12 @@ mod tests { vec![$($x),*].iter().sum() } + fn without_vmctx($($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + let _func = Func::new(with_vmctx); + let _func = Func::new(without_vmctx); } } } @@ -654,7 +659,12 @@ mod tests { 0 } + fn bar() -> i32 { + 0 + } + let _ = Func::new(foo); + let _ = Func::new(bar); } test_func_arity_n!(test_func_arity_1, a); From 6a1d490a30bbfd6710d73c575979c0b2e64755e4 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 30 Oct 2019 14:59:20 +0100 Subject: [PATCH 103/122] doc(runtimecore) Explain `ExternalFunctionKind` with more details. --- lib/runtime-core/src/typed_func.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 66c68845e..f70f16929 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -131,10 +131,32 @@ pub trait WasmTypeList { } /// Empty trait to specify the kind of `ExternalFunction`: With or -/// without a `vm::Ctx` argument. +/// without a `vm::Ctx` argument. See the `ExplicitVmCtx` and the +/// `ImplicitVmCtx` structures. +/// +/// This type is never aimed to be used by a user. It is used by the +/// trait system to automatically generate an appropriate `wrap` +/// function. pub trait ExternalFunctionKind {} +/// This empty structure indicates that an external function must +/// contain an explicit `vm::Ctx` argument (at first position). +/// +/// ```rs,ignore +/// fn add_one(_: mut &vm::Ctx, x: i32) -> i32 { +/// x + 1 +/// } +/// ``` pub struct ExplicitVmCtx {} + +/// This empty structure indicates that an external function has no +/// `vm::Ctx` argument (at first position). Its signature is: +/// +/// ```rs,ignore +/// fn add_one(x: i32) -> i32 { +/// x + 1 +/// } +/// ``` pub struct ImplicitVmCtx {} impl ExternalFunctionKind for ExplicitVmCtx {} From e7d1742c63bbba7a3091eb397f16c34132f0735f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 30 Oct 2019 13:11:29 -0700 Subject: [PATCH 104/122] Update module to be held by Rc> so that we can pass it to LLVMFunctionCodeGenerator. Use that to generate distinct TBAA labels for distinct local variables. --- lib/llvm-backend/src/backend.rs | 6 ++- lib/llvm-backend/src/code.rs | 73 +++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 20 deletions(-) diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index f7847f063..48a227cc8 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -9,12 +9,14 @@ use inkwell::{ use libc::c_char; use std::{ any::Any, + cell::RefCell, ffi::{c_void, CString}, fs::File, io::Write, mem, ops::Deref, ptr::{self, NonNull}, + rc::Rc, slice, str, sync::{Arc, Once}, }; @@ -167,14 +169,14 @@ pub struct LLVMBackend { impl LLVMBackend { pub fn new( - module: Module, + module: Rc>, _intrinsics: Intrinsics, _stackmaps: &StackmapRegistry, _module_info: &ModuleInfo, target_machine: &TargetMachine, ) -> (Self, LLVMCache) { let memory_buffer = target_machine - .write_to_memory_buffer(&module, FileType::Object) + .write_to_memory_buffer(&module.borrow_mut(), FileType::Object) .unwrap(); let mem_buf_slice = memory_buffer.as_slice(); diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index b5d7dd57b..d2b03ea8e 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -6,8 +6,8 @@ use inkwell::{ targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, types::{BasicType, BasicTypeEnum, FunctionType, PointerType, VectorType}, values::{ - BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, MetadataValue, PhiValue, - PointerValue, VectorValue, + BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, + MetadataValue, PhiValue, PointerValue, VectorValue, }, AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; @@ -647,6 +647,41 @@ fn resolve_memory_ptr( .into_pointer_value()) } +fn local_tbaa( + module: Rc>, + intrinsics: &Intrinsics, + instruction: InstructionValue, + index: u32, +) { + let module = module.borrow_mut(); + let context = module.get_context(); + + module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); + let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; + + let name = format!("local {}", index); + let local = context.metadata_string(name.as_str()); + module.add_global_metadata( + name.as_str(), + &MetadataValue::create_node(&[local.into(), tbaa_root.into()]), + ); + let local_tbaa = module.get_global_metadata(name.as_str())[0]; + + let name = name + "_memop"; + module.add_global_metadata( + name.as_str(), + &MetadataValue::create_node(&[ + local_tbaa.into(), + local_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let local_tbaa = module.get_global_metadata(name.as_str())[0]; + + let tbaa_kind = context.get_kind_id("tbaa"); + instruction.set_metadata(local_tbaa, tbaa_kind); +} + fn emit_stack_map( _module_info: &ModuleInfo, intrinsics: &Intrinsics, @@ -814,7 +849,7 @@ pub struct LLVMModuleCodeGenerator { function_signatures: Option>>, func_import_count: usize, personality_func: FunctionValue, - module: Module, + module: Rc>, stackmaps: Rc>, track_state: bool, target_machine: TargetMachine, @@ -842,6 +877,7 @@ pub struct LLVMFunctionCodeGenerator { index: usize, opcode_offset: usize, track_state: bool, + module: Rc>, memory_tbaa: MetadataValue, locals_tbaa: MetadataValue, globals_tbaa: MetadataValue, @@ -1548,10 +1584,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::GetLocal { local_index } => { let pointer_value = locals[local_index as usize]; let v = builder.build_load(pointer_value, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - v.as_instruction_value() - .unwrap() - .set_metadata(self.locals_tbaa, tbaa_kind); + local_tbaa( + self.module.clone(), + intrinsics, + v.as_instruction_value().unwrap(), + local_index, + ); state.push1(v); } Operator::SetLocal { local_index } => { @@ -1559,16 +1597,14 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v, i) = state.pop1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); let store = builder.build_store(pointer_value, v); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.locals_tbaa, tbaa_kind); + local_tbaa(self.module.clone(), intrinsics, store, local_index); } Operator::TeeLocal { local_index } => { let pointer_value = locals[local_index as usize]; let (v, i) = state.peek1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); let store = builder.build_store(pointer_value, v); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.locals_tbaa, tbaa_kind); + local_tbaa(self.module.clone(), intrinsics, store, local_index); } Operator::GetGlobal { global_index } => { @@ -7752,7 +7788,7 @@ impl ModuleCodeGenerator context: Some(context), builder: Some(builder), intrinsics: Some(intrinsics), - module, + module: Rc::new(RefCell::new(module)), functions: vec![], signatures: Map::new(), signatures_raw: Map::new(), @@ -7800,7 +7836,7 @@ impl ModuleCodeGenerator [FuncIndex::new(self.func_import_count + self.functions.len())]; let func_sig = self.signatures_raw[sig_id].clone(); - let function = self.module.add_function( + let function = self.module.borrow_mut().add_function( &format!("fn{}", self.func_import_count + self.functions.len()), self.signatures[sig_id], Some(Linkage::External), @@ -7873,6 +7909,7 @@ impl ModuleCodeGenerator index: local_func_index, opcode_offset: 0, track_state: self.track_state, + module: self.module.clone(), memory_tbaa: self.memory_tbaa, locals_tbaa: self.locals_tbaa, globals_tbaa: self.globals_tbaa, @@ -7906,7 +7943,7 @@ impl ModuleCodeGenerator generate_trampolines( module_info, &self.signatures, - &self.module, + &self.module.borrow_mut(), self.context.as_ref().unwrap(), self.builder.as_ref().unwrap(), self.intrinsics.as_ref().unwrap(), @@ -7916,7 +7953,7 @@ impl ModuleCodeGenerator })?; if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.pre_opt_ir } { - self.module.print_to_file(path).unwrap(); + self.module.borrow_mut().print_to_file(path).unwrap(); } let pass_manager = PassManager::create(()); @@ -7937,16 +7974,16 @@ impl ModuleCodeGenerator pass_manager.add_cfg_simplification_pass(); pass_manager.add_bit_tracking_dce_pass(); pass_manager.add_slp_vectorize_pass(); - pass_manager.run_on(&self.module); + pass_manager.run_on(&*self.module.borrow_mut()); if let Some(path) = unsafe { &crate::GLOBAL_OPTIONS.post_opt_ir } { - self.module.print_to_file(path).unwrap(); + self.module.borrow_mut().print_to_file(path).unwrap(); } let stackmaps = self.stackmaps.borrow(); let (backend, cache_gen) = LLVMBackend::new( - self.module, + self.module.clone(), self.intrinsics.take().unwrap(), &*stackmaps, module_info, From ea08431ab8269d47e0249f32e2db0b34944d95d5 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 30 Oct 2019 13:48:41 -0700 Subject: [PATCH 105/122] Add start of language intergrations table to feature matrix --- docs/feature_matrix.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index cdb6ff8ad..a5e75a49e 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -11,6 +11,7 @@ | OSR | 🔄 | ❓ | ❓ | | SIMD | ⬜ | ⬜ | ✅ | | WASI | ✅ | ✅ | ✅ | +| WASMER_BACKTRACE | ✅ | ⬜ | ⬜ | ## Language integration @@ -18,8 +19,13 @@ TODO: define a set of features that are relevant and mark them here Current ideas: -- WASI FS API - Callbacks -- Exiting early in hostcall - Metering - Caching + +;; TODO: expand this table, it's focused on new features that we haven't implemented yet and doesn't list all language integrations +|   | Rust | C / C++ | Go | Python | Ruby | +| - | :-: | :-: | :-: | :-: | :-: | +| Terminate in host call | ✅ | ⬜ | ⬜ | ⬜ | ⬜ | +| WASI | ✅ | ✅ | 🔄 | ⬜ | ⬜ | +| WASI FS API | ✅ | ⬜ | ⬜ | ⬜ | ⬜ | From 74eaec968e5984189c63dee18d1a33170f34fa87 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 30 Oct 2019 14:05:11 -0700 Subject: [PATCH 106/122] Remove all *_tbaa fields from LLVMModuleCodeGenerator and LLVMFunctionCodeGenerator. --- lib/llvm-backend/src/code.rs | 784 ++++++++++++++--------------------- 1 file changed, 319 insertions(+), 465 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index d2b03ea8e..103d27429 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -552,14 +552,13 @@ fn resolve_memory_ptr( builder: &Builder, intrinsics: &Intrinsics, context: &Context, + module: Rc>, function: &FunctionValue, state: &mut State, ctx: &mut CtxType, memarg: &MemoryImmediate, ptr_ty: PointerType, value_size: usize, - context_field_ptr_to_base_tbaa: MetadataValue, - context_field_ptr_to_bounds_tbaa: MetadataValue, ) -> Result { // Look up the memory base (as pointer) and bounds (as unsigned integer). let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); @@ -572,14 +571,20 @@ fn resolve_memory_ptr( .build_load(ptr_to_base_ptr, "base") .into_pointer_value(); let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); - let tbaa_kind = context.get_kind_id("tbaa"); - base.as_instruction_value() - .unwrap() - .set_metadata(context_field_ptr_to_base_tbaa, tbaa_kind); - bounds - .as_instruction_value() - .unwrap() - .set_metadata(context_field_ptr_to_bounds_tbaa, tbaa_kind); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_base", + base.as_instruction_value().unwrap(), + None, + ); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_bounds", + bounds.as_instruction_value().unwrap(), + None, + ); (base, bounds) } MemoryCache::Static { base_ptr, bounds } => (base_ptr, bounds), @@ -647,11 +652,12 @@ fn resolve_memory_ptr( .into_pointer_value()) } -fn local_tbaa( +fn tbaa_label( module: Rc>, intrinsics: &Intrinsics, + label: &str, instruction: InstructionValue, - index: u32, + index: Option, ) { let module = module.borrow_mut(); let context = module.get_context(); @@ -659,27 +665,31 @@ fn local_tbaa( module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; - let name = format!("local {}", index); - let local = context.metadata_string(name.as_str()); + let label = if let Some(idx) = index { + format!("{}{}", label, idx) + } else { + label.to_string() + }; + let type_label = context.metadata_string(label.as_str()); module.add_global_metadata( - name.as_str(), - &MetadataValue::create_node(&[local.into(), tbaa_root.into()]), + label.as_str(), + &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), ); - let local_tbaa = module.get_global_metadata(name.as_str())[0]; + let type_tbaa = module.get_global_metadata(label.as_str())[0]; - let name = name + "_memop"; + let label = label + "_memop"; module.add_global_metadata( - name.as_str(), + label.as_str(), &MetadataValue::create_node(&[ - local_tbaa.into(), - local_tbaa.into(), + type_tbaa.into(), + type_tbaa.into(), intrinsics.i64_zero.into(), ]), ); - let local_tbaa = module.get_global_metadata(name.as_str())[0]; + let type_tbaa = module.get_global_metadata(label.as_str())[0]; let tbaa_kind = context.get_kind_id("tbaa"); - instruction.set_metadata(local_tbaa, tbaa_kind); + instruction.set_metadata(type_tbaa, tbaa_kind); } fn emit_stack_map( @@ -853,11 +863,6 @@ pub struct LLVMModuleCodeGenerator { stackmaps: Rc>, track_state: bool, target_machine: TargetMachine, - memory_tbaa: MetadataValue, - locals_tbaa: MetadataValue, - globals_tbaa: MetadataValue, - context_field_ptr_to_base_tbaa: MetadataValue, - context_field_ptr_to_bounds_tbaa: MetadataValue, } pub struct LLVMFunctionCodeGenerator { @@ -878,11 +883,6 @@ pub struct LLVMFunctionCodeGenerator { opcode_offset: usize, track_state: bool, module: Rc>, - memory_tbaa: MetadataValue, - locals_tbaa: MetadataValue, - globals_tbaa: MetadataValue, - context_field_ptr_to_base_tbaa: MetadataValue, - context_field_ptr_to_bounds_tbaa: MetadataValue, } impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { @@ -1584,11 +1584,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::GetLocal { local_index } => { let pointer_value = locals[local_index as usize]; let v = builder.build_load(pointer_value, &state.var_name()); - local_tbaa( + tbaa_label( self.module.clone(), intrinsics, + "local", v.as_instruction_value().unwrap(), - local_index, + Some(local_index), ); state.push1(v); } @@ -1597,14 +1598,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v, i) = state.pop1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); let store = builder.build_store(pointer_value, v); - local_tbaa(self.module.clone(), intrinsics, store, local_index); + tbaa_label( + self.module.clone(), + intrinsics, + "local", + store, + Some(local_index), + ); } Operator::TeeLocal { local_index } => { let pointer_value = locals[local_index as usize]; let (v, i) = state.peek1_extra()?; let v = apply_pending_canonicalization(builder, intrinsics, v, i); let store = builder.build_store(pointer_value, v); - local_tbaa(self.module.clone(), intrinsics, store, local_index); + tbaa_label( + self.module.clone(), + intrinsics, + "local", + store, + Some(local_index), + ); } Operator::GetGlobal { global_index } => { @@ -1616,11 +1629,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } GlobalCache::Mut { ptr_to_value } => { let value = builder.build_load(ptr_to_value, "global_value"); - let tbaa_kind = context.get_kind_id("tbaa"); - value - .as_instruction_value() - .unwrap() - .set_metadata(self.locals_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "global", + value.as_instruction_value().unwrap(), + Some(global_index), + ); state.push1(value); } } @@ -1633,8 +1648,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { match global_cache { GlobalCache::Mut { ptr_to_value } => { let store = builder.build_store(ptr_to_value, value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.globals_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "global", + store, + Some(global_index), + ); } GlobalCache::Const { value: _ } => { return Err(CodegenError { @@ -4425,21 +4445,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::I64Load { ref memarg } => { @@ -4447,21 +4468,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::F32Load { ref memarg } => { @@ -4469,21 +4491,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.f32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::F64Load { ref memarg } => { @@ -4491,21 +4514,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.f64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } Operator::V128Load { ref memarg } => { @@ -4513,21 +4537,22 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i128_ptr_ty, 16, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let result = builder.build_load(effective_address, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + result.as_instruction_value().unwrap(), + Some(0), + ); state.push1(result); } @@ -4537,18 +4562,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let store = builder.build_store(effective_address, value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store { ref memarg } => { let value = state.pop1()?; @@ -4556,18 +4579,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let store = builder.build_store(effective_address, value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F32Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4576,18 +4597,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.f32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let store = builder.build_store(effective_address, v); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::F64Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4596,18 +4615,16 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.f64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let store = builder.build_store(effective_address, v); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::V128Store { ref memarg } => { let (v, i) = state.pop1_extra()?; @@ -4616,43 +4633,42 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i128_ptr_ty, 16, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let store = builder.build_store(effective_address, v); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Load8S { ref memarg } => { let effective_address = resolve_memory_ptr( builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I32Load16S { ref memarg } => { @@ -4660,25 +4676,27 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; - let narrow_result = builder - .build_load(effective_address, &state.var_name()) - .into_int_value(); - let result = - builder.build_int_s_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + let narrow_result = builder.build_load(effective_address, &state.var_name()); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); + let result = builder.build_int_s_extend( + narrow_result.into_int_value(), + intrinsics.i32_ty, + &state.var_name(), + ); state.push1(result); } Operator::I64Load8S { ref memarg } => { @@ -4686,25 +4704,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load16S { ref memarg } => { @@ -4712,25 +4731,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load32S { ref memarg } => { @@ -4738,25 +4758,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_s_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } @@ -4765,25 +4786,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I32Load16U { ref memarg } => { @@ -4791,25 +4813,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load8U { ref memarg } => { @@ -4817,25 +4840,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load16U { ref memarg } => { @@ -4843,25 +4867,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } Operator::I64Load32U { ref memarg } => { @@ -4869,25 +4894,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_result = builder .build_load(effective_address, &state.var_name()) .into_int_value(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + narrow_result.as_instruction_value().unwrap(), + Some(0), + ); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); - let tbaa_kind = context.get_kind_id("tbaa"); - result - .as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); state.push1(result); } @@ -4897,20 +4923,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i8_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32Store16 { ref memarg } | Operator::I64Store16 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4918,20 +4942,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i16_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64Store32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -4939,20 +4961,18 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; let narrow_value = builder.build_int_truncate(value, intrinsics.i32_ty, &state.var_name()); let store = builder.build_store(effective_address, narrow_value); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I8x16Neg => { let (v, i) = state.pop1_extra()?; @@ -5247,24 +5267,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); - let tbaa_kind = context.get_kind_id("tbaa"); - elem.as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i8x16_ty, &state.var_name(), ); @@ -5276,24 +5298,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); - let tbaa_kind = context.get_kind_id("tbaa"); - elem.as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i16x8_ty, &state.var_name(), ); @@ -5305,24 +5329,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); - let tbaa_kind = context.get_kind_id("tbaa"); - elem.as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i32x4_ty, &state.var_name(), ); @@ -5334,24 +5360,26 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; - let elem = builder.build_load(effective_address, "").into_int_value(); - let tbaa_kind = context.get_kind_id("tbaa"); - elem.as_instruction_value() - .unwrap() - .set_metadata(self.memory_tbaa, tbaa_kind); + let elem = builder.build_load(effective_address, ""); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + elem.as_instruction_value().unwrap(), + Some(0), + ); let res = splat_vector( builder, intrinsics, - elem.as_basic_value_enum(), + elem, intrinsics.i64x2_ty, &state.var_name(), ); @@ -5372,14 +5400,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5394,8 +5421,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I64AtomicLoad { ref memarg } => { @@ -5403,14 +5429,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5425,8 +5450,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(8).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); state.push1(result); } Operator::I32AtomicLoad8U { ref memarg } => { @@ -5434,14 +5458,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5458,8 +5481,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -5469,14 +5491,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5493,8 +5514,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i32_ty, &state.var_name()); state.push1(result); @@ -5504,14 +5524,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5528,8 +5547,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(1).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5539,14 +5557,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5563,8 +5580,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(2).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5574,14 +5590,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5598,8 +5613,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { load.set_alignment(4).unwrap(); load.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - load.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", load, Some(0)); let result = builder.build_int_z_extend(narrow_result, intrinsics.i64_ty, &state.var_name()); state.push1(result); @@ -5610,14 +5624,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5632,8 +5645,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore { ref memarg } => { let value = state.pop1()?; @@ -5641,14 +5653,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5663,8 +5674,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore8 { ref memarg } | Operator::I64AtomicStore8 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5672,14 +5682,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5696,8 +5705,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicStore16 { ref memarg } | Operator::I64AtomicStore16 { ref memarg } => { @@ -5706,14 +5714,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5730,8 +5737,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I64AtomicStore32 { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5739,14 +5745,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5763,8 +5768,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { store .set_atomic_ordering(AtomicOrdering::SequentiallyConsistent) .unwrap(); - let tbaa_kind = context.get_kind_id("tbaa"); - store.set_metadata(self.memory_tbaa, tbaa_kind); + tbaa_label(self.module.clone(), intrinsics, "memory", store, Some(0)); } Operator::I32AtomicRmw8UAdd { ref memarg } => { let value = state.pop1()?.into_int_value(); @@ -5772,14 +5776,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5808,14 +5811,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5844,14 +5846,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5877,14 +5878,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5913,14 +5913,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5949,14 +5948,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -5985,14 +5983,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6018,14 +6015,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6054,14 +6050,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6090,14 +6085,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6123,14 +6117,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6159,14 +6152,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6195,14 +6187,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6231,14 +6222,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6264,14 +6254,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6300,14 +6289,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6336,14 +6324,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6369,14 +6356,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6405,14 +6391,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6441,14 +6426,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6477,14 +6461,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6510,14 +6493,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6546,14 +6528,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6582,14 +6563,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6616,14 +6596,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6652,14 +6631,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6688,14 +6666,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6724,14 +6701,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6757,14 +6733,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6793,14 +6768,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6829,14 +6803,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6862,14 +6835,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6898,14 +6870,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6934,14 +6905,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -6970,14 +6940,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7003,14 +6972,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7039,14 +7007,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7075,14 +7042,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7108,14 +7074,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7144,14 +7109,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7180,14 +7144,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7216,14 +7179,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7250,14 +7212,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7294,14 +7255,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7338,14 +7298,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7374,14 +7333,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i8_ptr_ty, 1, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7418,14 +7376,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i16_ptr_ty, 2, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7462,14 +7419,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i32_ptr_ty, 4, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7506,14 +7462,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { builder, intrinsics, context, + self.module.clone(), &function, &mut state, &mut ctx, memarg, intrinsics.i64_ptr_ty, 8, - self.context_field_ptr_to_base_tbaa, - self.context_field_ptr_to_bounds_tbaa, )?; trap_if_misaligned( builder, @@ -7693,97 +7648,6 @@ impl ModuleCodeGenerator Some(Linkage::External), ); - module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); - let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; - let memory = context.metadata_string("memory"); - module.add_global_metadata( - "memory", - &MetadataValue::create_node(&[memory.into(), tbaa_root.into()]), - ); - let memory_tbaa = module.get_global_metadata("memory")[0]; - module.add_global_metadata( - "memory_memop", - &MetadataValue::create_node(&[ - memory_tbaa.into(), - memory_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let memory_tbaa = module.get_global_metadata("memory_memop")[0]; - - let locals = context.metadata_string("locals"); - module.add_global_metadata( - "locals", - &MetadataValue::create_node(&[locals.into(), tbaa_root.into()]), - ); - let locals_tbaa = module.get_global_metadata("locals")[0]; - module.add_global_metadata( - "locals_memop", - &MetadataValue::create_node(&[ - locals_tbaa.into(), - locals_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let locals_tbaa = module.get_global_metadata("locals_memop")[0]; - - let globals = context.metadata_string("globals"); - module.add_global_metadata( - "globals", - &MetadataValue::create_node(&[globals.into(), tbaa_root.into()]), - ); - let globals_tbaa = module.get_global_metadata("globals")[0]; - module.add_global_metadata( - "globals_memop", - &MetadataValue::create_node(&[ - globals_tbaa.into(), - globals_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let globals_tbaa = module.get_global_metadata("globals_memop")[0]; - - let context_field_ptr_to_base_tbaa = - context.metadata_string("context_field_ptr_to_base_tbaa"); - module.add_global_metadata( - "context_field_ptr_to_base_tbaa", - &MetadataValue::create_node(&[context_field_ptr_to_base_tbaa.into(), tbaa_root.into()]), - ); - let context_field_ptr_to_base_tbaa = - module.get_global_metadata("context_field_ptr_to_base_tbaa")[0]; - module.add_global_metadata( - "context_field_ptr_to_base_tbaa_memop", - &MetadataValue::create_node(&[ - context_field_ptr_to_base_tbaa.into(), - context_field_ptr_to_base_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let context_field_ptr_to_base_tbaa = - module.get_global_metadata("context_field_ptr_to_base_tbaa_memop")[0]; - - let context_field_ptr_to_bounds_tbaa = - context.metadata_string("context_field_ptr_to_bounds_tbaa"); - module.add_global_metadata( - "context_field_ptr_to_bounds_tbaa", - &MetadataValue::create_node(&[ - context_field_ptr_to_bounds_tbaa.into(), - tbaa_root.into(), - ]), - ); - let context_field_ptr_to_bounds_tbaa = - module.get_global_metadata("context_field_ptr_to_bounds_tbaa")[0]; - module.add_global_metadata( - "context_field_ptr_to_bounds_tbaa_memop", - &MetadataValue::create_node(&[ - context_field_ptr_to_bounds_tbaa.into(), - context_field_ptr_to_bounds_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let context_field_ptr_to_bounds_tbaa = - module.get_global_metadata("context_field_ptr_to_bounds_tbaa_memop")[0]; - LLVMModuleCodeGenerator { context: Some(context), builder: Some(builder), @@ -7798,11 +7662,6 @@ impl ModuleCodeGenerator stackmaps: Rc::new(RefCell::new(StackmapRegistry::default())), track_state: false, target_machine, - memory_tbaa, - locals_tbaa, - globals_tbaa, - context_field_ptr_to_base_tbaa, - context_field_ptr_to_bounds_tbaa, } } @@ -7910,11 +7769,6 @@ impl ModuleCodeGenerator opcode_offset: 0, track_state: self.track_state, module: self.module.clone(), - memory_tbaa: self.memory_tbaa, - locals_tbaa: self.locals_tbaa, - globals_tbaa: self.globals_tbaa, - context_field_ptr_to_base_tbaa: self.context_field_ptr_to_base_tbaa, - context_field_ptr_to_bounds_tbaa: self.context_field_ptr_to_bounds_tbaa, }; self.functions.push(code); Ok(self.functions.last_mut().unwrap()) From 25bcadbf74aede4d176c0ea4454d7b8639795d7e Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 30 Oct 2019 16:09:48 -0700 Subject: [PATCH 107/122] Export WasmPtr from wasmer_runtime --- lib/runtime/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index 2945ff3d5..aedd938ae 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -92,6 +92,7 @@ pub use wasmer_runtime_core::export::Export; pub use wasmer_runtime_core::global::Global; pub use wasmer_runtime_core::import::ImportObject; pub use wasmer_runtime_core::instance::{DynFunc, Instance}; +pub use wasmer_runtime_core::memory::ptr::{Array, Item, WasmPtr}; pub use wasmer_runtime_core::memory::Memory; pub use wasmer_runtime_core::module::Module; pub use wasmer_runtime_core::table::Table; From 15ce8bfda7a4965732c18d38427f41f1ca5031dc Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 30 Oct 2019 16:18:36 -0700 Subject: [PATCH 108/122] Label the loads in intrinsics.rs, most of which are the initial accesses off the context. Move tbaa_label to intrinsics.rs. Move TBAA pass to first in the list, it doesn't get invalidated. Add TBAA labels for internal fields. --- lib/llvm-backend/src/code.rs | 95 ++++++------- lib/llvm-backend/src/intrinsics.rs | 215 ++++++++++++++++++++++++++--- 2 files changed, 236 insertions(+), 74 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 103d27429..c29b2e881 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -6,8 +6,8 @@ use inkwell::{ targets::{CodeModel, InitializationConfig, RelocMode, Target, TargetMachine}, types::{BasicType, BasicTypeEnum, FunctionType, PointerType, VectorType}, values::{ - BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, - MetadataValue, PhiValue, PointerValue, VectorValue, + BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PhiValue, PointerValue, + VectorValue, }, AddressSpace, AtomicOrdering, AtomicRMWBinOp, FloatPredicate, IntPredicate, OptimizationLevel, }; @@ -29,7 +29,7 @@ use wasmer_runtime_core::{ use wasmparser::{BinaryReaderError, MemoryImmediate, Operator, Type as WpType}; use crate::backend::LLVMBackend; -use crate::intrinsics::{CtxType, GlobalCache, Intrinsics, MemoryCache}; +use crate::intrinsics::{tbaa_label, CtxType, GlobalCache, Intrinsics, MemoryCache}; use crate::read_info::{blocktype_to_type, type_to_type}; use crate::stackmap::{StackmapEntry, StackmapEntryKind, StackmapRegistry, ValueSemantic}; use crate::state::{ControlFrame, ExtraInfo, IfElseState, State}; @@ -561,7 +561,7 @@ fn resolve_memory_ptr( value_size: usize, ) -> Result { // Look up the memory base (as pointer) and bounds (as unsigned integer). - let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics); + let memory_cache = ctx.memory(MemoryIndex::new(0), intrinsics, module.clone()); let (mem_base, mem_bound) = match memory_cache { MemoryCache::Dynamic { ptr_to_base_ptr, @@ -652,46 +652,6 @@ fn resolve_memory_ptr( .into_pointer_value()) } -fn tbaa_label( - module: Rc>, - intrinsics: &Intrinsics, - label: &str, - instruction: InstructionValue, - index: Option, -) { - let module = module.borrow_mut(); - let context = module.get_context(); - - module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); - let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; - - let label = if let Some(idx) = index { - format!("{}{}", label, idx) - } else { - label.to_string() - }; - let type_label = context.metadata_string(label.as_str()); - module.add_global_metadata( - label.as_str(), - &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), - ); - let type_tbaa = module.get_global_metadata(label.as_str())[0]; - - let label = label + "_memop"; - module.add_global_metadata( - label.as_str(), - &MetadataValue::create_node(&[ - type_tbaa.into(), - type_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let type_tbaa = module.get_global_metadata(label.as_str())[0]; - - let tbaa_kind = context.get_kind_id("tbaa"); - instruction.set_metadata(type_tbaa, tbaa_kind); -} - fn emit_stack_map( _module_info: &ModuleInfo, intrinsics: &Intrinsics, @@ -1027,17 +987,33 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { InternalEvent::GetInternal(idx) => { if state.reachable { let idx = idx as usize; - let field_ptr = ctx.internal_field(idx, intrinsics, builder); + let field_ptr = + ctx.internal_field(idx, intrinsics, self.module.clone(), builder); let result = builder.build_load(field_ptr, "get_internal"); + tbaa_label( + self.module.clone(), + intrinsics, + "internal", + result.as_instruction_value().unwrap(), + Some(idx as u32), + ); state.push1(result); } } InternalEvent::SetInternal(idx) => { if state.reachable { let idx = idx as usize; - let field_ptr = ctx.internal_field(idx, intrinsics, builder); + let field_ptr = + ctx.internal_field(idx, intrinsics, self.module.clone(), builder); let v = state.pop1()?; - builder.build_store(field_ptr, v); + let store = builder.build_store(field_ptr, v); + tbaa_label( + self.module.clone(), + intrinsics, + "internal", + store, + Some(idx as u32), + ); } } } @@ -1622,7 +1598,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::GetGlobal { global_index } => { let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index, intrinsics); + let global_cache = ctx.global_cache(index, intrinsics, self.module.clone()); match global_cache { GlobalCache::Const { value } => { state.push1(value); @@ -1644,7 +1620,7 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (value, info) = state.pop1_extra()?; let value = apply_pending_canonicalization(builder, intrinsics, value, info); let index = GlobalIndex::new(global_index as usize); - let global_cache = ctx.global_cache(index, intrinsics); + let global_cache = ctx.global_cache(index, intrinsics, self.module.clone()); match global_cache { GlobalCache::Mut { ptr_to_value } => { let store = builder.build_store(ptr_to_value, value); @@ -1712,14 +1688,19 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { ) .collect(); - let func_ptr = - ctx.local_func(local_func_index, llvm_sig, intrinsics, builder); + let func_ptr = ctx.local_func( + local_func_index, + llvm_sig, + intrinsics, + self.module.clone(), + builder, + ); (params, func_ptr) } LocalOrImport::Import(import_func_index) => { let (func_ptr_untyped, ctx_ptr) = - ctx.imported_func(import_func_index, intrinsics); + ctx.imported_func(import_func_index, intrinsics, self.module.clone()); let params: Vec<_> = std::iter::once(ctx_ptr.as_basic_value_enum()) .chain( @@ -1822,8 +1803,12 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { Operator::CallIndirect { index, table_index } => { let sig_index = SigIndex::new(index as usize); let expected_dynamic_sigindex = ctx.dynamic_sigindex(sig_index, intrinsics); - let (table_base, table_bound) = - ctx.table(TableIndex::new(table_index as usize), intrinsics, builder); + let (table_base, table_bound) = ctx.table( + TableIndex::new(table_index as usize), + intrinsics, + self.module.clone(), + builder, + ); let func_index = state.pop1()?.into_int_value(); // We assume the table has the `anyfunc` element type. @@ -7814,11 +7799,11 @@ impl ModuleCodeGenerator if cfg!(test) { pass_manager.add_verifier_pass(); } + pass_manager.add_type_based_alias_analysis_pass(); pass_manager.add_lower_expect_intrinsic_pass(); pass_manager.add_scalar_repl_aggregates_pass(); pass_manager.add_instruction_combining_pass(); pass_manager.add_cfg_simplification_pass(); - pass_manager.add_type_based_alias_analysis_pass(); pass_manager.add_gvn_pass(); pass_manager.add_jump_threading_pass(); pass_manager.add_correlated_value_propagation_pass(); diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 36c3b7081..4ec87134b 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -7,12 +7,15 @@ use inkwell::{ BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType, }, values::{ - BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue, VectorValue, + BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, + MetadataValue, PointerValue, VectorValue, }, AddressSpace, }; +use std::cell::RefCell; use std::collections::HashMap; use std::marker::PhantomData; +use std::rc::Rc; use wasmer_runtime_core::{ memory::MemoryType, module::ModuleInfo, @@ -653,7 +656,12 @@ impl<'a> CtxType<'a> { ptr } - pub fn memory(&mut self, index: MemoryIndex, intrinsics: &Intrinsics) -> MemoryCache { + pub fn memory( + &mut self, + index: MemoryIndex, + intrinsics: &Intrinsics, + module: Rc>, + ) -> MemoryCache { let (cached_memories, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_memories, self.info, @@ -690,6 +698,13 @@ impl<'a> CtxType<'a> { let memory_array_ptr = cache_builder .build_load(memory_array_ptr_ptr, "memory_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "memory_array", + memory_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let memory_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -701,6 +716,13 @@ impl<'a> CtxType<'a> { let memory_ptr = cache_builder .build_load(memory_ptr_ptr, "memory_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "memory_ptr", + memory_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { ( @@ -714,14 +736,29 @@ impl<'a> CtxType<'a> { ptr_to_base_ptr, ptr_to_bounds, }, - MemoryType::Static | MemoryType::SharedStatic => MemoryCache::Static { - base_ptr: cache_builder + MemoryType::Static | MemoryType::SharedStatic => { + let base_ptr = cache_builder .build_load(ptr_to_base_ptr, "base") - .into_pointer_value(), - bounds: cache_builder + .into_pointer_value(); + let bounds = cache_builder .build_load(ptr_to_bounds, "bounds") - .into_int_value(), - }, + .into_int_value(); + tbaa_label( + module.clone(), + intrinsics, + "memory_base", + base_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "memory_bounds", + bounds.as_instruction_value().unwrap(), + Some(index as u32), + ); + MemoryCache::Static { base_ptr, bounds } + } } }) } @@ -730,6 +767,7 @@ impl<'a> CtxType<'a> { &mut self, index: TableIndex, intrinsics: &Intrinsics, + module: Rc>, ) -> (PointerValue, PointerValue) { let (cached_tables, info, ctx_ptr_value, cache_builder) = ( &mut self.cached_tables, @@ -768,6 +806,13 @@ impl<'a> CtxType<'a> { let table_array_ptr = cache_builder .build_load(table_array_ptr_ptr, "table_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_tables", + table_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let table_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep(table_array_ptr, &[const_index], "table_ptr_ptr") @@ -775,6 +820,13 @@ impl<'a> CtxType<'a> { let table_ptr = cache_builder .build_load(table_ptr_ptr, "table_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "table_ptr", + table_array_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let (ptr_to_base_ptr, ptr_to_bounds) = unsafe { ( @@ -796,15 +848,30 @@ impl<'a> CtxType<'a> { &mut self, index: TableIndex, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> (PointerValue, IntValue) { - let (ptr_to_base_ptr, ptr_to_bounds) = self.table_prepare(index, intrinsics); - ( - builder - .build_load(ptr_to_base_ptr, "base_ptr") - .into_pointer_value(), - builder.build_load(ptr_to_bounds, "bounds").into_int_value(), - ) + let (ptr_to_base_ptr, ptr_to_bounds) = + self.table_prepare(index, intrinsics, module.clone()); + let base_ptr = builder + .build_load(ptr_to_base_ptr, "base_ptr") + .into_pointer_value(); + let bounds = builder.build_load(ptr_to_bounds, "bounds").into_int_value(); + tbaa_label( + module.clone(), + intrinsics, + "table_base_ptr", + base_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "table_bounds", + bounds.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + (base_ptr, bounds) } pub fn local_func( @@ -812,6 +879,7 @@ impl<'a> CtxType<'a> { index: LocalFuncIndex, fn_ty: FunctionType, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> PointerValue { let local_func_array_ptr_ptr = unsafe { @@ -824,6 +892,13 @@ impl<'a> CtxType<'a> { let local_func_array_ptr = builder .build_load(local_func_array_ptr_ptr, "local_func_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_local_funcs", + local_func_array_ptr.as_instruction_value().unwrap(), + None, + ); let local_func_ptr_ptr = unsafe { builder.build_in_bounds_gep( local_func_array_ptr, @@ -834,6 +909,13 @@ impl<'a> CtxType<'a> { let local_func_ptr = builder .build_load(local_func_ptr_ptr, "local_func_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "local_func_ptr", + local_func_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); builder.build_pointer_cast( local_func_ptr, fn_ty.ptr_type(AddressSpace::Generic), @@ -875,7 +957,12 @@ impl<'a> CtxType<'a> { }) } - pub fn global_cache(&mut self, index: GlobalIndex, intrinsics: &Intrinsics) -> GlobalCache { + pub fn global_cache( + &mut self, + index: GlobalIndex, + intrinsics: &Intrinsics, + module: Rc>, + ) -> GlobalCache { let (cached_globals, ctx_ptr_value, info, cache_builder) = ( &mut self.cached_globals, self.ctx_ptr_value, @@ -923,6 +1010,13 @@ impl<'a> CtxType<'a> { let global_array_ptr = cache_builder .build_load(globals_array_ptr_ptr, "global_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_globals", + globals_array_ptr_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index, false); let global_ptr_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -934,6 +1028,13 @@ impl<'a> CtxType<'a> { let global_ptr = cache_builder .build_load(global_ptr_ptr, "global_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "global_ptr", + globals_array_ptr_ptr.as_instruction_value().unwrap(), + Some(index as u32), + ); let global_ptr_typed = cache_builder.build_pointer_cast(global_ptr, llvm_ptr_ty, "global_ptr_typed"); @@ -943,9 +1044,15 @@ impl<'a> CtxType<'a> { ptr_to_value: global_ptr_typed, } } else { - GlobalCache::Const { - value: cache_builder.build_load(global_ptr_typed, "global_value"), - } + let value = cache_builder.build_load(global_ptr_typed, "global_value"); + tbaa_label( + module.clone(), + intrinsics, + "global", + value.as_instruction_value().unwrap(), + Some(index as u32), + ); + GlobalCache::Const { value } } }) } @@ -954,6 +1061,7 @@ impl<'a> CtxType<'a> { &mut self, index: ImportedFuncIndex, intrinsics: &Intrinsics, + module: Rc>, ) -> (PointerValue, PointerValue) { let (cached_imported_functions, ctx_ptr_value, cache_builder) = ( &mut self.cached_imported_functions, @@ -972,6 +1080,13 @@ impl<'a> CtxType<'a> { let func_array_ptr = cache_builder .build_load(func_array_ptr_ptr, "func_array_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_imported_funcs", + func_array_ptr.as_instruction_value().unwrap(), + None, + ); let const_index = intrinsics.i32_ty.const_int(index.index() as u64, false); let imported_func_ptr = unsafe { cache_builder.build_in_bounds_gep( @@ -993,6 +1108,20 @@ impl<'a> CtxType<'a> { let ctx_ptr = cache_builder .build_load(ctx_ptr_ptr, "ctx_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "imported_func_ptr", + func_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); + tbaa_label( + module.clone(), + intrinsics, + "imported_func_ctx_ptr", + ctx_ptr.as_instruction_value().unwrap(), + Some(index.index() as u32), + ); ImportedFuncCache { func_ptr, ctx_ptr } }); @@ -1004,6 +1133,7 @@ impl<'a> CtxType<'a> { &mut self, index: usize, intrinsics: &Intrinsics, + module: Rc>, builder: &Builder, ) -> PointerValue { assert!(index < INTERNALS_SIZE); @@ -1018,6 +1148,13 @@ impl<'a> CtxType<'a> { let local_internals_ptr = builder .build_load(local_internals_ptr_ptr, "local_internals_ptr") .into_pointer_value(); + tbaa_label( + module.clone(), + intrinsics, + "context_field_ptr_to_internals", + local_internals_ptr_ptr.as_instruction_value().unwrap(), + None, + ); unsafe { builder.build_in_bounds_gep( local_internals_ptr, @@ -1027,3 +1164,43 @@ impl<'a> CtxType<'a> { } } } + +pub fn tbaa_label( + module: Rc>, + intrinsics: &Intrinsics, + label: &str, + instruction: InstructionValue, + index: Option, +) { + let module = module.borrow_mut(); + let context = module.get_context(); + + module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); + let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; + + let label = if let Some(idx) = index { + format!("{}{}", label, idx) + } else { + label.to_string() + }; + let type_label = context.metadata_string(label.as_str()); + module.add_global_metadata( + label.as_str(), + &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), + ); + let type_tbaa = module.get_global_metadata(label.as_str())[0]; + + let label = label + "_memop"; + module.add_global_metadata( + label.as_str(), + &MetadataValue::create_node(&[ + type_tbaa.into(), + type_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + let type_tbaa = module.get_global_metadata(label.as_str())[0]; + + let tbaa_kind = context.get_kind_id("tbaa"); + instruction.set_metadata(type_tbaa, tbaa_kind); +} From d10d54a4160ac6a62e26e1c307959feff010e649 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Wed, 30 Oct 2019 16:39:39 -0700 Subject: [PATCH 109/122] Add TBAA to atomic ops. --- lib/llvm-backend/src/code.rs | 343 +++++++++++++++++++++++++++++++++++ 1 file changed, 343 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index c29b2e881..43668db39 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -5787,6 +5787,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5822,6 +5829,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -5855,6 +5869,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UAdd { ref memarg } => { @@ -5889,6 +5910,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5924,6 +5952,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5959,6 +5994,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -5992,6 +6034,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8USub { ref memarg } => { @@ -6026,6 +6075,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6061,6 +6117,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6094,6 +6157,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8USub { ref memarg } => { @@ -6128,6 +6198,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6163,6 +6240,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6198,6 +6282,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6231,6 +6322,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UAnd { ref memarg } => { @@ -6265,6 +6363,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6300,6 +6405,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6333,6 +6445,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UAnd { ref memarg } => { @@ -6367,6 +6486,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6402,6 +6528,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6437,6 +6570,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6470,6 +6610,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UOr { ref memarg } => { @@ -6504,6 +6651,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6539,6 +6693,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6572,6 +6733,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6607,6 +6775,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6642,6 +6817,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6677,6 +6859,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6710,6 +6899,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UXor { ref memarg } => { @@ -6744,6 +6940,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6779,6 +6982,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -6812,6 +7022,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UXor { ref memarg } => { @@ -6846,6 +7063,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6881,6 +7105,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6916,6 +7147,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -6949,6 +7187,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UXchg { ref memarg } => { @@ -6983,6 +7228,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -7018,6 +7270,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i32_ty, &state.var_name()); state.push1(old); } @@ -7051,6 +7310,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I64AtomicRmw8UXchg { ref memarg } => { @@ -7085,6 +7351,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -7120,6 +7393,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -7155,6 +7435,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_int_z_extend(old, intrinsics.i64_ty, &state.var_name()); state.push1(old); } @@ -7188,6 +7475,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); state.push1(old); } Operator::I32AtomicRmw8UCmpxchg { ref memarg } => { @@ -7226,6 +7520,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -7269,6 +7570,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -7308,6 +7616,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_extract_value(old, 0, "").unwrap(); state.push1(old); } @@ -7347,6 +7662,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -7390,6 +7712,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -7433,6 +7762,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder .build_extract_value(old, 0, "") .unwrap() @@ -7472,6 +7808,13 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { AtomicOrdering::SequentiallyConsistent, ) .unwrap(); + tbaa_label( + self.module.clone(), + intrinsics, + "memory", + old.as_instruction_value().unwrap(), + Some(0), + ); let old = builder.build_extract_value(old, 0, "").unwrap(); state.push1(old); } From 912eb32be884aca7a7ee423e7b953d6d1ab69d9d Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 31 Oct 2019 11:00:07 +0100 Subject: [PATCH 110/122] chore(cargo) Update `Cargo.lock`. --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index d15d45dd6..f23b0c2e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,7 +1540,7 @@ dependencies = [ [[package]] name = "wasmer-runtime-core-tests" -version = "0.8.0" +version = "0.9.0" dependencies = [ "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-clif-backend 0.9.0", From 16124672a31a4c67dc1612a7dc6014ead01a23f0 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 31 Oct 2019 09:55:55 -0700 Subject: [PATCH 111/122] Add OS compatibility section to feature matrix --- docs/feature_matrix.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index a5e75a49e..8b475d190 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -13,6 +13,16 @@ | WASI | ✅ | ✅ | ✅ | | WASMER_BACKTRACE | ✅ | ⬜ | ⬜ | +## Operating System +|   | GNU Linux | Mac OSX | Windows NT | +| - | :-: | :-: | :-: | +| Cranelift Backend | ✅ | ✅ | ✅ | +| LLVM Backend | ✅ | ✅ | ✅ | +| Singlepass Backend | #347 | ✅ | ✅ | +| WASI | ✅ | ✅ | ✅* | + +* `poll_fd` is not fully implemented for Windows yet + ## Language integration TODO: define a set of features that are relevant and mark them here From 88427c969659e42db76c4c885347e7622bb56135 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 31 Oct 2019 11:48:21 -0700 Subject: [PATCH 112/122] Add some comments. --- lib/llvm-backend/src/intrinsics.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 4ec87134b..910e59746 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1165,6 +1165,8 @@ impl<'a> CtxType<'a> { } } +// Given an instruction that operates on memory, mark the access as not aliasing +// other memory accesses which have a different (label, index) pair. pub fn tbaa_label( module: Rc>, intrinsics: &Intrinsics, @@ -1172,12 +1174,27 @@ pub fn tbaa_label( instruction: InstructionValue, index: Option, ) { + // To convey to LLVM that two pointers must be pointing to distinct memory, + // we use LLVM's Type Based Aliasing Analysis, or TBAA, to mark the memory + // operations as having different types whose pointers may not alias. + // + // See the LLVM documentation at + // https://llvm.org/docs/LangRef.html#tbaa-metadata + // + // LLVM TBAA supports many features, but we use it in a simple way, with + // only scalar types that are children of the root node. Every TBAA type we + // declare is `noalias` with the others: + // https://llvm.org/docs/AliasAnalysis.html#must-may-and-no-alias-responses + let module = module.borrow_mut(); let context = module.get_context(); + // `!wasmer_tbaa_root = {}`, the TBAA root node for wasmer. module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; + // Construct (or look up) the type descriptor, for example + // `!"local 0" = !{!"local 0", !wasmer_tbaa_root}`. let label = if let Some(idx) = index { format!("{}{}", label, idx) } else { @@ -1190,6 +1207,12 @@ pub fn tbaa_label( ); let type_tbaa = module.get_global_metadata(label.as_str())[0]; + // Construct (or look up) the access tag, which is a struct of the form + // (base type, acess type, offset). + // + // "If BaseTy is a scalar type, Offset must be 0 and BaseTy and AccessTy + // must be the same". + // -- https://llvm.org/docs/LangRef.html#tbaa-metadata let label = label + "_memop"; module.add_global_metadata( label.as_str(), @@ -1201,6 +1224,7 @@ pub fn tbaa_label( ); let type_tbaa = module.get_global_metadata(label.as_str())[0]; + // Attach the access tag to the instruction. let tbaa_kind = context.get_kind_id("tbaa"); instruction.set_metadata(type_tbaa, tbaa_kind); } From 0ba686ffc6c87798b23de3bcb8d5baf57a6469e3 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 31 Oct 2019 11:49:36 -0700 Subject: [PATCH 113/122] Improve wording a little. --- lib/llvm-backend/src/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 910e59746..d424f9c12 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1183,7 +1183,8 @@ pub fn tbaa_label( // // LLVM TBAA supports many features, but we use it in a simple way, with // only scalar types that are children of the root node. Every TBAA type we - // declare is `noalias` with the others: + // declare is NoAlias with the others. See NoAlias, PartialAlias, + // MayAlias and MustAlias in the LLVM documentation: // https://llvm.org/docs/AliasAnalysis.html#must-may-and-no-alias-responses let module = module.borrow_mut(); From 2b236be941fcdad5d76d0094dd577c5f1eb63f67 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 31 Oct 2019 12:12:56 -0700 Subject: [PATCH 114/122] Update docs/feature_matrix.md --- docs/feature_matrix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index 8b475d190..63602083a 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -18,7 +18,7 @@ | - | :-: | :-: | :-: | | Cranelift Backend | ✅ | ✅ | ✅ | | LLVM Backend | ✅ | ✅ | ✅ | -| Singlepass Backend | #347 | ✅ | ✅ | +| Singlepass Backend | [#347](https://github.com/wasmerio/wasmer/issues/347) | ✅ | ✅ | | WASI | ✅ | ✅ | ✅* | * `poll_fd` is not fully implemented for Windows yet From e115d356a774345009fbdcc5d6467e80bf1317bf Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 31 Oct 2019 12:14:16 -0700 Subject: [PATCH 115/122] Update feature_matrix.md --- docs/feature_matrix.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index 63602083a..81602762b 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -33,7 +33,8 @@ Current ideas: - Metering - Caching -;; TODO: expand this table, it's focused on new features that we haven't implemented yet and doesn't list all language integrations +> TODO: expand this table, it's focused on new features that we haven't implemented yet and doesn't list all language integrations + |   | Rust | C / C++ | Go | Python | Ruby | | - | :-: | :-: | :-: | :-: | :-: | | Terminate in host call | ✅ | ⬜ | ⬜ | ⬜ | ⬜ | From ef4b3c34289211329467d9cbc6cebd5b1319d2e4 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 31 Oct 2019 12:40:32 -0700 Subject: [PATCH 116/122] Improve some TBAA label names, particular for memory. Memory can't change between static and dynamic, so use that in the TBAA label name. Distinguish between local and imported memory, table and globals. --- lib/llvm-backend/src/code.rs | 8 ++-- lib/llvm-backend/src/intrinsics.rs | 69 ++++++++++++++++-------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 69b2a7ad1..13e203154 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -577,16 +577,16 @@ fn resolve_memory_ptr( tbaa_label( module.clone(), intrinsics, - "context_field_ptr_to_base", + "dynamic_memory_base", base.as_instruction_value().unwrap(), - None, + Some(0), ); tbaa_label( module.clone(), intrinsics, - "context_field_ptr_to_bounds", + "dynamic_memory_bounds", bounds.as_instruction_value().unwrap(), - None, + Some(0), ); (base, bounds) } diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index d424f9c12..47d94747d 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -670,30 +670,33 @@ impl<'a> CtxType<'a> { ); *cached_memories.entry(index).or_insert_with(|| { - let (memory_array_ptr_ptr, index, memory_type) = match index.local_or_import(info) { - LocalOrImport::Local(local_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_memories()), - "memory_array_ptr_ptr", - ) - }, - local_mem_index.index() as u64, - info.memories[local_mem_index].memory_type(), - ), - LocalOrImport::Import(import_mem_index) => ( - unsafe { - cache_builder.build_struct_gep( - ctx_ptr_value, - offset_to_index(Ctx::offset_imported_memories()), - "memory_array_ptr_ptr", - ) - }, - import_mem_index.index() as u64, - info.imported_memories[import_mem_index].1.memory_type(), - ), - }; + let (memory_array_ptr_ptr, index, memory_type, field_name) = + match index.local_or_import(info) { + LocalOrImport::Local(local_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_memories()), + "memory_array_ptr_ptr", + ) + }, + local_mem_index.index() as u64, + info.memories[local_mem_index].memory_type(), + "context_field_ptr_to_local_memory", + ), + LocalOrImport::Import(import_mem_index) => ( + unsafe { + cache_builder.build_struct_gep( + ctx_ptr_value, + offset_to_index(Ctx::offset_imported_memories()), + "memory_array_ptr_ptr", + ) + }, + import_mem_index.index() as u64, + info.imported_memories[import_mem_index].1.memory_type(), + "context_field_ptr_to_imported_memory", + ), + }; let memory_array_ptr = cache_builder .build_load(memory_array_ptr_ptr, "memory_array_ptr") @@ -701,7 +704,7 @@ impl<'a> CtxType<'a> { tbaa_label( module.clone(), intrinsics, - "memory_array", + field_name, memory_array_ptr.as_instruction_value().unwrap(), None, ); @@ -746,14 +749,14 @@ impl<'a> CtxType<'a> { tbaa_label( module.clone(), intrinsics, - "memory_base", + "static_memory_base", base_ptr.as_instruction_value().unwrap(), Some(index as u32), ); tbaa_label( module.clone(), intrinsics, - "memory_bounds", + "static_memory_bounds", bounds.as_instruction_value().unwrap(), Some(index as u32), ); @@ -780,7 +783,7 @@ impl<'a> CtxType<'a> { ptr_to_base_ptr, ptr_to_bounds, } = *cached_tables.entry(index).or_insert_with(|| { - let (table_array_ptr_ptr, index) = match index.local_or_import(info) { + let (table_array_ptr_ptr, index, field_name) = match index.local_or_import(info) { LocalOrImport::Local(local_table_index) => ( unsafe { cache_builder.build_struct_gep( @@ -790,6 +793,7 @@ impl<'a> CtxType<'a> { ) }, local_table_index.index() as u64, + "context_field_ptr_to_local_table", ), LocalOrImport::Import(import_table_index) => ( unsafe { @@ -800,6 +804,7 @@ impl<'a> CtxType<'a> { ) }, import_table_index.index() as u64, + "context_field_ptr_to_import_table", ), }; @@ -809,7 +814,7 @@ impl<'a> CtxType<'a> { tbaa_label( module.clone(), intrinsics, - "context_field_ptr_to_tables", + field_name, table_array_ptr.as_instruction_value().unwrap(), None, ); @@ -971,7 +976,7 @@ impl<'a> CtxType<'a> { ); *cached_globals.entry(index).or_insert_with(|| { - let (globals_array_ptr_ptr, index, mutable, wasmer_ty) = + let (globals_array_ptr_ptr, index, mutable, wasmer_ty, field_name) = match index.local_or_import(info) { LocalOrImport::Local(local_global_index) => { let desc = info.globals[local_global_index].desc; @@ -986,6 +991,7 @@ impl<'a> CtxType<'a> { local_global_index.index() as u64, desc.mutable, desc.ty, + "context_field_ptr_to_local_globals", ) } LocalOrImport::Import(import_global_index) => { @@ -1001,6 +1007,7 @@ impl<'a> CtxType<'a> { import_global_index.index() as u64, desc.mutable, desc.ty, + "context_field_ptr_to_imported_globals", ) } }; @@ -1013,7 +1020,7 @@ impl<'a> CtxType<'a> { tbaa_label( module.clone(), intrinsics, - "context_field_ptr_to_globals", + field_name, globals_array_ptr_ptr.as_instruction_value().unwrap(), None, ); From bc521a2837a39c3f4df824b88ba53f6f1fe82898 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 31 Oct 2019 12:43:38 -0700 Subject: [PATCH 117/122] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b97be02..afe906514 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## **[Unreleased]** +- [#921](https://github.com/wasmerio/wasmer/pull/921) In LLVM backend, annotate all memory accesses with TBAA metadata. - [#883](https://github.com/wasmerio/wasmer/pull/883) Allow floating point operations to have arbitrary inputs, even including SNaNs. - [#856](https://github.com/wasmerio/wasmer/pull/856) Expose methods in the runtime C API to get a WASI import object From 20270411d93849d44bbce654191221fadcecafd0 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 1 Nov 2019 12:49:54 -0700 Subject: [PATCH 118/122] When the const memory access is not larger than the minimum, use a runtime check. The memory may have grown. --- lib/llvm-backend/src/code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 4fdd7caab..0cc165425 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -602,7 +602,7 @@ fn resolve_memory_ptr( IntPredicate::ULE, intrinsics.i64_ty.const_int(minimum.bytes().0 as u64, false), ); - if ptr_in_bounds.is_constant_int() { + if ptr_in_bounds.get_zero_extended_constant() == Some(1) { Some(ptr_in_bounds) } else { None From 132757ee9dfea68aa0b85525590c5816347a9f6e Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 1 Nov 2019 17:49:45 -0700 Subject: [PATCH 119/122] Fix leak. Only create one NamedMDNode for each name. --- lib/llvm-backend/src/intrinsics.rs | 49 +++++++++++++++++++----------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 47d94747d..173b814c3 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -1198,8 +1198,13 @@ pub fn tbaa_label( let context = module.get_context(); // `!wasmer_tbaa_root = {}`, the TBAA root node for wasmer. - module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); - let tbaa_root = module.get_global_metadata("wasmer_tbaa_root")[0]; + let tbaa_root = module + .get_global_metadata("wasmer_tbaa_root") + .pop() + .unwrap_or_else(|| { + module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); + module.get_global_metadata("wasmer_tbaa_root")[0] + }); // Construct (or look up) the type descriptor, for example // `!"local 0" = !{!"local 0", !wasmer_tbaa_root}`. @@ -1209,28 +1214,38 @@ pub fn tbaa_label( label.to_string() }; let type_label = context.metadata_string(label.as_str()); - module.add_global_metadata( - label.as_str(), - &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), - ); - let type_tbaa = module.get_global_metadata(label.as_str())[0]; + let type_tbaa = module + .get_global_metadata(label.as_str()) + .pop() + .unwrap_or_else(|| { + module.add_global_metadata( + label.as_str(), + &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), + ); + module.get_global_metadata(label.as_str())[0] + }); // Construct (or look up) the access tag, which is a struct of the form - // (base type, acess type, offset). + // (base type, access type, offset). // // "If BaseTy is a scalar type, Offset must be 0 and BaseTy and AccessTy // must be the same". // -- https://llvm.org/docs/LangRef.html#tbaa-metadata let label = label + "_memop"; - module.add_global_metadata( - label.as_str(), - &MetadataValue::create_node(&[ - type_tbaa.into(), - type_tbaa.into(), - intrinsics.i64_zero.into(), - ]), - ); - let type_tbaa = module.get_global_metadata(label.as_str())[0]; + let type_tbaa = module + .get_global_metadata(label.as_str()) + .pop() + .unwrap_or_else(|| { + module.add_global_metadata( + label.as_str(), + &MetadataValue::create_node(&[ + type_tbaa.into(), + type_tbaa.into(), + intrinsics.i64_zero.into(), + ]), + ); + module.get_global_metadata(label.as_str())[0] + }); // Attach the access tag to the instruction. let tbaa_kind = context.get_kind_id("tbaa"); From aaa0160c95d355ade24ba90d2b79c067bb7a6f42 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 4 Nov 2019 10:48:42 -0800 Subject: [PATCH 120/122] Fix values of __wasi_advice_t --- lib/wasi/src/syscalls/types.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/wasi/src/syscalls/types.rs b/lib/wasi/src/syscalls/types.rs index d2aaa0554..d0082ef69 100644 --- a/lib/wasi/src/syscalls/types.rs +++ b/lib/wasi/src/syscalls/types.rs @@ -8,12 +8,12 @@ use std::mem; use wasmer_runtime_core::types::ValueType; pub type __wasi_advice_t = u8; -pub const __WASI_ADVICE_DONTNEED: u8 = 0; -pub const __WASI_ADVICE_NOREUSE: u8 = 1; -pub const __WASI_ADVICE_NORMAL: u8 = 2; -pub const __WASI_ADVICE_RANDOM: u8 = 3; -pub const __WASI_ADVICE_SEQUENTIAL: u8 = 4; -pub const __WASI_ADVICE_WILLNEED: u8 = 5; +pub const __WASI_ADVICE_NORMAL: u8 = 0; +pub const __WASI_ADVICE_SEQUENTIAL: u8 = 1; +pub const __WASI_ADVICE_RANDOM: u8 = 2; +pub const __WASI_ADVICE_WILLNEED: u8 = 3; +pub const __WASI_ADVICE_DONTNEED: u8 = 4; +pub const __WASI_ADVICE_NOREUSE: u8 = 5; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(C)] From efbb53a91e3f524c7a64afb595bd22a7638f6762 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 4 Nov 2019 11:04:50 -0800 Subject: [PATCH 121/122] Add workaround for #927. --- Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e8d11bed0..7e2fc0978 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,8 @@ middleware-cranelift: cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features clif middleware-llvm: - cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features llvm +# TODO: remove workaround for https://github.com/wasmerio/wasmer/issues/927 + cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features llvm -- --test-threads=1 middleware: middleware-singlepass middleware-cranelift middleware-llvm From 1d8f2b767dfd6917276cbd591a4e010a627efbd3 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 4 Nov 2019 15:27:38 -0800 Subject: [PATCH 122/122] Build Metadata using the current Context. Fixes #927. Reverts #928. --- Cargo.lock | 10 +++++----- Makefile | 3 +-- lib/llvm-backend/src/intrinsics.rs | 8 ++++---- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 835d716a6..9012e4f6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -434,7 +434,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "generational-arena" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -522,7 +522,7 @@ dependencies = [ [[package]] name = "inkwell" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#10d180807ce6e621ae13d74001bf5677b0e1f179" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" dependencies = [ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "enum-methods 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -536,7 +536,7 @@ dependencies = [ [[package]] name = "inkwell_internal_macros" version = "0.1.0" -source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#10d180807ce6e621ae13d74001bf5677b0e1f179" +source = "git+https://github.com/wasmerio/inkwell?branch=llvm8-0#bd0d09a8041dc2217f698cd3631b6d4d4c0e696b" dependencies = [ "cargo_toml 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1590,7 +1590,7 @@ version = "0.9.0" dependencies = [ "bincode 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1717,7 +1717,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum field-offset 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64e9bc339e426139e02601fa69d101e96a92aee71b58bc01697ec2a63a5c9e68" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" -"checksum generational-arena 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "921c3803adaeb9f9639de5149d9f0f9f4b79f00c423915b701db2e02ed80b9ce" +"checksum generational-arena 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fd04ad33021a0409d3f1afbfb89d9f02c10caee73c28f5ac197474dd53e7cf7c" "checksum generic-array 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum ghost 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" diff --git a/Makefile b/Makefile index 7e2fc0978..e8d11bed0 100644 --- a/Makefile +++ b/Makefile @@ -60,8 +60,7 @@ middleware-cranelift: cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features clif middleware-llvm: -# TODO: remove workaround for https://github.com/wasmerio/wasmer/issues/927 - cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features llvm -- --test-threads=1 + cargo test --manifest-path lib/middleware-common-tests/Cargo.toml --release --features llvm middleware: middleware-singlepass middleware-cranelift middleware-llvm diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 1e87a9251..4c34b6d58 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -8,7 +8,7 @@ use inkwell::{ }, values::{ BasicValue, BasicValueEnum, FloatValue, FunctionValue, InstructionValue, IntValue, - MetadataValue, PointerValue, VectorValue, + PointerValue, VectorValue, }, AddressSpace, }; @@ -1218,7 +1218,7 @@ pub fn tbaa_label( .get_global_metadata("wasmer_tbaa_root") .pop() .unwrap_or_else(|| { - module.add_global_metadata("wasmer_tbaa_root", &MetadataValue::create_node(&[])); + module.add_global_metadata("wasmer_tbaa_root", &context.metadata_node(&[])); module.get_global_metadata("wasmer_tbaa_root")[0] }); @@ -1236,7 +1236,7 @@ pub fn tbaa_label( .unwrap_or_else(|| { module.add_global_metadata( label.as_str(), - &MetadataValue::create_node(&[type_label.into(), tbaa_root.into()]), + &context.metadata_node(&[type_label.into(), tbaa_root.into()]), ); module.get_global_metadata(label.as_str())[0] }); @@ -1254,7 +1254,7 @@ pub fn tbaa_label( .unwrap_or_else(|| { module.add_global_metadata( label.as_str(), - &MetadataValue::create_node(&[ + &context.metadata_node(&[ type_tbaa.into(), type_tbaa.into(), intrinsics.i64_zero.into(),