From cfa063502682c9b10dc07c1e3bb2fb56f48faa44 Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 28 Nov 2019 02:49:52 +0800 Subject: [PATCH 01/12] Add caching support for singlepass backend. --- Cargo.lock | 3 + lib/runtime-core/src/state.rs | 18 +-- lib/singlepass-backend/Cargo.toml | 3 + lib/singlepass-backend/src/codegen_x64.rs | 129 ++++++++++++++++++---- lib/singlepass-backend/src/lib.rs | 5 + 5 files changed, 127 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c92d5ceb1c3..ca2a8940491 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1561,12 +1561,15 @@ dependencies = [ name = "wasmer-singlepass-backend" version = "0.11.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)", "dynasm 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "dynasmrt 0.5.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)", "nix 0.15.0 (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)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.11.0", ] diff --git a/lib/runtime-core/src/state.rs b/lib/runtime-core/src/state.rs index 1b7d3f34bbe..a5a0a003647 100644 --- a/lib/runtime-core/src/state.rs +++ b/lib/runtime-core/src/state.rs @@ -7,11 +7,11 @@ use std::collections::BTreeMap; use std::ops::Bound::{Included, Unbounded}; /// An index to a register -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct RegisterIndex(pub usize); /// A kind of wasm or constant value -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum WasmAbstractValue { /// A wasm runtime value Runtime, @@ -20,7 +20,7 @@ pub enum WasmAbstractValue { } /// A container for the state of a running wasm instance. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct MachineState { /// Stack values. pub stack_values: Vec, @@ -37,7 +37,7 @@ pub struct MachineState { } /// A diff of two `MachineState`s. -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct MachineStateDiff { /// Last. pub last: Option, @@ -63,7 +63,7 @@ pub struct MachineStateDiff { } /// A kind of machine value. -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub enum MachineValue { /// Undefined. Undefined, @@ -86,7 +86,7 @@ pub enum MachineValue { } /// A map of function states. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct FunctionStateMap { /// Initial. pub initial: MachineState, @@ -111,7 +111,7 @@ pub struct FunctionStateMap { } /// A kind of suspend offset. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub enum SuspendOffset { /// A loop. Loop(usize), @@ -122,7 +122,7 @@ pub enum SuspendOffset { } /// Info for an offset. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct OffsetInfo { /// End offset. pub end_offset: usize, // excluded bound @@ -133,7 +133,7 @@ pub struct OffsetInfo { } /// A map of module state. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct ModuleStateMap { /// Local functions. pub local_functions: BTreeMap, diff --git a/lib/singlepass-backend/Cargo.toml b/lib/singlepass-backend/Cargo.toml index 81f006049e9..6ed704837a9 100644 --- a/lib/singlepass-backend/Cargo.toml +++ b/lib/singlepass-backend/Cargo.toml @@ -19,3 +19,6 @@ byteorder = "1.3" nix = "0.15" libc = "0.2.60" smallvec = "0.6" +serde = "1.0" +serde_derive = "1.0" +bincode = "1.2" diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index 87ce3116d16..b867d60e1a7 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -22,8 +22,10 @@ use std::{ }; use wasmer_runtime_core::{ backend::{ - get_inline_breakpoint_size, sys::Memory, Architecture, Backend, CacheGen, CompilerConfig, - MemoryBoundCheckMode, RunnableModule, Token, + get_inline_breakpoint_size, + sys::{Memory, Protect}, + Architecture, Backend, CacheGen, CompilerConfig, MemoryBoundCheckMode, RunnableModule, + Token, }, cache::{Artifact, Error as CacheError}, codegen::*, @@ -229,8 +231,6 @@ unsafe impl Sync for FuncPtr {} pub struct X64ExecutionContext { #[allow(dead_code)] code: CodeMemory, - #[allow(dead_code)] - functions: Vec, function_pointers: Vec, function_offsets: Vec, signatures: Arc>, @@ -239,6 +239,25 @@ pub struct X64ExecutionContext { msm: ModuleStateMap, } +/// On-disk cache format. +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct CacheImage { + /// Code for the whole module. + code: Vec, + + /// Offsets to the beginnings of each function. (including trampoline, if any) + function_pointers: Vec, + + /// Offsets to the beginnings of each function after trampoline. + function_offsets: Vec, + + /// Number of imported functions. + func_import_count: usize, + + /// Module state map. + msm: ModuleStateMap, +} + #[derive(Debug)] pub struct ControlFrame { pub label: DynamicLabel, @@ -257,6 +276,25 @@ pub enum IfElseState { Else, } +pub struct SinglepassCache { + buffer: Arc<[u8]>, +} + +impl CacheGen for SinglepassCache { + fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { + let mut memory = Memory::with_size_protect(self.buffer.len(), Protect::ReadWrite) + .map_err(CacheError::SerializeError)?; + + let buffer = &*self.buffer; + + unsafe { + memory.as_slice_mut()[..buffer.len()].copy_from_slice(buffer); + } + + Ok(([].as_ref().into(), memory)) + } +} + impl RunnableModule for X64ExecutionContext { fn get_func( &self, @@ -677,29 +715,41 @@ impl ModuleCodeGenerator .map(|x| (x.offset, x.fsm.clone())) .collect(); - struct Placeholder; - impl CacheGen for Placeholder { - fn generate_cache(&self) -> Result<(Box<[u8]>, Memory), CacheError> { - Err(CacheError::Unknown( - "the singlepass backend doesn't support caching yet".to_string(), - )) - } - } + let msm = ModuleStateMap { + local_functions: local_function_maps, + total_size, + }; + + let cache_image = CacheImage { + code: output.to_vec(), + function_pointers: out_labels + .iter() + .map(|x| { + (x.0 as usize) + .checked_sub(output.as_ptr() as usize) + .unwrap() + }) + .collect(), + function_offsets: out_offsets.iter().map(|x| x.0 as usize).collect(), + func_import_count: self.func_import_count, + msm: msm.clone(), + }; + + let cache = SinglepassCache { + buffer: Arc::from(bincode::serialize(&cache_image).unwrap().into_boxed_slice()), + }; + Ok(( X64ExecutionContext { code: output, - functions: self.functions, signatures: self.signatures.as_ref().unwrap().clone(), breakpoints: breakpoints, func_import_count: self.func_import_count, function_pointers: out_labels, function_offsets: out_offsets, - msm: ModuleStateMap { - local_functions: local_function_maps, - total_size, - }, + msm: msm, }, - Box::new(Placeholder), + Box::new(cache), )) } @@ -771,10 +821,45 @@ impl ModuleCodeGenerator })); Ok(()) } - unsafe fn from_cache(_artifact: Artifact, _: Token) -> Result { - Err(CacheError::Unknown( - "the singlepass compiler API doesn't support caching yet".to_string(), - )) + unsafe fn from_cache(artifact: Artifact, _: Token) -> Result { + let (info, _, memory) = artifact.consume(); + + let cache_image: CacheImage = bincode::deserialize(memory.as_slice()) + .map_err(|x| CacheError::DeserializeError(format!("{:?}", x)))?; + + let mut code_mem = CodeMemory::new(cache_image.code.len()); + code_mem[0..cache_image.code.len()].copy_from_slice(&cache_image.code); + code_mem.make_executable(); + + let function_pointers: Vec = cache_image + .function_pointers + .iter() + .map(|&x| FuncPtr(code_mem.as_ptr().offset(x as isize) as *const FuncPtrInner)) + .collect(); + let function_offsets: Vec = cache_image + .function_offsets + .iter() + .cloned() + .map(AssemblyOffset) + .collect(); + + let ec = X64ExecutionContext { + code: code_mem, + function_pointers, + function_offsets, + signatures: Arc::new(info.signatures.clone()), + breakpoints: Arc::new(HashMap::new()), + func_import_count: cache_image.func_import_count, + msm: cache_image.msm, + }; + Ok(ModuleInner { + runnable_module: Box::new(ec), + cache_gen: Box::new(SinglepassCache { + buffer: Arc::from(memory.as_slice().to_vec().into_boxed_slice()), + }), + + info, + }) } } diff --git a/lib/singlepass-backend/src/lib.rs b/lib/singlepass-backend/src/lib.rs index b920b56cdf3..5f3607b4576 100644 --- a/lib/singlepass-backend/src/lib.rs +++ b/lib/singlepass-backend/src/lib.rs @@ -20,6 +20,11 @@ compile_error!("This crate doesn't yet support compiling on operating systems ot extern crate dynasmrt; +extern crate serde; + +#[macro_use] +extern crate serde_derive; + #[macro_use] extern crate dynasm; From 70bc382843677c6a5823aed7b2cd6748506b09ee Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 28 Nov 2019 02:54:53 +0800 Subject: [PATCH 02/12] Add changelog entry. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60ff5c652ec..d3f542a6017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [#1006](https://github.com/wasmerio/wasmer/pull/1006) Fix minor panic issue when `wasmer::compile_with` called with llvm backend - [#1009](https://github.com/wasmerio/wasmer/pull/1009) Enable LLVM verifier for all tests, add new llvm-backend-tests crate. +- [#1022](https://github.com/wasmerio/wasmer/pull/1022) Add caching support for Singlepass backend. ## 0.11.0 - 2019-11-22 From c7f4ca5dd3896dc96e0ac4e5baee92d671bdcf9f Mon Sep 17 00:00:00 2001 From: losfair Date: Thu, 28 Nov 2019 03:01:09 +0800 Subject: [PATCH 03/12] Enable cache tests for singlepass. --- lib/runtime/src/cache.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/runtime/src/cache.rs b/lib/runtime/src/cache.rs index 7cc4386af3e..714fd9f5480 100644 --- a/lib/runtime/src/cache.rs +++ b/lib/runtime/src/cache.rs @@ -129,7 +129,7 @@ impl Cache for FileSystemCache { } } -#[cfg(all(test, not(feature = "singlepass")))] +#[cfg(test)] mod tests { use super::*; From 24ead779d6453d81ef2ea091be71812873842d40 Mon Sep 17 00:00:00 2001 From: Heyang Zhou Date: Thu, 28 Nov 2019 03:25:05 +0800 Subject: [PATCH 04/12] Remove extra '.'. Co-Authored-By: nlewycky --- lib/singlepass-backend/src/codegen_x64.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b867d60e1a7..d9f9d6f1ad4 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -245,7 +245,7 @@ pub struct CacheImage { /// Code for the whole module. code: Vec, - /// Offsets to the beginnings of each function. (including trampoline, if any) + /// Offsets to the beginnings of each function (including trampoline, if any). function_pointers: Vec, /// Offsets to the beginnings of each function after trampoline. From 513427be931f969350a6f702a3a2f7c55fa8caac Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 29 Nov 2019 01:30:08 +0800 Subject: [PATCH 05/12] Remove singlepass codegen dependence on runtime memory. --- lib/singlepass-backend/src/codegen_x64.rs | 52 ++++++++--------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index d9f9d6f1ad4..b5af131019b 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -3482,7 +3482,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static CANONICAL_NAN: u128 = 0x7FC0_0000; + static CANONICAL_NAN: u32 = 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)); @@ -3501,10 +3501,10 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::Imm32(CANONICAL_NAN), Location::GPR(tmpg1), ); - a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { @@ -3594,8 +3594,8 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static NEG_ZERO: u128 = 0x8000_0000; - static CANONICAL_NAN: u128 = 0x7FC0_0000; + static NEG_ZERO: u32 = 0x8000_0000; + static CANONICAL_NAN: u32 = 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)); @@ -3607,16 +3607,8 @@ 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(tmpg1), - ); - a.emit_mov( - Size::S64, - Location::Memory(tmpg1, 0), - Location::XMM(tmp_xmm2), - ); + a.emit_mov(Size::S64, Location::Imm32(NEG_ZERO), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), 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); @@ -3624,10 +3616,10 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::Imm32(CANONICAL_NAN), Location::GPR(tmpg1), ); - a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); a.emit_vblendvps(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { @@ -3906,7 +3898,7 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static CANONICAL_NAN: u128 = 0x7FF8_0000_0000_0000; + static CANONICAL_NAN: u64 = 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)); @@ -3925,10 +3917,10 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::Imm64(CANONICAL_NAN), Location::GPR(tmpg1), ); - a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { @@ -4018,8 +4010,8 @@ impl FunctionCodeGenerator for X64FunctionCode { 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; + static NEG_ZERO: u64 = 0x8000_0000_0000_0000; + static CANONICAL_NAN: u64 = 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)); @@ -4031,16 +4023,8 @@ 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(tmpg1), - ); - a.emit_mov( - Size::S64, - Location::Memory(tmpg1, 0), - Location::XMM(tmp_xmm2), - ); + a.emit_mov(Size::S64, Location::Imm64(NEG_ZERO), Location::GPR(tmpg1)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), 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); @@ -4048,10 +4032,10 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64((&CANONICAL_NAN as *const u128) as u64), + Location::Imm64(CANONICAL_NAN), Location::GPR(tmpg1), ); - a.emit_mov(Size::S64, Location::Memory(tmpg1, 0), Location::XMM(src2)); + a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); a.emit_vblendvpd(src1, XMMOrMemory::XMM(src2), tmp_xmm1, src1); match ret { Location::XMM(x) => { From c3f2481cedd22bb383b53a1bacaf9778ac14ab11 Mon Sep 17 00:00:00 2001 From: losfair Date: Fri, 29 Nov 2019 01:32:08 +0800 Subject: [PATCH 06/12] Update feature matrix. --- docs/feature_matrix.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/feature_matrix.md b/docs/feature_matrix.md index 54aa9810b43..18d30327051 100644 --- a/docs/feature_matrix.md +++ b/docs/feature_matrix.md @@ -4,11 +4,11 @@ |   | Singlepass | Cranelift | LLVM | | - | :-: | :-: | :-: | -| Caching | ⬜ | ✅ | ✅ | +| Caching | ✅ | ✅ | ✅ | | Emscripten | ✅ | ✅ | ✅ | | Metering | ✅ | ⬜ | ✅ | | Multi-value return | ⬜ | ⬜ | ⬜ | -| OSR | 🔄 | ❓ | ❓ | +| OSR | 🔄 | ⬜ | 🔄 | | SIMD | ⬜ | ⬜ | ✅ | | WASI | ✅ | ✅ | ✅ | | WASMER_BACKTRACE | ✅ | ⬜ | ⬜ | From 04d8df0a46af0c6be6af9c1090eb7e7cda2ff97d Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 3 Dec 2019 01:46:06 +0800 Subject: [PATCH 07/12] Add comments and remove unneeded `static`s. --- lib/singlepass-backend/src/codegen_x64.rs | 35 +++++++++++++---------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index b5af131019b..eee81e3b573 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -240,15 +240,18 @@ pub struct X64ExecutionContext { } /// On-disk cache format. +/// Offsets are relative to the start of the executable image. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct CacheImage { - /// Code for the whole module. + /// The executable image. code: Vec, - /// Offsets to the beginnings of each function (including trampoline, if any). + /// Offsets to the start of each function. Including trampoline, if any. + /// Trampolines are only present on AArch64. + /// On x86-64, `function_pointers` are identical to `function_offsets`. function_pointers: Vec, - /// Offsets to the beginnings of each function after trampoline. + /// Offsets to the start of each function after trampoline. function_offsets: Vec, /// Number of imported functions. @@ -3482,7 +3485,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static CANONICAL_NAN: u32 = 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)); @@ -3501,7 +3503,7 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm32(CANONICAL_NAN), + Location::Imm32(0x7FC0_0000), // Canonical NaN Location::GPR(tmpg1), ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); @@ -3594,8 +3596,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static NEG_ZERO: u32 = 0x8000_0000; - static CANONICAL_NAN: u32 = 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)); @@ -3607,7 +3607,11 @@ impl FunctionCodeGenerator for X64FunctionCode { a.emit_jmp(Condition::None, label2); a.emit_label(label1); // load float -0.0 - a.emit_mov(Size::S64, Location::Imm32(NEG_ZERO), Location::GPR(tmpg1)); + a.emit_mov( + Size::S64, + Location::Imm32(0x8000_0000), // Negative zero + Location::GPR(tmpg1), + ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp_xmm2)); a.emit_label(label2); a.emit_vcmpeqss(src1, XMMOrMemory::XMM(src2), tmp_xmm3); @@ -3616,7 +3620,7 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm32(CANONICAL_NAN), + Location::Imm32(0x7FC0_0000), // Canonical NaN Location::GPR(tmpg1), ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); @@ -3898,7 +3902,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static CANONICAL_NAN: u64 = 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)); @@ -3917,7 +3920,7 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64(CANONICAL_NAN), + Location::Imm64(0x7FF8_0000_0000_0000), // Canonical NaN Location::GPR(tmpg1), ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); @@ -4010,8 +4013,6 @@ impl FunctionCodeGenerator for X64FunctionCode { let tmp_xmm2 = XMM::XMM9; let tmp_xmm3 = XMM::XMM10; - static NEG_ZERO: u64 = 0x8000_0000_0000_0000; - static CANONICAL_NAN: u64 = 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)); @@ -4023,7 +4024,11 @@ 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), Location::GPR(tmpg1)); + a.emit_mov( + Size::S64, + Location::Imm64(0x8000_0000_0000_0000), // Negative zero + Location::GPR(tmpg1), + ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(tmp_xmm2)); a.emit_label(label2); a.emit_vcmpeqsd(src1, XMMOrMemory::XMM(src2), tmp_xmm3); @@ -4032,7 +4037,7 @@ impl FunctionCodeGenerator for X64FunctionCode { // load float canonical nan a.emit_mov( Size::S64, - Location::Imm64(CANONICAL_NAN), + Location::Imm64(0x7FF8_0000_0000_0000), // Canonical NaN Location::GPR(tmpg1), ); a.emit_mov(Size::S64, Location::GPR(tmpg1), Location::XMM(src2)); From 2eb11f50524200f9a1e1ae979db8589f4a953f01 Mon Sep 17 00:00:00 2001 From: losfair Date: Tue, 3 Dec 2019 01:46:13 +0800 Subject: [PATCH 08/12] Update Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f5cd33991f..eb081c3db9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2339,8 +2339,8 @@ 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)", - "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 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "wasmer-runtime-core 0.11.0", ] From 52348979890bcb6e326f8f9304ffcf1c77b4a2b4 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 2 Dec 2019 11:30:30 -0800 Subject: [PATCH 09/12] Improve portability of code by using c_char --- lib/emscripten/src/syscalls/unix.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/emscripten/src/syscalls/unix.rs b/lib/emscripten/src/syscalls/unix.rs index cb015af3a26..62d807c0273 100644 --- a/lib/emscripten/src/syscalls/unix.rs +++ b/lib/emscripten/src/syscalls/unix.rs @@ -7,6 +7,7 @@ use libc::{ accept, access, bind, + c_char, c_int, c_ulong, c_void, @@ -1063,14 +1064,14 @@ pub fn ___syscall220(ctx: &mut Ctx, _which: i32, mut varargs: VarArgs) -> i32 { let upper_bound = std::cmp::min((*dirent).d_reclen, 255) as usize; let mut i = 0; while i < upper_bound { - *(dirp.add(pos + 11 + i) as *mut i8) = (*dirent).d_name[i] as _; + *(dirp.add(pos + 11 + i) as *mut c_char) = (*dirent).d_name[i] as c_char; i += 1; } // We set the termination string char - *(dirp.add(pos + 11 + i) as *mut i8) = 0 as i8; + *(dirp.add(pos + 11 + i) as *mut c_char) = 0 as c_char; debug!( " => file {}", - CStr::from_ptr(dirp.add(pos + 11) as *const i8) + CStr::from_ptr(dirp.add(pos + 11) as *const c_char) .to_str() .unwrap() ); From ad752d66a7b8f4ca6746314119b0f11786c6092f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 2 Dec 2019 15:45:12 -0800 Subject: [PATCH 10/12] When modifying the value, also update its ExtraInfo. Fixes a debug_assert! on python3.7 and rustpython in wapm. --- lib/llvm-backend/src/code.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 7f7e1e32f6b..c0f6e07dd63 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -1730,15 +1730,17 @@ impl<'ctx> FunctionCodeGenerator for LLVMFunctionCodeGenerator<'ct // If the pending bits of v1 and v2 are the same, we can pass // them along to the result. Otherwise, apply pending // canonicalizations now. - let (v1, v2) = if i1.has_pending_f32_nan() != i2.has_pending_f32_nan() + let (v1, i1, v2, i2) = if i1.has_pending_f32_nan() != i2.has_pending_f32_nan() || i1.has_pending_f64_nan() != i2.has_pending_f64_nan() { ( apply_pending_canonicalization(builder, intrinsics, v1, i1), + i1.strip_pending(), apply_pending_canonicalization(builder, intrinsics, v2, i2), + i2.strip_pending(), ) } else { - (v1, v2) + (v1, i1, v2, i2) }; let cond_value = builder.build_int_compare( IntPredicate::NE, From 7c6d73d4d9ec64d6675772615e37ae0a841a0576 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 2 Dec 2019 15:49:33 -0800 Subject: [PATCH 11/12] Add test for debug-crash. This also was a wrong-code bug (I think), but we can't yet write tests for those. --- lib/llvm-backend-tests/tests/compile.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/llvm-backend-tests/tests/compile.rs b/lib/llvm-backend-tests/tests/compile.rs index edb59c4692f..17071a44a04 100644 --- a/lib/llvm-backend-tests/tests/compile.rs +++ b/lib/llvm-backend-tests/tests/compile.rs @@ -18,5 +18,23 @@ fn crash_return_with_float_on_stack() { "#; let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); - let instance = module.instantiate(&imports! {}).unwrap(); + module.instantiate(&imports! {}).unwrap(); +} + +#[test] +fn crash_select_with_mismatched_pending() { + const MODULE: &str = r#" + (module + (func (param f64) + f64.const 0x0p+0 (;=0;) + local.get 0 + f64.add + f64.const 0x0p+0 (;=0;) + i32.const 0 + select + drop)) +"#; + let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); + let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); + module.instantiate(&imports! {}).unwrap(); } From 3381e8867cba3dfc8a53fecf6477366e956ab3ff Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Mon, 2 Dec 2019 16:51:49 -0800 Subject: [PATCH 12/12] Fix some assorted warnings. --- lib/emscripten/src/lib.rs | 4 ++-- lib/middleware-common-tests/benches/metering_benchmark.rs | 4 ++-- lib/runtime/benches/many_instances.rs | 4 ++-- lib/singlepass-backend/src/emitter_x64.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 7dc808bde2b..1c9b8a1f70d 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -111,7 +111,7 @@ pub struct EmscriptenData<'a> { pub dyn_call_iii: Option>, pub dyn_call_iiii: Option>, pub dyn_call_iifi: Option>, - pub dyn_call_v: Option>, + pub dyn_call_v: Option>, pub dyn_call_vi: Option>, pub dyn_call_vii: Option>, pub dyn_call_viii: Option>, @@ -168,7 +168,7 @@ pub struct EmscriptenData<'a> { pub temp_ret_0: i32, pub stack_save: Option>, - pub stack_restore: Option>, + pub stack_restore: Option>, pub set_threw: Option>, pub mapped_dirs: HashMap, } diff --git a/lib/middleware-common-tests/benches/metering_benchmark.rs b/lib/middleware-common-tests/benches/metering_benchmark.rs index 79796646ad9..7c425ce991e 100644 --- a/lib/middleware-common-tests/benches/metering_benchmark.rs +++ b/lib/middleware-common-tests/benches/metering_benchmark.rs @@ -189,7 +189,7 @@ fn bench_metering(c: &mut Criterion) { let wasm_binary = wat2wasm(WAT).unwrap(); let module = compile_with(&wasm_binary, &compiler).unwrap(); let import_object = imports! {}; - let mut instance = module.instantiate(&import_object).unwrap(); + let instance = module.instantiate(&import_object).unwrap(); let add_to: Func<(i32, i32), i32> = instance.func("add_to").unwrap(); b.iter(|| black_box(add_to.call(100, 4))) }) @@ -202,7 +202,7 @@ fn bench_metering(c: &mut Criterion) { "gas" => Func::new(gas), }, }; - let mut gas_instance = gas_module.instantiate(&gas_import_object).unwrap(); + let gas_instance = gas_module.instantiate(&gas_import_object).unwrap(); let gas_add_to: Func<(i32, i32), i32> = gas_instance.func("add_to").unwrap(); b.iter(|| black_box(gas_add_to.call(100, 4))) }) diff --git a/lib/runtime/benches/many_instances.rs b/lib/runtime/benches/many_instances.rs index e1c655c789d..c10cf34e96f 100644 --- a/lib/runtime/benches/many_instances.rs +++ b/lib/runtime/benches/many_instances.rs @@ -4,7 +4,7 @@ use criterion::Criterion; use tempfile::tempdir; use wasmer_runtime::{ cache::{Cache, FileSystemCache, WasmHash}, - compile, func, imports, instantiate, validate, ImportObject, + compile, func, imports, instantiate, validate, }; use wasmer_runtime_core::vm::Ctx; @@ -71,7 +71,7 @@ fn calling_fn_benchmark(c: &mut Criterion) { ); let instance = instantiate(SIMPLE_WASM, &imports).unwrap(); c.bench_function("calling fn", move |b| { - let entry_point = instance.func::<(i32), i32>("plugin_entrypoint").unwrap(); + let entry_point = instance.func::("plugin_entrypoint").unwrap(); b.iter(|| entry_point.call(2).unwrap()) }); } diff --git a/lib/singlepass-backend/src/emitter_x64.rs b/lib/singlepass-backend/src/emitter_x64.rs index 0a6c04d08d6..0bf6fc2b079 100644 --- a/lib/singlepass-backend/src/emitter_x64.rs +++ b/lib/singlepass-backend/src/emitter_x64.rs @@ -1274,9 +1274,9 @@ impl Emitter for Assembler { fn emit_inline_breakpoint(&mut self, ty: InlineBreakpointType) { dynasm!(self ; ud2 - ; .byte 0x0f ; .byte (0xb9u8 as i8) // ud + ; .byte 0x0f ; .byte 0xb9u8 as i8 // ud ; int -1 - ; .byte (ty as u8 as i8) + ; .byte ty as u8 as i8 ); } }